8adad30ff2
- 新增 device 表 + /api/v1/device/{register,heartbeat} + 迁移 device_table
- heartbeat_monitor_worker 周期扫描心跳超时(App 被杀/无障碍停)→ 服务器终端打印告警
(推送本期未接,先用 logger 终端打印代替真实通知;integrations/jpush.py 已备,后续直接替换)
- config / .env.example 增 JPUSH_* / HEARTBEAT_*
- 见 spec(仓库外 e:\codes\spec\accessibility-liveness-push.md)
注:本提交同时快照了并行 session 未提交的 coupon_state 改动 + 相关 migration
(与本功能同迁移链耦合,无法单独拆分,经确认一并提交)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
67 lines
1.9 KiB
Python
67 lines
1.9 KiB
Python
"""设备注册 / 心跳 endpoint(无障碍保护存活检测)。
|
|
|
|
路由前缀 /api/v1/device,需 Bearer 鉴权(设备绑登录用户)。
|
|
POST /register 注册设备 / 更新 registration_id(App 前台、拿到 push token 时调)
|
|
POST /heartbeat 上报心跳(无障碍服务存活时周期调,刷新存活)
|
|
|
|
后端 heartbeat_monitor_worker 据此发现心跳超时的设备并极光推送告警。
|
|
见 spec: spec/accessibility-liveness-push.md。
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
|
|
from fastapi import APIRouter
|
|
|
|
from app.api.deps import CurrentUser, DbSession
|
|
from app.repositories import device as device_repo
|
|
from app.schemas.device import (
|
|
DeviceOut,
|
|
DeviceRegisterRequest,
|
|
HeartbeatRequest,
|
|
OkResponse,
|
|
)
|
|
|
|
logger = logging.getLogger("shagua.device")
|
|
|
|
router = APIRouter(prefix="/api/v1/device", tags=["device"])
|
|
|
|
|
|
@router.post("/register", response_model=DeviceOut, summary="注册设备/更新推送token")
|
|
def register_device(
|
|
req: DeviceRegisterRequest,
|
|
user: CurrentUser,
|
|
db: DbSession,
|
|
) -> DeviceOut:
|
|
device = device_repo.register_or_update(
|
|
db,
|
|
user_id=user.id,
|
|
device_id=req.device_id,
|
|
registration_id=req.registration_id,
|
|
platform=req.platform,
|
|
app_version=req.app_version,
|
|
)
|
|
logger.info(
|
|
"device register user_id=%d device_id=%s reg=%s",
|
|
user.id,
|
|
req.device_id,
|
|
bool(req.registration_id),
|
|
)
|
|
return DeviceOut.model_validate(device)
|
|
|
|
|
|
@router.post("/heartbeat", response_model=OkResponse, summary="上报心跳")
|
|
def report_heartbeat(
|
|
req: HeartbeatRequest,
|
|
user: CurrentUser,
|
|
db: DbSession,
|
|
) -> OkResponse:
|
|
device_repo.touch_heartbeat(
|
|
db,
|
|
user_id=user.id,
|
|
device_id=req.device_id,
|
|
accessibility_enabled=req.accessibility_enabled,
|
|
registration_id=req.registration_id,
|
|
)
|
|
return OkResponse()
|