Package brisa :: Package upnp :: Package control_point :: Module event
[hide private]
[frames] | no frames]

Source Code for Module brisa.upnp.control_point.event

  1  # Licensed under the MIT license 
  2  # http://opensource.org/licenses/mit-license.php or see LICENSE file. 
  3  # Copyright 2007-2008 Brisa Team <brisa-develop@garage.maemo.org> 
  4   
  5  """ Control point side UPnP event support. 
  6  """ 
  7   
  8  from xml.etree import ElementTree 
  9   
 10  from brisa.core import log, webserver 
 11  from brisa.core.threaded_call import run_async_function 
 12  from brisa.core.network import get_active_ifaces, get_ip_address 
 13   
 14   
15 -class EventListener(webserver.CustomResource):
16 """ EventListener resource available at the control point web server, 17 listening for events. 18 """ 19
20 - def __init__(self, observer):
21 """ Constructor for the EventListener class 22 23 @param observer: observer class with a _on_event() method. 24 """ 25 webserver.CustomResource.__init__(self, 'eventSub') 26 self.observer = observer
27
28 - def cleanup(self):
29 """ Removes reference to observer to make GC easier """ 30 self.observer = None
31
32 - def render(self, uri, request, response):
33 """ Event renderer method. As events come only on NOTIFY messages, this 34 method ignores any other type of message (GET, POST, ...). 35 36 @param uri: URI of the request 37 @param request: request object (Cherrypy) 38 @param response: response object (Cherrypy) 39 40 @type uri: string 41 42 @note: see Cherrypy documentation for further info about request and 43 response attributes and methods. 44 """ 45 log.debug('Received render (%s)' % str((uri, request, response))) 46 47 if request.method == 'NOTIFY': 48 log.debug('Ok, got notify!') 49 self.render_NOTIFY(request, response) 50 else: 51 log.debug('Did not get notify, got %s' % request.method) 52 53 log.debug('Returning from render') 54 55 return ['']
56
57 - def render_NOTIFY(self, request, response):
58 """ Renders the notify message for an event. 59 60 @param request: request object (Cherrypy) 61 @param response: response object (Cherrypy) 62 63 @note: see Cherrypy documentation for further info about request and 64 response attributes and methods. 65 """ 66 data = request.read() 67 # extraneous characters after the end of XML will choke ElementTree 68 data = data[data.find("<"):data.rfind(">")+1] 69 70 run_async_function(self.forward_notification, (request.headers, data), 71 0.0001) 72 return ""
73
74 - def forward_notification(self, received_headers, data):
75 """ Forwards notifications to the observer registered. 76 77 @param received_headers: headers received on the event notify 78 @param data: XML data for the event 79 80 @type received_headers: dictionary 81 @type data: string 82 """ 83 log.debug('forward notification') 84 headers = {} 85 changed_vars = {} 86 for k, v in received_headers.items(): 87 headers[k.lower()] = v 88 89 try: 90 tree = ElementTree.XML(data) 91 except: 92 log.debug('Event XML invalid: %s', data) 93 tree = None 94 95 if tree: 96 for prop1 in tree.findall('{%s}property' % 97 'urn:schemas-upnp-org:event-1-0'): 98 # prop1 = <e:property> <Ble> cont </Ble> </e:property> 99 for prop2 in prop1: 100 # <Ble>cont</Ble> 101 changed_vars[prop2.tag] = prop2.text 102 103 log.debug('Event changed vars: %s', changed_vars) 104 105 if self.observer and 'sid' in headers: 106 self.observer._on_event(headers['sid'], changed_vars) 107 108 for id, dev in self.observer._known_devices.items(): 109 service = self._find_service(dev, headers['sid']) 110 if service != None: 111 service._on_event(changed_vars) 112 return
113
114 - def _find_service(self, device, subscription_id):
115 """ Method to find a service with a specific subscription 116 id on the given device or on it children devices. 117 118 @param device: instance of a device 119 @param subscription_id: the id to compare with the service 120 121 @type device: RootDevice or Device 122 @type subscription_id: str 123 124 @return: if found, the service 125 @rtype: Service or None 126 """ 127 for k, service in device.services.items(): 128 if service.event_sid == subscription_id: 129 return service 130 for k, child_dev in device.devices: 131 service = self._find_service(child_dev, subscription_id) 132 if service: 133 return service 134 return None
135 136
137 -class EventListenerServer(object):
138 """ EventListener server. Wraps BRisa's web server and listens for events. 139 """ 140
141 - def __init__(self, observer):
142 """ Constructor for the EventListenerServer class. 143 144 @param observer: observer that implements the _on_event() method 145 """ 146 self.srv = None 147 self.event_listener = EventListener(observer)
148
149 - def host(self):
150 """ Returns a tuple in the form (host, port) where the server is being 151 hosted at. 152 153 @return: the host and port of the server host 154 @rtype: tuple 155 """ 156 if not self.srv: 157 self.srv = webserver.WebServer() 158 self.srv.start() 159 return (self.srv.get_host(), self.srv.get_port())
160
161 - def start(self, event_host=None):
162 if not self.srv: 163 self.srv = webserver.WebServer() 164 self.srv.start() 165 if event_host: 166 self.srv.listen_url = 'http://%s:%d' % event_host 167 self.srv.add_resource(self.event_listener)
168
169 - def stop(self):
170 """ Stops the EventListenerServer. For restarting after stopping with 171 this method use EventListenerServer.srv.start(). 172 """ 173 if self.srv: 174 self.srv.stop()
175
176 - def is_running(self):
177 if self.srv: 178 return self.srv.is_running() 179 else: 180 return False
181
182 - def destroy(self):
183 if self.is_running(): 184 self.stop() 185 self._cleanup()
186
187 - def _cleanup(self):
188 self.srv = None 189 self.event_listener.cleanup() 190 self.event_listener = None
191