Beispiel #1
0
class UPnPSubscription(BaseController):
    
    def __init__(self, callbacks, timeout, protocol):
        self._uuid = str(uuid4())
        super(UPnPSubscription, self).__init__(channel="subs:" + self._uuid)
        self._callbacks = callbacks
        self._used_callback = 0
        self._client = Client(self._callbacks[self._used_callback], 
                              self.channel).register(self)
        self._protocol = protocol
        self._seq = 0
        if timeout > 0:
            self._expiry_timer = Timer \
                (timeout, Event.create("upnp_subs_end"), self).register(self)

    @handler("registered")
    def _on_registered(self, component, parent):
        if component != self:
            return
        @handler("notification", channel=parent.notification_channel)
        def _on_notification_handler(self, state_vars):
            self._on_notification(state_vars)
        self.addHandler(_on_notification_handler)
        state_vars = dict()
        for name, method in getmembers \
            (self.parent, lambda x: ismethod(x) and hasattr(x, "_evented_by")):
            state_vars[name] = method()
        if len(state_vars) > 0:
            self._on_notification(state_vars)
        self.fire(Log(logging.DEBUG, "Subscribtion for " + str(self._callbacks)
                      + " on " + self.parent.notification_channel 
                      + " created"), "logger")

    def _on_notification(self, state_vars):
        root = Element(QName(UPNP_EVENT_NS, "propertyset"))
        for name, value in state_vars.items():
            prop = SubElement(root, QName(UPNP_EVENT_NS, "property"))
            val = SubElement(prop, QName(UPNP_EVENT_NS, name))
            if isinstance(value, bool):
                val.text = "1" if value else "0"
            else:
                val.text = str(value)
        misc.set_ns_prefixes(root, { "": UPNP_EVENT_NS })
        writer = StringIO()
        writer.write("<?xml version='1.0' encoding='utf-8'?>")
        ElementTree(root).write(writer, encoding="utf-8")
        body = writer.getvalue()
        self.fire(Log(logging.DEBUG, "Notifying " 
                      + self._callbacks[self._used_callback]
                      + " about " + str(state_vars)), "logger")
        self.fire(Request("NOTIFY", self._callbacks[self._used_callback], body,
                          { "CONTENT-TYPE": "text/xml; charset=\"utf-8\"",
                            "NT": "upnp:event",
                            "NTS": "upnp:propchange",
                            "SID": self.sid,
                            "SEQ": self._seq }))
        self._seq += 1

    @handler("upnp_subs_end")
    def _on_subs_end(self):
        self.unregister()
        self.fire(Log(logging.DEBUG, "Subscribtion for " + str(self._callbacks)
                      + " on " + self.parent.notification_channel
                      + " cancelled"), "logger")

    @handler("upnp_subs_renewal")
    def _on_renewal(self, timeout):
        self._expiry_timer.interval = timeout
        self._expiry_timer.reset()
        self.fire(Log(logging.DEBUG, "Subscribtion for " + str(self._callbacks)
                      + " on " + self.parent.notification_channel
                      + " renewed"), "logger")

    @property
    def sid(self):
        return "uuid:" + self._uuid

    @classmethod
    def sid2chan(cls, sid):
        return "subs:" + sid[5:]
