source: rc/puzzlebox_brainstorms_client.py @ 26

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

server:

  • now listening on all server's interfaces

configuration:

  • now listening on all server's interfaces

client:

client_interface:

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