251 lines
8.2 KiB
Python
251 lines
8.2 KiB
Python
from typing import List, Optional
|
|
|
|
from fastapi import APIRouter, Depends, File, HTTPException, Query, Request, UploadFile
|
|
|
|
from app.dependencies.auth import require_edge_auth
|
|
from app.schemas.edge import (
|
|
EdgeCommandRequest,
|
|
EdgeLogsResponse,
|
|
EdgeNativePreflightRequest,
|
|
EdgeNativePreflightResponse,
|
|
EdgeNodeHeartbeatResponse,
|
|
EdgeMonitorPacketsResponse,
|
|
EdgeMarkdownWriteRequest,
|
|
EdgeMonitorEnsureResponse,
|
|
EdgeNodeResourcesResponse,
|
|
EdgeNodeSelfResponse,
|
|
EdgeStateResponse,
|
|
EdgeStateWriteRequest,
|
|
EdgeStatusResponse,
|
|
EdgeWorkspaceSyncRequest,
|
|
)
|
|
from app.schemas.runtime import EdgeStartBotRequest
|
|
from app.services import provision_service as provision_service_module
|
|
from app.services import state_store_service as state_store_service_module
|
|
from app.services.runtime_service import edge_runtime_service
|
|
from app.services import workspace_service as workspace_service_module
|
|
|
|
router = APIRouter(dependencies=[Depends(require_edge_auth)])
|
|
|
|
|
|
@router.get("/api/edge/node/self", response_model=EdgeNodeSelfResponse)
|
|
def get_edge_node_self():
|
|
return edge_runtime_service.get_node_identity()
|
|
|
|
|
|
@router.get("/api/edge/node/resources", response_model=EdgeNodeResourcesResponse)
|
|
def get_edge_node_resources():
|
|
return edge_runtime_service.get_node_resource_summary()
|
|
|
|
|
|
@router.post("/api/edge/node/heartbeat", response_model=EdgeNodeHeartbeatResponse)
|
|
def heartbeat_edge_node():
|
|
return edge_runtime_service.heartbeat()
|
|
|
|
|
|
@router.post("/api/edge/runtime/native/preflight", response_model=EdgeNativePreflightResponse)
|
|
def native_preflight(payload: EdgeNativePreflightRequest):
|
|
return edge_runtime_service.native_preflight(
|
|
native_command=str(payload.native_command or "").strip() or None,
|
|
native_workdir=str(payload.native_workdir or "").strip() or None,
|
|
)
|
|
|
|
|
|
@router.post("/api/edge/bots/{bot_id}/start", response_model=EdgeStatusResponse)
|
|
async def start_bot(bot_id: str, payload: EdgeStartBotRequest):
|
|
return await edge_runtime_service.start_bot(bot_id=bot_id, payload=payload)
|
|
|
|
|
|
@router.post("/api/edge/bots/{bot_id}/stop", response_model=EdgeStatusResponse)
|
|
def stop_bot(bot_id: str):
|
|
return edge_runtime_service.stop_bot(bot_id=bot_id)
|
|
|
|
|
|
@router.post("/api/edge/bots/{bot_id}/command", response_model=EdgeStatusResponse)
|
|
def send_command(bot_id: str, payload: EdgeCommandRequest):
|
|
return edge_runtime_service.send_command(bot_id=bot_id, payload=payload)
|
|
|
|
|
|
@router.post("/api/edge/bots/{bot_id}/monitor/ensure", response_model=EdgeMonitorEnsureResponse)
|
|
def ensure_monitor(bot_id: str):
|
|
return edge_runtime_service.ensure_monitor(bot_id=bot_id)
|
|
|
|
|
|
@router.get("/api/edge/bots/{bot_id}/monitor/packets", response_model=EdgeMonitorPacketsResponse)
|
|
def get_monitor_packets(bot_id: str, after_seq: int = 0, limit: int = 200):
|
|
return edge_runtime_service.get_monitor_packets(bot_id=bot_id, after_seq=after_seq, limit=limit)
|
|
|
|
|
|
@router.get("/api/edge/bots/{bot_id}/logs", response_model=EdgeLogsResponse)
|
|
def get_logs(bot_id: str, tail: int = Query(300, ge=1, le=2000)):
|
|
return edge_runtime_service.get_recent_logs(bot_id=bot_id, tail=tail)
|
|
|
|
|
|
@router.get("/api/edge/bots/{bot_id}/runtime/status", response_model=EdgeStatusResponse)
|
|
def get_runtime_status(bot_id: str):
|
|
return edge_runtime_service.get_runtime_status(bot_id=bot_id)
|
|
|
|
|
|
@router.get("/api/edge/bots/{bot_id}/resources")
|
|
def get_resource_snapshot(bot_id: str):
|
|
return edge_runtime_service.get_resource_snapshot(bot_id=bot_id)
|
|
|
|
|
|
@router.post("/api/edge/bots/{bot_id}/workspace/sync", response_model=EdgeStatusResponse)
|
|
def sync_workspace(bot_id: str, payload: EdgeWorkspaceSyncRequest):
|
|
return provision_service_module.edge_provision_service.sync_bot_workspace(bot_id=bot_id, payload=payload)
|
|
|
|
|
|
@router.get("/api/edge/bots/{bot_id}/state/{state_key}", response_model=EdgeStateResponse)
|
|
def read_bot_state(bot_id: str, state_key: str, workspace_root: str | None = None):
|
|
return state_store_service_module.edge_state_store_service.read_state(
|
|
bot_id=bot_id,
|
|
state_key=state_key,
|
|
workspace_root=workspace_root,
|
|
)
|
|
|
|
|
|
@router.put("/api/edge/bots/{bot_id}/state/{state_key}", response_model=EdgeStateResponse)
|
|
def write_bot_state(bot_id: str, state_key: str, payload: EdgeStateWriteRequest):
|
|
return state_store_service_module.edge_state_store_service.write_state(
|
|
bot_id=bot_id,
|
|
state_key=state_key,
|
|
data=dict(payload.data or {}),
|
|
workspace_root=str(payload.workspace_root or "").strip() or None,
|
|
)
|
|
|
|
|
|
@router.get("/api/edge/bots/{bot_id}/workspace/tree")
|
|
def list_workspace_tree(
|
|
bot_id: str,
|
|
path: str | None = None,
|
|
recursive: bool = False,
|
|
workspace_root: str | None = None,
|
|
):
|
|
return workspace_service_module.edge_workspace_service.list_tree(
|
|
bot_id=bot_id,
|
|
path=path,
|
|
recursive=recursive,
|
|
workspace_root=workspace_root,
|
|
)
|
|
|
|
|
|
@router.get("/api/edge/bots/{bot_id}/workspace/file")
|
|
def read_workspace_file(
|
|
bot_id: str,
|
|
path: str = Query(...),
|
|
max_bytes: int = Query(200000, ge=4096, le=1000000),
|
|
workspace_root: str | None = None,
|
|
):
|
|
return workspace_service_module.edge_workspace_service.read_file(
|
|
bot_id=bot_id,
|
|
path=path,
|
|
max_bytes=max_bytes,
|
|
workspace_root=workspace_root,
|
|
)
|
|
|
|
|
|
@router.put("/api/edge/bots/{bot_id}/workspace/file/markdown")
|
|
def write_workspace_markdown(
|
|
bot_id: str,
|
|
path: str = Query(...),
|
|
payload: EdgeMarkdownWriteRequest = None,
|
|
workspace_root: str | None = None,
|
|
):
|
|
if payload is None:
|
|
raise HTTPException(status_code=400, detail="markdown payload is required")
|
|
return workspace_service_module.edge_workspace_service.write_markdown(
|
|
bot_id=bot_id,
|
|
path=path,
|
|
content=payload.content,
|
|
workspace_root=workspace_root,
|
|
)
|
|
|
|
|
|
@router.put("/api/edge/bots/{bot_id}/workspace/file/text")
|
|
def write_workspace_text(
|
|
bot_id: str,
|
|
path: str = Query(...),
|
|
payload: EdgeMarkdownWriteRequest = None,
|
|
workspace_root: str | None = None,
|
|
):
|
|
if payload is None:
|
|
raise HTTPException(status_code=400, detail="text payload is required")
|
|
return workspace_service_module.edge_workspace_service.write_text_file(
|
|
bot_id=bot_id,
|
|
path=path,
|
|
content=payload.content,
|
|
workspace_root=workspace_root,
|
|
)
|
|
|
|
|
|
@router.post("/api/edge/bots/{bot_id}/workspace/upload")
|
|
async def upload_workspace_files(
|
|
bot_id: str,
|
|
files: List[UploadFile] = File(...),
|
|
path: Optional[str] = None,
|
|
workspace_root: str | None = None,
|
|
):
|
|
return await workspace_service_module.edge_workspace_service.upload_files(
|
|
bot_id=bot_id,
|
|
files=files,
|
|
path=path,
|
|
workspace_root=workspace_root,
|
|
)
|
|
|
|
|
|
@router.delete("/api/edge/bots/{bot_id}/workspace/file")
|
|
def delete_workspace_path(
|
|
bot_id: str,
|
|
path: str = Query(...),
|
|
workspace_root: str | None = None,
|
|
):
|
|
return workspace_service_module.edge_workspace_service.delete_path(
|
|
bot_id=bot_id,
|
|
path=path,
|
|
workspace_root=workspace_root,
|
|
)
|
|
|
|
|
|
@router.get("/api/edge/bots/{bot_id}/workspace/download")
|
|
def download_workspace_file(
|
|
bot_id: str,
|
|
path: str = Query(...),
|
|
download: bool = False,
|
|
request: Request = None,
|
|
workspace_root: str | None = None,
|
|
):
|
|
return workspace_service_module.edge_workspace_service.serve_file(
|
|
bot_id=bot_id,
|
|
path=path,
|
|
download=download,
|
|
request=request,
|
|
workspace_root=workspace_root,
|
|
)
|
|
|
|
|
|
@router.get("/api/edge/bots/{bot_id}/workspace/raw/{path:path}")
|
|
def raw_workspace_file(
|
|
bot_id: str,
|
|
path: str,
|
|
download: bool = False,
|
|
request: Request = None,
|
|
workspace_root: str | None = None,
|
|
):
|
|
return workspace_service_module.edge_workspace_service.serve_file(
|
|
bot_id=bot_id,
|
|
path=path,
|
|
download=download,
|
|
request=request,
|
|
workspace_root=workspace_root,
|
|
)
|
|
|
|
|
|
@router.post("/api/edge/bots/{bot_id}/workspace/purge", response_model=EdgeStatusResponse)
|
|
def purge_workspace(bot_id: str, workspace_root: str | None = None):
|
|
result = workspace_service_module.edge_workspace_service.purge_bot_workspace(
|
|
bot_id=bot_id,
|
|
workspace_root=workspace_root,
|
|
)
|
|
return EdgeStatusResponse(status="deleted" if bool(result.get("deleted")) else "not_found")
|