Exemple #1
0
def parse_device_dict(xml_dict: dict) -> Dict:
    keys = list(xml_dict.keys())
    for k in keys:
        m = XML_ROOT_SANITY_PATTERN.findall(k)
        if len(m) == 3 and m[1][0] and m[2][5]:
            schema_key = m[1][0]
            root = m[2][5]
            xml_dict = flatten_keys(xml_dict, "{%s}" % schema_key)[root]
            break
    result = {}
    for k, v in xml_dict.items():
        if isinstance(xml_dict[k], dict):
            inner_d = {}
            for inner_k, inner_v in xml_dict[k].items():
                parsed_k = XML_OTHER_KEYS.findall(inner_k)
                if len(parsed_k) == 2:
                    inner_d[parsed_k[0]] = inner_v
                else:
                    assert len(parsed_k) == 3
                    inner_d[parsed_k[1]] = inner_v
            result[k] = inner_d
        else:
            result[k] = v

    return result
Exemple #2
0
def get_action_list(
    element_dict: dict
) -> List:  # [(<method>, [<input1>, ...], [<output1, ...]), ...]
    service_info = flatten_keys(element_dict, "{%s}" % SERVICE)
    if "actionList" in service_info:
        action_list = service_info["actionList"]
    else:
        return []
    if not len(action_list):  # it could be an empty string
        return []

    result: list = []
    if isinstance(action_list["action"], dict):
        arg_dicts = action_list["action"]['argumentList']['argument']
        if not isinstance(arg_dicts, list):  # when there is one arg
            arg_dicts = [arg_dicts]
        return [[
            action_list["action"]['name'],
            [i['name'] for i in arg_dicts if i['direction'] == 'in'],
            [i['name'] for i in arg_dicts if i['direction'] == 'out']
        ]]
    for action in action_list["action"]:
        if not action.get('argumentList'):
            result.append((action['name'], [], []))
        else:
            arg_dicts = action['argumentList']['argument']
            if not isinstance(arg_dicts, list):  # when there is one arg
                arg_dicts = [arg_dicts]
            result.append(
                (action['name'],
                 [i['name'] for i in arg_dicts if i['direction'] == 'in'],
                 [i['name'] for i in arg_dicts if i['direction'] == 'out']))
    return result
Exemple #3
0
def parse_device_dict(xml_dict: Dict[str, Any]) -> Dict[str, Any]:
    keys = list(xml_dict.keys())
    found = False
    for k in keys:
        m: List[Tuple[str, str, str, str, str, str]] = XML_ROOT_SANITY_PATTERN.findall(k)
        if len(m) == 3 and m[1][0] and m[2][5]:
            schema_key: str = m[1][0]
            root: str = m[2][5]
            flattened = flatten_keys(xml_dict, "{%s}" % schema_key)
            if root not in flattened:
                raise UPnPError("root device not found")
            xml_dict = flattened[root]
            found = True
            break
    if not found:
        raise UPnPError("device not found")
    result = {}
    for k, v in xml_dict.items():
        if isinstance(xml_dict[k], dict):
            inner_d = {}
            for inner_k, inner_v in xml_dict[k].items():
                parsed_k = XML_OTHER_KEYS.findall(inner_k)
                if len(parsed_k) == 2:
                    inner_d[parsed_k[0]] = inner_v
                else:
                    assert len(parsed_k) == 3, f"expected len=3, got {len(parsed_k)}"
                    inner_d[parsed_k[1]] = inner_v
            result[k] = inner_d
        else:
            result[k] = v
    return result
def deserialize_scpd_get_response(content: bytes) -> Dict:
    if XML_VERSION.encode() in content:
        parsed = CONTENT_PATTERN.findall(content)
        content = b'' if not parsed else parsed[0][0]
        xml_dict = etree_to_dict(ElementTree.fromstring(content.decode()))
        schema_key = DEVICE
        root = ROOT
        for k in xml_dict.keys():
            m = XML_ROOT_SANITY_PATTERN.findall(k)
            if len(m) == 3 and m[1][0] and m[2][5]:
                schema_key = m[1][0]
                root = m[2][5]
                break
        return flatten_keys(xml_dict, "{%s}" % schema_key)[root]
    return {}
