def connection_lost(self, exc: Exception) -> None: """Handle lost connections. Args: exc: Exception type """ if exc: logger.warning(f"SSDPServer closed with exception: {exc}")
def set_state(self, cmd: str, data: bytes) -> bool: """Call HTTP method, for use by `functools.partialmethod`. Args: cmd: Either `"on_cmd"` or `"off_cmd"`, for `getattr(self, cmd)` data: Either `"on_data"` or `"off_data"`, for `getattr(self, data)` Returns: Boolean indicating whether it state was set successfully """ req = urllib.request.Request(url=cmd, data=data, headers=self.headers, method=self.method) try: with self.urlopen(req) as resp: if isinstance(resp, http.client.HTTPResponse): return resp.status in (200, 201) except HTTPError as e: logger.warning(f"Error with request to {cmd}: {e}") return False
def handle_action(self, msg: str) -> None: """Execute `on`, `off`, or `get_state` method of plugin. Args: msg: Body of the Echo's HTTP request to trigger an action """ logger.debug(f"Handling action for plugin type {self.plugin}") success = False soap_format = ( '<s:Envelope ' 'xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" ' 's:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">' '<s:Body>' '<u:{action}BinaryStateResponse ' 'xmlns:u="urn:Belkin:service:basicevent:1">' '<BinaryState>{state_int}</BinaryState>' '</u:{action}BinaryStateResponse>' '</s:Body>' '</s:Envelope>').format command_format = ( 'SOAPACTION: "urn:Belkin:service:basicevent:1#{}BinaryState"' ).format soap_message: str = None action: str = None state_int: int = None if command_format("Get") in msg: logger.info(f"Attempting to get state for {self.plugin.name}") action = "Get" try: state = self.plugin.get_state() except AttributeError: logger.warning(f"Plugin {self.plugin.__module__} has not " "implemented a `get_state` method.") else: logger.info(f"{self.plugin.name} state: {state}") success = True state_int = int(state.lower() == "on") elif command_format("Set") in msg: action = "Set" if '<BinaryState>0</BinaryState>' in msg: logger.info(f"Attempting to turn off {self.plugin.name}") state_int = 0 success = self.plugin.off() elif '<BinaryState>1</BinaryState>' in msg: logger.info(f"Attempting to turn on {self.plugin.name}") state_int = 1 success = self.plugin.on() else: logger.warning(f"Unrecognized request:\n{msg}") if success: date_str = formatdate(timeval=None, localtime=False, usegmt=True) soap_message = soap_format(action=action, state_int=state_int) response = '\n'.join([ 'HTTP/1.1 200 OK', f'CONTENT-LENGTH: {len(soap_message)}', 'CONTENT-TYPE: text/xml charset="utf-8"', f'DATE: {date_str}', 'EXT:', 'SERVER: Unspecified, UPnP/1.0, Unspecified', 'X-User-Agent: Fauxmo', 'CONNECTION: close\n', f'{soap_message}', ]) logger.debug(response) self.transport.write(response.encode()) else: errmsg = (f"Unable to complete command for {self.plugin.name}:\n" f"{msg}") logger.warning(errmsg) self.transport.close()
def handle_action(self, msg: str) -> None: """Execute `on`, `off`, or `get_state` method of plugin. Args: msg: Body of the Echo's HTTP request to trigger an action """ logger.debug(f"Handling action for plugin type {self.plugin}") soap_format = ( "<s:Envelope " 'xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" ' 's:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">' "<s:Body>" "<u:{action}{action_type}Response " 'xmlns:u="urn:Belkin:service:basicevent:1">' "<{action_type}>{return_val}</{action_type}>" "</u:{action}{action_type}Response>" "</s:Body>" "</s:Envelope>").format command_format = ( 'SOAPACTION: "urn:Belkin:service:basicevent:1#{}"').format soap_message: str = None action: str = None action_type: str = None return_val: str = None success: bool = False if command_format("GetBinaryState").casefold() in msg.casefold(): logger.info(f"Attempting to get state for {self.plugin.name}") action = "Get" action_type = "BinaryState" state = self.plugin.get_state().casefold() logger.info(f"{self.plugin.name} state: {state}") if state in ["off", "on"]: success = True return_val = str(int(state.lower() == "on")) elif command_format("SetBinaryState").casefold() in msg.casefold(): action = "Set" action_type = "BinaryState" if "<BinaryState>0</BinaryState>" in msg: logger.info(f"Attempting to turn off {self.plugin.name}") return_val = "0" success = self.plugin.off() elif "<BinaryState>1</BinaryState>" in msg: logger.info(f"Attempting to turn on {self.plugin.name}") return_val = "1" success = self.plugin.on() else: logger.warning(f"Unrecognized request:\n{msg}") elif command_format("GetFriendlyName").casefold() in msg.casefold(): action = "Get" action_type = "FriendlyName" return_val = self.plugin.name success = True logger.info(f"{self.plugin.name} returning friendly name") if success: soap_message = soap_format(action=action, action_type=action_type, return_val=return_val) response = self.add_http_headers(soap_message) logger.debug(response) self.transport.write(response.encode()) else: errmsg = ( f"Unable to complete command for {self.plugin.name}:\n{msg}") logger.warning(errmsg) self.transport.close()
def connection_lost(self, exc): if exc: logger.warning("SSDPServer closed with exception: {}".format(exc))