Ticket #142: urlbase.patch

File urlbase.patch, 12.6 kB (added by Lawrence, 4 years ago)

patch file for service/device/event to handle urlBase

  • device.py

    old new  
    55# Copyright 2006, Frank Scholz <coherence@beebits.net> 
    66 
    77import urllib2 
     8from urlparse import urlparse,urljoin 
    89import time 
    910 
    1011from twisted.internet import defer 
     
    7980    def get_id(self): 
    8081        return self.udn 
    8182 
     83    def get_root_id(self): 
     84        if self.parent: 
     85            return self.parent.get_id() 
     86        return self.get_id() 
     87 
    8288    def get_uuid(self): 
    8389        return self.udn[5:] 
    8490 
     91    def get_root_uuid(self): 
     92        if self.parent: 
     93            return self.parent.get_root_uuid() 
     94        return self.get_uuid() 
     95 
    8596    def get_services(self): 
    8697        return self.services 
    8798 
     
    139150 
    140151    def parse_device(self, d): 
    141152        self.device_type = unicode(d.findtext('./{%s}deviceType' % ns)) 
     153        self.model_name = unicode(d.findtext('./{%s}modelName' % ns)) 
    142154        self.friendly_name = unicode(d.findtext('./{%s}friendlyName' % ns)) 
    143155        self.udn = d.findtext('.//{%s}UDN' % ns) 
    144156 
    145157        icon_list = d.find('./{%s}iconList' % ns) 
    146158        if icon_list is not None: 
    147159            import urllib2 
    148             url_base = "%s://%s" % urllib2.urlparse.urlparse(self.get_location())[:2] 
     160#            url_base = "%s://%s" % urllib2.urlparse.urlparse(self.get_location())[:2] 
    149161            for icon in icon_list.findall('./{%s}icon' % ns): 
    150162                try: 
    151163                    i = {} 
     
    154166                    i['height'] = icon.find('./{%s}height' % ns).text 
    155167                    i['depth'] = icon.find('./{%s}depth' % ns).text 
    156168                    i['url'] = icon.find('./{%s}url' % ns).text 
    157                     if i['url'].startswith('/'): 
    158                         i['url'] = ''.join((url_base,i['url'])) 
     169                    i['url'] = urljoin(get_url_base(), i['url']) 
     170#                    if i['url'].startswith('/'): 
     171#                        i['url'] = ''.join((url_base,i['url'])) 
    159172                    self.icons.append(i) 
    160173                    self.debug("adding icon %r for %r" % (i,self.friendly_name)) 
    161174                except: 
     
    183196                if len(controlUrl) == 0: 
    184197                    self.warning("service has no uri for controling") 
    185198                    continue 
    186                 self.add_service(Service(serviceType, serviceId, self.get_location(), 
     199                self.add_service(Service(serviceType, serviceId, self.get_url_base(), 
    187200                                         controlUrl, 
    188201                                         eventSubUrl, presentationUrl, scpdUrl, self)) 
    189202 
     
    199212    def get_location(self): 
    200213        return self.parent.get_location() 
    201214 
     215    def get_url_base(self): 
     216        return self.parent.get_url_base() 
     217 
    202218    def get_usn(self): 
    203219        return self.parent.get_usn() 
    204220 
     
    231247    def get_location(self): 
    232248        return self.location 
    233249 
     250    def get_url_base(self): 
     251        return self.url_base 
     252 
    234253    def get_host(self): 
    235254        return self.host 
    236255 
     
    279298            data, headers = x 
    280299            tree = utils.parse_xml(data, 'utf-8').getroot() 
    281300 
     301            # This is the base for all relative URLs 
     302            self.url_base = tree.findtext('./{%s}URLBase' % ns) 
     303            if self.url_base is None or len(self.url_base) == 0: 
     304                # not given in description so use location 
     305 
     306                # TODO should we parse out only protocol and host or use as is 
     307                # I think the url_base could contain part of a path as well. 
     308                parsed = urlparse(self.location) 
     309                # ensure has trailing slash 
     310                self.url_base = "%s://%s/" % (parsed[0], parsed[1]) 
     311            self.debug("url_base %r" % self.url_base) 
     312 
    282313            d = tree.find('.//{%s}device' % ns) 
    283314            if d is not None: 
    284315                self.parse_device(d) # root device 
  • event.py

    old new  
    243243    log_category = "event_protocol" 
    244244    log.info(log_category, "event.subscribe, action: %r", action) 
    245245 
    246     _,host_port,path,_,_ = urlsplit(service.get_base_url()) 
     246#    _,host_port,path,_,_ = urlsplit(service.get_base_url()) 
     247# have service keep complete event URL 
     248    _,host_port,path,_,_ = urlsplit(service.get_event_sub_url()) 
    247249    if host_port.find(':') != -1: 
    248250        host,port = tuple(host_port.split(':')) 
    249251        port = int(port) 
     
    253255 
    254256    def send_request(p, action): 
    255257        log.info(log_category, "event.subscribe.send_request %r, action: %r %r", 
    256                  p, action, service.get_event_sub_url()
     258                 p, action, path
    257259        if action == 'subscribe': 
    258260            timeout = service.timeout 
    259261            if timeout == 0: 
    260262                timeout = 1800 
    261             request = ["SUBSCRIBE %s HTTP/1.1" % service.get_event_sub_url()
     263            request = ["SUBSCRIBE %s HTTP/1.1" % path
    262264                        "HOST: %s:%d" % (host, port), 
    263265                        "TIMEOUT: Second-%d" % timeout, 
    264266                        ] 
    265267            service.event_connection = p 
    266268        else: 
    267             request = ["UNSUBSCRIBE %s HTTP/1.1" % service.get_event_sub_url()
     269            request = ["UNSUBSCRIBE %s HTTP/1.1" % path
    268270                        "HOST: %s:%d" % (host, port), 
    269271                        ] 
    270272 
     
    293295        #return d 
    294296 
    295297    def got_error(failure, action): 
    296         log.info(log_category, "error on %s request with %s" % (action,service.get_base_url())) 
     298        log.info(log_category, "error on %s request with %s", action,service.get_event_sub_url()) 
    297299        log.debug(log_category, failure) 
    298300 
    299301    def teardown_connection(c, d): 
  • service.py

    old new  
    77import os 
    88 
    99import time 
    10 import urllib2 
     10from urlparse import urlparse,urljoin 
    1111from coherence.upnp.core import action 
    1212from coherence.upnp.core import event 
    1313from coherence.upnp.core import variable 
     
    4141class Service(log.Loggable): 
    4242    logCategory = 'service_client' 
    4343 
    44     def __init__(self, service_type, service_id, location, control_url, 
     44    def __init__(self, service_type, service_id, url_base, control_url, 
    4545                 event_sub_url, presentation_url, scpd_url, device): 
    46         if not control_url.startswith('/'): 
    47             control_url = "/%s" % control_url 
    48         if not event_sub_url.startswith('/'): 
    49             event_sub_url = "/%s" % event_sub_url 
    50         if presentation_url and not presentation_url.startswith('/'): 
    51             presentation_url = "/%s" % presentation_url 
    52         if not scpd_url.startswith('/'): 
    53             scpd_url = "/%s" % scpd_url 
    54  
     46 
    5547        self.service_type = service_type 
    5648        self.detection_completed = False 
    57         self.id = service_id 
    58         self.control_url = control_url 
    59         self.event_sub_url = event_sub_url 
    60         self.presentation_url = presentation_url 
    61         self.scpd_url = scpd_url 
     49        self.id = service_id 
     50 
     51        self.control_url = urljoin(url_base, control_url) 
     52        self.event_sub_url = urljoin(url_base, event_sub_url) 
     53        self.presentation_url = urljoin(url_base, presentation_url) 
     54        self.scpd_url = urljoin(url_base, scpd_url) 
     55 
    6256        self.device = device 
    6357        self._actions = {} 
    6458        self._variables = { 0: {}} 
     
    7165 
    7266        self.client = None 
    7367 
    74         parsed = urllib2.urlparse.urlparse(location) 
    75         self.url_base = "%s://%s" % (parsed[0], parsed[1]) 
    76  
    7768        self.parse_actions() 
    78         self.info("%s %s %s initialized" % (self.device.friendly_name,self.service_type,self.id)) 
     69        self.info("%s %s %s initialized" % (self.device.friendly_name,self.service_type,self.id)) 
     70        self.debug("control_url %s", self.control_url) 
     71        self.debug("event_sub_url %s", self.event_sub_url) 
     72        self.debug("presentation_url %s", self.presentation_url) 
     73        self.debug("scpd_url %s", self.scpd_url) 
    7974 
    8075    def __repr__(self): 
    8176        return "Service %s %s" % (self.service_type,self.id) 
     
    151146        return self._actions 
    152147 
    153148    def get_action( self, name): 
    154         return self.get_actions()[name] 
     149        if self._actions.has_key(name): 
     150            return self._actions[name] 
     151        return None # not implemented 
    155152 
    156153    def get_state_variables(self, instance): 
    157         return self._variables.get(instance
     154        return self._variables.get(int(instance)
    158155 
    159156    def get_state_variable(self, name, instance=0): 
    160157        instance = int(instance) 
    161158        return self._variables.get(instance).get(name) 
    162159 
    163160    def get_control_url(self): 
    164         return self.url_base + self.control_url 
     161        return self.control_url 
    165162 
    166163    def get_event_sub_url(self): 
    167         #return self.url_base + self.event_sub_url 
    168         return self.event_sub_url 
     164        return self.event_sub_url 
    169165 
    170166    def get_presentation_url(self): 
    171         return self.url_base + self.presentation_url 
     167        return self.presentation_url 
    172168 
    173169    def get_scpd_url(self): 
    174         return self.url_base + self.scpd_url 
     170        return self.scpd_url 
    175171 
    176     def get_base_url(self): 
    177         return self.url_base 
     172#    def get_base_url(self): 
     173#        return self.url_base 
    178174 
    179175    def subscribe(self): 
    180176        self.debug("subscribe %s", self.id) 
     
    215211    def process_event(self,event): 
    216212        self.info("process event %r" % self) 
    217213        for var_name, var_value  in event.items(): 
    218             if var_name == 'LastChange': 
    219                 self.info("we have a LastChange event"
    220                 self.get_state_variable(var_name, 0).update(var_value) 
    221                 tree = utils.parse_xml(var_value, 'utf-8').getroot() 
     214            if var_name == 'LastChange': 
     215                self.info("we have a LastChange event %s", var_value
     216                self.get_state_variable(var_name, 0).update(var_value) 
     217                tree = utils.parse_xml(var_value, 'utf-8').getroot() 
    222218                namespace_uri, tag = tree.tag[1:].split( "}", 1) 
    223219                for instance in tree.findall('{%s}InstanceID' % namespace_uri): 
    224220                    instance_id = instance.attrib['val'] 
     
    226222                    for var in instance.getchildren(): 
    227223                        self.info("var %r" % var) 
    228224                        namespace_uri, tag = var.tag[1:].split("}", 1) 
    229                         self.info("%r %r %r" % (namespace_uri, tag,var.attrib['val'])) 
    230                         self.get_state_variable(tag, instance_id).update(var.attrib['val']) 
     225                        if len(var.attrib) > 1: 
     226                            self.info("Extended StateVariable %s - %s", var.tag, var.attrib) 
     227 
     228                        if var.attrib.has_key('channel') and var.attrib['channel'] != 'Master': 
     229                            # TODO handle attributes that them selves have multiple instances 
     230                            self.info("Skiiping update to %s its not for master channel %s", var.tag, var.attrib) 
     231                            pass 
     232                        else: 
     233                            if not self.get_state_variables(instance_id) : 
     234                                # TODO Create instance ? 
     235                                self.error("%r update failed (not self.get_state_variables(instance_id)) %r", self, instance_id) 
     236                            elif not self.get_state_variables(instance_id).has_key(tag): 
     237                                # TODO Create instance StateVariable? 
     238                                # SONOS stuff, it returns attributes that are not listed in the state decsription. The soap reply propogates the changes as state updates. 
     239                                self.error("%r update failed (not self.get_state_variables(instance_id).has_key(tag)) %r", self, tag) 
     240                            else: 
     241                                val = None 
     242                                if var.attrib.has_key('val'): 
     243                                    val = var.attrib['val'] 
     244                                #self.debug("%r update %r %r %r", self,namespace_uri, tag, var.attrib['val']) 
     245                                self.get_state_variable(tag, instance_id).update(val) 
    231246                        self.info("updated var %r" % var) 
    232247            else: 
    233248                self.get_state_variable(var_name, 0).update(var_value) 
     
    369384        self._pending_notifications = {} 
    370385 
    371386    def get_action(self, action_name): 
    372         return self._actions[action_name] 
     387        if self._actions.has_key(name): 
     388            return self._actions[name] 
     389        return None # not implemented 
    373390 
    374391    def get_actions(self): 
    375392        return self._actions