完善直播节点监控与边缘代理
This commit is contained in:
1 parent
058bb4b99f
commit
20cd99efa4
19 files changed
+401
-47
No files matched your search
+25
-3
@@ -5,14 +5,16 @@ from config import settings
|
||||
from routes.auth import require_auth
|
||||
from services.load_balancer import lb
|
||||
from services.multicast_detector import multicast_detector
|
||||
from services.node_store import save_nodes
|
||||
|
||||
router = APIRouter(prefix="/api/nodes", tags=["nodes"])
|
||||
|
||||
|
||||
class NodeUpdate(BaseModel):
|
||||
weight: int
|
||||
weight: int | None = None
|
||||
enabled: bool | None = None
|
||||
subnet: str | None = None
|
||||
name: str | None = None
|
||||
|
||||
|
||||
class StrategyUpdate(BaseModel):
|
||||
@@ -27,6 +29,12 @@ class NodeHeartbeat(BaseModel):
|
||||
bandwidth_mbps: float | None = None
|
||||
active_connections: int | None = None
|
||||
hls_readers: int | None = None
|
||||
network_in_mbps: float | None = None
|
||||
network_out_mbps: float | None = None
|
||||
viewer_count: int | None = None
|
||||
frame_drop_indicators: int | None = None
|
||||
packet_loss_indicators: int | None = None
|
||||
media_metrics_available: bool = False
|
||||
|
||||
|
||||
class NodeRegister(BaseModel):
|
||||
@@ -83,15 +91,22 @@ async def update_node(node_id: str, body: NodeUpdate, _: bool = Depends(require_
|
||||
found = False
|
||||
for n in settings.edge_nodes:
|
||||
if n["id"] == node_id:
|
||||
n["weight"] = body.weight
|
||||
if body.weight is not None:
|
||||
n["weight"] = body.weight
|
||||
if body.enabled is not None:
|
||||
n["enabled"] = body.enabled
|
||||
if body.subnet is not None:
|
||||
n["subnet"] = body.subnet
|
||||
if body.name is not None:
|
||||
name = body.name.strip()
|
||||
if not name:
|
||||
raise HTTPException(status_code=422, detail="Node name cannot be empty")
|
||||
n["name"] = name
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
raise HTTPException(status_code=404, detail="Node not found")
|
||||
save_nodes()
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
@@ -100,13 +115,13 @@ async def register_node(body: NodeRegister):
|
||||
for n in settings.edge_nodes:
|
||||
if n["id"] == body.node_id:
|
||||
n.update({
|
||||
"name": body.name,
|
||||
"host": body.host,
|
||||
"hls_port": body.hls_port,
|
||||
"api_port": body.api_port,
|
||||
"weight": body.weight,
|
||||
"subnet": body.subnet,
|
||||
})
|
||||
save_nodes()
|
||||
return {"ok": True, "action": "updated"}
|
||||
settings.edge_nodes.append({
|
||||
"id": body.node_id,
|
||||
@@ -119,6 +134,7 @@ async def register_node(body: NodeRegister):
|
||||
"subnet": body.subnet,
|
||||
"is_origin": False,
|
||||
})
|
||||
save_nodes()
|
||||
return {"ok": True, "action": "registered"}
|
||||
|
||||
|
||||
@@ -130,6 +146,12 @@ async def node_heartbeat(body: NodeHeartbeat):
|
||||
"bandwidth_mbps": body.bandwidth_mbps,
|
||||
"active_connections": body.active_connections,
|
||||
"hls_readers": body.hls_readers,
|
||||
"network_in_mbps": body.network_in_mbps,
|
||||
"network_out_mbps": body.network_out_mbps,
|
||||
"viewer_count": body.viewer_count,
|
||||
"frame_drop_indicators": body.frame_drop_indicators,
|
||||
"packet_loss_indicators": body.packet_loss_indicators,
|
||||
"media_metrics_available": body.media_metrics_available,
|
||||
})
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
@@ -62,14 +62,23 @@ async def list_streams(db: AsyncSession = Depends(get_db)):
|
||||
|
||||
@router.post("")
|
||||
async def create_stream(body: StreamCreate, db: AsyncSession = Depends(get_db),
|
||||
_: bool = Depends(require_auth)):
|
||||
_: bool = Depends(require_auth)):
|
||||
title = body.title.strip()
|
||||
if not title:
|
||||
raise HTTPException(status_code=422, detail="直播标题不能为空")
|
||||
svc = StreamService(db)
|
||||
stream = await svc.create_stream(
|
||||
title=body.title,
|
||||
description=body.description,
|
||||
cover_url=body.cover_url,
|
||||
scheduled_at=body.scheduled_at,
|
||||
)
|
||||
try:
|
||||
stream = await svc.create_stream(
|
||||
title=title,
|
||||
description=body.description,
|
||||
cover_url=body.cover_url,
|
||||
scheduled_at=body.scheduled_at,
|
||||
)
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=422, detail=str(exc)) from exc
|
||||
except Exception as exc:
|
||||
await db.rollback()
|
||||
raise HTTPException(status_code=500, detail="创建直播失败,请检查日期格式和数据库状态") from exc
|
||||
rtmp_url = media_service.get_rtmp_url(stream.stream_key)
|
||||
return {
|
||||
"id": stream.id,
|
||||
@@ -179,6 +188,7 @@ async def get_stream_by_key(stream_key: str, request: Request, db: AsyncSession
|
||||
"title": s.title,
|
||||
"status": s.status.value,
|
||||
"multicast_available": urls["multicast_available"],
|
||||
"selected_node": urls.get("selected_node"),
|
||||
"lines": urls["lines"],
|
||||
"qualities": urls["qualities"],
|
||||
}
|
||||
Reference in new issue
Block a user