33 from threading import Thread, currentThread, Semaphore |
33 from threading import Thread, currentThread, Semaphore |
34 import traceback |
34 import traceback |
35 import __builtin__ |
35 import __builtin__ |
36 import Pyro.core as pyro |
36 import Pyro.core as pyro |
37 |
37 |
38 from runtime import PLCObject, ServicePublisher |
38 from runtime import PLCObject, ServicePublisher, MainWorker |
39 import util.paths as paths |
39 import util.paths as paths |
40 |
40 |
41 |
41 |
42 def usage(): |
42 def usage(): |
43 print(""" |
43 print(""" |
399 return res |
399 return res |
400 |
400 |
401 |
401 |
402 class Server(object): |
402 class Server(object): |
403 def __init__(self, servicename, ip_addr, port, |
403 def __init__(self, servicename, ip_addr, port, |
404 workdir, argv, autostart=False, |
404 workdir, argv, |
405 statuschange=None, evaluator=default_evaluator, |
405 statuschange=None, evaluator=default_evaluator, |
406 pyruntimevars=None): |
406 pyruntimevars=None): |
407 self.continueloop = True |
407 self.continueloop = True |
408 self.daemon = None |
408 self.daemon = None |
409 self.servicename = servicename |
409 self.servicename = servicename |
411 self.port = port |
411 self.port = port |
412 self.workdir = workdir |
412 self.workdir = workdir |
413 self.argv = argv |
413 self.argv = argv |
414 self.plcobj = None |
414 self.plcobj = None |
415 self.servicepublisher = None |
415 self.servicepublisher = None |
416 self.autostart = autostart |
|
417 self.statuschange = statuschange |
416 self.statuschange = statuschange |
418 self.evaluator = evaluator |
417 self.evaluator = evaluator |
419 self.pyruntimevars = pyruntimevars |
418 self.pyruntimevars = pyruntimevars |
420 |
419 |
421 def Loop(self): |
420 def PyroLoop(self): |
422 while self.continueloop: |
421 while self.continueloop: |
423 pyro.initServer() |
422 pyro.initServer() |
424 self.daemon = pyro.Daemon(host=self.ip_addr, port=self.port) |
423 self.daemon = pyro.Daemon(host=self.ip_addr, port=self.port) |
425 # pyro never frees memory after connection close if no timeout set |
424 # pyro never frees memory after connection close if no timeout set |
426 # taking too small timeout value may cause |
425 # taking too small timeout value may cause |
427 # unwanted diconnection when IDE is kept busy for long periods |
426 # unwanted diconnection when IDE is kept busy for long periods |
428 self.daemon.setTimeout(60) |
427 self.daemon.setTimeout(60) |
429 self.Start() |
428 |
|
429 uri = self.daemon.connect(self.plcobj, "PLCObject") |
|
430 |
|
431 print(_("Pyro port :"), self.port) |
|
432 print(_("Pyro object's uri :"), uri) |
|
433 |
|
434 # Beremiz IDE detects daemon start by looking |
|
435 # for self.workdir in the daemon's stdout. |
|
436 # Therefore don't delete the following line |
|
437 print(_("Current working directory :"), self.workdir) |
|
438 |
|
439 # Configure and publish service |
|
440 # Not publish service if localhost in address params |
|
441 if self.servicename is not None and \ |
|
442 self.ip_addr is not None and \ |
|
443 self.ip_addr != "localhost" and \ |
|
444 self.ip_addr != "127.0.0.1": |
|
445 print(_("Publishing service on local network")) |
|
446 self.servicepublisher = ServicePublisher.ServicePublisher() |
|
447 self.servicepublisher.RegisterService(self.servicename, self.ip_addr, self.port) |
|
448 |
430 self.daemon.requestLoop() |
449 self.daemon.requestLoop() |
431 self.daemon.sock.close() |
450 self.daemon.sock.close() |
432 |
451 |
433 def Restart(self): |
452 def Restart(self): |
434 self._stop() |
453 self._stop() |
438 if self.plcobj is not None: |
457 if self.plcobj is not None: |
439 self.plcobj.StopPLC() |
458 self.plcobj.StopPLC() |
440 self.plcobj.UnLoadPLC() |
459 self.plcobj.UnLoadPLC() |
441 self._stop() |
460 self._stop() |
442 |
461 |
443 def Start(self): |
462 def RegisterPLCObject(self, plcobj): |
444 self.plcobj = PLCObject(self.workdir, self.daemon, self.argv, |
463 self.plcobj = plcobj |
445 self.statuschange, self.evaluator, |
|
446 self.pyruntimevars) |
|
447 |
|
448 uri = self.daemon.connect(self.plcobj, "PLCObject") |
|
449 |
|
450 print(_("Pyro port :"), self.port) |
|
451 print(_("Pyro object's uri :"), uri) |
|
452 |
|
453 # Beremiz IDE detects daemon start by looking |
|
454 # for self.workdir in the daemon's stdout. |
|
455 # Therefore don't delete the following line |
|
456 print(_("Current working directory :"), self.workdir) |
|
457 |
|
458 # Configure and publish service |
|
459 # Not publish service if localhost in address params |
|
460 if self.servicename is not None and \ |
|
461 self.ip_addr is not None and \ |
|
462 self.ip_addr != "localhost" and \ |
|
463 self.ip_addr != "127.0.0.1": |
|
464 print(_("Publishing service on local network")) |
|
465 self.servicepublisher = ServicePublisher.ServicePublisher() |
|
466 self.servicepublisher.RegisterService(self.servicename, self.ip_addr, self.port) |
|
467 |
|
468 self.plcobj.AutoLoad() |
|
469 if self.plcobj.GetPLCstatus()[0] != "Empty": |
|
470 if self.autostart: |
|
471 self.plcobj.StartPLC() |
|
472 self.plcobj.StatusChange() |
|
473 |
|
474 sys.stdout.flush() |
|
475 |
464 |
476 def _stop(self): |
465 def _stop(self): |
477 if self.plcobj is not None: |
466 if self.plcobj is not None: |
478 self.plcobj.StopPLC() |
467 self.plcobj.StopPLC() |
479 if self.servicepublisher is not None: |
468 if self.servicepublisher is not None: |
527 wx.CallAfter(wx_evaluator, o) |
516 wx.CallAfter(wx_evaluator, o) |
528 wx_eval_lock.acquire() |
517 wx_eval_lock.acquire() |
529 return o.res |
518 return o.res |
530 |
519 |
531 pyroserver = Server(servicename, given_ip, port, |
520 pyroserver = Server(servicename, given_ip, port, |
532 WorkingDir, argv, autostart, |
521 WorkingDir, argv, |
533 statuschange, evaluator, pyruntimevars) |
522 statuschange, evaluator, pyruntimevars) |
534 |
523 |
535 taskbar_instance = BeremizTaskBarIcon(pyroserver, enablewx) |
524 taskbar_instance = BeremizTaskBarIcon(pyroserver, enablewx) |
536 else: |
525 else: |
537 pyroserver = Server(servicename, given_ip, port, |
526 pyroserver = Server(servicename, given_ip, port, |
538 WorkingDir, argv, autostart, |
527 WorkingDir, argv, |
539 statuschange, pyruntimevars=pyruntimevars) |
528 statuschange, pyruntimevars=pyruntimevars) |
540 |
529 |
541 |
530 |
542 # Exception hooks |
531 # Exception hooks |
543 |
532 |
629 else: |
618 else: |
630 raise Exception(_("WAMP config is missing.")) |
619 raise Exception(_("WAMP config is missing.")) |
631 except Exception: |
620 except Exception: |
632 LogMessageAndException(_("WAMP client startup failed. ")) |
621 LogMessageAndException(_("WAMP client startup failed. ")) |
633 |
622 |
|
623 plcobj = PLCObject(pyroserver) |
|
624 |
|
625 plcobj.AutoLoad() |
|
626 if plcobj.GetPLCstatus()[0] == "Stopped": |
|
627 if autostart: |
|
628 plcobj.StartPLC() |
|
629 plcobj.StatusChange() |
|
630 |
|
631 pyro_thread = Thread(target=pyroserver.PyroLoop) |
|
632 pyro_thread.start() |
|
633 |
|
634 sys.stdout.flush() |
634 |
635 |
635 if havetwisted or havewx: |
636 if havetwisted or havewx: |
636 pyro_thread = Thread(target=pyroserver.Loop) |
|
637 pyro_thread.start() |
|
638 |
|
639 if havetwisted: |
637 if havetwisted: |
640 reactor.run() |
638 # reactor._installSignalHandlersAgain() |
641 elif havewx: |
639 def ui_thread_target(): |
642 app.MainLoop() |
640 # FIXME: had to disable SignaHandlers install because |
643 else: |
641 # signal not working in non-main thread |
644 try: |
642 reactor.run(installSignalHandlers=False) |
645 pyroserver.Loop() |
643 else : |
646 except KeyboardInterrupt: |
644 ui_thread_target = app.MainLoop |
647 pass |
645 |
|
646 ui_thread = Thread(target = ui_thread_target) |
|
647 ui_thread.start() |
|
648 |
|
649 try: |
|
650 MainWorker.runloop() |
|
651 except KeyboardInterrupt: |
|
652 pass |
|
653 |
648 pyroserver.Quit() |
654 pyroserver.Quit() |
649 sys.exit(0) |
655 sys.exit(0) |