1 # Copyright (C) 2007-2015 CEA/DEN, EDF R&D
3 # This library is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU Lesser General Public
5 # License as published by the Free Software Foundation; either
6 # version 2.1 of the License, or (at your option) any later version.
8 # This library is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 # Lesser General Public License for more details.
13 # You should have received a copy of the GNU Lesser General Public
14 # License along with this library; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 # Author : Adrien Bruneton (CEA)
22 import PVSERVER_ORB__POA
23 import SALOME_ComponentPy
27 import subprocess as subp
29 from time import sleep
31 #from SALOME_utilities import MESSAGE
34 """ Debug function """
36 #os.system("echo \"%s\" >> /tmp/paravis_log.txt" % m)
39 """ The core implementation (non CORBA, or Study related).
40 See the IDL for the documentation.
42 MAX_PVSERVER_PORT_TRIES = 1000 # Maximum number of tries to get a free port for the PVServer
43 PVSERVER_DEFAULT_PORT = 11111 # First port being tried to launch the pvserver
46 self.pvserverPort = -1
47 self.pvserverPop = None # Popen object from subprocess module
48 self.isGUIConnected = False # whether there is an active connection from the GUI.
53 raise Exception("PVSERVER_Impl.__init__ : \"import paraview\" failed !")
54 # deduce dynamically PARAVIEW_ROOT_DIR from the paraview module location
55 self.PARAVIEW_ROOT_DIR = None
56 ZE_KEY_TO_FIND_PV_ROOT_DIR="lib"
57 li=tmp.split(os.path.sep) ; li.reverse()
58 if ZE_KEY_TO_FIND_PV_ROOT_DIR not in li:
59 raise SALOME.SALOME_Exception(SALOME.ExceptionStruct(SALOME.INTERNAL_ERROR,
60 "PVSERVER_Impl.__init__ : error during dynamic deduction of PARAVIEW_ROOT_DIR : Loc of paraview module is \"%s\" ! \"%s\" is supposed to be the key to deduce it !"%(tmp,ZE_KEY_TO_FIND_PV_ROOT_DIR),
62 li=li[li.index("lib")+1:] ; li.reverse()
63 self.PARAVIEW_ROOT_DIR = os.path.sep.join(li)
66 Private. Identify a free port to launch the PVServer.
67 This is done by trying to bind a socket on the port.
68 We are still subject to a race condition between this detection mechanism and the actual launch of the pvserver
71 def __getFreePort(self, startPort):
74 while cnt < self.MAX_PVSERVER_PORT_TRIES:
76 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
77 s.bind(('', currPort))
80 except socket.error as e:
84 raise SALOME.SALOME_Exception(SALOME.ExceptionStruct(SALOME.INTERNAL_ERROR,
85 "[PVSERVER] maximum number of tries to retrieve a free port for the PVServer",
88 def FindOrStartPVServer( self, port ):
89 MESSAGE("[PVSERVER] FindOrStartPVServer ...")
92 if self.pvserverPop is None:
95 # Poll active server to check if still alive
96 self.pvserverPop.poll()
97 if not self.pvserverPop.returncode is None: # server terminated
101 return "cs://%s:%d" % (host, self.pvserverPort)
103 # (else) Server not alive, start it:
104 pvServerPath = os.path.join(self.PARAVIEW_ROOT_DIR, 'bin', 'pvserver')
107 port = self.__getFreePort(self.PVSERVER_DEFAULT_PORT)
108 self.pvserverPop = subp.Popen([pvServerPath, "--multi-clients", "--server-port=%d" % port, "--use-offscreen-rendering"])
109 sleep(3) # Give some time to the server to start up to avoid
110 # ugly messages on the client side saying that it cannot connect
111 # Is PID still alive? If yes, consider that the launch was successful
112 self.pvserverPop.poll()
113 if self.pvserverPop.returncode is None:
115 self.pvserverPort = port
116 MESSAGE("[PVSERVER] pvserver successfully launched on port %d" % port)
118 raise SALOME.SALOME_Exception(SALOME.ExceptionStruct(SALOME.INTERNAL_ERROR,
119 "[PVSERVER] Unable to start PVServer on port %d!" % port,
121 return "cs://%s:%d" % (host, self.pvserverPort)
123 def StopPVServer( self ):
124 MESSAGE("[PVSERVER] Trying to stop PVServer (sending KILL) ...")
125 if not self.pvserverPop is None:
126 self.pvserverPop.poll()
127 if self.pvserverPop.returncode is None:
128 # Terminate if still running:
129 self.pvserverPop.terminate()
130 MESSAGE("[PVSERVER] KILL signal sent.")
132 MESSAGE("[PVSERVER] Nothing to kill.")
135 def SetGUIConnected( self, isConnected ):
136 self.isGUIConnected = isConnected
138 def GetGUIConnected( self ):
139 return self.isGUIConnected
141 class PVSERVER(PVSERVER_ORB__POA.PVSERVER_Gen,
142 SALOME_ComponentPy.SALOME_ComponentPy_i,
145 Construct an instance of PVSERVER module engine.
146 The class PVSERVER implements CORBA interface PVSERVER_Gen (see PVSERVER_Gen.idl).
147 It is inherited from the classes SALOME_ComponentPy_i (implementation of
148 Engines::EngineComponent CORBA interface - SALOME component).
150 def __init__ ( self, orb, poa, contID, containerName, instanceName,
152 SALOME_ComponentPy.SALOME_ComponentPy_i.__init__(self, orb, poa,
153 contID, containerName, instanceName, interfaceName, 0)
154 PVSERVER_Impl.__init__(self)
156 self._naming_service = SALOME_ComponentPy.SALOME_NamingServicePy_i( self._orb )
159 """ Override base class destroy to make sure we try to kill the pvserver
165 SALOME_ComponentPy.destroy(self)
168 Get version information.
170 def getVersion( self ):
171 import salome_version
172 return salome_version.getVersion("PARAVIS", True)
178 return PVSERVER_utils.getEngineIOR()