runtime/PyroServer.py
changeset 3800 a5a6ee271e65
parent 3750 f62625418bff
child 3805 5a66d4be2e49
equal deleted inserted replaced
3799:2b995a4963a4 3800:a5a6ee271e65
    12 
    12 
    13 
    13 
    14 import sys
    14 import sys
    15 import os
    15 import os
    16 
    16 
    17 import Pyro
    17 import Pyro5
    18 import Pyro.core as pyro
    18 import Pyro5.server
       
    19 
    19 import runtime
    20 import runtime
    20 from runtime.ServicePublisher import ServicePublisher
    21 from runtime.ServicePublisher import ServicePublisher
    21 
    22 
       
    23 def make_pyro_exposed_stub(method_name):
       
    24     stub = lambda self, *args, **kwargs: \
       
    25         getattr(self.plc_object_instance, method_name)(self, *args, **kwargs)
       
    26     stub.__name__ = method_name
       
    27     Pyro5.server.expose(stub)
       
    28     return stub
       
    29     
       
    30 
       
    31 class PLCObjectPyroAdapter(type("PLCObjectPyroStubs", (), {
       
    32     name: make_pyro_exposed_stub(name) for name in [
       
    33         "AppendChunkToBlob",
       
    34         "GetLogMessage",
       
    35         "GetPLCID",
       
    36         "GetPLCstatus",
       
    37         "GetTraceVariables",
       
    38         "MatchMD5", 
       
    39         "NewPLC",
       
    40         "PurgeBlobs",
       
    41         "RemoteExec",
       
    42         "RepairPLC",
       
    43         "ResetLogCount",
       
    44         "SeedBlob",
       
    45         "SetTraceVariablesList",
       
    46         "StartPLC",
       
    47         "StopPLC"
       
    48     ]
       
    49 })):
       
    50     def __init__(self, plc_object_instance):
       
    51         self.plc_object_instance = plc_object_instance
       
    52     
    22 
    53 
    23 class PyroServer(object):
    54 class PyroServer(object):
    24     def __init__(self, servicename, ip_addr, port):
    55     def __init__(self, servicename, ip_addr, port):
    25         self.continueloop = True
    56         self.continueloop = True
    26         self.daemon = None
    57         self.daemon = None
    45     def PyroLoop(self, when_ready):
    76     def PyroLoop(self, when_ready):
    46         if self._to_be_published():
    77         if self._to_be_published():
    47             self.Publish()
    78             self.Publish()
    48 
    79 
    49         while self.continueloop:
    80         while self.continueloop:
    50             Pyro.config.PYRO_MULTITHREADED = 0
    81             self.daemon = Pyro5.server.Daemon(host=self.ip_addr, port=self.port)
    51             pyro.initServer()
       
    52             self.daemon = pyro.Daemon(host=self.ip_addr, port=self.port)
       
    53 
    82 
    54             # pyro never frees memory after connection close if no timeout set
    83             self.daemon.register(PLCObjectPyroAdapter(runtime.GetPLCObjectSingleton()), "PLCObject")
    55             # taking too small timeout value may cause
       
    56             # unwanted diconnection when IDE is kept busy for long periods
       
    57             self.daemon.setTimeout(60)
       
    58 
       
    59             pyro_obj = Pyro.core.ObjBase()
       
    60             pyro_obj.delegateTo(runtime.GetPLCObjectSingleton())
       
    61 
       
    62             self.daemon.connect(pyro_obj, "PLCObject")
       
    63 
    84 
    64             when_ready()
    85             when_ready()
    65 
    86 
    66             # "pipe to self" trick to to accelerate runtime shutdown 
    87             self.daemon.requestLoop()
    67             # instead of waiting for arbitrary pyro timeout.
       
    68             others = []
       
    69             if not sys.platform.startswith('win'):
       
    70                 self.piper, self.pipew = os.pipe()
       
    71                 others.append(self.piper)
       
    72 
    88 
    73             self.daemon.requestLoop(others=others, callback=lambda x: None)
       
    74             self.piper, self.pipew = None, None
       
    75             if hasattr(self, 'sock'):
       
    76                 self.daemon.sock.close()
       
    77         self.Unpublish()
    89         self.Unpublish()
    78 
    90 
    79     def Restart(self):
    91     def Restart(self):
    80         self.daemon.shutdown(True)
    92         self.daemon.shutdown(True)
    81 
    93 
    82     def Quit(self):
    94     def Quit(self):
    83         self.continueloop = False
    95         self.continueloop = False
    84         self.daemon.shutdown(True)
    96         self.daemon.shutdown()
    85         self.daemon.closedown()
       
    86         if not sys.platform.startswith('win'):
    97         if not sys.platform.startswith('win'):
    87             if self.pipew is not None:
    98             if self.pipew is not None:
    88                 os.write(self.pipew, "goodbye")
    99                 os.write(self.pipew, "goodbye")
    89 
   100 
    90     def Publish(self):
   101     def Publish(self):