initial commit
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
wire.py — 会话消息的打包 / 解包。
|
||||
|
||||
pynng 一条消息只能是单块二进制,所以这里做一层很简单的外壳:
|
||||
b"LS01" | u32 头长度 | JSON 头(UTF-8) | 二进制体
|
||||
|
||||
每个头里都带 session:
|
||||
{
|
||||
"id": "<一次运行一个 uuid>",
|
||||
"client_ip": "192.168.43.23", # 电脑自己的地址
|
||||
"board_ip": "192.168.43.50", # 板子的地址
|
||||
"started_ns": 1712345678901234567,
|
||||
"note": "..."
|
||||
}
|
||||
|
||||
这样每一条请求和应答都能看出属于哪个会话、从哪台机器来。
|
||||
"""
|
||||
import json
|
||||
import struct
|
||||
import time
|
||||
import uuid
|
||||
|
||||
MAGIC = b"LS01"
|
||||
_LEN = struct.Struct("<I")
|
||||
|
||||
|
||||
def new_session(board_ip, client_ip, note=""):
|
||||
"""新建一个会话(电脑端每次启动调一次)。"""
|
||||
return {
|
||||
"id": uuid.uuid4().hex,
|
||||
"client_ip": str(client_ip),
|
||||
"board_ip": str(board_ip),
|
||||
"started_ns": time.time_ns(),
|
||||
"note": str(note),
|
||||
}
|
||||
|
||||
|
||||
def pack(header, blob=b""):
|
||||
"""dict + 二进制体 -> bytes。"""
|
||||
h = json.dumps(header, separators=(",", ":"), ensure_ascii=False).encode("utf-8")
|
||||
return MAGIC + _LEN.pack(len(h)) + h + bytes(blob)
|
||||
|
||||
|
||||
def unpack(data):
|
||||
"""bytes -> (dict, 二进制体)。"""
|
||||
if len(data) < 8 or data[:4] != MAGIC:
|
||||
raise ValueError("bad frame magic")
|
||||
n = _LEN.unpack_from(data, 4)[0]
|
||||
if len(data) < 8 + n:
|
||||
raise ValueError("truncated header")
|
||||
header = json.loads(data[8:8 + n].decode("utf-8"))
|
||||
return header, data[8 + n:]
|
||||
|
||||
|
||||
def session_id(header):
|
||||
return (header.get("session") or {}).get("id")
|
||||
|
||||
|
||||
def check_session(header, session):
|
||||
"""应答必须属于当前会话,防止串台。"""
|
||||
got = session_id(header)
|
||||
if got != session["id"]:
|
||||
raise RuntimeError("session mismatch: got %r, want %r" % (got, session["id"]))
|
||||
Reference in New Issue
Block a user