109 lines
3.3 KiB
Python
109 lines
3.3 KiB
Python
"""
|
||
D6 多服务器注册中心 API
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
from typing import Any, Dict, List, Optional
|
||
|
||
from fastapi import APIRouter, HTTPException
|
||
from pydantic import BaseModel, Field
|
||
|
||
from services.registry_cluster import registry_cluster
|
||
|
||
router = APIRouter(prefix="/api/v3/registry", tags=["多服务器注册中心"])
|
||
|
||
|
||
class RegisterNodeBody(BaseModel):
|
||
node_id: str = Field(..., description="对端 SDK 唯一 ID")
|
||
base_url: str = Field(..., description="对端 HTTP Base,如 http://192.168.1.20:8899")
|
||
label: str = ""
|
||
token: Optional[str] = None
|
||
version: str = ""
|
||
|
||
|
||
class HeartbeatBody(BaseModel):
|
||
node_id: str
|
||
token: Optional[str] = None
|
||
device_count: int = 0
|
||
version: str = ""
|
||
|
||
|
||
@router.post("/nodes/register")
|
||
async def register_node(body: RegisterNodeBody) -> Dict[str, Any]:
|
||
try:
|
||
return {
|
||
"code": 200,
|
||
"data": await registry_cluster.register_peer(
|
||
body.node_id,
|
||
body.base_url,
|
||
body.label,
|
||
body.token,
|
||
body.version,
|
||
),
|
||
}
|
||
except PermissionError as e:
|
||
raise HTTPException(status_code=403, detail=str(e))
|
||
except Exception as e:
|
||
raise HTTPException(status_code=400, detail=str(e))
|
||
|
||
|
||
@router.post("/nodes/heartbeat")
|
||
async def node_heartbeat(body: HeartbeatBody) -> Dict[str, Any]:
|
||
try:
|
||
return {
|
||
"code": 200,
|
||
"data": await registry_cluster.heartbeat_peer(
|
||
body.node_id, body.token, body.device_count, body.version
|
||
),
|
||
}
|
||
except PermissionError as e:
|
||
raise HTTPException(status_code=403, detail=str(e))
|
||
except ValueError as e:
|
||
raise HTTPException(status_code=404, detail=str(e))
|
||
|
||
|
||
@router.get("/nodes")
|
||
async def list_nodes() -> Dict[str, Any]:
|
||
return {"code": 200, "data": {"nodes": registry_cluster.list_peers()}}
|
||
|
||
|
||
@router.delete("/nodes/{node_id}")
|
||
async def remove_node(node_id: str, token: Optional[str] = None) -> Dict[str, Any]:
|
||
try:
|
||
return {"code": 200, "data": await registry_cluster.unregister_peer(node_id, token)}
|
||
except PermissionError as e:
|
||
raise HTTPException(status_code=403, detail=str(e))
|
||
|
||
|
||
@router.get("/fleet/aggregate")
|
||
async def fleet_aggregate() -> Dict[str, Any]:
|
||
"""本机设备 + 已登记节点 + WORKPHONE_REGISTRY_PEERS 静态节点的合并视图。"""
|
||
data = await registry_cluster.aggregate_fleet()
|
||
return {"code": 200, "data": data}
|
||
|
||
|
||
@router.get("/info")
|
||
async def registry_info() -> Dict[str, Any]:
|
||
from services.registry_cluster import (
|
||
_local_public_base,
|
||
_local_server_id,
|
||
_registry_token_expected,
|
||
_static_peer_urls,
|
||
)
|
||
|
||
return {
|
||
"code": 200,
|
||
"data": {
|
||
"local_server_id": _local_server_id(),
|
||
"local_public_base_url": _local_public_base(),
|
||
"token_required": bool(_registry_token_expected()),
|
||
"static_peers_env": _static_peer_urls(),
|
||
"endpoints": {
|
||
"register": "POST /api/v3/registry/nodes/register",
|
||
"heartbeat": "POST /api/v3/registry/nodes/heartbeat",
|
||
"list": "GET /api/v3/registry/nodes",
|
||
"aggregate": "GET /api/v3/registry/fleet/aggregate",
|
||
},
|
||
},
|
||
}
|