def __init__(self): self.build_pipeline() self.__av_uri = None self.time_format = gst.Format(gst.FORMAT_TIME) self.player_state = 0 loop = LoopingCall(self.poll_bus) loop.start(0.2, True)
def __init__(self, service, subscription_duration, delivery_url, http_version, event_reload_time, force_event_reload): self.service = service self.subscription_id = uuid.uuid4() self.delivery_url = delivery_url url = parse_url(delivery_url) self.host = '%s:%d' % (url.hostname, url.port) self.event_key = 0 self.subscription_duration = subscription_duration self.http_version = http_version self.timestamp = datetime.now() self.eventing_variables = {} for name, state_var in self.service.get_variables().items(): state_var.subscribe_for_update(self._update_variable) self.force_event_reload = force_event_reload if not force_event_reload: self.looping_call = LoopingCall(self._send_variables) reactor.add_after_stop_func(self.looping_call.stop) self.looping_call.start(event_reload_time, False) sid = str(self.subscription_id) log.debug('Creating subscriber with subscription id: %s' % sid)
def __init__(self, ssdp, start=True, interval=DEFAULT_SEARCH_TIME, ssdp_addr=DEFAULT_SSDP_ADDR, ssdp_port=1900): """ Constructor for the MSearch class. @param ssdp: ssdp server instance that will receive new device events and subscriptions @param start: if True starts the search when constructed @param interval: interval between searchs @param ssdp_addr: ssdp address for listening (UDP) @param ssdp_port: ssdp port for listening (UDP) @type ssdp: SSDPServer @type start: boolean @type interval: float @type ssdp_addr: string @type ssdp_port integer """ self.ssdp = ssdp self.ssdp_addr = ssdp_addr self.ssdp_port = ssdp_port self.udp_transport = UDPTransport() self.listen_udp = UDPListener(ssdp_addr, data_callback=self._datagram_received, shared_socket=self.udp_transport.socket) self.loopcall = LoopingCall(self.double_discover) if start: self.start(interval)
class Subscriber: def __init__(self, service, subscription_duration, delivery_url, http_version, event_reload_time, force_event_reload): self.service = service self.subscription_id = uuid.uuid4() self.delivery_url = delivery_url url = parse_url(delivery_url) self.host = '%s:%d' % (url.hostname, url.port) self.event_key = 0 self.subscription_duration = subscription_duration self.http_version = http_version self.timestamp = datetime.now() self.eventing_variables = {} for name, state_var in self.service.get_variables().items(): state_var.subscribe_for_update(self._update_variable) self.force_event_reload = force_event_reload if not force_event_reload: self.looping_call = LoopingCall(self._send_variables) reactor.add_after_stop_func(self.looping_call.stop) self.looping_call.start(event_reload_time, False) sid = str(self.subscription_id) log.debug('Creating subscriber with subscription id: %s' % sid) def event_key_increment(self): self.event_key += 1 if self.event_key > 4294967295: self.event_key = 1 def _update_variable(self, name, value): if self.force_event_reload: self.eventing_variables[name] = value self._send_variables() return if name in self.eventing_variables.keys() and \ self.eventing_variables[name] != value: self._send_variables() self.eventing_variables[name] = value def _send_variables(self): if self.eventing_variables: EventMessage(self, self.eventing_variables, 0, "") self.eventing_variables = {} def stop(self): for name, state_var in self.service.get_variables().items(): state_var.unsubscribe_for_update(self._update_variable) # When called stop() manually, remove the before stop callback if not self.force_event_reload: reactor.rem_after_stop_func(self.looping_call.stop) self.looping_call.stop()
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.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 __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 __init__(self, ssdp, start=True, interval=DEFAULT_SEARCH_TIME, ssdp_addr='239.255.255.250', ssdp_port=1900): """ Constructor for the MSearch class. @param ssdp: ssdp server instance that will receive new device events and subscriptions @param start: if True starts the search when constructed @param interval: interval between searchs @param ssdp_addr: ssdp address for listening (UDP) @param ssdp_port: ssdp port for listening (UDP) @type ssdp: SSDPServer @type start: boolean @type interval: float @type ssdp_addr: string @type ssdp_port integer """ self.ssdp = ssdp self.ssdp_addr = ssdp_addr self.ssdp_port = ssdp_port self.udp_transport = UDPTransport() self.listen_udp = UDPListener(ssdp_addr, data_callback=self._datagram_received, shared_socket=self.udp_transport.socket) self.loopcall = LoopingCall(self.double_discover) if start: self.start(interval)
def __init__(self, server_name, xml_description_filename, max_age=1800, receive_notify=True, http_version="1.1", search_type="sspd:all", additional_headers={}): """ 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 self.receive_notify = receive_notify self.running = False self.http_version = http_version self.known_device = {} self.advertised = {} self._callbacks = {} self.additional_headers = additional_headers self.search_type = search_type self.udp_transport = UDPTransport() self.udp_listener = UDPListener(SSDP_ADDR, SSDP_PORT, data_callback=self._datagram_received) self.renew_loop = LoopingCall(self._renew_notifications) self.renew_loop.start(0.8 * self.max_age, now=True)
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 __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
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.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 send_variables(self): if not self.eventing_variables: return #FIXME - fix BOOTID.UPNP.ORG notify_msg = [ 'NOTIFY * HTTP/1.0', 'HOST: %s:%d' % (UPnPDefaults.MULTICAST_EVENT_ADDR, UPnPDefaults.MULTICAST_EVENT_PORT), 'CONTENT-TYPE: text/xml; charset="utf-8"', 'USN: %s::%s' % (str(self.parent_udn), self.service.service_type), 'SVCID: %s' % (str(self.service.id)), 'NT: upnp:event', 'NTS: upnp:propchange', 'SEQ: %d' % (self.event_key), 'LVL: upnp:/info', 'BOOTID.UPNP.ORG: 0' ] body = self._build_message_body(self.eventing_variables) notify_msg.append('CONTENT-LENGTH: %d' % len(body)) # Empyt line notify_msg.append('') notify_msg.append(body) self.udp_transport.send_data('\r\n'.join(notify_msg), UPnPDefaults.MULTICAST_EVENT_ADDR, UPnPDefaults.MULTICAST_EVENT_PORT) self.event_key_increment() self.eventing_variables = {} def _update_variable(self, name, value): if self.force_event_reload: self.eventing_variables[name] = value self.send_variables() return if self.eventing_variables.has_key(name) and \ self.eventing_variables[name] != value: self.send_variables() self.eventing_variables[name] = value def _build_message_body(self, variables): log.debug("Building multicast message body to variables: %s" % str(variables)) preamble = """<?xml version="1.0"?>""" return '%s%s' % (preamble, build_notify_message_body(variables)) def event_key_increment(self): self.event_key += 1 if self.event_key > 4294967295: self.event_key = 1 def is_running(self): """ Returns True if the listener is running. @rtype: boolean """ if not self.force_event_reload: self._is_running = self.l_call.is_running() return self._is_running def start(self): """ Starts the listener. """ if not self.is_running(): for name, state_var in self.service.get_variables().items(): if state_var.send_events and state_var.multicast: state_var.subscribe_for_update(self._update_variable) if not self.force_event_reload: self.l_call.start(self.event_reload_time) self._is_running = True log.debug( 'Multicast event controller started with event reload time: %d' % self.event_reload_time) else: log.warning(self.msg_already_started) def stop(self): """ Stops the search. """ if self.is_running(): log.debug('Multicast event controller stopped') for name, state_var in self.service.get_variables().items(): if state_var.send_events and state_var.multicast: state_var.unsubscribe_for_update(self._update_variable) if not self.force_event_reload: self.l_call.stop() reactor.rem_after_stop_func(self.stop) self._is_running = False else: log.warning(self.msg_already_stopped) def destroy(self): """ Destroys and quits MSearch. """ if self.is_running(): self.stop() self._cleanup() def _cleanup(self): """ Clean up references. """ self.service = None self.udp_transport = None self.eventing_variables = None self.l_call = None
class MSearch(object): """ Represents a MSearch. Contains some control functions for starting and stopping the search. While running, search will be repeated in regular intervals specified at construction or passed to the start() method. """ msg_already_started = 'tried to start() MSearch when already started' msg_already_stopped = 'tried to stop() MSearch when already stopped' def __init__(self, ssdp, start=True, interval=DEFAULT_SEARCH_TIME, ssdp_addr='239.255.255.250', ssdp_port=1900): """ Constructor for the MSearch class. @param ssdp: ssdp server instance that will receive new device events and subscriptions @param start: if True starts the search when constructed @param interval: interval between searchs @param ssdp_addr: ssdp address for listening (UDP) @param ssdp_port: ssdp port for listening (UDP) @type ssdp: SSDPServer @type start: boolean @type interval: float @type ssdp_addr: string @type ssdp_port integer """ self.ssdp = ssdp self.ssdp_addr = ssdp_addr self.ssdp_port = ssdp_port self.search_type = DEFAULT_SEARCH_TYPE self.udp_transport = UDPTransport() # self.listen_udp = UDPListener(ssdp_addr, ssdp_port, self.listen_udp = UDPListener(ssdp_addr, 2149, # WMP is not picked up if 1900 is used for source data_callback=self._datagram_received, shared_socket=self.udp_transport.socket) self.loopcall = LoopingCall(self.double_discover) if start: self.start(interval) def is_running(self): """ Returns True if the search is running (it's being repeated in the interval given). @rtype: boolean """ return self.loopcall.is_running() def start(self, interval=DEFAULT_SEARCH_TIME, search_type=DEFAULT_SEARCH_TYPE): """ Starts the search. @param interval: interval between searchs. Default is 600.0 seconds @param search_type: type of the search, default is "ssdp:all" @type interval: float @type search_type: string """ # interval = 30.0 if not self.is_running(): self.search_type = search_type self.listen_udp.start() # print ">>>>>>>>> interval: " + str(interval) self.loopcall.start(interval, now=True) log.debug('MSearch started') else: log.warning(self.msg_already_started) def stop(self): """ Stops the search. """ if self.is_running(): log.debug('MSearch stopped') self.listen_udp.stop() self.loopcall.stop() else: log.warning(self.msg_already_stopped) def destroy(self): """ Destroys and quits MSearch. """ if self.is_running(): self.stop() self.listen_udp.destroy() self.loopcall.destroy() self._cleanup() def double_discover(self, search_type=DEFAULT_SEARCH_TYPE): """ Sends a MSearch imediatelly. Each call to this method will yield a MSearch message, that is, it won't repeat automatically. """ # print "<<<<<<<<< start double discover >>>>>>>>>" self.discover(search_type) self.discover(search_type) # print "<<<<<<<<< end double discover >>>>>>>>>" def discover(self, type="ssdp:all"): # def discover(self, type="upnp:rootdevice"): """ Mounts and sends the discover message (MSearch). @param type: search type @type type: string """ # type = "urn:schemas-upnp-org:device:MediaServer:1" type = "upnp:rootdevice" # req = ['M-SEARCH * HTTP/1.1', # 'HOST: %s:%d' % (self.ssdp_addr, self.ssdp_port), # 'MAN: "ssdp:discover"', # 'MX: 5', # 'ST: ' + type, '', ''] # req = '\r\n'.join(req) req = ['M-SEARCH * HTTP/1.1', 'HOST:%s:%d' % (self.ssdp_addr, self.ssdp_port), 'MAN:"ssdp:discover"', # 'Host:%s:%d' % (self.ssdp_addr, self.ssdp_port), # 'Man:"ssdp:discover"', 'MX:5', 'ST:' + type, '', '', ''] req = '\r\n'.join(req) self.udp_transport.send_data(req, self.ssdp_addr, self.ssdp_port) 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 """ # print "datagram_received start" cmd, headers = parse_http_response(data) if cmd[0] == 'HTTP/1.1' and cmd[1] == '200': if self.ssdp != None: if not self.ssdp.is_known_device(headers['usn']): log.debug('Received MSearch answer %s,%s from %s:%s', headers['usn'], headers['st'], host, port) # print "_datagram_received _register" # print "_datagram_received headers: " + str(headers) self.ssdp._register(headers['usn'], headers['st'], headers['location'], headers['server'], headers['cache-control'])
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, http_version="1.1", search_type="sspd:all", additional_headers={}): """ 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 self.receive_notify = receive_notify self.running = False self.http_version = http_version self.known_device = {} self.advertised = {} self._callbacks = {} self.additional_headers = additional_headers self.search_type = search_type self.udp_transport = UDPTransport() self.udp_listener = UDPListener(SSDP_ADDR, SSDP_PORT, data_callback=self._datagram_received) 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(): 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() 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() 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. """ [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 """ try: header, payload = data.split('\r\n\r\n') except ValueError, err: log.error('Error while receiving datagram packet: %s', str(err)) return
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
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.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 send_variables(self): if not self.eventing_variables: return #FIXME - fix BOOTID.UPNP.ORG notify_msg = ['NOTIFY * HTTP/1.0', 'HOST: %s:%d' % (UPnPDefaults.MULTICAST_EVENT_ADDR, UPnPDefaults.MULTICAST_EVENT_PORT), 'CONTENT-TYPE: text/xml; charset="utf-8"', 'USN: %s::%s' % (str(self.parent_udn), self.service.service_type), 'SVCID: %s' % (str(self.service.id)), 'NT: upnp:event', 'NTS: upnp:propchange', 'SEQ: %d' % (self.event_key), 'LVL: upnp:/info', 'BOOTID.UPNP.ORG: 0'] body = self._build_message_body(self.eventing_variables) notify_msg.append('CONTENT-LENGTH: %d' % len(body)) # Empyt line notify_msg.append('') notify_msg.append(body) self.udp_transport.send_data('\r\n'.join(notify_msg), UPnPDefaults.MULTICAST_EVENT_ADDR, UPnPDefaults.MULTICAST_EVENT_PORT) self.event_key_increment() self.eventing_variables = {} def _update_variable(self, name, value): if self.force_event_reload: self.eventing_variables[name] = value self.send_variables() return if name in self.eventing_variables and \ self.eventing_variables[name] != value: self.send_variables() self.eventing_variables[name] = value def _build_message_body(self, variables): log.debug("Building multicast message body to variables: %s" % str(variables)) preamble = """<?xml version="1.0"?>""" return '%s%s' % (preamble, build_notify_message_body(variables)) def event_key_increment(self): self.event_key += 1 if self.event_key > 4294967295: self.event_key = 1 def is_running(self): """ Returns True if the listener is running. @rtype: boolean """ if not self.force_event_reload: self._is_running = self.l_call.is_running() return self._is_running def start(self): """ Starts the listener. """ if not self.is_running(): for name, state_var in list(self.service.get_variables().items()): if state_var.send_events and state_var.multicast: state_var.subscribe_for_update(self._update_variable) if not self.force_event_reload: self.l_call.start(self.event_reload_time) self._is_running = True log.debug('Multicast event controller started with event reload time: %d' % self.event_reload_time) else: log.warning(self.msg_already_started) def stop(self): """ Stops the search. """ if self.is_running(): log.debug('Multicast event controller stopped') for name, state_var in list(self.service.get_variables().items()): if state_var.send_events and state_var.multicast: state_var.unsubscribe_for_update(self._update_variable) if not self.force_event_reload: self.l_call.stop() reactor.rem_after_stop_func(self.stop) self._is_running = False else: log.warning(self.msg_already_stopped) def destroy(self): """ Destroys and quits MSearch. """ if self.is_running(): self.stop() self._cleanup() def _cleanup(self): """ Clean up references. """ self.service = None self.udp_transport = None self.eventing_variables = None self.l_call = None
class MSearch(object): """ Represents a MSearch. Contains some control functions for starting and stopping the search. While running, search will be repeated in regular intervals specified at construction or passed to the start() method. """ msg_already_started = 'tried to start() MSearch when already started' msg_already_stopped = 'tried to stop() MSearch when already stopped' def __init__(self, ssdp, start=True, interval=DEFAULT_SEARCH_TIME, ssdp_addr=DEFAULT_SSDP_ADDR, ssdp_port=1900): """ Constructor for the MSearch class. @param ssdp: ssdp server instance that will receive new device events and subscriptions @param start: if True starts the search when constructed @param interval: interval between searchs @param ssdp_addr: ssdp address for listening (UDP) @param ssdp_port: ssdp port for listening (UDP) @type ssdp: SSDPServer @type start: boolean @type interval: float @type ssdp_addr: string @type ssdp_port integer """ self.ssdp = ssdp self.ssdp_addr = ssdp_addr self.ssdp_port = ssdp_port self.udp_transport = UDPTransport() self.listen_udp = UDPListener(ssdp_addr, data_callback=self._datagram_received, shared_socket=self.udp_transport.socket) self.loopcall = LoopingCall(self.double_discover) if start: self.start(interval) def is_running(self): """ Returns True if the search is running (it's being repeated in the interval given). @rtype: boolean """ return self.loopcall.is_running() def start(self, interval=DEFAULT_SEARCH_TIME, search_type=DEFAULT_SEARCH_TYPE, http_version="1.1", man='"ssdp:discover"', mx=1, additionals={}): """ Starts the search. @param interval: interval between searchs. Default is 600.0 seconds @param search_type: type of the search, default is "ssdp:all" @param http_version: http version for m-search (default is 1.1) @param man: man field for m-search (default is ssdp:discover) @param mx: mx field for m-search (default is 1) @param additionals: dict containing additional field to be appended in the end of the m-search message (default is a empty dictionary) @type interval: float @type search_type: string @type http_version: string @type man: string @type mx: int @type additionals: dict """ if not self.is_running(): self.ssdp.search_type = search_type self.listen_udp.start() self.loopcall._args = (search_type, http_version, man, mx, additionals, ) self.loopcall.start(interval, now=True) log.debug('MSearch started') else: log.warning(self.msg_already_started) def stop(self): """ Stops the search. """ if self.is_running(): log.debug('MSearch stopped') self.listen_udp.stop() self.loopcall.stop() else: log.warning(self.msg_already_stopped) def destroy(self): """ Destroys and quits MSearch. """ if self.is_running(): self.stop() self.listen_udp.destroy() self.loopcall.destroy() self._cleanup() def double_discover(self, search_type=DEFAULT_SEARCH_TYPE, http_version="1.1", man='"ssdp:discover"', mx=1, additionals={}): """ Sends a MSearch imediatelly. Each call to this method will yield a MSearch message, that is, it won't repeat automatically. """ log.info("Doing double discover for %s, HTTP_VERSION=%s, MAN=%s, \ MX=%d, additionals=%s" % (search_type, http_version, man, mx, additionals)) self.discover(search_type, http_version, man, mx, additionals) def discover(self, search_type=DEFAULT_SEARCH_TYPE, http_version="1.1", man='"ssdp:discover"', mx=1, additionals={}): """ Builds and sends the discover message (MSearch). @param type: search type @type type: string """ if (mx > 120): mx = 120 elif (mx < 1): mx = 1 req = ['M-SEARCH * HTTP/%s' % http_version, 'HOST: %s:%d' % (self.ssdp_addr, self.ssdp_port), 'MAN: %s' % man, 'MX: %s' % mx, 'ST: %s' % search_type] append = req.append [append('%s: %s' % (k, v)) for k, v in additionals.items()] append('') append('') req = '\r\n'.join(req) self.udp_transport.send_data(req, self.ssdp_addr, self.ssdp_port) 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 """ cmd, headers = parse_http_response(data) if cmd[0].startswith('HTTP/1.') and cmd[1] == '200': if self.ssdp != None: if not self.ssdp.is_known_device(headers['usn']): log.debug('Received MSearch answer %s,%s from %s:%s', headers['usn'], headers['st'], host, port) default_fields_name = ["usn", "st", "location", "server", "cache-control", "ext"] default_header = {} for field in default_fields_name: default_header[field] = headers.pop(field, "") self.ssdp.register(default_header['usn'], default_header['st'], default_header['location'], default_header['server'], default_header['cache-control'], "remote", headers)
class MSearch(object): """ Represents a MSearch. Contains some control functions for starting and stopping the search. While running, search will be repeated in regular intervals specified at construction or passed to the start() method. """ msg_already_started = 'tried to start() MSearch when already started' msg_already_stopped = 'tried to stop() MSearch when already stopped' def __init__(self, ssdp, start=True, interval=DEFAULT_SEARCH_TIME, ssdp_addr='239.255.255.250', ssdp_port=1900): """ Constructor for the MSearch class. @param ssdp: ssdp server instance that will receive new device events and subscriptions @param start: if True starts the search when constructed @param interval: interval between searchs @param ssdp_addr: ssdp address for listening (UDP) @param ssdp_port: ssdp port for listening (UDP) @type ssdp: SSDPServer @type start: boolean @type interval: float @type ssdp_addr: string @type ssdp_port integer """ self.ssdp = ssdp self.ssdp_addr = ssdp_addr self.ssdp_port = ssdp_port self.udp_transport = UDPTransport() self.listen_udp = UDPListener(ssdp_addr, data_callback=self._datagram_received, shared_socket=self.udp_transport.socket) self.loopcall = LoopingCall(self.double_discover) if start: self.start(interval) def is_running(self): """ Returns True if the search is running (it's being repeated in the interval given). @rtype: boolean """ return self.loopcall.is_running() def start(self, interval=DEFAULT_SEARCH_TIME, search_type=DEFAULT_SEARCH_TYPE): """ Starts the search. @param interval: interval between searchs. Default is 600.0 seconds @param search_type: type of the search, default is "ssdp:all" @type interval: float @type search_type: string """ if not self.is_running(): self.listen_udp.start() self.loopcall._args = (search_type, ) self.loopcall.start(interval, now=True) log.debug('MSearch started') else: log.warning(self.msg_already_started) def stop(self): """ Stops the search. """ if self.is_running(): log.debug('MSearch stopped') self.listen_udp.stop() self.loopcall.stop() else: log.warning(self.msg_already_stopped) def destroy(self): """ Destroys and quits MSearch. """ if self.is_running(): self.stop() self.listen_udp.destroy() self.loopcall.destroy() self._cleanup() def double_discover(self, search_type=DEFAULT_SEARCH_TYPE): """ Sends a MSearch imediatelly. Each call to this method will yield a MSearch message, that is, it won't repeat automatically. """ log.info("Doing double discover for %s", search_type) self.discover(search_type) self.discover(search_type) def discover(self, type="ssdp:all"): """ Mounts and sends the discover message (MSearch). @param type: search type @type type: string """ req = ['M-SEARCH * HTTP/1.1', 'HOST: %s:%d' % (self.ssdp_addr, self.ssdp_port), 'MAN: "ssdp:discover"', 'MX: 5', 'ST: ' + type, '', ''] req = '\r\n'.join(req) self.udp_transport.send_data(req, self.ssdp_addr, self.ssdp_port) 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 """ cmd, headers = parse_http_response(data) if cmd[0] == 'HTTP/1.1' and cmd[1] == '200': if self.ssdp != None: if not self.ssdp.is_known_device(headers['usn']): log.debug('Received MSearch answer %s,%s from %s:%s', headers['usn'], headers['st'], host, port) self.ssdp._register(headers['usn'], headers['st'], headers['location'], headers['server'], headers['cache-control'])
class MSearch(object): """ Represents a MSearch. Contains some control functions for starting and stopping the search. While running, search will be repeated in regular intervals specified at construction or passed to the start() method. """ msg_already_started = 'tried to start() MSearch when already started' msg_already_stopped = 'tried to stop() MSearch when already stopped' def __init__(self, ssdp, start=True, interval=DEFAULT_SEARCH_TIME, ssdp_addr=DEFAULT_SSDP_ADDR, ssdp_port=1900): """ Constructor for the MSearch class. @param ssdp: ssdp server instance that will receive new device events and subscriptions @param start: if True starts the search when constructed @param interval: interval between searchs @param ssdp_addr: ssdp address for listening (UDP) @param ssdp_port: ssdp port for listening (UDP) @type ssdp: SSDPServer @type start: boolean @type interval: float @type ssdp_addr: string @type ssdp_port integer """ self.ssdp = ssdp self.ssdp_addr = ssdp_addr self.ssdp_port = ssdp_port self.udp_transport = UDPTransport() self.listen_udp = UDPListener(ssdp_addr, data_callback=self._datagram_received, shared_socket=self.udp_transport.socket) self.loopcall = LoopingCall(self.double_discover) if start: self.start(interval) def is_running(self): """ Returns True if the search is running (it's being repeated in the interval given). @rtype: boolean """ return self.loopcall.is_running() def start(self, interval=DEFAULT_SEARCH_TIME, search_type=DEFAULT_SEARCH_TYPE, http_version="1.1", man='"ssdp:discover"', mx=1, additionals={}): """ Starts the search. @param interval: interval between searchs. Default is 600.0 seconds @param search_type: type of the search, default is "ssdp:all" @param http_version: http version for m-search (default is 1.1) @param man: man field for m-search (default is ssdp:discover) @param mx: mx field for m-search (default is 1) @param additionals: dict containing additional field to be appended in the end of the m-search message (default is a empty dictionary) @type interval: float @type search_type: string @type http_version: string @type man: string @type mx: int @type additionals: dict """ if not self.is_running(): self.ssdp.search_type = search_type self.listen_udp.start() self.loopcall._args = ( search_type, http_version, man, mx, additionals, ) self.loopcall.start(interval, now=True) log.debug('MSearch started') else: log.warning(self.msg_already_started) def stop(self): """ Stops the search. """ if self.is_running(): log.debug('MSearch stopped') self.listen_udp.stop() self.loopcall.stop() else: log.warning(self.msg_already_stopped) def destroy(self): """ Destroys and quits MSearch. """ if self.is_running(): self.stop() self.listen_udp.destroy() self.loopcall.destroy() self._cleanup() def double_discover(self, search_type=DEFAULT_SEARCH_TYPE, http_version="1.1", man='"ssdp:discover"', mx=1, additionals={}): """ Sends a MSearch imediatelly. Each call to this method will yield a MSearch message, that is, it won't repeat automatically. """ log.info("Doing double discover for %s, HTTP_VERSION=%s, MAN=%s, \ MX=%d, additionals=%s" % (search_type, http_version, man, mx, additionals)) self.discover(search_type, http_version, man, mx, additionals) def discover(self, search_type=DEFAULT_SEARCH_TYPE, http_version="1.1", man='"ssdp:discover"', mx=1, additionals={}): """ Builds and sends the discover message (MSearch). @param type: search type @type type: string """ if (mx > 120): mx = 120 elif (mx < 1): mx = 1 req = [ 'M-SEARCH * HTTP/%s' % http_version, 'HOST: %s:%d' % (self.ssdp_addr, self.ssdp_port), 'MAN: %s' % man, 'MX: %s' % mx, 'ST: %s' % search_type ] append = req.append [append('%s: %s' % (k, v)) for k, v in additionals.items()] append('') append('') req = '\r\n'.join(req) self.udp_transport.send_data(req, self.ssdp_addr, self.ssdp_port) 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 """ cmd, headers = parse_http_response(data) if cmd[0].startswith('HTTP/1.') and cmd[1] == '200': if self.ssdp != None: if not self.ssdp.is_known_device(headers['usn']): log.debug('Received MSearch answer %s,%s from %s:%s', headers['usn'], headers['st'], host, port) default_fields_name = [ "usn", "st", "location", "server", "cache-control", "ext" ] default_header = {} for field in default_fields_name: default_header[field] = headers.pop(field, "") self.ssdp.register(default_header['usn'], default_header['st'], default_header['location'], default_header['server'], default_header['cache-control'], "remote", headers)