Esempio n. 1
0
def present(message, options, file=sys.stdout):
    """Write a message payload to the output, pretty printing and/or coloring
    it as configured in the options."""
    if not message.payload:
        return

    payload = None

    mime = media_types.get(message.opt.content_format,
            'application/octet-stream')
    if options.pretty_print:
        from aiocoap.util.prettyprint import pretty_print
        prettyprinted = pretty_print(message)
        if prettyprinted is not None:
            (infos, mime, payload) = prettyprinted
            if not options.quiet:
                for i in infos:
                    print(colored(i, options, 'grey', attrs=['bold']),
                            file=sys.stderr)

    color = options.color
    if color:
        from aiocoap.util.prettyprint import lexer_for_mime
        import pygments
        try:
            lexer = lexer_for_mime(mime)
        except pygments.util.ClassNotFound:
            color = False

    if color and payload is None:
        # Coloring requires a unicode-string style payload, either from the
        # mime type or from the pretty printer.
        try:
            payload = message.payload.decode('utf8')
        except UnicodeDecodeError:
            color = False

    if color:
        from pygments.formatters import TerminalFormatter
        from pygments import highlight
        highlit = highlight(
            payload,
            lexer,
            TerminalFormatter(),
            )
        # The TerminalFormatter already adds an end-of-line character, not
        # trying to add one for any missing trailing newlines.
        print(highlit, file=file, end="")
        file.flush()
    else:
        if payload is None:
            file.buffer.write(message.payload)
            if file.isatty() and message.payload[-1:] != b'\n':
                file.write("\n")
        else:
            file.write(payload)
            if file.isatty() and payload[-1] != '\n':
                file.write("\n")
Esempio n. 2
0
def present(message, options, file=sys.stdout):
    """Write a message payload to the output, pretty printing and/or coloring
    it as configured in the options."""
    if not message.payload:
        return

    payload = None

    mime = media_types.get(message.opt.content_format,
                           'application/octet-stream')
    if options.pretty_print:
        from aiocoap.util.prettyprint import pretty_print
        prettyprinted = pretty_print(message)
        if prettyprinted is not None:
            (infos, mime, payload) = prettyprinted
            if not options.quiet:
                for i in infos:
                    print(colored(i, options, 'grey', attrs=['bold']),
                          file=sys.stderr)

    color = options.color
    if color:
        from aiocoap.util.prettyprint import lexer_for_mime
        import pygments
        try:
            lexer = lexer_for_mime(mime)
        except pygments.util.ClassNotFound:
            color = False

    if color and payload is None:
        # Coloring requires a unicode-string style payload, either from the
        # mime type or from the pretty printer.
        try:
            payload = message.payload.decode('utf8')
        except UnicodeDecodeError:
            color = False

    if color:
        from pygments.formatters import TerminalFormatter
        from pygments import highlight
        highlit = highlight(
            payload,
            lexer,
            TerminalFormatter(),
        )
        # The TerminalFormatter already adds an end-of-line character, not
        # trying to add one for any missing trailing newlines.
        print(highlit, file=file, end="")
        file.flush()
    else:
        if payload is None:
            file.buffer.write(message.payload)
            if file.isatty() and message.payload[-1:] != b'\n':
                file.write("\n")
        else:
            file.write(payload)
            if file.isatty() and payload[-1] != '\n':
                file.write("\n")
Esempio n. 3
0
 async def _common(self):
     coap_client = await get_coap_client()
     target = self.get_query_argument("target")
     p = urllib.parse.urlparse(target)
     if p.scheme not in coap_schemes:
         raise tornado.web.HTTPError(400)
     assert self.request.method in CoapRequestHandler.METHODS
     request = Message(code=CoapRequestHandler.METHODS[self.request.method],
                       uri=target)
     try:
         if "Content-Type" in self.request.headers:
             request.opt.content_format = \
                     media_types_rev[self.request.headers["Content-Type"]]
     except KeyError:
         raise tornado.web.HTTPError(400)
     request.payload = self.request.body
     pr = coap_client.request(request)
     app_log.info("waiting for {} response".format(self.request.method))
     try:
         resp = await pr.response
     except socket.gaierror as e:
         self.log_exception(*sys.exc_info())
         raise tornado.web.HTTPError(400, str(e))
     except OSError as e:
         self.log_exception(*sys.exc_info())
         raise tornado.web.HTTPError(404, str(e))
     cf = resp.opt.content_format
     mime_type = media_types.get(cf, "type %s" % cf)
     mime_type, *parameters = mime_type.split(";")
     self.content_type = mime_type
     status_class, status_detail = divmod(resp.code, 0x20)
     status = ((status_class * 100) + status_detail)
     if resp.code.is_successful():
         app_log.info("Success {}, {}".format(resp, resp.payload))
         if not self.request.method in ["HEAD"]:
             if (mime_type == "application/json"):
                 resp.payload.replace(b'""', b'null')
             self.write(resp.payload)
     else:
         app_log.error("Error {}, {}".format(resp, resp.payload))
         raise tornado.web.HTTPError(status,
                                     resp.payload,
                                     reason=resp.code.name_printable)
