mirror of
https://github.com/pyMC-dev/pyMC_Repeater.git
synced 2026-08-07 09:23:06 +02:00
Refactor CompanionFrameServer for non-blocking message synchronization
- Changed the _get_companion_stats method to be asynchronous, improving responsiveness. - Added a new async method _cmd_sync_next_message to handle message synchronization without blocking the event loop, enhancing performance during message processing. - Introduced constants for response codes to streamline message handling in the CompanionFrameServer.
This commit is contained in:
@@ -10,8 +10,16 @@ from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import struct
|
||||
from typing import Optional
|
||||
|
||||
from pymc_core.companion.constants import (
|
||||
RESP_CODE_CHANNEL_MSG_RECV,
|
||||
RESP_CODE_CHANNEL_MSG_RECV_V3,
|
||||
RESP_CODE_CONTACT_MSG_RECV,
|
||||
RESP_CODE_CONTACT_MSG_RECV_V3,
|
||||
RESP_CODE_NO_MORE_MESSAGES,
|
||||
)
|
||||
from pymc_core.companion.frame_server import CompanionFrameServer as _BaseFrameServer
|
||||
from pymc_core.companion.models import QueuedMessage
|
||||
|
||||
@@ -83,6 +91,71 @@ class CompanionFrameServer(_BaseFrameServer):
|
||||
path_len=msg_dict.get("path_len", 0),
|
||||
)
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# Non-blocking command overrides (keep event loop responsive)
|
||||
# -----------------------------------------------------------------
|
||||
|
||||
async def _cmd_sync_next_message(self, data: bytes) -> None:
|
||||
"""Sync next message; run persistence read in thread so SQLite does not block."""
|
||||
msg = self.bridge.sync_next_message()
|
||||
if msg is None:
|
||||
msg = await asyncio.to_thread(self._sync_next_from_persistence)
|
||||
if msg is None:
|
||||
self._write_frame(bytes([RESP_CODE_NO_MORE_MESSAGES]))
|
||||
return
|
||||
if msg.is_channel:
|
||||
path_len_byte = msg.path_len if msg.path_len < 256 else 0xFF
|
||||
txt_type = 0
|
||||
text_bytes = (msg.text or "").rstrip("\x00").encode("utf-8", errors="replace")
|
||||
if self._app_target_ver >= 3:
|
||||
frame = (
|
||||
bytes(
|
||||
[
|
||||
RESP_CODE_CHANNEL_MSG_RECV_V3,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
msg.channel_idx,
|
||||
path_len_byte,
|
||||
txt_type,
|
||||
]
|
||||
)
|
||||
+ struct.pack("<I", msg.timestamp)
|
||||
+ text_bytes
|
||||
)
|
||||
else:
|
||||
frame = bytes(
|
||||
[
|
||||
RESP_CODE_CHANNEL_MSG_RECV,
|
||||
msg.channel_idx,
|
||||
path_len_byte,
|
||||
txt_type,
|
||||
]
|
||||
)
|
||||
frame += struct.pack("<I", msg.timestamp) + text_bytes
|
||||
else:
|
||||
prefix = (
|
||||
msg.sender_key[:6] if len(msg.sender_key) >= 6 else msg.sender_key.ljust(6, b"\x00")
|
||||
)
|
||||
path_len_byte = msg.path_len if msg.path_len < 256 else 0xFF
|
||||
text_bytes = msg.text.encode("utf-8", errors="replace")
|
||||
if self._app_target_ver >= 3:
|
||||
frame = (
|
||||
bytes([RESP_CODE_CONTACT_MSG_RECV_V3, 0, 0, 0])
|
||||
+ prefix
|
||||
+ bytes([path_len_byte, msg.txt_type])
|
||||
+ struct.pack("<I", msg.timestamp)
|
||||
+ text_bytes
|
||||
)
|
||||
else:
|
||||
frame = (
|
||||
bytes([RESP_CODE_CONTACT_MSG_RECV])
|
||||
+ prefix
|
||||
+ bytes([path_len_byte, msg.txt_type])
|
||||
)
|
||||
frame += struct.pack("<I", msg.timestamp) + text_bytes
|
||||
self._write_frame(frame)
|
||||
|
||||
@staticmethod
|
||||
def _contact_to_dict(c) -> dict:
|
||||
"""Convert a Contact object to a persistence dict."""
|
||||
|
||||
+1
-1
@@ -651,7 +651,7 @@ class RepeaterDaemon:
|
||||
|
||||
return stats
|
||||
|
||||
def _get_companion_stats(self, stats_type: int) -> dict:
|
||||
async def _get_companion_stats(self, stats_type: int) -> dict:
|
||||
"""Return stats dict for companion CMD_GET_STATS (format expected by frame_server + meshcore_py)."""
|
||||
from repeater.companion.constants import (
|
||||
STATS_TYPE_CORE,
|
||||
|
||||
Reference in New Issue
Block a user