def InitXMLRPCServer(self): self.rpcserver = SimpleXMLRPCServer(("", self.port), allow_none=True) self.rpcserver.register_function(self.set_client_version, "set_client_version") self.rpcserver.register_function(self.get_client_version, "get_client_version") self.rpcserver.register_function(self.set_tags, "set_tags") self.rpcserver.register_function(self.register_tags_events, "register_tags_events") self.rpcserver.register_function(self.list_clients, "list_clients") self.rpcserver.register_function(self.list_tags, "list_tags") self.rpcserver.register_function(self.suspend_client, "suspend_client") self.rpcserver.register_function(self.resume_client, "resume_client") self.rpcserver.register_function(self.reload_config, "reload_config") self.rpcserver.register_function(self.register_share, "register_share") self.rpcserver.register_function(self.unregister_share, "unregister_share") self.rpcserver.register_function(self.get_client_info, "get_client_info") self.rpcserver.register_function(self.list_shares, "list_shares") self.rpcserver.register_function(self.list_shared_events, "list_shared_events") self.rpcserver.register_function(self.list_subscriptions, "list_subscriptions") self.rpcserver.register_function(self.check_connection, "check_connection") self.rpcserver.register_function(self.ping, "ping")
class ConnectionManager(Unpickable(topologyInfo=TopologyInfo, lock=PickableLock, alive=(bool, False), tags_file=str), ICallbackAcceptor): def InitXMLRPCServer(self): self.rpcserver = SimpleXMLRPCServer(("", self.port), allow_none=True) self.rpcserver.register_function(self.set_client_version, "set_client_version") self.rpcserver.register_function(self.get_client_version, "get_client_version") self.rpcserver.register_function(self.set_tags, "set_tags") self.rpcserver.register_function(self.register_tags_events, "register_tags_events") self.rpcserver.register_function(self.list_clients, "list_clients") self.rpcserver.register_function(self.list_tags, "list_tags") self.rpcserver.register_function(self.suspend_client, "suspend_client") self.rpcserver.register_function(self.resume_client, "resume_client") self.rpcserver.register_function(self.reload_config, "reload_config") self.rpcserver.register_function(self.register_share, "register_share") self.rpcserver.register_function(self.unregister_share, "unregister_share") self.rpcserver.register_function(self.get_client_info, "get_client_info") self.rpcserver.register_function(self.list_shares, "list_shares") self.rpcserver.register_function(self.list_shared_events, "list_shared_events") self.rpcserver.register_function(self.list_subscriptions, "list_subscriptions") self.rpcserver.register_function(self.check_connection, "check_connection") self.rpcserver.register_function(self.ping, "ping") def UpdateContext(self, context): self.scheduler = context.Scheduler self.network_name = context.network_name self.tags_file = context.remote_tags_db_file self.port = context.system_port if self.tags_file: self.acceptors = MapSetDB(self.tags_file) self.topologyInfo.UpdateContext(context) self.max_remotetags_resend_delay = context.max_remotetags_resend_delay def Start(self): if not self.network_name or not self.tags_file or not self.port: logging.warning("ConnectionManager could'n start: wrong configuration. " + "network_name: %s, remote_tags_db_file: %s, system_port: %r", self.network_name, self.tags_file, self.port) return self.ReloadConfig() logging.debug("after_reload_config") for client in self.topologyInfo.servers.values(): if client.active and client.name != self.network_name: client.TryInitializePeersVersions(self.network_name) logging.debug("after_clients_versions_init") self.alive = True self.InitXMLRPCServer() self._accept_loop_thread = ProfiledThread(target=self.ServerLoop, name_prefix='ConnManager') self._accept_loop_thread.start() logging.debug("after_connection_manager_loop_start") for client in self.topologyInfo.servers.values(): self.scheduler.ScheduleTaskT(0, self.SendData, client, skip_logging=True) def Stop(self): self.alive = False self._accept_loop_thread.join() self.rpcserver = None # shutdown listening socket def ServerLoop(self): rpc_fd = self.rpcserver.fileno() while self.alive: rout, _, _ = select.select((rpc_fd,), (), (), 0.01) if rpc_fd in rout: self.rpcserver.handle_request() def SendData(self, client): if self.alive and client.active: client.SendDataIfNeed(self.network_name) if hasattr(self, "scheduler"): self.scheduler.ScheduleTaskT( min(client.PENALTY_FACTOR ** client.errorsCnt, self.max_remotetags_resend_delay), self.SendData, client, skip_logging=True ) def RegisterTagEvent(self, tag, event, message=None): if not isinstance(tag, TagBase): raise RuntimeError("%s is not Tag class instance", tag.GetName()) if tag.IsRemote(): return tagname = tag.GetName() with self.lock: # see register_share acceptors = self.acceptors.get(tagname) if acceptors: logging.debug("on %s connmanager %s with acceptors list %s", TagEventName[event], tagname, acceptors) for clientname in acceptors: self.RegisterTagEventForClient(clientname, tagname, event, message) def RegisterTagEventForClient(self, clientname, tagname, event, message=None): logging.debug("%s remote tag %s on host %s", TagEventName[event], tagname, clientname) client = self.topologyInfo.GetClient(clientname, checkname=False) if client is None: logging.error("unknown client %s appeared", clientname) return False client.RegisterTagEvent("%s:%s" % (self.network_name, tagname), event, message) def ReloadConfig(self, filename=None): old_servers = set(self.topologyInfo.servers.keys()) self.topologyInfo.ReloadConfig() new_servers = set(self.topologyInfo.servers.keys()) new_servers -= old_servers if self.alive: for client in new_servers: self.scheduler.ScheduleTaskT(0, self.SendData, self.topologyInfo.servers[client], skip_logging=True) def Subscribe(self, tag): if tag.IsRemote(): client = self.topologyInfo.GetClient(tag.GetRemoteHost(), checkname=True) client.Subscribe(tag.GetName()) return True return False @traced_rpc_method() def set_tags(self, tags): # obsolete logging.debug("set %d remote tags", len(tags)) for tagname in tags: self.scheduler.tagRef.AcquireTag(tagname).CheckRemote().Set() return True @traced_rpc_method() def set_client_version(self, clientname, version): self.topologyInfo.GetClient(clientname, checkname=True).SetVersion(int(version)) logging.debug("set client version for %s to %s", clientname, version) return True @traced_rpc_method() def get_client_version(self): return PROTOCOL_VERSION @traced_rpc_method() def register_tags_events(self, updates): tagRef = self.scheduler.tagRef logging.debug("register_tags_events %d: %s", len(updates), updates) for update in updates: tagRef.AcquireTag(update[0]).CheckRemote().Modify(*update[1:]) logging.debug("done with: %s", update) logging.debug("register_tags_events %d: done", len(updates)) return True @traced_rpc_method() def list_clients(self): return [{"name": client.name, "url": client.url, "systemUrl": client.systemUrl, "active": client.active, "version": client.version, "errorsCount": client.errorsCnt, "tagsCount": len(client.events), "subscriptionsCount": len(client.subscriptions), "lastError": str(client.lastError)} for client in self.topologyInfo.servers.values()] @traced_rpc_method() def list_tags(self, name_prefix): data = set() for server in self.topologyInfo.servers.values(): if name_prefix is None or server.name.startswith(name_prefix): data.update(server.GetEventsAsTagsToSet()) return list(data) @traced_rpc_method() def suspend_client(self, name): client = self.topologyInfo.GetClient(name) return client.Suspend() @traced_rpc_method() def resume_client(self, name): client = self.topologyInfo.GetClient(name) return client.Resume() @traced_rpc_method() def reload_config(self, location=None): self.ReloadConfig(location) @traced_rpc_method() def register_share(self, tags, clientname): tagRef = self.scheduler.tagRef logging.debug("register_share %d tags for %s: %s", len(tags), clientname, tags) for tagname in tags: # XXX # 1. this lock only guarantee eventual-consistency of tag's history # 2. clients of self may see duplicates of events (even Reset) # 3. also guard self.acceptors with self.lock: self.acceptors.add(tagname, clientname) if tagRef._RawTag(tagname).IsLocallySet(): self.RegisterTagEventForClient(clientname, tagname, ETagEvent.Set) logging.debug("register_share %d tags for %s: done", len(tags), clientname) @traced_rpc_method() def unregister_share(self, tagname, clientname): with self.lock: return self.acceptors.remove(tagname, clientname) @traced_rpc_method() def get_client_info(self, clientname): client = self.topologyInfo.GetClient(clientname) res = {"name": client.name, "url": client.url, "systemUrl": client.systemUrl, "active": client.active, "version": client.version, "errorsCount": client.errorsCnt, "deferedTagsCount": len(client.events), "subscriptionsCount": len(client.subscriptions), "lastError": str(client.lastError)} return res @traced_rpc_method() def list_shares(self, clientname): client = self.topologyInfo.GetClient(clientname) return _get_tags_to_set(client.GetEventsAsList()) @traced_rpc_method() def list_shared_events(self, clientname): client = self.topologyInfo.GetClient(clientname) return client.GetEventsAsList() @traced_rpc_method() def list_subscriptions(self, clientname): client = self.topologyInfo.GetClient(clientname) return list(client.subscriptions) @traced_rpc_method() def check_connection(self, clientname): client = self.topologyInfo.GetClient(clientname) return client.connection.ping() @traced_rpc_method() def ping(self): return True def __getstate__(self): sdict = self.__dict__.copy() sdict.pop("scheduler", None) sdict.pop("rpcserver", None) sdict.pop("acceptors", None) sdict.pop("_accept_loop_thread", None) sdict["alive"] = False return getattr(super(ConnectionManager, self), "__getstate__", lambda: sdict)()