source: rc/puzzlebox_brainstorms_client.py @ 33

Last change on this file since 33 was 31, checked in by sc, 12 years ago

GPL v2 header added to all files

File size: 7.6 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4# Puzzlebox - Brainstorms - Client
5#
6# Copyright Puzzlebox Productions, LLC (2010)
7#
8# This code is released under the GNU Pulic License (GPL) version 2
9# For more information please refer to http://www.gnu.org/copyleft/gpl.html
10#
11# Last Update: 2010.02.03
12#
13#####################################################################
14
15import os, sys
16import cPickle as pickle
17
18from twisted.internet import reactor, protocol, defer
19
20import puzzlebox_brainstorms_configuration as configuration
21#import puzzlebox_logger
22
23#####################################################################
24# Globals
25#####################################################################
26
27DEBUG = 1
28
29SERVER_HOST = configuration.SERVER_HOST
30SERVER_PORT = configuration.SERVER_PORT
31
32MAX_CONNECTION_ATTEMPTS = configuration.MAX_CONNECTION_ATTEMPTS
33NO_REPLY_WAIT = configuration.NO_REPLY_WAIT
34
35#####################################################################
36# Classes
37#####################################################################
38
39class puzzlebox_brainstorms_client:
40       
41        def __init__(self, log, \
42                          server_host, \
43                          server_port, \
44                          max_connection_attempts = MAX_CONNECTION_ATTEMPTS):
45               
46                self.log = log
47                self.server_host = server_host
48                self.server_port = server_port
49                self.max_connection_attempts = max_connection_attempts
50       
51       
52        ##################################################################
53       
54        def send_command(self, \
55                         command, \
56                         max_connection_attempts=MAX_CONNECTION_ATTEMPTS):
57               
58                factory = puzzlebox_brainstorms_client_send_command_factory(self.log, \
59                                                       command, \
60                                                       self.server_host, \
61                                                       self.server_port, \
62                                                       max_connection_attempts, \
63                                                       self.DEBUG)
64               
65                reactor.connectTCP(self.server_host, self.server_port, factory)
66               
67                return factory.replyDefer
68
69
70#####################################################################
71# Client Protocol class
72#####################################################################
73
74class puzzlebox_brainstorms_client_send_command_protocol(protocol.Protocol):
75       
76        def __init__(self):
77               
78                self.DEBUG = DEBUG
79                self.data_chunk = ""
80       
81       
82        ##################################################################
83       
84        def connectionMade(self):
85               
86                data = pickle.dumps(self.factory.command)
87                self.transport.write(data)
88               
89                self.factory.noReply = reactor.callLater(NO_REPLY_WAIT, self.noReply)
90       
91       
92        ##################################################################
93       
94        def noReply(self):
95               
96                try:
97                        self.factory.replyDefer.callback('NO_REPLY')
98                except:
99                        if self.DEBUG:
100                                print "noReply failed to call callback"
101                        #self.factory.log.error("noReply failed to call callback")
102               
103                self.transport.loseConnection()
104       
105       
106        ##################################################################
107       
108        def dataReceived(self, data):
109               
110                try:
111                        self.factory.noReply.cancel()
112                except:
113                        if self.DEBUG:
114                                print "dataReceived after noReply triggered (or cancelled)"
115                        #self.factory.log.error("dataReceived after noReply triggered (or cancelled)")
116               
117                self.data_chunk += data
118               
119                try:
120                        reply = pickle.loads(self.data_chunk)
121                except Exception, e:
122                        if self.DEBUG:
123                                print "Partial data received (or error: %s)." % e
124                        #self.factory.log.error("Partial data received (or error: %s)." % e)
125                else:
126                        self.data_chunk = ""
127                       
128                        try:
129                                self.factory.replyDefer.callback(reply)
130                        except:
131                                if self.DEBUG:
132                                        print "dataReceived failed to call callback"
133                                #self.factory.log.error("dataReceived failed to call callback")
134                                pass
135                       
136                        self.transport.loseConnection()
137
138
139#####################################################################
140# Client Factory class
141#####################################################################
142
143class puzzlebox_brainstorms_client_send_command_factory(protocol.ClientFactory):
144       
145        def __init__(self, log, \
146                     command, \
147                     server_host=SERVER_HOST, \
148                     server_port=SERVER_PORT, \
149                     max_connection_attempts=MAX_CONNECTION_ATTEMPTS, \
150                     DEBUG=DEBUG):
151               
152                self.log = log
153                self.DEBUG = DEBUG
154                self.server_host = server_host
155                self.server_port = server_port
156                self.command = command
157               
158                self.max_connection_attempts = max_connection_attempts
159                self.connection_attempt = 1
160               
161                self.protocol = \
162                   puzzlebox_brainstorms_client_send_command_protocol
163               
164                self.replyDefer = defer.Deferred()
165       
166       
167        ##################################################################
168       
169        def clientConnectionFailed(self, connector, reason):
170               
171                if self.DEBUG:
172                        print "Client failed to connect to remote component at %s:%i" % \
173                           (self.server_host, self.server_port)
174               
175                reply = 'FAILED_TO_CONNECT'
176               
177                self.connection_attempt = self.connection_attempt + 1
178               
179                if ((self.max_connection_attempts == None) or \
180                         (self.connection_attempt <= self.max_connection_attempts)):
181                       
182                        # If connection failed retry after one second
183                        reactor.callLater(1, connector.connect)
184               
185                else:
186                        if self.DEBUG:
187                                print "Maximum connection retries reached, aborting"
188                       
189                       
190                        self.replyDefer.callback(reply)
191       
192       
193        ##################################################################
194       
195        def clientConnectionLost(self, connector, reason):
196               
197                # Losing Connection is expected after data exchange is complete
198                try:
199                        self.replyDefer.callback(reason)
200                except:
201                        pass
202
203
204#####################################################################
205# Command line class
206#####################################################################
207
208class puzzlebox_brainstorms_client_command_line(puzzlebox_brainstorms_client):
209       
210        def __init__(self, log, \
211                          command_parameters, \
212                          server_host=SERVER_HOST, \
213                          server_port=SERVER_PORT, \
214                          DEBUG=DEBUG):
215               
216                self.log = log
217                self.DEBUG=DEBUG
218               
219                self.command_parameters = command_parameters
220                self.server_host = SERVER_HOST
221                self.server_port = SERVER_PORT
222                self.max_connection_attempts = MAX_CONNECTION_ATTEMPTS
223       
224       
225        ##################################################################
226       
227        def execute_command_line(self):
228               
229                (command) = self.parse_command_line(self.command_parameters)
230               
231                d = self.send_command(command)
232                d.addCallback(self.print_response_and_stop)
233       
234       
235        ##################################################################
236       
237        def print_response_and_stop(self, response):
238               
239                if self.DEBUG:
240                        print "---> [Client] Server Response:",
241                        print response
242               
243                try:
244                        reactor.stop()
245                except:
246                        print "ERROR: Can't stop reactor that isn't running."
247       
248       
249        ##################################################################
250       
251        def parse_command_line(self, command_parameters):
252               
253                try:
254                        command = command_parameters[0]
255                except:
256                        command = None
257               
258               
259                return(command)
260
261
262#####################################################################
263# Main
264#####################################################################
265
266if __name__ == '__main__':
267       
268        #log = puzzlebox_logger.puzzlebox_logger(logfile='client')
269        log = None
270       
271        command_parameters = sys.argv[1:]
272       
273        #log.info("Command parameters: %s" % command_parameters)
274       
275        client = puzzlebox_brainstorms_client_command_line(log, \
276                                                           command_parameters, \
277                                                           server_host=SERVER_HOST, \
278                                                           server_port=SERVER_PORT, \
279                                                           DEBUG=DEBUG)
280       
281        reactor.callWhenRunning(client.execute_command_line)
282        reactor.run()
283
Note: See TracBrowser for help on using the repository browser.