Files
server-core/dispatcher.py
T
Pine 985b85cb4e feat(oss): 统一OSS/CDN对象存储与直链出口体系
- infrastructure/oss.py 重写:服务端上传/预签名上下行/CDN鉴权直链(方式A)/resolve_url·to_object_path 出入口规范
- config.py 新增 OSS_REGION/OSS_CDN_BASE_URL/OSS_CDN_AUTH_KEY
- media_upload 统一走 oss 单例,返回 CDN 直链;dispatcher /oss 前缀路由
- 管理端用户列表头像出口 CDN 化
2026-08-28 17:17:38 +08:00

76 lines
2.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""server-core 统一入口(dispatcher)—— 对外生产服务 opc.pinesound.cn 单入口。
按「端口专属前缀」把请求分流到对应子应用,每端口自带前缀子路由、互不冲突:
/park/* → 园区子应用(app.park,大屏/MQTT/园区数据)
/api/*、/uploads/*、/SpXvScDiDT.txt → 培训子应用(app.training,独立 data/opc.db
/auth /opc /admin /government /investor …→ 平台应用(app.main,身份 + 业务域,各端口子路由)
启动(server-core 目录):
uv run uvicorn dispatcher:app --host 0.0.0.0 --port 8090 --reload
"""
from __future__ import annotations
import logging
from app.main import app as core_app
from app.park.app import app as park_app
from app.training.main import app as training_app
logger = logging.getLogger(__name__)
ROUTE_TRAINING_PREFIXES = ("/api", "/uploads", "/oss", "/SpXvScDiDT.txt")
ROUTE_PARK_PREFIX = "/park"
def _prefix_app(path: str):
"""按路径前缀匹配目标子应用;未命中返回 None 交由平台应用(app.main)。"""
if path.startswith(ROUTE_PARK_PREFIX):
return park_app
if path.startswith(ROUTE_TRAINING_PREFIXES):
return training_app
return None
class Dispatcher:
"""极简 ASGI 分发器:驱动子应用 lifespan(核心库初始化)+ 按路径路由。"""
def __init__(self, apps: list):
self._apps = apps
async def _run_lifespan(self, receive, send):
"""依次进入各子应用 lifespan(核心应用负责建表/种子),按启动/停止消息配对退出。"""
started: list = []
try:
while True:
message = await receive()
if message["type"] == "lifespan.startup":
for a in self._apps:
cm = a.router.lifespan_context(app=a)
await cm.__aenter__()
started.append(cm)
await send({"type": "lifespan.startup.complete"})
elif message["type"] == "lifespan.shutdown":
for cm in reversed(started):
await cm.__aexit__(None, None, None)
started = []
await send({"type": "lifespan.shutdown.complete"})
return
except BaseException:
for cm in reversed(started):
try:
await cm.__aexit__(None, None, None)
except Exception: # noqa: BLE001
pass
raise
async def __call__(self, scope, receive, send):
if scope["type"] == "lifespan":
await self._run_lifespan(receive, send)
return
path = scope.get("path", "")
target = _prefix_app(path) or core_app
await target(scope, receive, send)
app = Dispatcher([core_app, training_app, park_app])