networkctl.py 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. """LuaNetworkController stub + msg 对象构造 + 分发。"""
  2. from __future__ import annotations
  3. from typing import Any
  4. from apilot.wire import Frame
  5. from apilot.stubs.netclient import NetClientStub
  6. MSG_LUA = """
  7. local function mkmsg(recog, msgId, p1, p2, p3, body)
  8. local pos = 1
  9. local reader = {}
  10. function reader:ReadString(n)
  11. local s = string.sub(body, pos, pos + n - 1)
  12. pos = pos + n
  13. return s
  14. end
  15. local m = {}
  16. function m:GetMsgId() return msgId end
  17. function m:GetHeader()
  18. return {recog=recog, param1=p1, param2=p2, param3=p3, msgId=msgId}
  19. end
  20. function m:GetDataLength() return #body end
  21. function m:GetData() return reader end
  22. return m
  23. end
  24. return mkmsg
  25. """
  26. class NetworkCtlStub:
  27. def __init__(self, nc: NetClientStub) -> None:
  28. self.nc = nc
  29. self._tail = 0
  30. self.handlers: dict[int, Any] = {}
  31. self._installed: set[int] = set() # 已 install 的 lua runtime id
  32. def _next_tail(self) -> int:
  33. self._tail += 1
  34. return self._tail
  35. def send_msg(self, msg_id: int, recog: int, p1: int, p2: int, p3: int,
  36. data_str: "bytes | str | None", data_len: int) -> None:
  37. if data_str is None:
  38. body = b""
  39. elif isinstance(data_str, str):
  40. body = data_str.encode("utf-8")
  41. else:
  42. body = bytes(data_str)
  43. self.nc.send_frame(Frame(recog=recog, msg_id=msg_id, p1=p1, p2=p2, p3=p3,
  44. tail=self._next_tail(), body=body))
  45. def register_lua_handler(self, msg_id: int, cb: Any) -> None:
  46. self.handlers[int(msg_id)] = cb
  47. def unregister_all(self) -> None:
  48. self.handlers.clear()
  49. def install_to_lua(self, lua: Any) -> None:
  50. g = lua.globals()
  51. g["AP_networkCtl"] = self
  52. # 冒号调用 networkCtl:SendMsg(...) 兼容:__index 返回 (self, ...) 闭包
  53. lua.execute("""
  54. networkCtl = networkCtl or {}
  55. setmetatable(networkCtl, {__index = function(_, k)
  56. local self = AP_networkCtl
  57. local map = {SendMsg="send_msg",
  58. RegisterLuaHandler="register_lua_handler",
  59. UnregisterAllLuaHandler="unregister_all"}
  60. local pyname = map[k]
  61. if pyname then
  62. return function(_, ...) return self[pyname](self, ...) end
  63. end
  64. return function(...) return nil end
  65. end})
  66. LuaNetworkController = {Inst = function() return networkCtl end}
  67. """)
  68. lua.execute("AP_mkmsg = (function() " + MSG_LUA + " end)()")
  69. self._installed.add(id(lua))
  70. def make_msg_object(lua: Any, frame: Frame) -> Any:
  71. """名义接口: 等价 AP_mkmsg 闭包,按帧构造 Lua msg 对象(需先 install_to_lua)。"""
  72. mkmsg = lua.globals()["AP_mkmsg"]
  73. body = frame.body.decode("latin-1")
  74. return mkmsg(frame.recog, frame.msg_id, frame.p1, frame.p2, frame.p3, body)
  75. def dispatch_frame(lua: Any, ctl: NetworkCtlStub, f: Frame) -> None:
  76. cb = ctl.handlers.get(f.msg_id)
  77. if cb is None:
  78. return
  79. if id(lua) not in ctl._installed:
  80. ctl.install_to_lua(lua)
  81. cb(make_msg_object(lua, f))