def __init__(self, conn, system=None): # conn has to be always supplied because of rpyc.Service __init__ if conn is not None: # remote service self._remote = True super(Service, self).__init__(conn) else: self._remote = False self._result = ServiceResultGenerator() self._result.log_service_name(self.get_service_name()) self._result.log_service_aliases(self.get_service_aliases()) if system is not None: # we are running local service assert conn is None self.system = system else: # in this case we are running remote service, system should be passed # by SystemEnvelope by calling on_startup() assert conn is not None self.system = self.__class__._system self.signal_init()
class Service(RpycService): # a list of locks for resources so each thread has it's own locks for currently manipulated resources # this avoids to block all threads every time a resource is accessed _resource_lock = Lock() _resource_lock_list = {} _service_lock = Lock() class ResourceLock(object): def __enter__(self): return Lock() def __exit__(self, type_, value, traceback): with Service._resource_lock: if self in Service._resource_lock_list: Service._resource_lock_list.remove(self) def __init__(self, conn, system=None): # conn has to be always supplied because of rpyc.Service __init__ if conn is not None: # remote service self._remote = True super(Service, self).__init__(conn) else: self._remote = False self._result = ServiceResultGenerator() self._result.log_service_name(self.get_service_name()) self._result.log_service_aliases(self.get_service_aliases()) if system is not None: # we are running local service assert conn is None self.system = system else: # in this case we are running remote service, system should be passed # by SystemEnvelope by calling on_startup() assert conn is not None self.system = self.__class__._system self.signal_init() def __del__(self): self.signal_destruct() @classmethod def on_termination(cls): cls.signal_termination() def on_connect(self): if self.is_remote(): self._result.log_connect_time() self.signal_connect() def on_disconnect(self): self.signal_destruct() self.signal_disconnect() def _rpyc_getattr(self, name): func = getattr(self, name) if hasattr(func, 'action') and func.action is True: return ActionWrapper( func, self._result, prehook=self.signal_process, posthook=self.signal_processed ) else: raise AttributeError("Service '%s' does not expose action '%s'" % (self.get_service_name(), name)) def _get_resource_lock(self, resource): with self.__class__._resource_lock: if resource in self.__class__._resource_lock_list: ret = self.__class__._resource_lock_list[resource] else: ret = Service.ResourceLock() self.__class__._resource_lock_list[resource] = ret return ret def get_lock(self, resource = None): if resource is not None: return self._get_resource_lock(resource) else: return self.__class__._service_lock @classmethod def signal_startup(cls, config): pass @classmethod def signal_termination(cls): pass def signal_init(self): pass def signal_destruct(self): pass def signal_connect(self): pass def signal_disconnect(self): pass def signal_process(self): pass def signal_processed(self, was_error): pass def is_local(self): return not self.is_remote() def is_remote(self): return self._remote @classmethod def get_service_version(cls): return VERSION @classmethod def get_host(cls): # this is pretty dummy way, but there is nothing we can do with it for now remote = cls._config.get('remote') remote = remote == 'True' if remote is False: return None return cls._config.get('host') @classmethod def get_port(cls): # this is pretty dummy way, but there is nothing we can do with it for now remote = cls._config.get('remote') remote = remote == 'True' if remote is False: return None return cls._config.get('port') def version(self): return self.__class__.get_service_version()