# Copyright (c) 2001 LOGILAB S.A. (Paris, FRANCE). # http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along with # this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place - Suite 330, Boston, MA 02111-1307 # USA. __revision__ = "$Id: pyro.py,v 1.6 2002/02/28 11:07:58 alf Exp $" from narval.communication.RPCFactory import ServerInterface, ProxyInterface,\ decode_uri from narval.services.BaseService import BaseService import socket, time from Pyro import naming, core, config from Pyro.errors import PyroError, NamingError GROUP = ':narval' class PYROServer(core.Daemon, BaseService, ServerInterface): def __init__(self, port, method_handler, debug=0) : BaseService.__init__(self, 'PYRO') host = socket.gethostname() # init pyro daemon core.initServer() config.PYRO_NS_DEFAULTGROUP = GROUP #config.PYRO_NS_ROOTCHAR = ':' #config.PYRO_NS_GROUPSEP = '.' if debug: print 'PYRO DEBUG MODE ON' config.PYRO_LOGFILE = config.PYRO_USER_LOGFILE = '/tmp/narval%d-pyro.log'%port config.PYRO_TRACELEVEL = 3 config.PYRO_USER_TRACELEVEL = 3 core.Daemon.__init__(self, host=host, port=port) # get (start if necessary) the NS ns = get_pyro_ns() self.useNameServer(ns) # make sure our namespace group exists try: ns.createGroup(GROUP) except NamingError: pass # create dispatcher dispatcher = generate_dispatcher(method_handler, 'core.ObjBase') # register dispatcher object o_uri = encode_pyro_uri(host, port, method_handler.NAME) try: ns.unregister(o_uri) except NamingError: pass print 'register', o_uri self._o_uri = o_uri self.connect(dispatcher, o_uri) def __del__(self): ns = get_pyro_ns() ns.unregister(self._o_uri) def _run(self): while self.loop: self.handleRequests(1.0) class PYROProxy(ProxyInterface): def __init__(self, uri): core.initClient() config.PYRO_NS_DEFAULTGROUP = GROUP # get (start if necessary) the pyro name server ns = get_pyro_ns() # resolve the pyro object type, host, port, obj_name = decode_uri(uri) uri = encode_pyro_uri(host, port, obj_name) pyro_uri = ns.resolve(uri) # retrieve proxy object self.obj = core.getProxyForURI(pyro_uri) def encode_pyro_uri(host, port, name): host = host.split('.')[0] return '%s%s%s' % (host, port, name) def get_pyro_ns(): locator = naming.NameServerLocator() try: ns = locator.getNS() except PyroError: from os import spawnv, P_NOWAIT from sys import executable,platform if platform == 'win32': script = '"import Pyro.naming; Pyro.naming.main()"' else: script = 'import Pyro.naming; Pyro.naming.main()' spawnv(P_NOWAIT , executable, (executable, '-c', script)) time.sleep(1) ns = locator.getNS(socket.gethostname()) return ns def generate_dispatcher(method_handler, parent_class=None): """ Create a dispatcher class and return an instance of it from a dispatcher definition. The definition is a class with the following attributes: _ EXPORTED_METHOD: dictionary where keys are method names and values class attribute names of the attributes holding references to an object implementing the method _ attributes defined in EXPORTED_METHODS values. They must contain an object instance which implements the respective methods (EXPORTED_METHODS keys) Ex: class TestDispatchHandler: EXPORTED_METHODS = {'method1': 'attr1', 'method2': 'attr1', 'method3': 'attr2'} attr1 = Object1() attr2 = Object2() where Object1 is a class which provides method1 and method2 and Object2 a class which provides method3 obj_inst = generate_dispatcher(TestDispatchHandler) will affect in 'obj_inst' a class instance which provide method1, method2 and method3 by delegate it to the correct object """ # class definition if parent_class: class_str = 'class Dispatcher(%s):\n' % parent_class statements = ' %s.__init__(self)\n' % parent_class else: class_str = 'class Dispatcher:\n' statements = '' # methods definition registered = [] for method, objname in method_handler.EXPORTED_METHODS.items(): if not objname in registered: registered.append(objname) class_str = '%s def %s(self, *attrs):\n return self.%s.%s(*attrs)\n'%\ (class_str, method, objname, method) # constructor definition attrs = '' for objname in registered: attrs = '%s, %s' % (attrs, objname) statements = '%s self.%s=%s\n' % (statements, objname, objname) # retrieve object reference in current context exec '%s=getattr(method_handler, "%s")'%(objname, objname) # assemble all parts class_str = '%s def __init__(self%s):\n%s' % (class_str, attrs, statements) # now we can eval the full class exec class_str # return an instance of constructed class return eval('Dispatcher(%s)'%attrs[2:]) # attrs[2:] for removing ', '