tg-bot/backend/app/api/routes.py
2025-12-04 09:52:39 +08:00

180 lines
6.1 KiB
Python

import json
from fastapi import APIRouter, Depends, HTTPException, Query
from starlette.responses import StreamingResponse
from ..schemas.auth import User
from ..schemas.config import (
CredentialCreate,
CredentialRecord,
CredentialUpdate,
CredentialsList,
EntriesPayload,
)
from ..schemas.scanner import ScannerStatus
from ..services.config_repo import ConfigRepository
from ..services.match_store import MatchStore
from ..services.scanner_manager import ScannerManager
def get_router(
repo: ConfigRepository,
match_store: MatchStore,
scanner_manager: ScannerManager,
require_user,
token_verifier,
) -> APIRouter:
router = APIRouter()
def get_repo() -> ConfigRepository:
return repo
def get_match_store() -> MatchStore:
return match_store
def get_scanner() -> ScannerManager:
return scanner_manager
@router.get("/credentials", response_model=CredentialsList)
def list_credentials(
repository: ConfigRepository = Depends(get_repo),
current_user: User = Depends(require_user),
):
return CredentialsList(items=repository.list_credentials())
@router.get("/credentials/active", response_model=CredentialRecord)
def get_active_credentials(
repository: ConfigRepository = Depends(get_repo),
current_user: User = Depends(require_user),
):
data = repository.get_active_credentials()
if not data:
raise HTTPException(status_code=404, detail="Credentials not configured.")
return data
@router.post("/credentials", response_model=CredentialRecord)
def create_credentials(
payload: CredentialCreate,
repository: ConfigRepository = Depends(get_repo),
current_user: User = Depends(require_user),
):
return repository.create_credentials(payload)
@router.put("/credentials/{credential_id}", response_model=CredentialRecord)
def update_credentials(
credential_id: str,
payload: CredentialUpdate,
repository: ConfigRepository = Depends(get_repo),
current_user: User = Depends(require_user),
):
try:
return repository.update_credentials(credential_id, payload)
except ValueError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
@router.delete("/credentials/{credential_id}")
def delete_credentials(
credential_id: str,
repository: ConfigRepository = Depends(get_repo),
current_user: User = Depends(require_user),
):
try:
repository.delete_credentials(credential_id)
except ValueError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
return {"deleted": True}
@router.post("/credentials/{credential_id}/activate", response_model=CredentialRecord)
def activate_credentials(
credential_id: str,
repository: ConfigRepository = Depends(get_repo),
current_user: User = Depends(require_user),
):
try:
return repository.activate_credentials(credential_id)
except ValueError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
@router.get("/keywords", response_model=EntriesPayload)
def get_keywords(
repository: ConfigRepository = Depends(get_repo),
current_user: User = Depends(require_user),
):
return EntriesPayload(items=repository.read_keywords())
@router.put("/keywords", response_model=EntriesPayload)
def put_keywords(
payload: EntriesPayload,
repository: ConfigRepository = Depends(get_repo),
current_user: User = Depends(require_user),
):
return EntriesPayload(items=repository.write_keywords(payload.items))
@router.get("/channels", response_model=EntriesPayload)
def get_channels(
repository: ConfigRepository = Depends(get_repo),
current_user: User = Depends(require_user),
):
return EntriesPayload(items=repository.read_channels())
@router.put("/channels", response_model=EntriesPayload)
def put_channels(
payload: EntriesPayload,
repository: ConfigRepository = Depends(get_repo),
current_user: User = Depends(require_user),
):
return EntriesPayload(items=repository.write_channels(payload.items))
@router.post("/scanner/start", response_model=ScannerStatus)
async def start_scanner(
scanner: ScannerManager = Depends(get_scanner),
current_user: User = Depends(require_user),
):
await scanner.start()
return await scanner.status()
@router.post("/scanner/stop", response_model=ScannerStatus)
async def stop_scanner(
scanner: ScannerManager = Depends(get_scanner),
current_user: User = Depends(require_user),
):
await scanner.stop()
return await scanner.status()
@router.get("/scanner/status", response_model=ScannerStatus)
async def get_status(
scanner: ScannerManager = Depends(get_scanner),
current_user: User = Depends(require_user),
):
return await scanner.status()
@router.get("/matches")
async def get_matches(
limit: int = Query(50, ge=1, le=200),
store: MatchStore = Depends(get_match_store),
current_user: User = Depends(require_user),
):
return await store.get_recent(limit)
@router.get("/matches/stream")
async def stream_matches(
store: MatchStore = Depends(get_match_store),
token: str | None = Query(default=None),
):
if not token:
raise HTTPException(status_code=401, detail="Missing token")
token_verifier(token)
queue = await store.subscribe()
async def event_generator():
try:
while True:
item = await queue.get()
data = json.dumps(item.model_dump(), default=str)
yield f"data: {data}\n\n"
finally:
await store.unsubscribe(queue)
return StreamingResponse(event_generator(), media_type="text/event-stream")
return router