def mount_device_async_gotdata(self, fd, cargo=None): try: log.debug('to object async got data getting tree') tree = ElementTree(file=fd).getroot() except Exception as e: log.error("Bad device XML %s" % e.message) self.callback(self.cargo, None) return DeviceBuilder(self.device, self.location, tree).cleanup() if brisa.__skip_service_xml__: self.callback(self.cargo, self.device) else: log.debug("Fetching device services") log.debug("embedded devices: %s" % str(self.device.devices)) embedded_services = [] for d in list(self.device.devices.values()): embedded_services.extend(list(d.services.items())) log.debug("Embedded devices services are %s" % str(embedded_services)) self.pending_services = len(self.device.services) + \ len(embedded_services) for service_name, service_object in \ list(self.device.services.items()): service_object._build_async(self.service_has_been_built) for s_name, s_obj in embedded_services: s_obj._build_async(self.service_has_been_built)
def response(self, http_response, cargo): """ Callback for receiving the HTTP response on a successful HTTP call. @param http_response: response object @param cargo: callback parameters passed at construction @type http_response: HTTPResponse @rtype: boolean """ log.debug("response") compressed_headers = {} for k, v in dict(http_response.getheaders()).items(): if not v: v = "" compressed_headers[k.lower()] = v.strip() if 'sid' in compressed_headers: sid = compressed_headers['sid'] timeout = 300 if 'timeout' in compressed_headers: stimeout = compressed_headers['timeout'] if stimeout[0:7] == "Second-": try: timeout = int(stimeout[7:]) except ValueError: log.error("value convert of timeout failed using default 300 seconds") self.service.event_sid = sid self.service.event_timeout = timeout if self.callback and sid: self.callback(self.cargo, sid, timeout) return True
def run(self): """ Implementation of the call procedure. """ if self.delay: # This runs in a thread. We can sleep here instead using time safe_sleep(self.delay) log.debug('sleeping for %d' % self.delay) if self.is_cancelled(): self.cleanup() return try: log.debug('calling function') # Performing the call self.result = self.function(*self.args, **self.kwargs) log.debug('got result %s' % self.result) if self.success_callback: log.debug('forwarding to success_callback') self.success_callback(self.result, self.success_callback_cargo) self.set_completed() except Exception, e: log.error('exception happened (%s), forwarding...' % str(e)) # Storing exception for handling self.result = e if self.error_callback: self.error_callback(self.error_callback_cargo, e) self.set_completed()
def application(self, environ, start_response): """ WSGI application callback. May not be called directly by the user. """ path = wsgiref.util.shift_path_info(environ) if path in self._tree: # Path directly available return self._tree[path].application(environ, start_response) else: # End point or needs redirect. In case get_render is overriden, # then a request should be handled by returned get_render() # object. req = Request(environ) resp = Response(200, start_response) render = self.get_render(req.uri, req.params) if not render: log.error('Could not find resource at %s' % req.uri) return simple_response(404, start_response) resp.body = render.render(req.uri, req, resp) if not resp.body and not req.headers: log.error('Body and headers were empty.') return simple_response(404, start_response) else: resp._respond() return resp.body return simple_response(404, start_response)
def soap_Browse(self, *args, **kwargs): """ Implements the Browse action for the ContentDirectory. @param args: list of arguments for the Browse UPnP\ function @param kwargs: dict of arguments for the Browse UPnP\ function @type args: list @type kwargs: dict @return: the results of the browsing @rtype: dict """ log.debug('Action on ContentDirectory: Browse%s', args) # Formats the parameters for the real soap browse args = (kwargs['ObjectID'], kwargs['BrowseFlag'], kwargs['Filter'], kwargs['StartingIndex'], kwargs['RequestedCount'], kwargs['SortCriteria']) l = {} l['query'] = 'Browse(ObjectID=%s, BrowseFlags=%s, Filter=%s, ' \ 'StartingIndex=%s RequestedCount=%s SortCriteria=%s)' % \ tuple(map(repr, args)) try: ret = self._soap_Browse(*args) except Exception as e: log.error('Action Browse on ContentDirectory: %s', e.message) l['response'] = ret return ret
def run(self): """ Implementation of the call procedure. """ if self.delay: # This runs in a thread. We can sleep here instead using time safe_sleep(self.delay) log.debug('sleeping for %d' % self.delay) if self.is_cancelled(): self.cleanup() return try: log.debug('calling function') # Performing the call self.result = self.function(*self.args, **self.kwargs) log.debug('got result %s' % self.result) if self.success_callback: log.debug('forwarding to success_callback') self.success_callback(self.result, self.success_callback_cargo) self.set_completed() except Exception as e: log.error('exception happened (%s), forwarding...' % str(e)) # Storing exception for handling self.result = e if self.error_callback: self.error_callback(self.error_callback_cargo, e) self.set_completed()
def soap_Browse(self, *args, **kwargs): """ Implements the Browse action for the ContentDirectory. @param args: list of arguments for the Browse UPnP\ function @param kwargs: dict of arguments for the Browse UPnP\ function @type args: list @type kwargs: dict @return: the results of the browsing @rtype: dict """ log.debug('Action on ContentDirectory: Browse%s', args) # Formats the parameters for the real soap browse args = (kwargs['ObjectID'], kwargs['BrowseFlag'], kwargs['Filter'], kwargs['StartingIndex'], kwargs['RequestedCount'], kwargs['SortCriteria']) l = {} l['query'] = 'Browse(ObjectID=%s, BrowseFlags=%s, Filter=%s, ' \ 'StartingIndex=%s RequestedCount=%s SortCriteria=%s)' % \ tuple(map(repr, args)) try: ret = self._soap_Browse(*args) except Exception, e: log.error('Action Browse on ContentDirectory: %s', e.message)
def response(self, http_response, cargo): """ Callback for receiving the HTTP response on a successful HTTP call. @param http_response: response object @param cargo: callback parameters passed at construction @type http_response: HTTPResponse @rtype: boolean """ log.debug("response") compressed_headers = {} for k, v in dict(http_response.getheaders()).items(): if not v: v = "" compressed_headers[k.lower()] = v.strip() if 'sid' in compressed_headers: sid = compressed_headers['sid'] timeout = 300 if 'timeout' in compressed_headers: stimeout = compressed_headers['timeout'] if stimeout[0:7] == "Second-": try: timeout = int(stimeout[7:]) except ValueError: log.error( "value convert of timeout failed using default 300 seconds" ) self.service.event_sid = sid self.service.event_timeout = timeout if self.callback and sid: self.callback(self.cargo, sid, timeout) return True
def _soap_Browse(self, *args): """ Real implementation of the soap browse. @param args: list of arguments @type args: list @return: the results of browsing @rtype: dict """ (object_id, browse_flag, filter, starting_index, requested_count, sort_criteria) = args try: starting_index = int(starting_index) requested_count = int(requested_count) last_index = None plugin = self.plugin_manager.root_plugin if browse_flag == 'BrowseDirectChildren' and \ requested_count != 0: last_index = requested_count + starting_index if ':' in object_id: namespace = object_id.split(':')[0] plugin = self.plugin_manager.plugins_instances[namespace] if not plugin: log.error('Could not get plugin associated with this'\ 'browse action on id %s' % object_id) elements = plugin.browse(object_id, browse_flag, filter, starting_index, requested_count, sort_criteria) elements.sort(cmp=compare_objects) didl = Element() total = 0 if plugin.has_browse_filter: for item in elements: didl.add_item(item) total = total + 1 else: for item in elements[starting_index: last_index]: didl.add_item(item) total = total + 1 didl_xml = didl.to_string() soap_result = {'Result': didl_xml, 'TotalMatches': len(elements), 'NumberReturned': total, 'UpdateID': self.updateID} except Exception as e: soap_result = {'Result': '', 'TotalMatches': 0, 'NumberReturned': 0, 'UpdateID': self.updateID} log.error('ContentDirectory.Browse internal problem: %s', e) return soap_result
def daemonize(stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'): try: pid = os.fork() if pid > 0: sys.exit(0) # Exit first parent. except OSError, e: log.error("fork #1 failed: (%d) %s\n", e.errno, e.strerror) sys.exit(1)
def mount_device_async_gotdata(self, fd, cargo=None): try: log.debug('to object async got data getting tree') tree = ElementTree(file=fd).getroot() except Exception, e: log.error("Bad device XML %s" % e.message) self.callback(self.cargo, None) return
def stop(self): self.player.set_state(gst.STATE_NULL) if self.player.set_state(gst.STATE_READY) == gst.STATE_CHANGE_FAILURE: log.error("error stopping") return self.player_state = 0 self.av_uri = self.__av_uri
def play(self): if self.av_uri is not None: if (self.player.set_state(gst.STATE_PLAYING) == gst.STATE_CHANGE_FAILURE): log.error("error trying to play %s.", self.av_uri) self.player_state = 1 else: log.info("av_uri is None, unable to play.")
def play(self): if self.av_uri is not None: if (self.player.set_state( gst.STATE_PLAYING) == gst.STATE_CHANGE_FAILURE): log.error("error trying to play %s.", self.av_uri) self.player_state = 1 else: log.info("av_uri is None, unable to play.")
def _load_plugins(self): """ Loads all plugins selected using _load_plugin() method. """ try: plugins = self.plugins_instances.values() for plugin in plugins: self._load_plugin(plugin) except Exception, e: log.error("Error loading plugin %s: %s", plugin.name, e)
def play(self): if self.av_uri is not None: if self.player.set_state(gst.STATE_PLAYING) == \ gst.STATE_CHANGE_FAILURE: log.error("gst_renderer error while trying to play") return self.player_state = 1 else: log.info("av_uri is None, unable to play.")
def _datagram_received(self, data, address): """ Callback for the UDPListener when messages arrive. @param data: raw data received @param host: host where data came from @param port: port where data came from @type data: string @type host: string @type port: integer """ (host, port) = address try: cmd, headers = parse_http_response(data) body = data[data.find("<"):data.rfind(">")+1] except Exception as err: log.error('Error while receiving datagram packet: %s', str(err)) return # Render notify message if not (cmd[0] == 'NOTIFY' and cmd[1] == '*' and cmd[2] == 'HTTP/1.0' and \ 'content-type' in headers and \ headers['content-type'] == 'text/xml; charset="utf-8"' and \ 'nt' in headers and headers['nt'] == 'upnp:event' and \ 'nts' in headers and headers['nts'] == 'upnp:propchange' and \ 'host' in headers and 'usn' in headers and \ 'svcid' in headers and 'seq' in headers and \ 'lvl' in headers and 'bootid.upnp.org' in headers and \ 'content-length' in headers): log.warning('Invalid message') return addr = headers['host'].split(':')[0] port = int(headers['host'].split(':')[1]) udn = headers['usn'].split('::')[0] service_type = headers['usn'].split('::')[1] svcid = headers['svcid'] seq = int(headers['seq']) lvl = headers['lvl'] content_length = int(headers['content-length']) bootid = int(headers['bootid.upnp.org']) if addr != UPnPDefaults.MULTICAST_EVENT_ADDR or \ port != UPnPDefaults.MULTICAST_EVENT_PORT: log.warning('Invalid address %s:%d' % (addr, port)) return changed_vars = read_notify_message_body(body) self.control_point._on_event('', changed_vars) for id, dev in list(self.control_point._known_devices.items()): service = self._find_service(dev, udn, service_type, svcid) if service != None: service._on_event(changed_vars) log.debug('Multicast event. Event changed vars: %s', changed_vars)
def _instantiate_plugins(self): """ Instantiates all plugin classes into the plugin manager. """ plugins = self.plugins_classes.values() for plugin in plugins: if plugin.usage: try: self.plugins_instances[plugin.name] = plugin() except Exception, e: log.error("Error while instantiating %s: %s" % (plugin.name, str(e)))
def application(self, environ, start_response): """ WSGI application callback. May not be called directly by the user. """ # if environ['HTTP_USER_AGENT'] != 'TeraStation-IMHTTP/1.8.225': # print "@ Resource.application @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" # print environ # print start_response path = wsgiref.util.shift_path_info(environ) # print path # print self._tree # circuits # print environ['wsgi.input'].getvalue() # cherrypy # print environ['wsgi.input'].read() if path in self._tree: # print "PATH" # print self._tree[path] # print self._tree[path].application # Path directly available return self._tree[path].application(environ, start_response) else: # End point or needs redirect. In case get_render is overriden, # then a request should be handled by returned get_render() # object. # print "NO PATH" req = Request(environ) resp = Response(200, start_response) # print "resp: " + str(resp) render = self.get_render(req.uri, req.params) # print "RENDER: " + str(render) if not render: log.error('Could not find resource at %s' % req.uri) return simple_response(404, start_response) # print "~~~~~ before >>>>>>>>>>>>>>>>>>>>" resp.body = render.render(req.uri, req, resp) # print "~~~~~ after >>>>>>>>>>>>>>>>>>>>>" # print "resp.body: " + str(resp.body) if not resp.body and not req.headers: log.error('Body and headers were empty.') return simple_response(404, start_response) else: resp._respond() # print "resp.body2: " + str(resp.body) return resp.body return simple_response(404, start_response)
def _instantiate_plugins(self): """ Instantiates all plugin classes into the plugin manager. """ plugins = self.plugins_classes.values() for plugin in plugins: if plugin.usage: try: self.plugins_instances[plugin.name] = plugin() except Exception, e: log.error("Error while instantiating %s: %s" % \ (plugin.name, str(e)))
def start(self): """ Starts the device. """ log.info('Starting device %s' % self.friendly_name) log.info('Starting device\'s services') for k, v in self.services.items(): try: log.info('Starting service %s' % k) v.start() except Exception, e: log.error('Error starting service %s: %s' % (k, e))
def on_message(self, bus, message): t = message.type if t == gst.MESSAGE_EOS: self.player.set_state(gst.STATE_NULL) self.player_state = 0 self.player.set_state(gst.STATE_READY) elif t == gst.MESSAGE_ERROR: self.player.set_state(gst.STATE_NULL) log.error(str(message)) self.player_state = 0 self.player.set_state(gst.STATE_READY)
def _validate_renew_request(self, request, compressed_headers): if 'callback' in compressed_headers or 'nt' in compressed_headers: log.error('Missing callback or nt') return 400, None subs = self._find_subscriber(compressed_headers['sid']) if not subs: log.error('Subscriber does not exist') return 412, None #TODO: Put the verification of error 5xx # No errors return 200, subs
def _build_error(self, request, response_obj, status): log.error('Building error response') response = soap.build_soap_error(status) response_obj.status = 500 if self.encoding is not None: mime_type = 'text/xml; charset="%s"' % self.encoding else: mime_type = "text/xml" response_obj.headers["Content-type"] = mime_type response_obj.headers["Content-length"] = str(len(response)) response_obj.headers["EXT"] = '' response_obj.body = response return response
def _find_and_import_plugins(self, plugins_folder, plugins_modules_path): for root, dirs, files in os.walk(plugins_folder): if root != plugins_folder: break for dir in dirs: if not dir.startswith("."): try: module_path = '%s.%s' % (plugins_modules_path, dir) __import__(module_path) except Exception, e: msg = 'Error while importing %s plugin. The module '\ 'path used to load was: %s. Error: %s' % \ (dir, module_path, e) log.error(msg)
def _validate_subscribe_request(self, request, compressed_headers): log.debug('Validating subscribe request') #TODO: verify if the callback url is a valid one if not 'callback' in compressed_headers: log.error('There is not a callback at the request') return 412 if (not 'nt' in compressed_headers) or \ (compressed_headers['nt'] != "upnp:event"): return 412 #TODO: Put the verification of error 5xx # No errors return 200
def _main_trigger_timers(self): """ Triggers the timers that are ready. """ for callback in self._timers.values(): if callback.timeout_abs - callback.threshold < time.time(): log.debug('Callback ready: %s' % str(callback)) if self.is_running(): try: callback() except KeyboardInterrupt, k: # Ctrl-C would be ignored return False except: log.error('Error while processing timer %s' % str(callback))
def start(self): """ Starts the device. """ log.info('Starting device %s' % self.friendly_name) log.info('Starting device\'s services') for k, v in self.services.items(): try: if self._force_event_reload: v._set_force_event_reload(self._force_event_reload) else: if self._event_reload_time: v._set_event_reload_time(self._event_reload_time) log.info('Starting service %s' % k) v.start() except Exception, e: log.error('Error starting service %s: %s' % (k, str(e)))
def start(self): """ Starts the device. """ log.info('Starting device %s' % self.friendly_name) log.info('Starting device\'s services') for k, v in self.services.items(): try: if self._force_event_reload: v._set_force_event_reload(self._force_event_reload) else: if self._event_reload_time: v._set_event_reload_time(self._event_reload_time) log.info('Starting service %s' % k) v.start() except Exception, e: log.error('Error starting service %s: %s' % (k, e))
def __init__(self, subscriber, variables, event_delay, cargo): """ Constructor for the EventMessage class. @param subscriber: subscriber that will receive the message @param variables: variables of the event @param event_delay: delay to wait before sending the event @param cargo: callback parameters @type subscriber: Subscriber @type variables: dict @type event_delay: float """ log.debug("event message") if not variables: log.error("There are no variables to send") return self.cargo = cargo headers = {} headers["HOST"] = subscriber.delivery_url headers["CONTENT-TYPE"] = 'text/xml' headers["NT"] = 'upnp:event' headers["NTS"] = 'upnp:propchange' headers["SID"] = "uuid:" + str(subscriber.subscription_id) headers["SEQ"] = str(subscriber.event_key) subscriber.event_key_increment() event_body = self._build_message_body(variables) headers["CONTENT-LENGTH"] = str(len(event_body)) log.debug("Running http call") run_async_call(http_call, success_callback=self.response, error_callback=self.error, delay=event_delay, method='NOTIFY', url=subscriber.delivery_url, body=event_body, headers=headers)
def update(self, value): """ Updates the state variable value. The new value must has the same type as specified at data type. @param value: new value. @type value: data_type """ # log.debug("Updating state variable") if self._value == value: log.debug("Don't update") return self._value = value if self.send_events: for callback in self._callbacks: try: callback(self.name, self._value) except Exception, e: log.error('Error at callback %s' % str(callback)) raise e
class MulticastEventController: msg_already_started = 'tried to start() MulticastEventController when already started' msg_already_stopped = 'tried to stop() MulticastEventController when already stopped' def __init__(self, parent_udn, service, event_reload_time, force_event_reload): self.service = service self.parent_udn = parent_udn self.udp_transport = UDPTransport() self.listen_udp = UDPListener(UPnPDefaults.MULTICAST_EVENT_ADDR, UPnPDefaults.MULTICAST_EVENT_PORT, data_callback=self._datagram_received, shared_socket=self.udp_transport.socket) self.eventing_variables = {} self.event_key = 0 self.event_reload_time = event_reload_time self.force_event_reload = force_event_reload if not self.force_event_reload: self.l_call = LoopingCall(self.send_variables) reactor.add_after_stop_func(self.stop) self._is_running = False def _datagram_received(self, data, (host, port)): """ Callback for the UDPListener when messages arrive. @param data: raw data received @param host: host where data came from @param port: port where data came from @type data: string @type host: string @type port: integer """ log.debug("device.MEC._datagram_received host: %s, port: %s\ndata: %s", host, port, data) try: cmd, headers = parse_http_response(data) body = data[data.find("<"):data.rfind(">")+1] except Exception, err: log.error('Error while receiving datagram packet: %s', str(err)) return
def start(self): """ Starts the device. """ log.info('Starting device %s' % self.friendly_name) log.info('Starting device\'s services') for k, v in list(self.services.items()): try: if self._force_event_reload: v._set_force_event_reload(self._force_event_reload) else: if self._event_reload_time: v._set_event_reload_time(self._event_reload_time) log.info('Starting service %s' % k) v.start() except Exception as e: log.error('Error starting service %s: %s' % (k, str(e))) self._publish() self.SSDP.register_device(self) self.webserver.start() self.SSDP.start() self.SSDP.announce_device() log.info('Finished starting device %s' % self.friendly_name)
def update(self, value): """ Updates the state variable value. The new value must has the same type as specified at data type. @param value: new value. @type value: data_type """ log.debug("Updating state variable %s: %s" % (self.name, str(value))) if self._value == value: log.debug("Don't update. Same value.") return self._value = value if self.send_events: cbs = self._callbacks[:] log.debug("Calling callbacks") for callback in cbs: try: callback(self.name, self._value) except Exception, e: log.error('Error at callback %s' % str(callback)) self._callbacks.remove(callback)
def update(self, value): """ Updates the state variable value. The new value must has the same type as specified at data type. @param value: new value. @type value: data_type """ # unicode issue log.debug("Updating state variable %s: %s" % (self.name, str(value))) if self._value == value: log.debug("Don't update. Same value.") return self._value = value if self.send_events: cbs = self._callbacks[:] log.debug("Calling callbacks") for callback in cbs: try: callback(self.name, self._value) except Exception, e: log.error('Error at callback %s' % str(callback)) raise e
def build_notify_message_body(variables): log.debug("Building event message body") property_set = ElementTree.Element("e:propertyset") property_set.attrib.update({'xmlns:e': "urn:schemas-upnp-org:event-1-0"}) for var_name, var_value in variables.items(): property = ElementTree.SubElement(property_set, "e:property") try: var_val = map_upnp_value(var_value) except: #TODO - raise an error? log.error("Unknown state variable type") pass if var_val == None: var_val = '' e = ElementTree.SubElement(property, var_name) e.text = var_val return ElementTree.tostring(property_set, 'utf-8')
def __init__(self, subscriber, variables, event_delay, cargo): """ Constructor for the EventMessage class. @param subscriber: subscriber that will receive the message @param variables: variables of the event @param event_delay: delay to wait before sending the event @param cargo: callback parameters @type subscriber: Subscriber @type variables: dict @type event_delay: float """ log.debug("event message") if not variables: log.error("There are no variables to send") return self.cargo = cargo headers = {} # headers["HOST"] = subscriber.delivery_url headers["HOST"] = subscriber.host headers["CONTENT-TYPE"] = 'text/xml' headers["NT"] = 'upnp:event' headers["NTS"] = 'upnp:propchange' headers["SID"] = "uuid:" + str(subscriber.subscription_id) headers["SEQ"] = str(subscriber.event_key) subscriber.event_key_increment() event_body = self._build_message_body(variables) headers["CONTENT-LENGTH"] = str(len(event_body)) log.debug("Running http call") run_async_call(http_call, success_callback=self.response, error_callback=self.error, delay=event_delay, method='NOTIFY', url=subscriber.delivery_url, body=event_body, headers=headers)
class MulticastEventListener: """ Represents a multicast event listener. Contains some control functions for starting and stopping the listener. """ msg_already_started = 'tried to start() MulticastEventListener when already started' msg_already_stopped = 'tried to stop() MulticastEventListener when already stopped' def __init__(self, control_point, start=True): """ Constructor for the MulticastEventListener class. @param ssdp: ssdp server instance that will receive new device events and subscriptions @param start: if True starts the search when constructed @param ssdp_addr: ssdp address for listening (UDP) @param ssdp_port: ssdp port for listening (UDP) @type ssdp: SSDPServer @type start: boolean @type ssdp_addr: string @type ssdp_port integer """ self.udp_transport = UDPTransport() self.listen_udp = UDPListener(UPnPDefaults.MULTICAST_EVENT_ADDR, UPnPDefaults.MULTICAST_EVENT_PORT, data_callback=self._datagram_received, shared_socket=self.udp_transport.socket) self.control_point = control_point if start: self.start() def _datagram_received(self, data, (host, port)): """ Callback for the UDPListener when messages arrive. @param data: raw data received @param host: host where data came from @param port: port where data came from @type data: string @type host: string @type port: integer """ log.debug("cp.event._datagram_received host: %s, port: %s\ndata: %s", host, port, data) try: cmd, headers = parse_http_response(data) body = data[data.find("<"):data.rfind(">") + 1] except Exception, err: log.error('Error while receiving datagram packet: %s', str(err)) return
def __call__(self, *args, **kwargs): log.debug('Entering at action %s __call__' % self.name) # Update in arguments in_kwargs = {} log.debug('Updating IN variables') for arg_name, arg_value in kwargs.iteritems(): if arg_name != '__header__': arg = self.get_in_argument(arg_name) if not arg: log.error('Input argument "%s" not' \ ' present on action definition.' \ % arg_name) raise InvalidActionInput('Input argument "%s" not' \ ' present on action definition.' \ % arg_name) if arg.state_var: arg.state_var.update(arg_value) in_kwargs[arg_name] = arg_value log.debug('Calling run function') returned_kwargs = self.run_function(*(), **in_kwargs) if not isinstance(returned_kwargs, dict): msg = 'returned value from service function is not a dict.' log.error(msg) raise InvalidActionOutput(msg) # Update out arguments out_kwargs = {} log.debug('Updating OUT variables') for arg_name, arg_value in returned_kwargs.iteritems(): if arg_name != '__header__': arg = self.get_out_argument(arg_name) if not arg: log.error('output contains argument "%s" not'\ ' present on action definition' % \ arg_name) raise InvalidActionOutput('output contains argument "%s" not'\ ' present on action definition' % \ arg_name) if arg.state_var: arg.state_var.update(arg_value) out_kwargs[arg_name] = arg_value log.debug('Returning from action %s __call__' % self.name) if "__header__" in out_kwargs: header = out_kwargs.pop('__header__', {}) return {self.name + "Response": out_kwargs, "__header__": header} else: return {self.name + "Response": out_kwargs}
def _validate_unsubscribe_request(self, request, compressed_headers): if not 'sid' in compressed_headers: log.error('Missing sid') return 412, None if 'callback' in compressed_headers or 'nt' in compressed_headers: log.error('Missing callback or nt') return 400, None subs = self._find_subscriber(compressed_headers['sid']) if not subs: log.error('Subscriber does not exist') return 412, None # No errors return 200, subs
def __call__(self, *args, **kwargs): log.debug('Entering at action %s __call__' % self.name) # Update in arguments in_kwargs = {} log.debug('Updating IN variables') for arg_name, arg_value in kwargs.iteritems(): arg = self.get_in_argument(arg_name) if not arg: log.error('Input argument "%s" not' \ ' present on action definition.' \ % arg_name) raise InvalidActionInput('Input argument "%s" not' \ ' present on action definition.' \ % arg_name) arg.state_var.update(arg_value) in_kwargs[arg_name] = arg_value log.debug('Calling run function') out_args = self.run_function(*(), **in_kwargs) if not isinstance(out_args, dict): log.error('output is not a dict.') raise InvalidActionOutput('output is not a dict.') # Update out arguments return_args = {} log.debug('Updating OUT variables') for arg_name, arg_value in out_args.iteritems(): arg = self.get_out_argument(arg_name) if not arg: log.error('output contains argument "%s" not'\ ' present on action definition' % \ arg_name) raise InvalidActionOutput('output contains argument "%s" not'\ ' present on action definition' % \ arg_name) arg.state_var.update(arg_value) return_args[arg_name] = arg_value log.debug('Returning from action %s __call__' % self.name) return {self.name + "Response": return_args}
def mount_device_async_error(self, cargo, error): log.error("Error fetching %s - Error: %s" % (self.location, str(error))) self.callback(self.cargo, None) return True
hcopy = dict(headers.iteritems()) hcopy['st'] = self.known_device[i]['ST'] self._discovery_request(hcopy, (host, port)) return for key in self.known_device.keys(): if self.known_device[key]['ST'].split()[0] == ( headers['st']).split()[0]: right_key = key break else: log.debug('Discovery request ST %s not found', headers['st']) return if right_key == 0: log.error('Unknown error in DiscoveryRequest for %s', headers['st']) return # Generate a response response = [] response.append('HTTP/1.1 200 OK') append = response.append [ append('%s: %s' % (k, v)) for k, v in self.known_device[right_key].items() ] response.extend(('', '')) delay = random.randint(0, int(headers['mx'])) # Avoid using a timer with delay 0 :) if delay:
class SSDPServer(object): """ Implementation of a SSDP server. The notify_received and search_received methods are called when the appropriate type of datagram is received by the server. """ msg_already_started = 'tried to start() SSDPServer when already started' msg_already_stopped = 'tried to stop() SSDPServer when already stopped' def __init__(self, server_name, xml_description_filename, max_age=1800, receive_notify=True, udp_listener=''): """ Constructor for the SSDPServer class. @param server_name: server name @param xml_description_filename: XML description filename @param max_age: max age parameter, default 1800. @param receive_notify: if False, ignores notify messages @type server_name: string @type xml_description_filename: @type max_age: integer @type receive_notify: boolean """ self.server_name = server_name self.xml_description_filename = xml_description_filename self.max_age = max_age log.debug("max_age: %s", max_age) self.receive_notify = receive_notify self.running = False self.known_device = {} self.advertised = {} self._callbacks = {} self.udp_transport = UDPTransport() if udp_listener == '': self.udp_listener = UDPListener( SSDP_ADDR, SSDP_PORT, data_callback=self._datagram_received) else: self.udp_listener = None udp_listener.subscribe(self) self.renew_loop = LoopingCall(self._renew_notifications) self.renew_loop.start(0.8 * self.max_age, now=True) def is_running(self): """ Returns True if the SSDPServer is running, False otherwise. """ return self.running def start(self): """ Starts the SSDPServer. """ if not self.is_running(): if self.udp_listener != None: self.udp_listener.start() self.running = True else: log.warning(self.msg_already_started) def stop(self): """ Sends bye bye notifications and stops the SSDPServer. """ if self.is_running(): # Avoid racing conditions own_temp = self.advertised.copy() for usn in own_temp: self._do_byebye(usn) self.renew_loop.stop() if self.udp_listener != None: self.udp_listener.stop() self.running = False else: log.warning(self.msg_already_stopped) def destroy(self): """ Destroys the SSDPServer. """ if self.is_running(): self.stop() self.renew_loop.destroy() if self.udp_listener != None: self.udp_listener.destroy() self._cleanup() def clear_device_list(self): """ Clears the device list. """ self.known_device.clear() def discovered_device_failed(self, dev): """ Device could not be fully built, so forget it. """ usn = dev['USN'] if usn in self.known_device: self.known_device.pop(usn) def is_known_device(self, usn): """ Returns if the device with the passed usn is already known. @param usn: device's usn @type usn: string @return: True if it is known @rtype: boolean """ return usn in self.known_device def subscribe(self, name, callback): """ Subscribes a callback for an event. @param name: name of the event. May be "new_device_event" or "removed_device_event" @param callback: callback @type name: string @type callback: callable """ self._callbacks.setdefault(name, []).append(callback) def unsubscribe(self, name, callback): """ Unsubscribes a callback for an event. @param name: name of the event @param callback: callback @type name: string @type callback: callable """ callbacks = self._callbacks.get(name, []) [callbacks.remove(c) for c in callbacks] self._callbacks[name] = callbacks def announce_device(self): """ Announces the device. """ log.debug("announce_device") [self._do_notify(usn) for usn in self.advertised] def register_device(self, device): """ Registers a device on the SSDP server. @param device: device to be registered @type device: Device """ self._register_device(device) if device.is_root_device(): [self._register_device(d) for d in device.devices.values()] # Messaging def _datagram_received(self, data, (host, port)): """ Handles a received multicast datagram. @param data: raw data @param host: datagram source host @param port: datagram source port @type data: string @type host: string @type port: integer """ log.debug("SSDP._datagram_received host: %s, port: %s\ndata: %s", host, port, data) try: header, payload = data.split('\r\n\r\n') except ValueError, err: log.error('Error while receiving datagram packet: %s', str(err)) return