mirror of
https://github.com/CopterExpress/clever-show.git
synced 2026-05-26 07:07:58 +00:00
109 lines
3.7 KiB
Python
109 lines
3.7 KiB
Python
import io
|
|
import sys
|
|
import json
|
|
import struct
|
|
|
|
|
|
class Message:
|
|
def __init__(self):
|
|
self.income_raw = b""
|
|
self._jsonheader_len = None
|
|
self.jsonheader = None
|
|
self.content = None
|
|
|
|
@staticmethod
|
|
def _json_encode(obj, encoding="utf-8"):
|
|
return json.dumps(obj, ensure_ascii=False).encode(encoding)
|
|
|
|
@staticmethod
|
|
def _json_decode(json_bytes, encoding="utf-8"):
|
|
with io.TextIOWrapper(io.BytesIO(json_bytes), encoding=encoding, newline="") as tiow:
|
|
obj = json.load(tiow)
|
|
return obj
|
|
|
|
@classmethod
|
|
def create_message(cls, content_bytes, content_type, message_type, content_encoding="utf-8",
|
|
additional_headers=None):
|
|
jsonheader = {
|
|
"byteorder": sys.byteorder,
|
|
"content-type": content_type,
|
|
"content-encoding": content_encoding,
|
|
"content-length": len(content_bytes),
|
|
"message-type": message_type,
|
|
}
|
|
if additional_headers:
|
|
jsonheader.update(additional_headers)
|
|
|
|
jsonheader_bytes = cls._json_encode(jsonheader, "utf-8")
|
|
message_hdr = struct.pack(">H", len(jsonheader_bytes))
|
|
message = message_hdr + jsonheader_bytes + content_bytes
|
|
return message
|
|
|
|
@classmethod
|
|
def create_json_message(cls, contents):
|
|
message = cls.create_message(cls._json_encode(contents), "json", "message")
|
|
return message
|
|
|
|
@classmethod
|
|
def create_simple_message(cls, command, args=None):
|
|
if args is None:
|
|
args = {}
|
|
message = cls.create_json_message({"command": command, "args": args})
|
|
return message
|
|
|
|
@classmethod
|
|
def create_request(cls, requested_value, request_id, args=None):
|
|
if args is None:
|
|
args = {}
|
|
contents = {"requested_value": requested_value,
|
|
"requst_id": request_id,
|
|
"args": args,
|
|
}
|
|
message = cls.create_message(cls._json_encode(contents), "json", "request")
|
|
return message
|
|
|
|
def _process_protoheader(self):
|
|
header_len = 2
|
|
if len(self.income_raw) >= header_len:
|
|
self._jsonheader_len = struct.unpack(">H", self.income_raw[:header_len])[0]
|
|
self.income_raw = self.income_raw[header_len:]
|
|
|
|
def _process_jsonheader(self):
|
|
header_len = self._jsonheader_len
|
|
if len(self.income_raw) >= header_len:
|
|
self.jsonheader = self._json_decode(self.income_raw[:header_len], "utf-8")
|
|
self.income_raw = self.income_raw[header_len:]
|
|
for reqhdr in (
|
|
"byteorder",
|
|
"content-length",
|
|
"content-type",
|
|
"content-encoding",
|
|
"message-type",
|
|
):
|
|
if reqhdr not in self.jsonheader:
|
|
raise ValueError('Missing required header {}'.format(reqhdr))
|
|
|
|
def _process_content(self):
|
|
content_len = self.jsonheader["content-length"]
|
|
if not len(self.income_raw) >= content_len:
|
|
return
|
|
data = self.income_raw[:content_len]
|
|
self.income_raw = self.income_raw[content_len:]
|
|
if self.jsonheader["content-type"] == "json":
|
|
encoding = self.jsonheader["content-encoding"]
|
|
self.content = self._json_decode(data, encoding)
|
|
else:
|
|
self.content = data
|
|
|
|
def process_message(self):
|
|
if self._jsonheader_len is None:
|
|
self._process_protoheader()
|
|
|
|
if self._jsonheader_len is not None:
|
|
if self.jsonheader is None:
|
|
self._process_jsonheader()
|
|
|
|
if self.jsonheader:
|
|
if self.content is None:
|
|
self._process_content()
|