source: rc/puzzlebox_brainstorms_client.py @ 16

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

client:

  • drive_reverse fixed
File size: 10.4 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.01
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#####################################################################
39# Classes
40#####################################################################
41
42#####################################################################
43# MCC Base class
44#####################################################################
45
46class puzzlebox_brainstorms_client:
47       
48        def __init__(self, log, hostname, port, \
49                          service_name = 'MCC', \
50                          target_name = 'MCP', \
51                          max_connection_attempts = MAX_CONNECTION_ATTEMPTS):
52               
53                self.log = log
54                self.hostname = hostname
55                self.port = port
56                self.service_name = service_name
57                self.target_name = target_name
58                self.max_connection_attempts = max_connection_attempts
59       
60       
61        ##################################################################
62       
63        #def test_drive(self):
64               
65                #instruction = {}
66                #instruction['command'] = 'test_drive'
67               
68                ##self.log.debug("Requesting to hide_all_components")
69               
70                #return self.send_instruction(instruction)
71       
72       
73        ##################################################################
74       
75        def send_instruction(self, instruction, component=None, \
76                                        max_connection_attempts=MAX_CONNECTION_ATTEMPTS):
77               
78                if not component:
79                        component = {}
80                        component['hostname'] = self.hostname
81                        component['port'] = self.port
82                        component['source'] = self.service_name
83                        component['target'] = self.target_name
84               
85                factory = puzzlebox_brainstorms_client_send_instruction_factory(self.log, \
86                                                       component, \
87                                                       instruction, \
88                                                       max_connection_attempts)
89               
90                reactor.connectTCP(component['hostname'], component['port'], factory)
91               
92                return factory.replyDefer
93
94
95#####################################################################
96# MCC Protocol class
97#####################################################################
98
99class mcc_send_instruction_protocol(protocol.Protocol):
100       
101        def __init__(self):
102                self.data_chunk = ""
103       
104       
105        ##################################################################
106       
107        def connectionMade(self):
108                data = pickle.dumps(self.factory.instruction)
109                self.transport.write(data)
110               
111                #self.factory.log.debug("%s sent '%s' to remote %s component at %s:%s " % \
112                                #(self.factory.component['source'], \
113                                 #self.factory.instruction['command'], \
114                                 #self.factory.component['target'], \
115                                 #self.factory.component['hostname'], \
116                                 #self.factory.component['port']))
117               
118                self.factory.noReply = reactor.callLater(NO_REPLY_WAIT, self.noReply)
119       
120       
121        ##################################################################
122       
123        def noReply(self):
124               
125                #self.factory.log.error('No reply from %s for instruction %s' % \
126                        #(self.factory.component['target'], self.factory.instruction))
127               
128                try:
129                        self.factory.replyDefer.callback(('NO_REPLY', self.factory.component))
130                except:
131                        self.factory.log.error("noReply failed to call callback?")
132               
133                self.transport.loseConnection()
134       
135       
136        ##################################################################
137       
138        def dataReceived(self, data):
139               
140                try:
141                        self.factory.noReply.cancel()
142                except:
143                        self.factory.log.error("dataReceived after noReply triggered (or cancelled)?!")
144               
145                self.data_chunk += data
146                try:
147                        reply = pickle.loads(self.data_chunk)
148                except Exception, e:
149                        self.factory.log.error("Partial data received (or error: %s)." % e)
150                else:
151                        self.data_chunk = ""
152                       
153                        #self.factory.log.debug('%s received reply from %s: %s' % \
154                                #(self.factory.component['source'], \
155                                 #self.factory.component['target'], \
156                                 #reply))
157                       
158                        try:
159                                self.factory.replyDefer.callback((reply, self.factory.component))
160                        except:
161                                #self.factory.log.error("dataReceived failed to call callback?")
162                                pass
163                       
164                        self.transport.loseConnection()
165
166
167#####################################################################
168# MCC Factory class
169#####################################################################
170
171class puzzlebox_brainstorms_client_send_instruction_factory(protocol.ClientFactory):
172               
173        def __init__(self, log, \
174                     component, \
175                     instruction, \
176                     max_connection_attempts=MAX_CONNECTION_ATTEMPTS):
177               
178                self.protocol = mcc_send_instruction_protocol
179                self.log = log
180                self.component = component
181                self.instruction = instruction
182               
183                self.max_connection_attempts = max_connection_attempts
184                self.connection_attempt = 1
185               
186                self.replyDefer = defer.Deferred()
187       
188       
189        ##################################################################
190       
191        def clientConnectionFailed(self, connector, reason):
192               
193                #self.log.error("%s failed to connect to remote %s compontent at %s:%i" % \
194                                #(self.component['source'], \
195                                 #self.component['target'], \
196                                 #self.component['hostname'], \
197                                 #self.component['port']))
198               
199                reply='FAILED_TO_CONNECT'
200               
201                self.connection_attempt = self.connection_attempt + 1
202               
203                if self.max_connection_attempts == None or \
204                        self.connection_attempt <= self.max_connection_attempts:
205               
206                        # If connection failed retry after one second
207                        reactor.callLater(1, connector.connect)
208               
209                else:
210                        #self.log.error("Maximum connection retries from %s to %s reached, aborting" % \
211                                       #(self.component['source'], self.component['target']))
212                        pass
213                       
214                        self.replyDefer.callback((reply, self.component))
215       
216       
217        ##################################################################
218       
219        def clientConnectionLost(self, connector, reason):
220               
221                # Losing Connection is expected after data exchange is complete
222                #self.log.debug("Connection to %s lost for instruction %s" % (self.component, self.instruction))
223                try:
224                        self.replyDefer.callback((reason, self.component))
225                except:
226                        pass
227
228
229#####################################################################
230# Command line class
231#####################################################################
232
233class puzzlebox_brainstorms_client_command_line(puzzlebox_brainstorms_client):
234       
235        def __init__(self, log, \
236                          command_parameters, \
237                          server_host=SERVER_HOST, \
238                          server_port=SERVER_PORT, \
239                          DEBUG=DEBUG):
240               
241                self.log = log
242                self.DEBUG=DEBUG
243               
244                self.command_parameters = command_parameters
245                self.hostname = SERVER_HOST
246                self.port = SERVER_PORT
247                self.service_name = 'MCC-CL'
248                self.target_name = 'MCP'
249                self.max_connection_attempts = MAX_CONNECTION_ATTEMPTS
250       
251       
252        ##################################################################
253       
254        def execute_command_line(self):
255               
256                (command, information) = self.parse_command_list(self.command_parameters)
257               
258                instruction = {}
259                instruction['command'] = command
260                instruction['information'] = information
261               
262                d = self.send_instruction(instruction)
263                d.addCallback(self.print_response_and_stop)
264       
265       
266        ##################################################################
267       
268        def print_response_and_stop(self, response):
269               
270                print response[0]
271               
272                reactor.stop()
273       
274       
275        ##################################################################
276       
277        def parse_command_list(self, command_parameters):
278               
279                command = None
280                data = {}
281               
282                if (command_parameters[0] == 'test_drive'):
283                        command = 'test_drive'
284                elif (command_parameters[0] == 'drive_forward'):
285                        command = 'drive_forward'
286                elif (command_parameters[0] == 'drive_reverse'):
287                        command = 'drive_reverse'
288                elif (command_parameters[0] == 'turn_left'):
289                        command = 'turn_left'
290                elif (command_parameters[0] == 'turn_right'):
291                        command = 'turn_right'
292                elif (command_parameters[0] == 'turn_in_reverse'):
293                        command = 'turn_in_reverse'
294               
295               
296                else:
297                        self.log.error("Unrecognized command received: %s" % command_parameters[0])
298               
299               
300                return (command, data)
301       
302       
303        ##################################################################
304       
305        #def run_blocking_mcc_command(self, instruction, \
306                                #component={}, \
307                                #max_connection_attempts = MAX_CONNECTION_ATTEMPTS):
308               
309                #command = 'puzzlebox_master_control_client.py'
310                #command = '%s %s' % (command, instruction['command'])
311               
312                #if 'hostname' in component.keys() and \
313                                #component['hostname'] != None:
314                        #command = '%s %s' % (command, component['hostname'])
315               
316                #if 'port' in component.keys() and \
317                                #component['port'] != None:
318                        #command = '%s %s' % (command, component['port'])
319               
320                #if 'source' in component.keys() and \
321                                #component['source'] != None:
322                        #command = '%s %s' % (command, component['source'])
323               
324                #if 'target' in component.keys() and \
325                                #component['target'] != None:
326                        #command = '%s %s' % (command, component['target'])
327               
328                #if 'information' in instruction.keys() and \
329                                #'window_id' in instruction['information'].keys():
330                        #command = '%s %s' % (command, instruction['information']['window_id'])
331               
332                #self.log.info("Executing external command: [%s]" % command)
333               
334                #result = os.popen(command, 'r').read()
335                #result = result.strip()
336               
337                #print "MCC-CL Result:",
338                #print result
339               
340                #return result
341
342
343#####################################################################
344# Main
345#####################################################################
346
347if __name__ == '__main__':
348       
349        #log = puzzlebox_logger.puzzlebox_logger(logfile='mcc')
350        log = None
351       
352        command_parameters = sys.argv[1:]
353       
354        #log.info("Command parameters: %s" % command_parameters)
355       
356        client = puzzlebox_brainstorms_client_command_line(log, \
357                                                           command_parameters, \
358                                                           server_host=SERVER_HOST, \
359                                                           server_port=SERVER_PORT, \
360                                                           DEBUG=DEBUG)
361        reactor.callWhenRunning(client.execute_command_line)
362        reactor.run()
363
Note: See TracBrowser for help on using the repository browser.