source: rc/puzzlebox_brainstorms_client.py @ 17

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

client:

  • deprecated comment cleanup

client_interface:

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