source: rc/puzzlebox_brainstorms_client.py @ 5

Last change on this file since 5 was 5, checked in by sc, 13 years ago

rc:

  • modified to use configuration module

server:

  • test_drive function added

configuration:

  • initial checkin

client:

  • initial checkin
File size: 16.1 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_common_operations as common_operations
24#import puzzlebox_logger
25
26
27#####################################################################
28# Globals
29#####################################################################
30
31SERVER_HOST = configuration.SERVER_HOST
32SERVER_PORT = configuration.SERVER_PORT
33
34MAX_CONNECTION_ATTEMPTS = configuration.MAX_CONNECTION_ATTEMPTS
35#HEALTH_CHECK_CONNECTION_ATTEMPTS = puzzlebox_configuration.HEALTH_CHECK_CONNECTION_ATTEMPTS
36NO_REPLY_WAIT = configuration.NO_REPLY_WAIT
37
38
39#####################################################################
40# Classes
41#####################################################################
42
43#####################################################################
44# MCC Base class
45#####################################################################
46
47class puzzlebox_brainstorms_client:
48
49        def __init__(self, log, hostname, port, \
50                          service_name = 'MCC', \
51                          target_name = 'MCP', \
52                          max_connection_attempts = MAX_CONNECTION_ATTEMPTS):
53
54                self.log = log
55                self.hostname = hostname
56                self.port = port
57                self.service_name = service_name
58                self.target_name = target_name
59                self.max_connection_attempts = max_connection_attempts
60
61
62        ##################################################################
63
64        def test_drive(self):
65
66                instruction = {}
67                instruction['command'] = 'test_drive'
68
69                #self.log.debug("Requesting to hide_all_components")
70
71                return self.send_instruction(instruction)
72
73
74        ##################################################################
75
76        #def hide_all_components(self):
77
78                #instruction = {}
79                #instruction['command'] = 'hide_all_components'
80
81                #self.log.debug("Requesting to hide_all_components")
82
83                #return self.send_instruction(instruction)
84
85
86        ##################################################################
87
88        #def register_window(self, window_id):
89
90                #instruction = {}
91                #instruction['command'] = 'register_window'
92                #instruction['information'] = {}
93                #instruction['information']['window_id'] = window_id
94
95                #return self.send_instruction(instruction)
96
97
98        ##################################################################
99
100        #def get_window_data(self, window_id):
101
102                #instruction = {}
103                #instruction['command'] = 'get_window_data'
104                #instruction['information'] = {}
105                #instruction['information']['window_id'] = window_id
106               
107                #return self.send_instruction(instruction)
108
109
110        ##################################################################
111
112        #def get_registry(self):
113               
114                #registry = {}
115               
116                #instruction = {}
117                #instruction['command'] = 'get_registry'
118                #instruction['information'] = {}
119               
120                #return self.send_instruction(instruction)
121
122
123        ##################################################################
124
125        #def unregister_all_windows(self):
126
127                #instruction = {}
128                #instruction['command'] = 'unregister_all_windows'
129                #instruction['information'] = {}
130
131                #return self.send_instruction(instruction)
132
133
134        ##################################################################
135
136        #def unregister_component(self, component):
137
138                #instruction = {}
139                #instruction['command'] = 'unregister_component'
140                #instruction['information'] = {}
141                #instruction['information']['pid'] = component['pid']
142
143                #return self.send_instruction(instruction)
144
145
146        ##################################################################
147
148        #def restart_component(self, component):
149
150                #instruction = {}
151                #instruction['command'] = 'restart_component'
152                #instruction['information'] = {}
153                #instruction['information']['pid'] = component['pid']
154
155                #return self.send_instruction(instruction)
156
157
158        ##################################################################
159
160        #def exit_content_set(self):
161
162                #instruction = {}
163                #instruction['command'] = 'exit_content_set'
164                #instruction['information'] = {}
165
166                #return self.send_instruction(instruction)
167
168
169        ##################################################################
170
171        #def change_content_set(self, data):
172
173                #instruction = {}
174                #instruction['command'] = 'change_content_set'
175                #instruction['information'] = {}
176                #instruction['information']['content_set_id'] = data['content_set_id']
177
178                #return self.send_instruction(instruction)
179
180
181        ##################################################################
182
183        #def end_current_entry(self, data):
184
185                #instruction = {}
186                #instruction['command'] = 'end_current_entry'
187                #instruction['information'] = {}
188                #instruction['information']['window_id'] = data['window_id']
189
190                #return self.send_instruction(instruction)
191
192
193        ##################################################################
194
195        #def request_screenshot(self):
196
197                #instruction = {}
198                #instruction['command'] = 'request_screenshot'
199                #instruction['information'] = {}
200
201                #return self.send_instruction(instruction)
202
203
204        ##################################################################
205
206        #def upload_screenshot(self):
207
208                #instruction = {}
209                #instruction['command'] = 'upload_screenshot'
210                #instruction['information'] = {}
211
212                #return self.send_instruction(instruction)
213
214
215        ##################################################################
216
217        #def export_schedule(self, data):
218
219                #instruction = {}
220                #instruction['command'] = 'export_schedule'
221                #instruction['information'] = {}
222
223                #for key in data.keys():
224                        #instruction['information'][key] = data[key]
225
226                #return self.send_instruction(instruction)
227
228
229        ##################################################################
230
231        #def check_health(self, component={}):
232
233                #instruction = {}
234                #instruction['command'] = 'check_health'
235                #instruction['information'] = {}
236
237                #return self.send_instruction(instruction, component, \
238                                        #max_connection_attempts=HEALTH_CHECK_CONNECTION_ATTEMPTS)
239
240
241        ##################################################################
242
243        def send_instruction(self, instruction, component=None, \
244                                        max_connection_attempts=MAX_CONNECTION_ATTEMPTS):
245
246                if not component:
247                        component = {}
248                        component['hostname'] = self.hostname
249                        component['port'] = self.port
250                        component['source'] = self.service_name
251                        component['target'] = self.target_name
252
253                factory = puzzlebox_brainstorms_client_send_instruction_factory(self.log, \
254                                                       component, \
255                                                       instruction, \
256                                                       max_connection_attempts)
257
258                reactor.connectTCP(component['hostname'], component['port'], factory)
259
260                return factory.replyDefer
261
262
263#####################################################################
264# MCC Protocol class
265#####################################################################
266
267class mcc_send_instruction_protocol(protocol.Protocol):
268
269        def __init__(self):
270                self.data_chunk = ""
271
272
273        ##################################################################
274
275        def connectionMade(self):
276                data = pickle.dumps(self.factory.instruction)
277                self.transport.write(data)
278
279                #self.factory.log.debug("%s sent '%s' to remote %s component at %s:%s " % \
280                                #(self.factory.component['source'], \
281                                 #self.factory.instruction['command'], \
282                                 #self.factory.component['target'], \
283                                 #self.factory.component['hostname'], \
284                                 #self.factory.component['port']))
285
286                self.factory.noReply = reactor.callLater(NO_REPLY_WAIT, self.noReply)
287
288
289        ##################################################################
290
291        def noReply(self):
292
293                #self.factory.log.error('No reply from %s for instruction %s' % \
294                        #(self.factory.component['target'], self.factory.instruction))
295
296                try:
297                        self.factory.replyDefer.callback(('NO_REPLY', self.factory.component))
298                except:
299                        self.factory.log.error("noReply failed to call callback?")
300
301                self.transport.loseConnection()
302
303
304        ##################################################################
305
306        def dataReceived(self, data):
307
308                try:
309                        self.factory.noReply.cancel()
310                except:
311                        self.factory.log.error("dataReceived after noReply triggered (or cancelled)?!")
312
313                self.data_chunk += data
314                try:
315                        reply = pickle.loads(self.data_chunk)
316                except Exception, e:
317                        self.factory.log.error("Partial data received (or error: %s)." % e)
318                else:
319                        self.data_chunk = ""
320
321                        #self.factory.log.debug('%s received reply from %s: %s' % \
322                                #(self.factory.component['source'], \
323                                 #self.factory.component['target'], \
324                                 #reply))
325
326                        try:
327                                self.factory.replyDefer.callback((reply, self.factory.component))
328                        except:
329                                #self.factory.log.error("dataReceived failed to call callback?")
330                                pass
331
332                        self.transport.loseConnection()
333
334
335#####################################################################
336# MCC Factory class
337#####################################################################
338
339class puzzlebox_brainstorms_client_send_instruction_factory(protocol.ClientFactory):
340
341        def __init__(self, log, \
342                     component, \
343                     instruction, \
344                     max_connection_attempts=MAX_CONNECTION_ATTEMPTS):
345
346                self.protocol = mcc_send_instruction_protocol
347                self.log = log
348                self.component = component
349                self.instruction = instruction
350
351                self.max_connection_attempts = max_connection_attempts
352                self.connection_attempt = 1
353
354                self.replyDefer = defer.Deferred()
355
356
357        ##################################################################
358
359        def clientConnectionFailed(self, connector, reason):
360               
361                #self.log.error("%s failed to connect to remote %s compontent at %s:%i" % \
362                                #(self.component['source'], \
363                                 #self.component['target'], \
364                                 #self.component['hostname'], \
365                                 #self.component['port']))
366
367                reply='FAILED_TO_CONNECT'
368
369                self.connection_attempt = self.connection_attempt + 1
370
371                if self.max_connection_attempts == None or \
372                        self.connection_attempt <= self.max_connection_attempts:
373
374                        # If connection failed retry after one second
375                        reactor.callLater(1, connector.connect)
376
377                else:
378                        #self.log.error("Maximum connection retries from %s to %s reached, aborting" % \
379                                 #(self.component['source'], self.component['target']))
380                        pass
381
382                        self.replyDefer.callback((reply, self.component))
383
384
385        ##################################################################
386
387        def clientConnectionLost(self, connector, reason):
388
389                # Losing Connection is expected after data exchange is complete
390                #self.log.debug("Connection to %s lost for instruction %s" % (self.component, self.instruction))
391                try:
392                        self.replyDefer.callback((reason, self.component))
393                except:
394                        pass
395
396
397#####################################################################
398# Command line class
399#####################################################################
400
401class puzzlebox_brainstorms_client_command_line(puzzlebox_brainstorms_client):
402
403        def __init__(self, log, command_parameters, SERVER_HOST, SERVER_PORT):
404               
405                self.log = log
406                self.command_parameters = command_parameters
407                self.hostname = SERVER_HOST
408                self.port = SERVER_PORT
409                self.service_name = 'MCC-CL'
410                self.target_name = 'MCP'
411                self.max_connection_attempts = MAX_CONNECTION_ATTEMPTS
412
413
414        ##################################################################
415
416        def execute_command_line(self):
417
418                (command, information) = self.parse_command_list(self.command_parameters)
419
420                instruction = {}
421                instruction['command'] = command
422                instruction['information'] = information
423
424                d = self.send_instruction(instruction)
425                d.addCallback(self.print_response_and_stop)
426
427
428        ##################################################################
429       
430        def print_response_and_stop(self, response):
431       
432                print response[0]
433       
434                reactor.stop()
435
436       
437        ##################################################################
438
439        def parse_command_list(self, command_parameters):
440
441                command = None
442                data = {}
443
444                if (command_parameters[0] == 'test_drive'):
445
446                        command = 'test_drive'
447
448
449                #if command_parameters[0] == '/usr/sbin/chroot':
450
451                        #self.command_parameters = command_parameters[:5]
452                        #command_parameters = command_parameters[5:]
453                        #if self.DEBUG:
454                                #print "Chroot command parameters:",
455                                #print self.command_parameters
456                                #print "Data command parameters:",
457                                #print command_parameters
458
459
460                #elif (command_parameters[0] == 'hide_all_components'):
461
462                        #command = 'hide_all_components'
463
464
465                #elif (command_parameters[0] == 'unregister_all_windows'):
466
467                        #command = 'unregister_all_windows'
468
469
470                #elif (command_parameters[0] == 'unregister_component'):
471
472                        #command = 'unregister_component'
473                        #data['pid'] = int(command_parameters[-1])
474
475
476                #elif (command_parameters[0] == 'restart_component'):
477
478                        #command = 'restart_component'
479                        #data['pid'] = int(command_parameters[-1])
480
481
482                #elif (command_parameters[0] == 'animation_started'):
483
484                        #command = 'animation_started'
485                        #data['window_id'] = int(command_parameters[-1])
486
487
488                #elif (command_parameters[0] == 'register_window'):
489
490                        #command = 'register_window'
491                        #data['window_id'] = int(command_parameters[-1])
492
493
494                #elif (command_parameters[0] == 'register_channel_detection'):
495
496                        #command = 'register_component'
497                        #data['type'] = 'channel_detection'
498                        #data['pid'] = int(command_parameters[-2])
499                        #data['device'] = command_parameters[-1]
500
501
502                #elif (command_parameters[0] == 'exit_content_set'):
503
504                        #command = 'exit_content_set'
505
506
507                #elif (command_parameters[0] == 'change_content_set'):
508
509                        #command = 'change_content_set'
510                        #data['content_set_id'] = int(command_parameters[-1])
511
512
513                #elif (command_parameters[0] == 'end_current_entry'):
514
515                        #command = 'end_current_entry'
516                        #data['window_id'] = int(command_parameters[-1])
517
518
519                #elif (command_parameters[0] == 'request_screenshot'):
520
521                        #command = 'request_screenshot'
522
523
524                #elif (command_parameters[0] == 'upload_screenshot'):
525
526                        #command = 'upload_screenshot'
527
528
529                #elif (command_parameters[0] == 'check_health'):
530
531                        #command = 'check_health'
532
533                        #if self.DEBUG > 1:
534                                #print "-->Check health command parameters:", command_parameters
535
536                        #data['hostname'] = command_parameters[1]
537                        #data['port'] = command_parameters[2]
538                        #data['source'] = command_parameters[3]
539                        #data['target'] = command_parameters[4]
540                        #data['execute_inside_screen'] = False
541
542
543                #elif (command_parameters[0] == 'export_schedule'):
544
545                        #command = 'export_schedule'
546                        #data['content_set_sequence_schedule_id'] = int(command_parameters[-1])
547
548
549                else:
550
551                        self.log.error("Unrecognized command received: %s" % command_parameters[0])
552
553
554                return (command, data)
555
556
557        ##################################################################
558
559        #def run_blocking_mcc_command(self, instruction, \
560                                #component={}, \
561                                #max_connection_attempts = MAX_CONNECTION_ATTEMPTS):
562
563                #command = 'puzzlebox_master_control_client.py'
564                #command = '%s %s' % (command, instruction['command'])
565
566                #if 'hostname' in component.keys() and \
567                                #component['hostname'] != None:
568                        #command = '%s %s' % (command, component['hostname'])
569
570                #if 'port' in component.keys() and \
571                                #component['port'] != None:
572                        #command = '%s %s' % (command, component['port'])
573
574                #if 'source' in component.keys() and \
575                                #component['source'] != None:
576                        #command = '%s %s' % (command, component['source'])
577
578                #if 'target' in component.keys() and \
579                                #component['target'] != None:
580                        #command = '%s %s' % (command, component['target'])
581
582                #if 'information' in instruction.keys() and \
583                                #'window_id' in instruction['information'].keys():
584                        #command = '%s %s' % (command, instruction['information']['window_id'])
585
586                #self.log.info("Executing external command: [%s]" % command)
587
588                #result = os.popen(command, 'r').read()
589                #result = result.strip()
590
591                #print "MCC-CL Result:",
592                #print result
593
594                #return result
595
596
597#####################################################################
598# Main
599#####################################################################
600
601if __name__ == '__main__':
602
603        #log = puzzlebox_logger.puzzlebox_logger(logfile='mcc')
604        log = None
605
606        command_parameters = sys.argv[1:]
607
608        #log.info("Command parameters: %s" % command_parameters)
609
610        client = puzzlebox_brainstorms_client_command_line(log, command_parameters, SERVER_HOST, SERVER_PORT)
611        reactor.callWhenRunning(client.execute_command_line)
612        reactor.run()
613
Note: See TracBrowser for help on using the repository browser.