示例#1
0
    def connection_lost(self, exc: Exception) -> None:
        """Handle lost connections.

        Args:
            exc: Exception type
        """
        if exc:
            logger.warning(f"SSDPServer closed with exception: {exc}")
示例#2
0
    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
示例#3
0
    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()
示例#4
0
    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()
示例#5
0
 def connection_lost(self, exc):
     if exc:
         logger.warning("SSDPServer closed with exception: {}".format(exc))