Beispiel #2
0
class UPnPSubscription(BaseController):
    
    def __init__(self, callbacks, timeout, protocol):
        self._uuid = str(uuid4())
        super(UPnPSubscription, self).__init__(channel="subs:" + self._uuid)
        self._callbacks = callbacks
        self._used_callback = 0
        self._client = Client(self._callbacks[self._used_callback], 
                              self.channel).register(self)
        self._protocol = protocol
        self._seq = 0
        if timeout > 0:
            self._expiry_timer = Timer \
                (timeout, Event.create("upnp_subs_end"), self).register(self)

    @handler("registered")
    def _on_registered(self, component, parent):
        if component != self:
            return
        @handler("upnp_notification", channel=parent.notification_channel)
        def _on_notification_handler(self, state_vars):
            self._on_notification(state_vars)
        self.addHandler(_on_notification_handler)
        state_vars = dict()
        for name, method in getmembers \
            (self.parent, lambda x: ismethod(x) and hasattr(x, "_evented_by")):
            state_vars[name] = method()
        if len(state_vars) > 0:
            self._on_notification(state_vars)
        self.fire(log(logging.DEBUG, "Subscribtion for " + str(self._callbacks)
                      + " on " + self.parent.notification_channel 
                      + " created"), "logger")

    def _on_notification(self, state_vars):
        root = Element(QName(UPNP_EVENT_NS, "propertyset"))
        for name, value in state_vars.items():
            prop = SubElement(root, QName(UPNP_EVENT_NS, "property"))
            val = SubElement(prop, QName(UPNP_EVENT_NS, name))
            if isinstance(value, bool):
                val.text = "1" if value else "0"
            else:
                val.text = unicode(value)
        misc.set_ns_prefixes(root, { "": UPNP_EVENT_NS })
        # Keep body as str for safe request handling
        body = "<?xml version='1.0' encoding='utf-8'?>" \
            + ElementTree.tostring(root, encoding="utf-8")
        self.fire(log(logging.DEBUG, "Notifying " 
                      + self._callbacks[self._used_callback]
                      + " about " + str(state_vars)), "logger")
        self.fire(request("NOTIFY", self._callbacks[self._used_callback], body,
                          { "CONTENT-TYPE": "text/xml; charset=\"utf-8\"",
                            "NT": "upnp:event",
                            "NTS": "upnp:propchange",
                            "SID": self.sid,
                            "SEQ": self._seq }))
        self._seq += 1

    @handler("upnp_subs_end")
    def _on_subs_end(self):
        self.unregister()
        self.fire(log(logging.DEBUG, "Subscribtion for " + str(self._callbacks)
                      + " on " + self.parent.notification_channel
                      + " cancelled"), "logger")

    @handler("upnp_subs_renewal")
    def _on_renewal(self, timeout):
        self._expiry_timer.interval = timeout
        self._expiry_timer.reset()
        self.fire(log(logging.DEBUG, "Subscribtion for " + str(self._callbacks)
                      + " on " + self.parent.notification_channel
                      + " renewed"), "logger")

    @property
    def sid(self):
        return "uuid:" + self._uuid

    @classmethod
    def sid2chan(cls, sid):
        return "subs:" + sid[5:]
Beispiel #3
0
class UPnPRootDevice(BaseComponent):

    def __init__(self, location, max_age, usn):
        super(UPnPRootDevice, self).__init__(channel=usn)
        self._location = location
        self._usn = usn
        self._ready = False
        self._comm_chan = "client." + usn
        self._client = Client(location, channel=self._comm_chan).register(self)
        @handler("response", channel=self._comm_chan)
        def _on_response(self, response):
            if response.status == http_client.OK:
                self._initialize(response.read())
        self.addHandler(_on_response)
        @handler("error", channel=self._comm_chan)
        def _on_error(self, *args, **kwargs):
            self._client.close()
            self.unregister()
        self.addHandler(_on_error)
        self.fire(Request("GET", self._location), self._client)
        self._expiry_timer \
            = Timer(max_age, UPnPDeviceByeBye(usn)).register(self)

    def _initialize(self, xml_src):
        data = XML(xml_src)
        self._friendly_name = data.findtext \
            ("{%s}device/{%s}friendlyName" \
             % (SSDP_DEVICE_SCHEMA, SSDP_DEVICE_SCHEMA))
        icons = data.findall \
            ("{%s}device/{%s}iconList/{%s}icon" \
             % (SSDP_DEVICE_SCHEMA, SSDP_DEVICE_SCHEMA, SSDP_DEVICE_SCHEMA))
        self._icons = []
        for icon in icons:
            width = int(icon.findtext("{%s}width" % SSDP_DEVICE_SCHEMA))
            height = int(icon.findtext("{%s}height" % SSDP_DEVICE_SCHEMA))
            url = urljoin(self._location,
                          icon.findtext("{%s}url" % SSDP_DEVICE_SCHEMA))
            self._icons.append(IconInfo(width, height, url))
        self._ready = True

    @handler("upnp_device_alive")
    def _on_device_alive \
        (self, location, notification_type, max_age, server, usn):
        self._expiry_timer.interval = max_age
        self._expiry_timer.reset()

    @handler("upnp_device_bye_bye")
    def _on_device_bye_bye (self, usn):
        self._client.close()
        self.unregister()

    @property
    def usn(self):
        return getattr(self, "_usn", None)
        
    @property
    def location(self):
        return getattr(self, "_location", None)

    @property
    def ready(self):
        return getattr(self, "_ready", None)

    @property
    def friendly_name(self):
        return getattr(self, "_friendly_name", None)

    @property
    def icons(self):
        return copy(getattr(self, "_icons", None))
    
    @property
    def valid_until(self):
        return self._expiry_timer._eTime \
            if hasattr(self, "_expiry_timer") else None
        
