def __init__(self): self.__class__.stateVariables = Lict(self.__class__.stateVariables) for name, arguments in self.__class__.actions.items(): self.__class__.actions[name] = Lict(arguments) # Build action function map self.actionFunctions = {} for attr in dir(self): obj = getattr(self, attr) if callable(obj) and hasattr(obj, 'actionName'): setattr(self, attr, ServiceActionWrapper(self, obj)) self.actionFunctions[getattr(obj, 'actionName')] = obj self.subscriptions = Lict(searchNames='sid') if self.event_properties is None: self.event_properties = Lict(searchNames='name')
def _instance_initialize(self, instance): if not hasattr(instance, 'stateVariables'): raise TypeError() if self.name not in instance.stateVariables: raise KeyError() if not instance.stateVariables[self.name].sendEvents: raise ValueError() self.instance = instance self.state_variable = instance.stateVariables[self.name] if self.instance.event_properties is None: self.instance.event_properties = Lict(searchNames='name') self.instance.event_properties.append(self) self.initialized = True if self.value is None: self.value = self._default()
class Service(object): version = (1, 0) serviceType = None serviceId = None actions = {} stateVariables = {} event_properties = None subscription_timeout_range = (1800, None) _description = None def __init__(self): self.__class__.stateVariables = Lict(self.__class__.stateVariables) for name, arguments in self.__class__.actions.items(): self.__class__.actions[name] = Lict(arguments) # Build action function map self.actionFunctions = {} for attr in dir(self): obj = getattr(self, attr) if callable(obj) and hasattr(obj, 'actionName'): setattr(self, attr, ServiceActionWrapper(self, obj)) self.actionFunctions[getattr(obj, 'actionName')] = obj self.subscriptions = Lict(searchNames='sid') if self.event_properties is None: self.event_properties = Lict(searchNames='name') def _generate_subscription_sid(self): result = None retries = 0 while result is None and retries < 10: generated_uuid = str(uuid.uuid4()) if generated_uuid not in self.subscriptions: result = generated_uuid else: retries += 1 if result is None: raise Exception() return result def subscribe(self, callback, timeout): sid = 'uuid:' + self._generate_subscription_sid() if (self.subscription_timeout_range[0] is not None and timeout < self.subscription_timeout_range[0]): timeout = self.subscription_timeout_range[0] if (self.subscription_timeout_range[1] is not None and timeout > self.subscription_timeout_range[1]): timeout = self.subscription_timeout_range[1] subscription = EventSubscription(sid, callback, timeout) # Send initial event property notifications # TODO: calling this in 1 second isn't really a great way to do this reactor.callLater(1, subscription.notify, self.event_properties.values()) self.subscriptions.append(subscription) return {'SID': sid, 'TIMEOUT': 'Second-' + str(timeout)} def notify(self, prop): for sid in self.subscriptions.keys(): subscription = self.subscriptions[sid] if subscription.expired: self.subscriptions.popvalue(sid) else: subscription.notify(prop) def dump(self): Logr.debug("xml tree dumped") scpd = et.Element('scpd', attrib={ 'xmlns': 'urn:schemas-upnp-org:service-1-0', }) # specVersion specVersion = et.Element('specVersion') specVersion.append(make_element('major', str(self.version[0]))) specVersion.append(make_element('minor', str(self.version[1]))) scpd.append(specVersion) # actionList actionList = et.Element('actionList') for action_name, action_args in self.actions.items(): action = et.Element('action') action.append(make_element('name', action_name)) argumentList = et.Element('argumentList') for arg in action_args: argumentList.append(arg.dump()) action.append(argumentList) actionList.append(action) scpd.append(actionList) # serviceStateTable serviceStateTable = et.Element('serviceStateTable') for stateVariable in self.stateVariables.values(): serviceStateTable.append(stateVariable.dump()) scpd.append(serviceStateTable) return scpd def dumps(self, force=False): if self.__class__._description is None or force: self.__class__._description = '<?xml version="1.0" encoding="utf-8"?>' + \ et.tostring(self.dump()) return self.__class__._description
class Service(object): version = (1, 0) serviceType = None serviceId = None actions = {} stateVariables = {} event_properties = None subscription_timeout_range = (1800, None) _description = None def __init__(self): self.__class__.stateVariables = Lict(self.__class__.stateVariables) for name, arguments in self.__class__.actions.items(): self.__class__.actions[name] = Lict(arguments) # Build action function map self.actionFunctions = {} for attr in dir(self): obj = getattr(self, attr) if callable(obj) and hasattr(obj, 'actionName'): setattr(self, attr, ServiceActionWrapper(self, obj)) self.actionFunctions[getattr(obj, 'actionName')] = obj self.subscriptions = Lict(searchNames='sid') if self.event_properties is None: self.event_properties = Lict(searchNames='name') def _generate_subscription_sid(self): result = None retries = 0 while result is None and retries < 10: generated_uuid = str(uuid.uuid4()) if generated_uuid not in self.subscriptions: result = generated_uuid else: retries += 1 if result is None: raise Exception() return result def subscribe(self, callback, timeout): sid = 'uuid:' + self._generate_subscription_sid() if (self.subscription_timeout_range[0] is not None and timeout < self.subscription_timeout_range[0]): timeout = self.subscription_timeout_range[0] if (self.subscription_timeout_range[1] is not None and timeout > self.subscription_timeout_range[1]): timeout = self.subscription_timeout_range[1] subscription = EventSubscription(sid, callback, timeout) # Send initial event property notifications # TODO: calling this in 1 second isn't really a great way to do this reactor.callLater(1, subscription.notify, self.event_properties.values()) self.subscriptions.append(subscription) return { 'SID': sid, 'TIMEOUT': 'Second-' + str(timeout) } def notify(self, prop): for sid in self.subscriptions.keys(): subscription = self.subscriptions[sid] if subscription.expired: self.subscriptions.popvalue(sid) else: subscription.notify(prop) def dump(self): Logr.debug("xml tree dumped") scpd = et.Element('scpd', attrib={ 'xmlns': 'urn:schemas-upnp-org:service-1-0', }) # specVersion specVersion = et.Element('specVersion') specVersion.append(make_element('major', str(self.version[0]))) specVersion.append(make_element('minor', str(self.version[1]))) scpd.append(specVersion) # actionList actionList = et.Element('actionList') for action_name, action_args in self.actions.items(): action = et.Element('action') action.append(make_element('name', action_name)) argumentList = et.Element('argumentList') for arg in action_args: argumentList.append(arg.dump()) action.append(argumentList) actionList.append(action) scpd.append(actionList) # serviceStateTable serviceStateTable = et.Element('serviceStateTable') for stateVariable in self.stateVariables.values(): serviceStateTable.append(stateVariable.dump()) scpd.append(serviceStateTable) return scpd def dumps(self, force=False): if self.__class__._description is None or force: self.__class__._description = '<?xml version="1.0" encoding="utf-8"?>' + \ et.tostring(self.dump()) return self.__class__._description