PhoneWork/standalone.py
Yuyao Huang (Sam) 64297e5e27 feat: 实现多主机架构的核心组件
新增路由器、主机客户端和共享协议模块,支持多主机部署模式:
- 路由器作为中央节点管理主机连接和消息路由
- 主机客户端作为工作节点运行本地代理
- 共享协议定义通信消息格式
- 新增独立运行模式standalone.py
- 更新配置系统支持路由模式
2026-03-28 14:08:47 +08:00

73 lines
1.7 KiB
Python

"""Run router + host client in a single process (localhost mode).
Equivalent to the pre-M3 single-machine setup.
Users run `python standalone.py` and get the exact same experience as `python main.py`,
but the code paths use the multi-host architecture internally.
"""
from __future__ import annotations
import asyncio
import logging
import secrets
import sys
import uvicorn
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
)
logger = logging.getLogger(__name__)
async def run_standalone() -> None:
"""Run router + host client in a single process."""
secret = secrets.token_hex(16)
router_url = "ws://127.0.0.1:8000/ws/node"
from router.main import create_app
from host_client.main import NodeClient
from host_client.config import HostConfig
config = HostConfig.from_keyring()
config.router_url = router_url
config.router_secret = secret
app = create_app(router_secret=secret)
config_obj = uvicorn.Config(
app,
host="0.0.0.0",
port=8000,
log_level="info",
)
server = uvicorn.Server(config_obj)
async def run_server():
await server.serve()
async def run_client():
await asyncio.sleep(1.5)
client = NodeClient(config)
try:
await client.run()
except Exception as e:
logger.exception("Host client error: %s", e)
server.should_exit = True
await asyncio.gather(run_server(), run_client())
def main() -> None:
"""Entry point."""
logger.info("Starting PhoneWork in standalone mode...")
try:
asyncio.run(run_standalone())
except KeyboardInterrupt:
logger.info("Shutting down...")
if __name__ == "__main__":
main()