Esempio n. 4
0
    def incoming_observation(self, response):
        links = {}
        nodes = {}

        logging.info("Received response {} for {}".format(
            response, self.resource))
        if response.code.is_successful():
            cf = response.opt.content_format
            mime_type = media_types.get(cf, "type %s" % cf)
            mime_type, *parameters = mime_type.split(";")
            logging.info("Content format: {}".format(mime_type))
            if mime_type == "application/link-format":
                ls = linkformat.parse(response.payload.decode('utf-8'))
                for link in ls.links:
                    link = link.as_json_data()
                    pr = urllib.parse.urlparse(link["href"])
                    if pr.path.endswith("reboot"):
                        reboot_resources.add(link["href"])
                    link["addr"] = pr.netloc
                    link["path"] = pr.path
                    links[link["href"]] = link
        else:
            logging.error("Error: {}: {}".format(response, response.payload))
            return
        if self.websocket is not None and not self.websocket.is_closed():
            self.websocket.write_message(response.payload)
        elif self.websocket is None:
            for link in links.values():
                if link["addr"].startswith("[fe80::"):
                    logging.error("address {} link-local".format(link["addr"]))
                    continue
                path = link["path"]
                node, *rest = path.strip("/").split("/")
                if (len(rest) > 0) and (node not in nodes):
                    nodes[node] = {rest[0]: link}
                elif (len(rest) > 0):
                    nodes[node][rest[0]] = link
            if "btn" in nodes and "target" in nodes["btn"] and \
               "dsp" in nodes and "points" in nodes["dsp"]:
                asyncio.ensure_future(register(nodes["btn"], nodes["dsp"]))
            if "dsp" in nodes and "target" in nodes["dsp"] and \
               "dino" in nodes and "points" in nodes["dino"]:
                asyncio.ensure_future(register(nodes["dsp"], nodes["dino"]))
Esempio n. 5
0
def pretty_print(message):
    """Given a CoAP message, reshape its payload into something human-readable.
    The return value is a triple (infos, mime, text) where text represents the
    payload, mime is a type that could be used to syntax-highlight the text
    (not necessarily related to the original mime type, eg. a report of some
    binary data that's shaped like Markdown could use a markdown mime type),
    and some line of infos that give additional data (like the reason for a hex
    dump or the original mime type).
    """
    infos = []
    info = lambda m: infos.append(m)

    cf = message.opt.content_format
    mime_type = media_types.get(cf, "type %s" % cf)

    mime_type, *parameters = mime_type.split(';')
    type, _, subtype = mime_type.partition('/')

    show_hex = None

    if linkformat is not None and mime_type == 'application/link-format':
        try:
            parsed = linkformat.link_header.parse(
                message.payload.decode('utf8'))
        except ValueError:
            pass
        else:
            info("application/link-format content was re-formatted")
            prettyprinted = ",\n".join(str(l) for l in parsed.links)
            return (infos, 'application/link-format', prettyprinted)

    elif subtype == 'cbor' or subtype.endswith('+cbor'):
        try:
            parsed = cbor.loads(message.payload)
        except ValueError:
            show_hex = "CBOR value is invalid"
        else:
            info("CBOR message shown in naïve Python decoding")
            # Formatting it via Python b/c that's reliably available (as
            # opposed to JSON which might not round-trip well). The repr for
            # tags might still not be parsable, but I think chances of good
            # highlighting are best this way
            formatted = pprint.pformat(parsed)
            return (infos, 'text/x-python3', formatted)

    elif subtype == 'json' or subtype.endswith('+json'):
        try:
            parsed = json.loads(message.payload.decode('utf8'))
        except ValueError:
            pass
        else:
            info("JSON re-formated and indented")
            formatted = json.dumps(parsed, indent=4)
            return (infos, 'application/json', formatted)

    # That's about the formats we do for now.

    if show_hex is None:
        try:
            text = message.payload.decode('utf8')
        except UnicodeDecodeError:
            show_hex = "Message can not be parsed as UTF-8"
        else:
            return (infos, 'text/plain;charset=utf8', text)

    info("Showing hex dump of %s payload%s" %
         (mime_type if cf is not None else "untyped",
          ": " + show_hex if show_hex is not None else ""))
    data = message.payload
    # Not the most efficient hex dumper, but we won't stream video over
    # this anyway
    formatted = []
    offset = 0
    while data:
        line, data = data[:16], data[16:]

        formatted.append("%08x  " % offset + \
                " ".join("%02x" % line[i] if i < len(line) else "  " for i in range(8)) + "  " + \
                " ".join("%02x" % line[i] if i < len(line) else "  " for i in range(8, 16)) + "  |" + \
                "".join(chr(x) if 32 <= x < 127 else '.' for x in line) + \
                "|\n")

        offset += len(line)
    if offset % 16 != 0:
        formatted.append("%08x\n" % offset)
    return (infos, MEDIATYPE_HEXDUMP, "".join(formatted))
