checking system…
Docs / back / src/maf/dashboard/routers/watch.py · line 58
Python · 85 lines
 1"""Watch list endpoints.
 2
 3The watch list is the single source of truth for "what targets are
 4interesting right now". Anything expensive (Kronos forecasts, MiroFish
 5crowd-sims) keys off this set, so cold targets cost nothing.
 6"""
 7
 8from __future__ import annotations
 9
10from typing import Any
11
12from fastapi import APIRouter
13from pydantic import BaseModel
14
15from maf.dashboard import state
16
17router = APIRouter()
18
19
20class WatchAddRequest(BaseModel):
21    target_id: str
22    kind: str = "symbol"
23    ttl_seconds: int = 6 * 3600
24    attrs: dict[str, Any] = {}
25
26
27def _redis_url() -> str | None:
28    """Lazy resolution — only need it on actual watchlist operations."""
29    app = state.get_maf_app()
30    return app.config.redis_url if app else None
31
32
33@router.get("/api/watch")
34async def list_watch(kind: str | None = None) -> dict[str, Any]:
35    """Return current watch-list entries; filter by kind if given."""
36    from maf.watch.list import WatchList
37
38    wl = WatchList(redis_url=_redis_url())
39    try:
40        members = await wl.members(kind=kind)
41        return {
42            "members": [
43                {
44                    "target_id": m.target_id,
45                    "kind": m.kind,
46                    "expires_at": m.expires_at,
47                    "remaining_seconds": round(m.remaining_seconds, 1),
48                    "attrs": m.attrs,
49                }
50                for m in members
51            ],
52        }
53    finally:
54        await wl.aclose()
55
56
57@router.post("/api/watch")
58async def add_watch(req: WatchAddRequest) -> dict[str, Any]:
59    from maf.watch.list import WatchList
60
61    wl = WatchList(redis_url=_redis_url())
62    try:
63        e = await wl.add(
64            req.target_id, kind=req.kind,
65            ttl_seconds=req.ttl_seconds, attrs=req.attrs,
66        )
67        return {
68            "ok": True, "target_id": e.target_id,
69            "kind": e.kind, "expires_at": e.expires_at,
70        }
71    finally:
72        await wl.aclose()
73
74
75@router.delete("/api/watch/{target_id}")
76async def remove_watch(target_id: str, kind: str | None = None) -> dict[str, Any]:
77    from maf.watch.list import WatchList
78
79    wl = WatchList(redis_url=_redis_url())
80    try:
81        removed = await wl.remove(target_id, kind=kind)
82        return {"ok": True, "removed": removed}
83    finally:
84        await wl.aclose()