Files
mai-bot/src/plugin_runtime/transport/uds.py
DrSmoothl 69219e36f7 Refactor protocol and transport modules to use type hints for improved clarity and consistency
- Updated Codec class to use abstract methods for encoding and decoding envelopes.
- Changed Envelope class to use Dict and Optional for payload and error fields.
- Refined error handling in RPCError class with Optional type hints for details.
- Enhanced manifest validation logic with type hints for better type safety.
- Improved plugin loading mechanism with consistent type annotations.
- Updated RPCClient to utilize Optional for codec and connection attributes.
- Refactored transport classes to use Optional for server attributes and socket paths.
2026-03-11 00:07:13 +08:00

74 lines
2.2 KiB
Python

"""Unix Domain Socket 传输实现
适用于 Linux / macOS 平台。
"""
from pathlib import Path
from typing import Optional
import asyncio
import os
import tempfile
from .base import Connection, ConnectionHandler, TransportClient, TransportServer
class UDSConnection(Connection):
"""基于 UDS 的连接"""
pass # 直接复用 Connection 基类的分帧读写
class UDSTransportServer(TransportServer):
"""UDS 传输服务端"""
def __init__(self, socket_path: Optional[str] = None):
if socket_path is None:
# 默认放在临时目录,使用 uuid 确保同一进程多实例不碰撞
import uuid
socket_path = os.path.join(tempfile.gettempdir(), f"maibot-plugin-{os.getpid()}-{uuid.uuid4().hex[:8]}.sock")
self._socket_path = socket_path
self._server: Optional[asyncio.AbstractServer] = None
async def start(self, handler: ConnectionHandler) -> None:
# 清理残留 socket 文件
if os.path.exists(self._socket_path):
os.unlink(self._socket_path)
# 确保父目录存在
Path(self._socket_path).parent.mkdir(parents=True, exist_ok=True)
async def _on_connect(reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
conn = UDSConnection(reader, writer)
try:
await handler(conn)
finally:
await conn.close()
self._server = await asyncio.start_unix_server(_on_connect, path=self._socket_path)
# 设置文件权限为仅当前用户可访问
os.chmod(self._socket_path, 0o600)
async def stop(self) -> None:
if self._server:
self._server.close()
await self._server.wait_closed()
self._server = None
# 清理 socket 文件
if os.path.exists(self._socket_path):
os.unlink(self._socket_path)
def get_address(self) -> str:
return self._socket_path
class UDSTransportClient(TransportClient):
"""UDS 传输客户端"""
def __init__(self, socket_path: str):
self._socket_path = socket_path
async def connect(self) -> Connection:
reader, writer = await asyncio.open_unix_connection(self._socket_path)
return UDSConnection(reader, writer)