Esempio n. 6
0
def pretty_print(message):
    """Given a CoAP message, reshape its payload into something human-readable.
    The return value is a triple (infos, mime, text) where text represents the
    payload, mime is a type that could be used to syntax-highlight the text
    (not necessarily related to the original mime type, eg. a report of some
    binary data that's shaped like Markdown could use a markdown mime type),
    and some line of infos that give additional data (like the reason for a hex
    dump or the original mime type).
    """
    infos = []
    info = lambda m: infos.append(m)

    cf = message.opt.content_format
    mime_type = media_types.get(cf, "type %s" % cf)

    mime_type, *parameters = mime_type.split(';')
    type, _, subtype = mime_type.partition('/')

    show_hex = None

    if linkformat is not None and mime_type == 'application/link-format':
        try:
            parsed = linkformat.link_header.parse(message.payload.decode('utf8'))
        except ValueError:
            pass
        else:
            info("application/link-format content was re-formatted")
            prettyprinted = ",\n".join(str(l) for l in parsed.links)
            return (infos, 'application/link-format', prettyprinted)

    elif subtype == 'cbor' or subtype.endswith('+cbor'):
        try:
            parsed = cbor.loads(message.payload)
        except ValueError:
            show_hex = "CBOR value is invalid"
        else:
            info("CBOR message shown in naïve Python decoding")
            # Formatting it via Python b/c that's reliably available (as
            # opposed to JSON which might not round-trip well). The repr for
            # tags might still not be parsable, but I think chances of good
            # highlighting are best this way
            formatted = pprint.pformat(parsed)
            return (infos, 'text/x-python3', formatted)

    elif subtype == 'json' or subtype.endswith('+json'):
        try:
            parsed = json.loads(message.payload.decode('utf8'))
        except ValueError:
            pass
        else:
            info("JSON re-formated and indented")
            formatted = json.dumps(parsed, indent=4)
            return (infos, 'application/json', formatted)

    # That's about the formats we do for now.

    if show_hex is None:
        try:
            text = message.payload.decode('utf8')
        except UnicodeDecodeError:
            show_hex = "Message can not be parsed as UTF-8"
        else:
            return (infos, 'text/plain;charset=utf8', text)

    info("Showing hex dump of %s payload%s" % (
        mime_type if cf is not None else "untyped",
        ": " + show_hex if show_hex is not None else ""))
    data = message.payload
    # Not the most efficient hex dumper, but we won't stream video over
    # this anyway
    formatted = []
    offset = 0
    while data:
        line, data = data[:16], data[16:]

        formatted.append("%08x  " % offset + \
                " ".join("%02x" % line[i] if i < len(line) else "  " for i in range(8)) + "  " + \
                " ".join("%02x" % line[i] if i < len(line) else "  " for i in range(8, 16)) + "  |" + \
                "".join(chr(x) if 32 <= x <= 127 else '.' for x in line) + \
                "|\n")

        offset += len(line)
    if offset % 16 != 0:
        formatted.append("%08x\n" % offset)
    return (infos, MEDIATYPE_HEXDUMP, "".join(formatted))