Exemplo n.º 1
0
 def Connect(self):
     self.connection = XMLRPCServerProxy(self.systemUrl, allow_none=True,
                                         timeout=self.SOCKET_TIMEOUT)
Exemplo n.º 2
0
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)