Beremiz_service.py
changeset 3884 34da877021d5
parent 3843 832bcf1b5b60
equal deleted inserted replaced
3883:a6e7dd8bac36 3884:34da877021d5
    34 from threading import Thread, Semaphore, Lock, current_thread
    34 from threading import Thread, Semaphore, Lock, current_thread
    35 import builtins
    35 import builtins
    36 from functools import partial
    36 from functools import partial
    37 
    37 
    38 import runtime
    38 import runtime
    39 from runtime.PyroServer import PyroServer
    39 from runtime.eRPCServer import eRPCServer as RPCServer
    40 from runtime.xenomai import TryPreloadXenomai
    40 from runtime.xenomai import TryPreloadXenomai
    41 from runtime import LogMessageAndException
    41 from runtime import LogMessageAndException
    42 from runtime import PlcStatus
    42 from runtime import PlcStatus
    43 from runtime import default_evaluator
    43 from runtime import default_evaluator
    44 from runtime.Stunnel import ensurePSK
    44 from runtime.Stunnel import ensurePSK
   268             TBMENU_CHANGE_NAME = wx.NewIdRef()
   268             TBMENU_CHANGE_NAME = wx.NewIdRef()
   269             TBMENU_CHANGE_PORT = wx.NewIdRef()
   269             TBMENU_CHANGE_PORT = wx.NewIdRef()
   270             TBMENU_CHANGE_INTERFACE = wx.NewIdRef()
   270             TBMENU_CHANGE_INTERFACE = wx.NewIdRef()
   271             TBMENU_LIVE_SHELL = wx.NewIdRef()
   271             TBMENU_LIVE_SHELL = wx.NewIdRef()
   272             TBMENU_WXINSPECTOR = wx.NewIdRef()
   272             TBMENU_WXINSPECTOR = wx.NewIdRef()
   273             TBMENU_CHANGE_WD = wx.NewIdRef()
   273             # TBMENU_CHANGE_WD = wx.NewIdRef()
   274             TBMENU_QUIT = wx.NewIdRef()
   274             TBMENU_QUIT = wx.NewIdRef()
   275 
   275 
   276             def __init__(self, pyroserver):
   276             def __init__(self, rpc_server):
   277                 wx.adv.TaskBarIcon.__init__(self)
   277                 wx.adv.TaskBarIcon.__init__(self)
   278                 self.pyroserver = pyroserver
   278                 self.rpc_server = rpc_server
   279                 # Set the image
   279                 # Set the image
   280                 self.UpdateIcon(None)
   280                 self.UpdateIcon(None)
   281 
   281 
   282                 # bind some events
   282                 # bind some events
   283                 self.Bind(wx.EVT_MENU, self.OnTaskBarStartPLC, id=self.TBMENU_START)
   283                 self.Bind(wx.EVT_MENU, self.OnTaskBarStartPLC, id=self.TBMENU_START)
   285                 self.Bind(wx.EVT_MENU, self.OnTaskBarChangeName, id=self.TBMENU_CHANGE_NAME)
   285                 self.Bind(wx.EVT_MENU, self.OnTaskBarChangeName, id=self.TBMENU_CHANGE_NAME)
   286                 self.Bind(wx.EVT_MENU, self.OnTaskBarChangeInterface, id=self.TBMENU_CHANGE_INTERFACE)
   286                 self.Bind(wx.EVT_MENU, self.OnTaskBarChangeInterface, id=self.TBMENU_CHANGE_INTERFACE)
   287                 self.Bind(wx.EVT_MENU, self.OnTaskBarLiveShell, id=self.TBMENU_LIVE_SHELL)
   287                 self.Bind(wx.EVT_MENU, self.OnTaskBarLiveShell, id=self.TBMENU_LIVE_SHELL)
   288                 self.Bind(wx.EVT_MENU, self.OnTaskBarWXInspector, id=self.TBMENU_WXINSPECTOR)
   288                 self.Bind(wx.EVT_MENU, self.OnTaskBarWXInspector, id=self.TBMENU_WXINSPECTOR)
   289                 self.Bind(wx.EVT_MENU, self.OnTaskBarChangePort, id=self.TBMENU_CHANGE_PORT)
   289                 self.Bind(wx.EVT_MENU, self.OnTaskBarChangePort, id=self.TBMENU_CHANGE_PORT)
   290                 self.Bind(wx.EVT_MENU, self.OnTaskBarChangeWorkingDir, id=self.TBMENU_CHANGE_WD)
   290                 # self.Bind(wx.EVT_MENU, self.OnTaskBarChangeWorkingDir, id=self.TBMENU_CHANGE_WD)
   291                 self.Bind(wx.EVT_MENU, self.OnTaskBarQuit, id=self.TBMENU_QUIT)
   291                 self.Bind(wx.EVT_MENU, self.OnTaskBarQuit, id=self.TBMENU_QUIT)
   292 
   292 
   293             def CreatePopupMenu(self):
   293             def CreatePopupMenu(self):
   294                 """
   294                 """
   295                 This method is called by the base class when it needs to popup
   295                 This method is called by the base class when it needs to popup
   302                 menu.Append(self.TBMENU_STOP, _("Stop PLC"))
   302                 menu.Append(self.TBMENU_STOP, _("Stop PLC"))
   303                 menu.AppendSeparator()
   303                 menu.AppendSeparator()
   304                 menu.Append(self.TBMENU_CHANGE_NAME, _("Change Name"))
   304                 menu.Append(self.TBMENU_CHANGE_NAME, _("Change Name"))
   305                 menu.Append(self.TBMENU_CHANGE_INTERFACE, _("Change IP of interface to bind"))
   305                 menu.Append(self.TBMENU_CHANGE_INTERFACE, _("Change IP of interface to bind"))
   306                 menu.Append(self.TBMENU_CHANGE_PORT, _("Change Port Number"))
   306                 menu.Append(self.TBMENU_CHANGE_PORT, _("Change Port Number"))
   307                 menu.Append(self.TBMENU_CHANGE_WD, _("Change working directory"))
   307                 # menu.Append(self.TBMENU_CHANGE_WD, _("Change working directory"))
   308                 menu.AppendSeparator()
   308                 menu.AppendSeparator()
   309                 menu.Append(self.TBMENU_LIVE_SHELL, _("Launch a live Python shell"))
   309                 menu.Append(self.TBMENU_LIVE_SHELL, _("Launch a live Python shell"))
   310                 menu.Append(self.TBMENU_WXINSPECTOR, _("Launch WX GUI inspector"))
   310                 menu.Append(self.TBMENU_WXINSPECTOR, _("Launch WX GUI inspector"))
   311                 menu.AppendSeparator()
   311                 menu.AppendSeparator()
   312                 menu.Append(self.TBMENU_QUIT, _("Quit"))
   312                 menu.Append(self.TBMENU_QUIT, _("Quit"))
   330 
   330 
   331             def OnTaskBarStopPLC(self, evt):
   331             def OnTaskBarStopPLC(self, evt):
   332                 runtime.GetPLCObjectSingleton().StopPLC()
   332                 runtime.GetPLCObjectSingleton().StopPLC()
   333 
   333 
   334             def OnTaskBarChangeInterface(self, evt):
   334             def OnTaskBarChangeInterface(self, evt):
   335                 ip_addr = self.pyroserver.ip_addr
   335                 ip_addr = self.rpc_server.ip_addr
   336                 ip_addr = '' if ip_addr is None else ip_addr
   336                 ip_addr = '' if ip_addr is None else ip_addr
   337                 dlg = ParamsEntryDialog(None, _("Enter the IP of the interface to bind"), defaultValue=ip_addr)
   337                 dlg = ParamsEntryDialog(None, _("Enter the IP of the interface to bind"), defaultValue=ip_addr)
   338                 dlg.SetTests([(re.compile(r'\d{1,3}(?:\.\d{1,3}){3}$').match, _("IP is not valid!")),
   338                 dlg.SetTests([(re.compile(r'\d{1,3}(?:\.\d{1,3}){3}$').match, _("IP is not valid!")),
   339                               (lambda x:len([x for x in x.split(".") if 0 <= int(x) <= 255]) == 4,
   339                               (lambda x:len([x for x in x.split(".") if 0 <= int(x) <= 255]) == 4,
   340                                _("IP is not valid!"))])
   340                                _("IP is not valid!"))])
   341                 if dlg.ShowModal() == wx.ID_OK:
   341                 if dlg.ShowModal() == wx.ID_OK:
   342                     self.pyroserver.ip_addr = dlg.GetValue()
   342                     self.rpc_server.ip_addr = dlg.GetValue()
   343                     self.pyroserver.Restart()
   343                     self.rpc_server.Restart()
   344 
   344 
   345             def OnTaskBarChangePort(self, evt):
   345             def OnTaskBarChangePort(self, evt):
   346                 dlg = ParamsEntryDialog(None, _("Enter a port number "), defaultValue=str(self.pyroserver.port))
   346                 dlg = ParamsEntryDialog(None, _("Enter a port number "), defaultValue=str(self.rpc_server.port))
   347                 dlg.SetTests([(str.isdigit, _("Port number must be an integer!")), (lambda port: 0 <= int(port) <= 65535, _("Port number must be 0 <= port <= 65535!"))])
   347                 dlg.SetTests([(str.isdigit, _("Port number must be an integer!")), (lambda port: 0 <= int(port) <= 65535, _("Port number must be 0 <= port <= 65535!"))])
   348                 if dlg.ShowModal() == wx.ID_OK:
   348                 if dlg.ShowModal() == wx.ID_OK:
   349                     self.pyroserver.port = int(dlg.GetValue())
   349                     self.rpc_server.port = int(dlg.GetValue())
   350                     self.pyroserver.Restart()
   350                     self.rpc_server.Restart()
   351 
   351 
   352             def OnTaskBarChangeWorkingDir(self, evt):
   352             # def OnTaskBarChangeWorkingDir(self, evt):
   353                 dlg = wx.DirDialog(None, _("Choose a working directory "), self.pyroserver.workdir, wx.DD_NEW_DIR_BUTTON)
   353             #     dlg = wx.DirDialog(None, _("Choose a working directory "), self.rpc_server.workdir, wx.DD_NEW_DIR_BUTTON)
   354                 if dlg.ShowModal() == wx.ID_OK:
   354             #     if dlg.ShowModal() == wx.ID_OK:
   355                     self.pyroserver.workdir = dlg.GetPath()
   355             #         self.rpc_server.workdir = dlg.GetPath()
   356                     self.pyroserver.Restart()
   356             #         self.rpc_server.Restart()
   357 
   357 
   358             def OnTaskBarChangeName(self, evt):
   358             def OnTaskBarChangeName(self, evt):
   359                 _servicename = self.pyroserver.servicename
   359                 _servicename = self.rpc_server.servicename
   360                 _servicename = '' if _servicename is None else _servicename
   360                 _servicename = '' if _servicename is None else _servicename
   361                 dlg = ParamsEntryDialog(None, _("Enter a name "), defaultValue=_servicename)
   361                 dlg = ParamsEntryDialog(None, _("Enter a name "), defaultValue=_servicename)
   362                 dlg.SetTests([(lambda name: len(name) != 0, _("Name must not be null!"))])
   362                 dlg.SetTests([(lambda name: len(name) != 0, _("Name must not be null!"))])
   363                 if dlg.ShowModal() == wx.ID_OK:
   363                 if dlg.ShowModal() == wx.ID_OK:
   364                     self.pyroserver.servicename = dlg.GetValue()
   364                     self.rpc_server.servicename = dlg.GetValue()
   365                     self.pyroserver.Restart()
   365                     self.rpc_server.Restart()
   366 
   366 
   367             def _LiveShellLocals(self):
   367             def _LiveShellLocals(self):
   368                 return {"locals": runtime.GetPLCObjectSingleton().python_runtime_vars}
   368                 return {"locals": runtime.GetPLCObjectSingleton().python_runtime_vars}
   369 
   369 
   370             def OnTaskBarLiveShell(self, evt):
   370             def OnTaskBarLiveShell(self, evt):
   381                 wnd = wx.GetApp()
   381                 wnd = wx.GetApp()
   382                 InspectionTool().Show(wnd, True)
   382                 InspectionTool().Show(wnd, True)
   383 
   383 
   384             def OnTaskBarQuit(self, evt):
   384             def OnTaskBarQuit(self, evt):
   385                 if wx.Platform == '__WXMSW__':
   385                 if wx.Platform == '__WXMSW__':
   386                     Thread(target=self.pyroserver.Quit).start()
   386                     Thread(target=self.rpc_server.Quit).start()
   387                 self.RemoveIcon()
   387                 self.RemoveIcon()
   388                 wx.CallAfter(wx.GetApp().ExitMainLoop)
   388                 wx.CallAfter(wx.GetApp().ExitMainLoop)
   389 
   389 
   390             def UpdateIcon(self, plcstatus):
   390             def UpdateIcon(self, plcstatus):
   391                 if plcstatus is PlcStatus.Started:
   391                 if plcstatus is PlcStatus.Started:
   511     ensurePSK(servicename, PSKpath)
   511     ensurePSK(servicename, PSKpath)
   512 
   512 
   513 runtime.CreatePLCObjectSingleton(
   513 runtime.CreatePLCObjectSingleton(
   514     WorkingDir, argv, statuschange, evaluator, pyruntimevars)
   514     WorkingDir, argv, statuschange, evaluator, pyruntimevars)
   515 
   515 
   516 pyroserver = PyroServer(servicename, interface, port)
   516 rpc_server = RPCServer(servicename, interface, port)
   517 
   517 
   518 if havewx:
   518 if havewx:
   519     taskbar_instance = BeremizTaskBarIcon(pyroserver)
   519     taskbar_instance = BeremizTaskBarIcon(rpc_server)
   520 
   520 
   521 if havetwisted:
   521 if havetwisted:
   522     if webport is not None:
   522     if webport is not None:
   523         try:
   523         try:
   524             website = NS.RegisterWebsite(interface, webport)
   524             website = NS.RegisterWebsite(interface, webport)
   531             WC.RegisterWampClient(wampconf, PSKpath)
   531             WC.RegisterWampClient(wampconf, PSKpath)
   532             WC.RegisterWebSettings(NS)
   532             WC.RegisterWebSettings(NS)
   533         except Exception:
   533         except Exception:
   534             LogMessageAndException(_("WAMP client startup failed. "))
   534             LogMessageAndException(_("WAMP client startup failed. "))
   535 
   535 
   536 pyro_thread = None
   536 rpc_server_thread = None
   537 
   537 
   538 def FirstWorkerJob():
   538 def FirstWorkerJob():
   539     """
   539     """
   540     RPC through pyro/wamp/UI may lead to delegation to Worker,
   540     RPC through rpc/wamp/UI may lead to delegation to Worker,
   541     then this function ensures that Worker is already
   541     then this function ensures that Worker is already
   542     created when pyro starts
   542     created when rpc starts
   543     """
   543     """
   544     global pyro_thread, pyroserver
   544     global rpc_server_thread, rpc_server
   545 
   545 
   546     pyro_thread_started = Lock()
   546     rpc_thread_started = Lock()
   547     pyro_thread_started.acquire()
   547     rpc_thread_started.acquire()
   548     pyro_thread = Thread(target=pyroserver.PyroLoop,
   548     rpc_server_thread = Thread(target=rpc_server.Loop,
   549                          kwargs=dict(when_ready=pyro_thread_started.release),
   549                          kwargs=dict(when_ready=rpc_thread_started.release),
   550                          name="PyroThread")
   550                          name="RPCThread")
   551 
   551 
   552     pyro_thread.start()
   552     rpc_server_thread.start()
   553 
   553 
   554     # Wait for pyro thread to be effective
   554     # Wait for rpc thread to be effective
   555     pyro_thread_started.acquire()
   555     rpc_thread_started.acquire()
   556 
   556 
   557     pyroserver.PrintServerInfo()
   557     rpc_server.PrintServerInfo()
   558 
   558 
   559     # Beremiz IDE detects LOCAL:// runtime is ready by looking
   559     # Beremiz IDE detects LOCAL:// runtime is ready by looking
   560     # for self.workdir in the daemon's stdout.
   560     # for self.workdir in the daemon's stdout.
   561     if sys.stdout:
   561     if sys.stdout:
   562         sys.stdout.write(_("Current working directory :") + WorkingDir + "\n")
   562         sys.stdout.write(_("Current working directory :") + WorkingDir + "\n")
   614         runtime.MainWorker.runloop(FirstWorkerJob)
   614         runtime.MainWorker.runloop(FirstWorkerJob)
   615     except KeyboardInterrupt:
   615     except KeyboardInterrupt:
   616         pass
   616         pass
   617 
   617 
   618 
   618 
   619 pyroserver.Quit()
   619 rpc_server.Quit()
   620 pyro_thread.join()
   620 rpc_server_thread.join()
   621 
   621 
   622 plcobj = runtime.GetPLCObjectSingleton()
   622 plcobj = runtime.GetPLCObjectSingleton()
   623 try:
   623 try:
   624     plcobj.StopPLC()
   624     plcobj.StopPLC()
   625     plcobj.UnLoadPLC()
   625     plcobj.UnLoadPLC()