feat: 实现多主机架构的核心组件
新增路由器、主机客户端和共享协议模块,支持多主机部署模式: - 路由器作为中央节点管理主机连接和消息路由 - 主机客户端作为工作节点运行本地代理 - 共享协议定义通信消息格式 - 新增独立运行模式standalone.py - 更新配置系统支持路由模式
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
"""Shared module for Router <-> Host Client communication."""
|
||||
|
||||
from shared.protocol import (
|
||||
RegisterMessage,
|
||||
ForwardRequest,
|
||||
ForwardResponse,
|
||||
TaskComplete,
|
||||
Heartbeat,
|
||||
NodeStatus,
|
||||
encode,
|
||||
decode,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"RegisterMessage",
|
||||
"ForwardRequest",
|
||||
"ForwardResponse",
|
||||
"TaskComplete",
|
||||
"Heartbeat",
|
||||
"NodeStatus",
|
||||
"encode",
|
||||
"decode",
|
||||
]
|
||||
@@ -0,0 +1,94 @@
|
||||
"""Shared protocol module for Router <-> Host Client communication.
|
||||
|
||||
All message types are dataclasses that serialize to/from JSON.
|
||||
Both router and host client import from this module.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from dataclasses import asdict, dataclass, field
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
|
||||
@dataclass
|
||||
class RegisterMessage:
|
||||
"""Host client -> Router: Register this node."""
|
||||
type: str = "register"
|
||||
node_id: str = ""
|
||||
serves_users: List[str] = field(default_factory=list)
|
||||
working_dir: str = ""
|
||||
capabilities: List[str] = field(default_factory=list)
|
||||
display_name: str = ""
|
||||
|
||||
|
||||
@dataclass
|
||||
class ForwardRequest:
|
||||
"""Router -> Host client: Forward a user message."""
|
||||
type: str = "forward"
|
||||
id: str = ""
|
||||
user_id: str = ""
|
||||
chat_id: str = ""
|
||||
text: str = ""
|
||||
|
||||
|
||||
@dataclass
|
||||
class ForwardResponse:
|
||||
"""Host client -> Router: Reply to a forwarded message."""
|
||||
type: str = "forward_response"
|
||||
id: str = ""
|
||||
reply: str = ""
|
||||
error: str = ""
|
||||
|
||||
|
||||
@dataclass
|
||||
class TaskComplete:
|
||||
"""Host client -> Router: Background task finished."""
|
||||
type: str = "task_complete"
|
||||
task_id: str = ""
|
||||
user_id: str = ""
|
||||
chat_id: str = ""
|
||||
result: str = ""
|
||||
|
||||
|
||||
@dataclass
|
||||
class Heartbeat:
|
||||
"""Bidirectional ping/pong."""
|
||||
type: str = "ping"
|
||||
|
||||
|
||||
@dataclass
|
||||
class NodeStatus:
|
||||
"""Host client -> Router: Periodic status update."""
|
||||
type: str = "node_status"
|
||||
node_id: str = ""
|
||||
sessions: int = 0
|
||||
active_sessions: List[Dict[str, Any]] = field(default_factory=list)
|
||||
|
||||
|
||||
MESSAGE_TYPES = {
|
||||
"register": RegisterMessage,
|
||||
"forward": ForwardRequest,
|
||||
"forward_response": ForwardResponse,
|
||||
"task_complete": TaskComplete,
|
||||
"ping": Heartbeat,
|
||||
"pong": Heartbeat,
|
||||
"node_status": NodeStatus,
|
||||
}
|
||||
|
||||
|
||||
def encode(msg: Any) -> str:
|
||||
"""Encode a message to JSON string."""
|
||||
if hasattr(msg, "type"):
|
||||
return json.dumps(asdict(msg), ensure_ascii=False)
|
||||
raise ValueError(f"Invalid message type: {type(msg)}")
|
||||
|
||||
|
||||
def decode(data: str) -> Any:
|
||||
"""Decode a JSON string to a message object."""
|
||||
obj = json.loads(data)
|
||||
msg_type = obj.get("type")
|
||||
if msg_type not in MESSAGE_TYPES:
|
||||
raise ValueError(f"Unknown message type: {msg_type}")
|
||||
cls = MESSAGE_TYPES[msg_type]
|
||||
return cls(**{k: v for k, v in obj.items() if k in cls.__dataclass_fields__})
|
||||
Reference in New Issue
Block a user