1 | #!/usr/bin/env python |
---|
2 | # -*- coding: utf-8 -*- |
---|
3 | # |
---|
4 | # Puzzlebox - Brainstorms - Server |
---|
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.27 |
---|
14 | # |
---|
15 | ##################################################################### |
---|
16 | |
---|
17 | import os, signal, time |
---|
18 | import cPickle as pickle |
---|
19 | |
---|
20 | from twisted.internet import reactor, protocol, defer |
---|
21 | |
---|
22 | #import puzzlebox_configuration |
---|
23 | import puzzlebox_master_control_client |
---|
24 | #import puzzlebox_logger |
---|
25 | |
---|
26 | |
---|
27 | ##################################################################### |
---|
28 | # Globals |
---|
29 | ##################################################################### |
---|
30 | |
---|
31 | DEBUG = 1 |
---|
32 | |
---|
33 | #SERVER_HOST = puzzlebox_configuration.SERVER_HOST |
---|
34 | #SERVER_PORT = puzzlebox_configuration.SERVER_PORT |
---|
35 | SERVER_HOST = '127.0.0.1' |
---|
36 | SERVER_PORT = 8194 |
---|
37 | |
---|
38 | #MAX_COMPONENTS = puzzlebox_configuration.MAX_COMPONENTS |
---|
39 | #GTKMOZ_PROFILE_DIR = puzzlebox_configuration.GTKMOZ_PROFILE_DIR |
---|
40 | #AUTOBIT_TIMEOUT = puzzlebox_configuration.AUTOBIT_TIMEOUT |
---|
41 | |
---|
42 | |
---|
43 | ##################################################################### |
---|
44 | # Classes |
---|
45 | ##################################################################### |
---|
46 | |
---|
47 | class puzzlebox_master_control(protocol.ServerFactory): |
---|
48 | |
---|
49 | def __init__(self, log, DEBUG=DEBUG): |
---|
50 | |
---|
51 | self.protocol = puzzlebox_master_control_server_protocol |
---|
52 | |
---|
53 | self.log = log |
---|
54 | self.DEBUG = DEBUG |
---|
55 | |
---|
56 | self.registry = {} |
---|
57 | #self.registry['components'] = {} |
---|
58 | #self.registry['windows'] = {} |
---|
59 | |
---|
60 | #self.csc = puzzlebox_master_control_client.puzzlebox_master_control_client( \ |
---|
61 | #self.log, \ |
---|
62 | #puzzlebox_configuration.CONTENT_SET_HOST, \ |
---|
63 | #puzzlebox_configuration.CONTENT_SET_PORT, \ |
---|
64 | #service_name = 'MCP', \ |
---|
65 | #target_name = 'CS') |
---|
66 | |
---|
67 | |
---|
68 | ################################################################## |
---|
69 | |
---|
70 | def process_instruction(self, instruction): |
---|
71 | |
---|
72 | #self.log.debug("Received instruction: %s" % instruction) |
---|
73 | #if self.DEBUG: |
---|
74 | #print "Received instruction: %s" % instruction |
---|
75 | |
---|
76 | d = defer.Deferred() |
---|
77 | response = 'instruction received' |
---|
78 | |
---|
79 | if 'command' in instruction: |
---|
80 | |
---|
81 | response = '%s instruction received' % instruction['command'] |
---|
82 | |
---|
83 | |
---|
84 | if 'information' in instruction: |
---|
85 | information = instruction['information'] |
---|
86 | |
---|
87 | |
---|
88 | #if instruction['command'] == 'register_component': |
---|
89 | |
---|
90 | #if information['pid'] in self.registry['components']: |
---|
91 | #self.log.error("Duplicate component registering - replacing old component (assumed dead).") |
---|
92 | #self.log.error("Old component: %s" % self.registry['components'][information['pid']]) |
---|
93 | #self.log.error("New Component: %s" % information) |
---|
94 | |
---|
95 | #if self.DEBUG: |
---|
96 | #print "Duplicate component registering - replacing old component (assumed dead)." |
---|
97 | #print "Old component: %s" % self.registry['components'][information['pid']] |
---|
98 | #print "New Component: %s" % information |
---|
99 | |
---|
100 | #self.registry['components'][information['pid']] = information |
---|
101 | |
---|
102 | |
---|
103 | #elif instruction['command'] == 'unregister_component': |
---|
104 | |
---|
105 | #if information['pid'] in self.registry['components']: |
---|
106 | #self.log.debug("Removing component from registry: %s" % self.registry['components'][information['pid']]) |
---|
107 | |
---|
108 | #if self.DEBUG: |
---|
109 | #print "Removing component from registry: %s" % \ |
---|
110 | #self.registry['components'][information['pid']] |
---|
111 | |
---|
112 | #del(self.registry['components'][information['pid']]) |
---|
113 | |
---|
114 | #else: |
---|
115 | #self.log.error("Unknown component attempted to unregister") |
---|
116 | #if self.DEBUG: |
---|
117 | #print "Unknown component attempted to unregister" |
---|
118 | |
---|
119 | |
---|
120 | #elif instruction['command'] == 'update_component': |
---|
121 | |
---|
122 | #if information['pid'] in self.registry['components']: |
---|
123 | |
---|
124 | #component = self.registry['components'][information['pid']] |
---|
125 | |
---|
126 | #for key in information: |
---|
127 | #component[key] = information[key] |
---|
128 | |
---|
129 | #else: |
---|
130 | #self.log.error("Unknown component attempted to update: %s" % information) |
---|
131 | #if self.DEBUG: |
---|
132 | #print "Unknown component attempted to update: %s" % information |
---|
133 | |
---|
134 | |
---|
135 | #elif instruction['command'] == 'restart_component': |
---|
136 | |
---|
137 | #self.restart_component(information['pid']) |
---|
138 | |
---|
139 | |
---|
140 | #elif instruction['command'] == 'load_url': |
---|
141 | |
---|
142 | #found_component = False |
---|
143 | |
---|
144 | #for each in self.registry['components']: |
---|
145 | |
---|
146 | #component = self.registry['components'][each] |
---|
147 | |
---|
148 | #if component['type'] == information['type'] and \ |
---|
149 | #component['display_pos_x'] == information['display_pos_x'] and \ |
---|
150 | #component['display_pos_y'] == information['display_pos_y'] and \ |
---|
151 | #component['window_size_x'] == information['window_size_x'] and \ |
---|
152 | #component['window_size_y'] == information['window_size_y']: |
---|
153 | |
---|
154 | #found_component = True |
---|
155 | |
---|
156 | #if component['active']: |
---|
157 | #self.log.debug("Matched an active component, activating callback.") |
---|
158 | #if self.DEBUG: |
---|
159 | #print "Matched an active component, activating callback." |
---|
160 | #component['callback'].callback("browser exit") |
---|
161 | |
---|
162 | #component['callback'] = d |
---|
163 | |
---|
164 | #try: |
---|
165 | #component['autobit'].cancel() |
---|
166 | #except: |
---|
167 | #pass |
---|
168 | |
---|
169 | #if int(information['enable_autobit']) == 1: |
---|
170 | #self.log.debug("Window %i loading with autobit enabled." % information['window_id']) |
---|
171 | |
---|
172 | #if self.DEBUG: |
---|
173 | #print "Window %i loading with autobit enabled." % \ |
---|
174 | #information['window_id'] |
---|
175 | |
---|
176 | #component['autobit'] = \ |
---|
177 | #reactor.callLater(AUTOBIT_TIMEOUT, self.restart_component, each) |
---|
178 | |
---|
179 | #component['active'] = True |
---|
180 | |
---|
181 | #for key in information: |
---|
182 | #component[key] = information[key] |
---|
183 | |
---|
184 | #component['source'] = 'MCP' |
---|
185 | #component['target'] = component['type'] |
---|
186 | |
---|
187 | #dw = self.csc.send_instruction(instruction, component=component) |
---|
188 | |
---|
189 | #dw.addCallback(self.process_component_response, instruction) |
---|
190 | |
---|
191 | #break |
---|
192 | |
---|
193 | #if not found_component: |
---|
194 | |
---|
195 | #self.log.debug("No component found matching load_url information, spawning new.") |
---|
196 | #if self.DEBUG: |
---|
197 | #print "No component found matching load_url information, spawning new." |
---|
198 | #self.spawn_new_component(instruction, d) |
---|
199 | |
---|
200 | #response = None |
---|
201 | |
---|
202 | |
---|
203 | #elif instruction['command'] == 'animation_started': |
---|
204 | |
---|
205 | #window_id = information['window_id'] |
---|
206 | |
---|
207 | #self.log.debug("Got animation started for window id %i" % window_id) |
---|
208 | #if self.DEBUG: |
---|
209 | #print "Got animation started for window id %i" % window_id |
---|
210 | |
---|
211 | #for each in self.registry['components']: |
---|
212 | #if 'window_id' in self.registry['components'][each] and \ |
---|
213 | #int(self.registry['components'][each]['window_id']) == int(window_id): |
---|
214 | |
---|
215 | #self.log.debug("Found window %i" % window_id) |
---|
216 | #if self.DEBUG: |
---|
217 | #print "Found window %i" % window_id |
---|
218 | |
---|
219 | #if 'autobit' in self.registry['components'][each]: |
---|
220 | #self.log.debug("Window %i cancelling autobit restart." % window_id) |
---|
221 | #if self.DEBUG: |
---|
222 | #print "Window %i cancelling autobit restart." % window_id |
---|
223 | |
---|
224 | #try: |
---|
225 | #self.registry['components'][each]['autobit'].cancel() |
---|
226 | #except: |
---|
227 | #self.log.error("Window %i error trying to cancel autobit restart" % window_id) |
---|
228 | #if self.DEBUG: |
---|
229 | #print "Window %i error trying to cancel autobit restart" % window_id |
---|
230 | |
---|
231 | #self.log.debug("Window %i white flash fix unhiding browser." % window_id) |
---|
232 | #tinstr = {'command': 'unhide'} |
---|
233 | #self.csc.send_instruction(tinstr, component=self.registry['components'][each]) |
---|
234 | |
---|
235 | |
---|
236 | #elif instruction['command'] == 'hide_all_components': |
---|
237 | |
---|
238 | #dlist = [] |
---|
239 | |
---|
240 | #for each in self.registry['components']: |
---|
241 | |
---|
242 | #component = self.safe_component(self.registry['components'][each]) |
---|
243 | |
---|
244 | #tinstr = {'command': 'hide'} |
---|
245 | |
---|
246 | #dlist.append(self.csc.send_instruction(tinstr, component)) |
---|
247 | |
---|
248 | #if dlist: |
---|
249 | #response = None |
---|
250 | #dl = defer.DeferredList(dlist) |
---|
251 | #dl.addCallback(d.callback) |
---|
252 | |
---|
253 | |
---|
254 | #elif instruction['command'] == 'register_window': |
---|
255 | |
---|
256 | #if information['window_id'] in self.registry['windows']: |
---|
257 | #self.log.error("Duplicate window attempted to register: %s" % information) |
---|
258 | #if self.DEBUG: |
---|
259 | #print "Duplicate window attempted to register: %s" % information |
---|
260 | |
---|
261 | #else: |
---|
262 | #self.registry['windows'][information['window_id']] = information |
---|
263 | |
---|
264 | |
---|
265 | #elif instruction['command'] == 'get_window_data': |
---|
266 | |
---|
267 | #if information['window_id'] == 'all': |
---|
268 | |
---|
269 | #response = self.registry['windows'] |
---|
270 | |
---|
271 | #elif information['window_id'] in self.registry['windows']: |
---|
272 | |
---|
273 | #response = self.registry['windows'][information['window_id']] |
---|
274 | |
---|
275 | #else: |
---|
276 | #self.log.error("Attempt to request data for unknown window: %s" % information) |
---|
277 | #if self.DEBUG: |
---|
278 | #print "Attempt to request data for unknown window: %s" % information |
---|
279 | |
---|
280 | |
---|
281 | #elif instruction['command'] == 'unregister_all_windows': |
---|
282 | |
---|
283 | #self.registry['windows'] = {} |
---|
284 | |
---|
285 | |
---|
286 | #elif instruction['command'] == 'exit_content_set': |
---|
287 | |
---|
288 | #self.log.debug("Requesting current content set to exit.") |
---|
289 | #if self.DEBUG: |
---|
290 | #print "Requesting current content set to exit." |
---|
291 | #self.csc.exit_content_set() |
---|
292 | |
---|
293 | |
---|
294 | #elif instruction['command'] == 'change_content_set': |
---|
295 | |
---|
296 | #self.log.debug("Requesting to change content set to content_set_id %i" % information['content_set_id']) |
---|
297 | #if self.DEBUG: |
---|
298 | #print "Requesting to change content set to content_set_id %i" % \ |
---|
299 | #information['content_set_id'] |
---|
300 | #self.csc.change_content_set(information) |
---|
301 | |
---|
302 | |
---|
303 | #elif instruction['command'] == 'end_current_entry': |
---|
304 | |
---|
305 | #self.log.debug("Requesting to end content in window_id %i" % information['window_id']) |
---|
306 | #if self.DEBUG: |
---|
307 | #print "Requesting to end content in window_id %i" % \ |
---|
308 | #information['window_id'] |
---|
309 | #self.csc.end_current_entry(information) |
---|
310 | |
---|
311 | |
---|
312 | #elif instruction['command'] == 'request_screenshot': |
---|
313 | |
---|
314 | #self.log.debug("Requesting content set to take screenshot") |
---|
315 | #if self.DEBUG: |
---|
316 | #print "Requesting content set to take screenshot" |
---|
317 | #self.csc.request_screenshot() |
---|
318 | |
---|
319 | |
---|
320 | #elif instruction['command'] == 'upload_screenshot': |
---|
321 | |
---|
322 | #self.log.debug("Requesting content set to upload system screenshot") |
---|
323 | #if self.DEBUG: |
---|
324 | #print "Requesting content set to upload system screenshot" |
---|
325 | #self.csc.upload_screenshot() |
---|
326 | |
---|
327 | |
---|
328 | #elif instruction['command'] == 'export_schedule': |
---|
329 | |
---|
330 | #self.log.debug("Requesting content set to export content_set_sequence_schedule_id %i" % \ |
---|
331 | #information['content_set_sequence_schedule_id']) |
---|
332 | #if self.DEBUG: |
---|
333 | #print "Requesting content set to export content_set_sequence_schedule_id %i" % \ |
---|
334 | #information['content_set_sequence_schedule_id'] |
---|
335 | #self.csc.export_schedule(information) |
---|
336 | |
---|
337 | |
---|
338 | #elif instruction['command'] == 'check_health': |
---|
339 | |
---|
340 | #response = 'health_okay' |
---|
341 | |
---|
342 | |
---|
343 | #elif instruction['command'] == 'get_registry': |
---|
344 | |
---|
345 | # unfortunately registry needs to have volatile components removed |
---|
346 | # before it can be passed via pickle, e.g. the deferred objects in callback. |
---|
347 | # may end up changing the structure around so it's less hassle to pass |
---|
348 | |
---|
349 | #safe_registry = {} |
---|
350 | #safe_registry['components'] = {} |
---|
351 | #safe_registry['windows'] = {} |
---|
352 | |
---|
353 | #for each in self.registry['components']: |
---|
354 | #safe_registry['components'][each] = \ |
---|
355 | #self.safe_component(self.registry['components'][each]) |
---|
356 | |
---|
357 | #for each in self.registry['windows']: |
---|
358 | #safe_registry['windows'][each] = self.registry['windows'][each].copy() |
---|
359 | |
---|
360 | #response = safe_registry |
---|
361 | |
---|
362 | |
---|
363 | #elif instruction['command'] == '/usr/bin/puzzlebox_xorg_reset.py': |
---|
364 | |
---|
365 | #response = "EXECUTE OK" |
---|
366 | |
---|
367 | |
---|
368 | else: |
---|
369 | |
---|
370 | #self.log.error("Unrecognized command received: %s" % instruction) |
---|
371 | if self.DEBUG: |
---|
372 | print "Unrecognized command received: %s" % instruction |
---|
373 | reponse = 'unrecognized instruction' |
---|
374 | |
---|
375 | |
---|
376 | if response: |
---|
377 | d.callback(response) |
---|
378 | |
---|
379 | return d |
---|
380 | |
---|
381 | |
---|
382 | ################################################################## |
---|
383 | |
---|
384 | #def process_component_response(self, result, instruction): |
---|
385 | |
---|
386 | #result, component = result[0], result[1] |
---|
387 | |
---|
388 | #if result == 'OK': |
---|
389 | |
---|
390 | #self.log.debug('%s responded OK' % component['type']) |
---|
391 | #if self.DEBUG: |
---|
392 | #print '%s responded OK' % component['type'] |
---|
393 | |
---|
394 | |
---|
395 | #elif result == 'FAILED_TO_CONNECT' or result == 'NO_REPLY': |
---|
396 | |
---|
397 | #self.log.error('%s responded %s' % (component['type'], result)) |
---|
398 | #if self.DEBUG: |
---|
399 | #print '%s responded %s' % (component['type'], result) |
---|
400 | |
---|
401 | #if instruction['command'] == 'duration_expire': |
---|
402 | ## not sure what else to do here, since duration expire is meant to make the browser go away |
---|
403 | ## if it is already gone, no real point in bringing it back? |
---|
404 | #self.log.debug("Failed to connect for duration_expire... well whatever then.") |
---|
405 | #if self.DEBUG: |
---|
406 | #print "Failed to connect for duration_expire... well whatever then." |
---|
407 | |
---|
408 | #elif instruction['command'] == 'load_url': |
---|
409 | #self.log.error("Failed to connect for load_url, restarting the web_browser.") |
---|
410 | #if self.DEBUG: |
---|
411 | #print "Failed to connect for load_url, restarting the web_browser." |
---|
412 | #self.restart_component(component[pid]) |
---|
413 | |
---|
414 | #else: |
---|
415 | #self.log.error("%s" % result) |
---|
416 | #if self.DEBUG: |
---|
417 | #print "%s" % result |
---|
418 | |
---|
419 | |
---|
420 | ################################################################## |
---|
421 | |
---|
422 | #def safe_component(self, component): |
---|
423 | |
---|
424 | ## remove volatile data from a component so it can be safely passed through pickle |
---|
425 | |
---|
426 | #tcomp = component.copy() |
---|
427 | #tcomp['callback'] = None |
---|
428 | #tcomp['autobit'] = None |
---|
429 | |
---|
430 | #return tcomp |
---|
431 | |
---|
432 | |
---|
433 | ################################################################## |
---|
434 | |
---|
435 | #def restart_component(self, pid): |
---|
436 | |
---|
437 | #if pid in self.registry['components']: |
---|
438 | #try: |
---|
439 | #os.kill(pid, signal.SIGKILL) |
---|
440 | #self.log.debug("Killed component %s" % pid) |
---|
441 | #if self.DEBUG: |
---|
442 | #print "Killed component %s" % pid |
---|
443 | #return True |
---|
444 | #except: |
---|
445 | #self.log.error("Failed to kill component %s" % pid) |
---|
446 | #if self.DEBUG: |
---|
447 | #print "Failed to kill component %s" % pid |
---|
448 | #return False |
---|
449 | |
---|
450 | |
---|
451 | ################################################################## |
---|
452 | |
---|
453 | #def process_connection_lost(self, instruction): |
---|
454 | |
---|
455 | #if not instruction: |
---|
456 | |
---|
457 | #self.log.debug("Connection lost with no instruction?") |
---|
458 | #if self.DEBUG: |
---|
459 | #print "Connection lost with no instruction?" |
---|
460 | #return |
---|
461 | |
---|
462 | #else: |
---|
463 | |
---|
464 | #if instruction['command'] == 'load_url': |
---|
465 | |
---|
466 | #found_component = False |
---|
467 | #information = instruction['information'] |
---|
468 | |
---|
469 | #for each in self.registry['components']: |
---|
470 | |
---|
471 | #component = self.registry['components'][each] |
---|
472 | |
---|
473 | ## should only ever be 1 of each type of component per window_id |
---|
474 | #if component['type'] == information['type'] and \ |
---|
475 | #component['window_id'] == information['window_id']: |
---|
476 | |
---|
477 | #found_component = True |
---|
478 | |
---|
479 | #component['active'] = False |
---|
480 | #component['last_active'] = time.time() |
---|
481 | |
---|
482 | #component['source'] = 'MCP' |
---|
483 | #component['target'] = component['type'] |
---|
484 | |
---|
485 | #instruction['command'] = 'duration_expire' |
---|
486 | #instruction['information'] = None |
---|
487 | |
---|
488 | #dw = self.csc.send_instruction(instruction, component=component) |
---|
489 | |
---|
490 | #dw.addCallback(self.process_component_response, instruction) |
---|
491 | |
---|
492 | #break |
---|
493 | |
---|
494 | #if not found_component: |
---|
495 | |
---|
496 | #self.log.debug("Connection lost for a non-existent component? Weird.") |
---|
497 | #if self.DEBUG: |
---|
498 | #print "Connection lost for a non-existent component? Weird." |
---|
499 | |
---|
500 | |
---|
501 | ################################################################## |
---|
502 | |
---|
503 | #def stop_oldest_component(self): |
---|
504 | ## return True if a component can be stopped |
---|
505 | #oldest = {'last_active': time.time()} |
---|
506 | #for each in self.registry['components']: |
---|
507 | #component = self.registry['components'][each] |
---|
508 | |
---|
509 | #if not component['active'] and \ |
---|
510 | #component['last_active'] < oldest['last_active']: |
---|
511 | #oldest = component |
---|
512 | |
---|
513 | #if 'pid' in oldest: |
---|
514 | ## in this case restart just means kill since the component is not currently active |
---|
515 | #return self.restart_component(oldest['pid']) |
---|
516 | |
---|
517 | #return False |
---|
518 | |
---|
519 | |
---|
520 | ################################################################## |
---|
521 | |
---|
522 | #def spawn_new_component(self, instruction, d): |
---|
523 | |
---|
524 | #if len(self.registry['components']) >= MAX_COMPONENTS and \ |
---|
525 | #not self.stop_oldest_component(): |
---|
526 | #self.log.error("Max components exceeded, not spawning any new ones.") |
---|
527 | #if self.DEBUG: |
---|
528 | #print "Max components exceeded, not spawning any new ones." |
---|
529 | #return |
---|
530 | |
---|
531 | #if instruction['command'] == 'load_url': |
---|
532 | |
---|
533 | #information = instruction['information'] |
---|
534 | |
---|
535 | ## command = '/usr/bin/screen -S web_browser ' + \ |
---|
536 | ## '%s %i %i %i %i %i %i %i %i %i %s' % \ |
---|
537 | #command = '%s %i %i %i %i %i %i %i %i %i %i %s' % \ |
---|
538 | #('/usr/bin/puzzlebox_web_browser.py', \ |
---|
539 | #information['window_id'], \ |
---|
540 | #information['display_pos_x'], \ |
---|
541 | #information['display_pos_y'], \ |
---|
542 | #information['window_size_x'], \ |
---|
543 | #information['window_size_y'], \ |
---|
544 | #information['display_fullscreen'], \ |
---|
545 | #information['refresh_interval'], \ |
---|
546 | #information['duration'], \ |
---|
547 | #information['hide_on_duration_expire'], \ |
---|
548 | #information['autobit_white_flash_fix'], \ |
---|
549 | #information['url']) |
---|
550 | |
---|
551 | #args = command.strip().split() |
---|
552 | #file = args[0] |
---|
553 | |
---|
554 | #self.log.debug("Spawning process from command: [%s]" % command) |
---|
555 | #if self.DEBUG: |
---|
556 | #print "Spawning process from command: [%s]" % command |
---|
557 | |
---|
558 | #pp = puzzlebox_mcp_browser_pp(self.log, instruction, self.registry, \ |
---|
559 | #self.spawn_new_component, self.restart_component, d, self.DEBUG) |
---|
560 | #process = reactor.spawnProcess(pp, file, args, os.environ, usePTY=True) |
---|
561 | |
---|
562 | #else: |
---|
563 | #self.log.debug("Not spawning process because command is '%s'" % instruction['command']) |
---|
564 | #if self.DEBUG: |
---|
565 | #print "Not spawning process because command is '%s'" % instruction['command'] |
---|
566 | |
---|
567 | |
---|
568 | ##################################################################### |
---|
569 | # Process Protocol |
---|
570 | ##################################################################### |
---|
571 | |
---|
572 | #class puzzlebox_mcp_browser_pp(protocol.ProcessProtocol): |
---|
573 | |
---|
574 | #def __init__(self, log, \ |
---|
575 | #instruction, \ |
---|
576 | #registry, \ |
---|
577 | #spawn_new_component, \ |
---|
578 | #restart_component, \ |
---|
579 | #d, \ |
---|
580 | #DEBUG=DEBUG): |
---|
581 | |
---|
582 | #self.log = log |
---|
583 | #self.instruction = instruction |
---|
584 | #self.information = self.instruction['information'] |
---|
585 | #self.registry = registry |
---|
586 | #self.spawn_new_component = spawn_new_component |
---|
587 | #self.restart_component = restart_component |
---|
588 | #self.d = d |
---|
589 | #self.DEBUG = DEBUG |
---|
590 | |
---|
591 | |
---|
592 | ################################################################## |
---|
593 | |
---|
594 | #def connectionMade(self): |
---|
595 | #self.pid = self.transport.pid |
---|
596 | #self.registry['components'][self.pid] = self.instruction['information'] |
---|
597 | #self.registry['components'][self.pid]['pid'] = self.pid |
---|
598 | #self.registry['components'][self.pid]['active'] = True |
---|
599 | #self.registry['components'][self.pid]['callback'] = self.d |
---|
600 | |
---|
601 | #if int(self.information['enable_autobit']) == 1: |
---|
602 | #self.log.debug("Window %i started with autobit enabled." % self.information['window_id']) |
---|
603 | #if self.DEBUG: |
---|
604 | #print "Window %i started with autobit enabled." % self.information['window_id'] |
---|
605 | #self.registry['components'][self.pid]['autobit'] = \ |
---|
606 | #reactor.callLater(AUTOBIT_TIMEOUT, self.restart_component, self.pid) |
---|
607 | |
---|
608 | #self.log.debug("Sub-process started with pid %i" % self.pid) |
---|
609 | #if self.DEBUG: |
---|
610 | #print "Sub-process started with pid %i" % self.pid |
---|
611 | |
---|
612 | |
---|
613 | ################################################################## |
---|
614 | |
---|
615 | #def childDataReceived(self, childFD, data): |
---|
616 | |
---|
617 | ## attempt to log any errors... might not work for exceptions |
---|
618 | #self.log.error(data) |
---|
619 | |
---|
620 | #if self.DEBUG: |
---|
621 | #print data |
---|
622 | |
---|
623 | |
---|
624 | ################################################################## |
---|
625 | |
---|
626 | #def processEnded(self, status_object): |
---|
627 | |
---|
628 | #self.log.debug("Sub-process with pid %i ended" % self.pid) |
---|
629 | #if self.DEBUG: |
---|
630 | #print "Sub-process with pid %i ended" % self.pid |
---|
631 | |
---|
632 | ## this is kind of unnecessary as i could just use |
---|
633 | ## component = self.instruction['information'] |
---|
634 | ## but for now i want to make sure it still exists in registry too |
---|
635 | #if self.pid in self.registry['components']: |
---|
636 | |
---|
637 | #component = self.registry['components'][self.pid] |
---|
638 | |
---|
639 | #if component['active']: |
---|
640 | #self.log.debug("Component is still active, respawning...") |
---|
641 | #if self.DEBUG: |
---|
642 | #print "Component is still active, respawning..." |
---|
643 | ## for key in self.instruction['information']: |
---|
644 | ## self.instruction['information'][key] = component[key] |
---|
645 | #self.spawn_new_component(self.instruction, component['callback']) |
---|
646 | #else: |
---|
647 | #self.log.debug("Component inactive, not respawning.") |
---|
648 | #if self.DEBUG: |
---|
649 | #print "Component inactive, not respawning." |
---|
650 | |
---|
651 | ## clean up the old component data in either case |
---|
652 | ## and remove gtkmoz profile |
---|
653 | #del(self.registry['components'][self.pid]) |
---|
654 | #profile_dir = os.path.join(GTKMOZ_PROFILE_DIR, "%s" % self.pid) |
---|
655 | #if os.path.exists(profile_dir): |
---|
656 | #command = 'rm -rf %s' % profile_dir |
---|
657 | #self.log.debug("Executing command: [%s]" % command) |
---|
658 | #if self.DEBUG: |
---|
659 | #print "Executing command: [%s]" % command |
---|
660 | #os.system(command) |
---|
661 | |
---|
662 | #else: |
---|
663 | #self.log.error("Could not find component associated with this sub-process. Odd.") |
---|
664 | #if self.DEBUG: |
---|
665 | #print "Could not find component associated with this sub-process. Odd." |
---|
666 | |
---|
667 | |
---|
668 | ##################################################################### |
---|
669 | # Protocol |
---|
670 | ##################################################################### |
---|
671 | |
---|
672 | class puzzlebox_master_control_server_protocol(protocol.Protocol): |
---|
673 | |
---|
674 | def __init__(self): |
---|
675 | self.instruction = {} |
---|
676 | self.data_chunk = "" |
---|
677 | |
---|
678 | |
---|
679 | ################################################################## |
---|
680 | |
---|
681 | def dataReceived(self, data): |
---|
682 | |
---|
683 | self.data_chunk += data |
---|
684 | try: |
---|
685 | self.instruction = pickle.loads(self.data_chunk) |
---|
686 | except Exception, e: |
---|
687 | self.factory.log.error("Partial data received (or error: %s)." % e) |
---|
688 | else: |
---|
689 | self.data_chunk = "" |
---|
690 | |
---|
691 | d = self.factory.process_instruction(self.instruction.copy()) |
---|
692 | d.addCallback(self.send_response) |
---|
693 | |
---|
694 | |
---|
695 | ################################################################## |
---|
696 | |
---|
697 | def send_response(self, response): |
---|
698 | |
---|
699 | #if response == "browser exit": |
---|
700 | #self.instruction['command'] = response |
---|
701 | |
---|
702 | response = pickle.dumps(response) |
---|
703 | |
---|
704 | self.transport.write(response) |
---|
705 | |
---|
706 | |
---|
707 | ################################################################## |
---|
708 | |
---|
709 | def connectionLost(self, reason): |
---|
710 | |
---|
711 | self.factory.process_connection_lost(self.instruction) |
---|
712 | |
---|
713 | |
---|
714 | ##################################################################### |
---|
715 | # Main |
---|
716 | ##################################################################### |
---|
717 | |
---|
718 | if __name__ == '__main__': |
---|
719 | |
---|
720 | #log = puzzlebox_logger.puzzlebox_logger(logfile='master_control') |
---|
721 | log = None |
---|
722 | |
---|
723 | # Collect default settings and command line parameters |
---|
724 | server_host = SERVER_HOST |
---|
725 | server_port = SERVER_PORT |
---|
726 | |
---|
727 | for each in sys.argv: |
---|
728 | |
---|
729 | if each.startswith("--host="): |
---|
730 | server_host = each[ len("--host="): ] |
---|
731 | if each.startswith("--port="): |
---|
732 | server_port = each[ len("--port="): ] |
---|
733 | |
---|
734 | mcp = puzzlebox_master_control(log, DEBUG) |
---|
735 | reactor.listenTCP(port=server_port, factory=mcp, interface=server_host) |
---|
736 | reactor.run() |
---|
737 | |
---|