Exemple #5
0
def deserialize_soap_post_response(
        response: bytes, method: str,
        service_id: str) -> typing.Dict[str, typing.Dict[str, str]]:
    parsed: typing.List[
        typing.List[bytes]] = CONTENT_NO_XML_VERSION_PATTERN.findall(response)
    content = b'' if not parsed else parsed[0][0]
    content_dict = xml_to_dict(content.decode())
    envelope = content_dict[ENVELOPE]
    if not isinstance(envelope[BODY], dict):
        # raise UPnPError('blank response')
        return {}  # TODO: raise
    response_body: typing.Dict[str, typing.Dict[str, typing.Dict[
        str, str]]] = flatten_keys(envelope[BODY], f"{'{' + service_id + '}'}")
    if not response_body:
        # raise UPnPError('blank response')
        return {}  # TODO: raise
    if FAULT in response_body:
        fault: typing.Dict[str,
                           typing.Dict[str,
                                       typing.Dict[str, str]]] = flatten_keys(
                                           response_body[FAULT],
                                           "{%s}" % CONTROL)
        try:
            raise UPnPError(fault['detail']['UPnPError']['errorDescription'])
        except (KeyError, TypeError, ValueError):
            raise UPnPError(
                f"Failed to decode error response: {json.dumps(fault)}")
    response_key = None
    for key in response_body:
        if method in key:
            response_key = key
            break
    if not response_key:
        raise UPnPError(
            f"unknown response fields for {method}: {response_body}")
    return response_body[response_key]
def deserialize_soap_post_response(response: bytes, method: str, service_id: str) -> dict:
    parsed = CONTENT_NO_XML_VERSION_PATTERN.findall(response)
    content = b'' if not parsed else parsed[0][0]
    content_dict = etree_to_dict(ElementTree.fromstring(content.decode()))
    envelope = content_dict[ENVELOPE]
    response_body = flatten_keys(envelope[BODY], "{%s}" % service_id)
    body = handle_fault(response_body)  # raises UPnPError if there is a fault
    response_key = None
    if not body:
        return {}
    for key in body:
        if method in key:
            response_key = key
            break
    if not response_key:
        raise UPnPError("unknown response fields for %s: %s" % (method, body))
    return body[response_key]
Exemple #7
0
def get_action_list(
    element_dict: typing.Dict[str, typing.Union[str, typing.Dict[
        str, str], typing.List[typing.Dict[str, typing.Dict[str, str]]]]]
) -> typing.List[typing.Tuple[str, typing.List[str], typing.List[str]]]:
    service_info = flatten_keys(element_dict, "{%s}" % SERVICE)
    result: typing.List[typing.Tuple[str, typing.List[str],
                                     typing.List[str]]] = []
    if "actionList" in service_info:
        action_list = service_info["actionList"]
    else:
        return result
    if not len(action_list):  # it could be an empty string
        return result

    action = action_list["action"]
    if isinstance(action, dict):
        arg_dicts: typing.List[typing.Dict[str, str]] = []
        if not isinstance(action['argumentList']['argument'],
                          list):  # when there is one arg
            arg_dicts.extend([action['argumentList']['argument']])
        else:
            arg_dicts.extend(action['argumentList']['argument'])

        result.append(
            (action_list["action"]['name'],
             [i['name'] for i in arg_dicts if i['direction'] == 'in'
              ], [i['name'] for i in arg_dicts if i['direction'] == 'out']))
        return result
    assert isinstance(action, list)
    for _action in action:
        if not _action.get('argumentList'):
            result.append((_action['name'], [], []))
        else:
            if not isinstance(_action['argumentList']['argument'],
                              list):  # when there is one arg
                arg_dicts = [_action['argumentList']['argument']]
            else:
                arg_dicts = _action['argumentList']['argument']
            result.append(
                (_action['name'],
                 [i['name'] for i in arg_dicts if i['direction'] == 'in'],
                 [i['name'] for i in arg_dicts if i['direction'] == 'out']))
    return result
Exemple #8
0
def handle_fault(response: dict) -> dict:
    if FAULT in response:
        fault = flatten_keys(response[FAULT], "{%s}" % CONTROL)
        error_description = fault['detail']['UPnPError']['errorDescription']
        raise UPnPError(error_description)
    return response