refactor: S06.2 backend router auto-discovery via ROUTER_CONFIGS manifest (replaces 18 explicit imports)

This commit is contained in:
Gan, Jimmy
2026-07-11 01:33:19 +08:00
parent eece551ea9
commit a85bbd2411
2 changed files with 54 additions and 68 deletions
+30 -68
View File
@@ -21,25 +21,6 @@ import auth_service as auth_module
import config
from config import CORS_ORIGINS, TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID, VOLUME_ROOT, get_client_ip
from rbac import require_page
from routers import auth as auth_router
from routers import (
chat_summary,
conversation_tracker,
files,
gitea,
litellm,
opc_agents,
opc_projects,
opc_tasks,
opc_ws,
passkey,
security,
system,
terminal,
totp,
transmission,
)
_tz_cst = timezone(timedelta(hours=8))
@@ -271,57 +252,38 @@ async def _inject_user(request: Request, user=Depends(auth_module.get_current_us
return user
# Public auth endpoints
app.include_router(auth_router.router, prefix="/api/auth", tags=["auth"])
app.include_router(passkey.router, prefix="/api/auth", tags=["passkey"])
app.include_router(totp.router, prefix="/api/auth", tags=["totp"])
# Auto-discovered router registration (from ROUTER_CONFIGS manifest)
from routers import ROUTER_CONFIGS, WS_ROUTES
import importlib
import re
# Protected endpoints with page-level RBAC
app.include_router(
gitea.router, prefix="/api/gitea", dependencies=[Depends(_inject_user), Depends(require_page("gitea"))]
)
app.include_router(
files.router, prefix="/api/files", dependencies=[Depends(_inject_user)]
)
# Public file download endpoint (no auth required for token-based downloads)
app.include_router(files.public_router, prefix="/api/files")
app.include_router(
system.router, prefix="/api/system", dependencies=[Depends(_inject_user), Depends(require_page("dashboard"))]
)
app.include_router(
litellm.router, prefix="/api/litellm", dependencies=[Depends(_inject_user), Depends(require_page("dashboard"))]
)
app.include_router(
chat_summary.router,
prefix="/api/chat-summary",
dependencies=[Depends(_inject_user), Depends(require_page("chat-digest"))],
)
app.include_router(
conversation_tracker.router,
prefix="/api/conversations",
dependencies=[Depends(_inject_user), Depends(require_page("conversations"))],
)
app.include_router(
security.router, prefix="/api/security", dependencies=[Depends(_inject_user), Depends(require_page("security"))]
)
app.include_router(
transmission.router, dependencies=[Depends(_inject_user), Depends(require_page("transmission"))]
)
for cfg in ROUTER_CONFIGS:
mod = importlib.import_module('routers.' + cfg['module'])
router_attr = cfg.get('router_attr', 'router')
router_obj = getattr(mod, router_attr)
prefix = cfg.get('prefix')
tags = cfg.get('tags')
deps = cfg.get('deps', [])
dep_objects = []
for d in deps:
if d == '_inject_user':
dep_objects.append(Depends(_inject_user))
elif d.startswith('require_page('):
# Extract page name from require_page('gitea') or require_page(gitea)
m = re.search(r'require_page\(["\'](.*?)["\']\)', d)
page_name = m.group(1) if m else d.split('(')[1].rstrip(')')
dep_objects.append(Depends(require_page(page_name)))
kwargs = {'dependencies': dep_objects} if dep_objects else {}
if prefix is not None:
kwargs['prefix'] = prefix
if tags:
kwargs['tags'] = tags
app.include_router(router_obj, **kwargs)
# OPC endpoints
app.include_router(
opc_tasks.router, prefix="/api/opc", dependencies=[Depends(_inject_user), Depends(require_page("opc"))]
)
app.include_router(
opc_agents.router, prefix="/api/opc", dependencies=[Depends(_inject_user), Depends(require_page("opc"))]
)
app.include_router(
opc_projects.router, prefix="/api/opc", dependencies=[Depends(_inject_user), Depends(require_page("opc"))]
)
# WebSocket endpoint (auth handled inside handler via auth cookie; query token fallback temporary)
app.add_api_websocket_route("/ws/terminal", terminal.ws_endpoint)
app.add_api_websocket_route("/ws/opc", opc_ws.websocket_endpoint)
for ws in WS_ROUTES:
mod = importlib.import_module('routers.' + ws['module'])
handler = getattr(mod, ws['handler'])
app.add_api_websocket_route(ws['path'], handler)
# Mount static files (skip if directory doesn't exist, e.g., in test environments)
import os
+24
View File
@@ -0,0 +1,24 @@
"""Router auto-discovery manifest.
Each entry defines how a router module gets registered.
"""
ROUTER_CONFIGS = [
{"module": "auth", "prefix": "/api/auth", "tags": ["auth"]},
{"module": "passkey", "prefix": "/api/auth", "tags": ["passkey"]},
{"module": "totp", "prefix": "/api/auth", "tags": ["totp"]},
{"module": "gitea", "prefix": "/api/gitea", "deps": ["_inject_user", "require_page(\"gitea\")"]},
{"module": "files", "prefix": "/api/files", "deps": ["_inject_user"]},
{"module": "files", "router_attr": "public_router", "prefix": "/api/files"},
{"module": "system", "prefix": "/api/system", "deps": ["_inject_user", "require_page(\"dashboard\")"]},
{"module": "litellm", "prefix": "/api/litellm", "deps": ["_inject_user", "require_page(\"dashboard\")"]},
{"module": "chat_summary", "prefix": "/api/chat-summary", "deps": ["_inject_user", "require_page(\"chat-digest\")"]},
{"module": "conversation_tracker", "prefix": "/api/conversations", "deps": ["_inject_user", "require_page(\"conversations\")"]},
{"module": "security", "prefix": "/api/security", "deps": ["_inject_user", "require_page(\"security\")"]},
{"module": "transmission", "prefix": None, "deps": ["_inject_user", "require_page(\"transmission\")"]},
{"module": "opc_tasks", "prefix": "/api/opc", "deps": ["_inject_user", "require_page(\"opc\")"]},
{"module": "opc_agents", "prefix": "/api/opc", "deps": ["_inject_user", "require_page(\"opc\")"]},
{"module": "opc_projects", "prefix": "/api/opc", "deps": ["_inject_user", "require_page(\"opc\")"]},
]
WS_ROUTES = [
{"module": "terminal", "path": "/ws/terminal", "handler": "ws_endpoint"},
{"module": "opc_ws", "path": "/ws/opc", "handler": "websocket_endpoint"},
]