def Connect(self): self.connection = XMLRPCServerProxy(self.systemUrl, allow_none=True, timeout=self.SOCKET_TIMEOUT)
class ClientInfo(Unpickable(events=Deque, name=str, subscriptions=set, errorsCnt=(int, 0), version=(int, PROTOCOL_VERSION), send_events_lock=PickableLock, active=(bool, True))): MAX_TAGS_BULK = 100 PENALTY_FACTOR = 6 SOCKET_TIMEOUT = 120.0 def __init__(self, *args, **kws): getattr(super(ClientInfo, self), "__init__")(*args, **kws) self.update(*args, **kws) self.lastError = None def Connect(self): self.connection = XMLRPCServerProxy(self.systemUrl, allow_none=True, timeout=self.SOCKET_TIMEOUT) def RegisterTagEvent(self, tag, event, message=None): self.events.push((tag, event, message)) def Subscribe(self, tagname): self.subscriptions.add(tagname) def GetEventsAsTagsToSet(self): return _get_tags_to_set(self.events.as_list()) def GetEventsAsList(self): return self.events.as_list() def update(self, name=None, url=None, systemUrl=None): if name: self.name = name if url: self.url = url if systemUrl: self.systemUrl = systemUrl self.Connect() def __setstate__(self, sdict): taglist = sdict.pop('taglist', None) # old backup super(ClientInfo, self).__setstate__(sdict) if taglist: for tag in taglist: self.RegisterTagEvent(tag, ETagEvent.Set) def Resume(self): self.Connect() self.active = True def Suspend(self): self.active = False def SetVersion(self, version): logging.debug("set client '%s' version to %s" % (self.name, version)) self.version = version def _DoSendEventsIfNeed(self): tosend = self.events[:self.MAX_TAGS_BULK] if not tosend: return logging.debug("SendData to %s: %d events", self.name, len(tosend)) def send_as_events(): try: self.connection.register_tags_events(tosend) return True except XMLRPCMethodNotSupported: self.SetVersion(1) return False def send_as_set_tags(): tags = _get_tags_to_set(tosend) if not tags: return self.connection.set_tags(tags) if self.version < 2 or not send_as_events(): send_as_set_tags() self.events.pop(len(tosend)) def _SendEventsIfNeed(self): with self.send_events_lock: # ATW this lock is redundant self._DoSendEventsIfNeed() def _SendSubscriptionsIfNeed(self, local_server_network_name): tosend = list(self.subscriptions)[:self.MAX_TAGS_BULK] if not tosend: return logging.debug("SendData to %s: %d subscriptions", self.name, len(tosend)) self.connection.register_share(tosend, local_server_network_name) self.subscriptions.difference_update(tosend) def TryUpdatePeerVersion(self): try: version = self.connection.get_client_version() except XMLRPCMethodNotSupported: self.SetVersion(1) return False self.SetVersion(version) return True def TrySendMyVersion(self, local_server_network_name): try: self.connection.set_client_version(local_server_network_name, PROTOCOL_VERSION) except XMLRPCMethodNotSupported: self.SetVersion(1) def _Communicate(self, f): self.Connect() try: f() self.errorsCnt = 0 logging.debug("SendData to %s: ok", self.name) except (IOError, socket.timeout) as e: logging.warning("SendData to %s: failed: %s", self.name, e) self.lastError = e self.errorsCnt += 1 except Exception as e: logging.error("SendData to %s: failed: %s", self.name, e) def SendDataIfNeed(self, local_server_network_name): if not self.subscriptions and not self.events: return def impl(): if self.errorsCnt: self.TryUpdatePeerVersion() self._SendEventsIfNeed() self._SendSubscriptionsIfNeed(local_server_network_name) self._Communicate(impl) def TryInitializePeersVersions(self, local_server_network_name): def impl(): self.TryUpdatePeerVersion() self.TrySendMyVersion(local_server_network_name) self._Communicate(impl) def __getstate__(self): sdict = self.__dict__.copy() sdict.pop("connection", None) return getattr(super(ClientInfo, self), "__getstate__", lambda: sdict)() def __repr__(self): return "<ClientInfo %s alive: %r>" % (self.name, self.active)