feat: 把 A 端的 Session/KCP/视频/控制 都收口到一个本地 daemon 进程里,Django 和输入发送端都改成通过本机 UDS HTTP 去访问它,同时补齐了观测、性能和可用性上的几个关键问题。
This commit is contained in:
1
backend/control/__init__.py
Normal file
1
backend/control/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
default_app_config = "control.apps.ControlConfig"
|
||||
6
backend/control/apps.py
Normal file
6
backend/control/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ControlConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "control"
|
||||
51
backend/control/services.py
Normal file
51
backend/control/services.py
Normal file
@@ -0,0 +1,51 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
||||
WORKSPACE_ROOT = PROJECT_ROOT.parent
|
||||
|
||||
|
||||
def _load_client_api():
|
||||
try:
|
||||
from omnisocket_a_side.client import OmniDaemonClient, OmniDaemonError
|
||||
except ImportError:
|
||||
python_dir = WORKSPACE_ROOT / "OmniSocketGo" / "python"
|
||||
if python_dir.exists():
|
||||
sys.path.insert(0, str(python_dir))
|
||||
from omnisocket_a_side.client import OmniDaemonClient, OmniDaemonError
|
||||
return OmniDaemonClient, OmniDaemonError
|
||||
|
||||
|
||||
_OmniDaemonClient, OmniDaemonError = _load_client_api()
|
||||
_daemon_client = _OmniDaemonClient()
|
||||
|
||||
|
||||
def get_daemon_client():
|
||||
return _daemon_client
|
||||
|
||||
|
||||
class ControlProxyService:
|
||||
def get_status(self) -> dict[str, Any]:
|
||||
return get_daemon_client().get_control_status()
|
||||
|
||||
def send_event(
|
||||
self,
|
||||
*,
|
||||
event_code: str,
|
||||
drive_value: float = 1.0,
|
||||
source: str = "django-api",
|
||||
client_time_ms: int | None = None,
|
||||
) -> dict[str, Any]:
|
||||
return get_daemon_client().send_control_event(
|
||||
source=source,
|
||||
event_code=event_code,
|
||||
drive_value=drive_value,
|
||||
client_time_ms=client_time_ms,
|
||||
)
|
||||
|
||||
|
||||
control_service = ControlProxyService()
|
||||
9
backend/control/urls.py
Normal file
9
backend/control/urls.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from django.urls import path
|
||||
|
||||
from . import views
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path("event/", views.control_event, name="control-event"),
|
||||
path("status/", views.control_status, name="control-status"),
|
||||
]
|
||||
59
backend/control/views.py
Normal file
59
backend/control/views.py
Normal file
@@ -0,0 +1,59 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from rest_framework.decorators import api_view
|
||||
from rest_framework.response import Response
|
||||
|
||||
from .services import OmniDaemonError, control_service
|
||||
|
||||
|
||||
@api_view(["GET"])
|
||||
def control_status(request):
|
||||
try:
|
||||
return Response(control_service.get_status())
|
||||
except OmniDaemonError as error:
|
||||
return Response(
|
||||
{
|
||||
"connected": False,
|
||||
"queue_depth": 0,
|
||||
"last_seq_id": None,
|
||||
"last_error": str(error),
|
||||
"peer_id": "",
|
||||
"target_peer": "",
|
||||
},
|
||||
status=503,
|
||||
)
|
||||
|
||||
|
||||
@api_view(["POST"])
|
||||
def control_event(request):
|
||||
event_code = str(request.data.get("event_code", "")).strip()
|
||||
if not event_code:
|
||||
return Response({"error": "event_code is required"}, status=400)
|
||||
|
||||
try:
|
||||
drive_value = float(request.data.get("drive_value", 1.0))
|
||||
except (TypeError, ValueError):
|
||||
return Response({"error": "drive_value must be numeric"}, status=400)
|
||||
|
||||
raw_client_time_ms = request.data.get("client_time_ms")
|
||||
if raw_client_time_ms in (None, ""):
|
||||
client_time_ms = None
|
||||
else:
|
||||
try:
|
||||
client_time_ms = int(raw_client_time_ms)
|
||||
except (TypeError, ValueError):
|
||||
return Response({"error": "client_time_ms must be an integer"}, status=400)
|
||||
|
||||
source = str(request.data.get("source", "django-api")).strip() or "django-api"
|
||||
|
||||
try:
|
||||
payload = control_service.send_event(
|
||||
event_code=event_code,
|
||||
drive_value=drive_value,
|
||||
source=source,
|
||||
client_time_ms=client_time_ms,
|
||||
)
|
||||
except OmniDaemonError as error:
|
||||
return Response({"error": str(error)}, status=503)
|
||||
|
||||
return Response(payload, status=200 if payload.get("accepted") else 503)
|
||||
Reference in New Issue
Block a user