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")
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)
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"]))
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))
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))