Files
FishServer/fish_api/app/main.py
2026-05-13 09:19:31 +08:00

94 lines
3.3 KiB
Python
Raw Permalink 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.
from __future__ import annotations
import asyncio
from contextlib import asynccontextmanager
from typing import List
from fastapi import FastAPI
from loguru import logger
from app.logging_config import setup_logging
from app.media_static import MediaStaticFiles
from app.db import init_db
from app.routers import biomass, debug, ingest, zed
from app.services.action_watch import run_action_watch_loop
from app.services.measure_watch import run_measure_watch_loop
from app.services.sonar_video import run_sonar_video_watch_loop
from app.settings import get_settings
# 第一次:仅装 stderr sinklifespan 启动时再装文件 sink
setup_logging()
@asynccontextmanager
async def lifespan(app: FastAPI):
s = get_settings()
# 第二次lifespan 内部用 Settings 装 runtime/events 文件 sink。
setup_logging(s, force=True)
init_db(s)
s.media_root.mkdir(parents=True, exist_ok=True)
s.stream_tmp_dir.mkdir(parents=True, exist_ok=True)
logger.bind(pipeline="fish_api").info(
"[fish_api] 启动完成 | 公网基址={} | 日志目录={} | 文件级别={} | 保留={} 天 | rotation={}",
s.public_base_url,
s.log_dir,
(s.log_file_level or s.log_level).upper(),
s.log_retention_days,
s.log_rotation,
)
logger.bind(pipeline="fish_api").info(
"[fish_api] 后台监控配置 | action_watch={} | measure_watch={} | sonar_watch={}",
s.action_watch_dir or "(未启用)",
s.measure_watch_dir or "(未启用)",
s.biomass_sonar_video_dir or "(未启用)",
)
tasks = [] # type: List[asyncio.Task]
if s.action_watch_dir is not None:
tasks.append(asyncio.create_task(run_action_watch_loop(s)))
if s.measure_watch_dir is not None:
tasks.append(asyncio.create_task(run_measure_watch_loop(s)))
if s.biomass_sonar_video_dir is not None:
tasks.append(asyncio.create_task(run_sonar_video_watch_loop(s)))
yield
logger.bind(pipeline="fish_api").info("[fish_api] 收到关停信号,停止后台监控任务")
for t in tasks:
t.cancel()
for t in tasks:
try:
await t
except asyncio.CancelledError:
pass
logger.bind(pipeline="fish_api").info("[fish_api] 已优雅停止")
app = FastAPI(title="Fish API", lifespan=lifespan)
app.include_router(ingest.router)
app.include_router(biomass.router)
app.include_router(debug.router)
app.include_router(zed.router)
_settings = get_settings()
_settings.media_root.mkdir(parents=True, exist_ok=True)
app.mount(
"/media",
MediaStaticFiles(directory=str(_settings.media_root)),
name="media",
)
@app.get("/")
async def root():
return {
"service": "fish-api",
"docs": "/docs",
"ingest": "/api/v1/ingest/",
"biomass_camera": "/api/v1/biomass/real/camera/",
"biomass_health": "/api/v1/biomass/health/result/",
"biomass_water_video": "/api/v1/biomass/water/video/",
"biomass_sonar_video": "/api/v1/biomass/sonar/video/",
"debug_measure": "/api/v1/debug/meause",
"zed_recording": "/api/v1/zed/recording/start|stop|status",
"note": "若配置了 ACTION_WATCH_DIR / MEASURE_WATCH_DIR启动后会后台监控对应目录。ZED 分段录制由独立进程/脚本负责,不由 fish_api 启停;可选 HTTP /api/v1/zed/recording/start|stop|status。",
}