Beispiel #4
0
class UPnPRootDevice(BaseComponent):

    def __init__(self, location, max_age, usn):
        super(UPnPRootDevice, self).__init__(channel=usn)
        self._location = location
        self._usn = usn
        self._ready = False
        self._comm_chan = "client." + usn
        self._client = Client(location, channel=self._comm_chan).register(self)
        @handler("response", channel=self._comm_chan)
        def _on_response(self, response):
            if response.status == httplib.OK:
                self._initialize(response.read())
        self.addHandler(_on_response)
        @handler("error", channel=self._comm_chan)
        def _on_error(self, *args, **kwargs):
            self._client.close()
            self.unregister()
        self.addHandler(_on_error)
        self.fire(Request("GET", self._location), self._client)
        self._expiry_timer \
            = Timer(max_age, UPnPDeviceByeBye(usn)).register(self)

    def _initialize(self, xml_src):
        data = XML(xml_src)
        self._friendly_name = data.findtext \
            ("{%s}device/{%s}friendlyName" \
             % (SSDP_DEVICE_SCHEMA, SSDP_DEVICE_SCHEMA))
        icons = data.findall \
            ("{%s}device/{%s}iconList/{%s}icon" \
             % (SSDP_DEVICE_SCHEMA, SSDP_DEVICE_SCHEMA, SSDP_DEVICE_SCHEMA))
        self._icons = []
        for icon in icons:
            width = int(icon.findtext("{%s}width" % SSDP_DEVICE_SCHEMA))
            height = int(icon.findtext("{%s}height" % SSDP_DEVICE_SCHEMA))
            url = urljoin(self._location,
                          icon.findtext("{%s}url" % SSDP_DEVICE_SCHEMA))
            self._icons.append(IconInfo(width, height, url))
        self._ready = True

    @handler("upnp_device_alive")
    def _on_device_alive \
        (self, location, notification_type, max_age, server, usn):
        self._expiry_timer.interval = max_age
        self._expiry_timer.reset()

    @handler("upnp_device_bye_bye")
    def _on_device_bye_bye (self, usn):
        self._client.close()
        self.unregister()

    @property
    def usn(self):
        return getattr(self, "_usn", None)
        
    @property
    def location(self):
        return getattr(self, "_location", None)

    @property
    def ready(self):
        return getattr(self, "_ready", None)

    @property
    def friendly_name(self):
        return getattr(self, "_friendly_name", None)

    @property
    def icons(self):
        return copy(getattr(self, "_icons", None))
    
    @property
    def valid_until(self):
        return self._expiry_timer._eTime \
            if hasattr(self, "_expiry_timer") else None