source: rc/puzzlebox_brainstorms_client.py @ 7

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

all driving commands added to client and server

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