diff --git a/digital-avatar-app/backend/routers/takeover.py b/digital-avatar-app/backend/routers/takeover.py index 5f0728e..d8f0b1d 100644 --- a/digital-avatar-app/backend/routers/takeover.py +++ b/digital-avatar-app/backend/routers/takeover.py @@ -12,6 +12,7 @@ from routers.authorizations import _require_authorization from routers.avatars import _require_owned_avatar router = APIRouter(tags=["分身接管"]) +BOXIM_STATUS_FRESH_SECONDS = 60 @router.get("/avatar/{avatar_id}/takeover/status") @@ -44,7 +45,9 @@ def get_takeover_status( cursor and cursor.initialized and cursor.last_polled_at - and cursor.last_polled_at >= datetime.utcnow() - timedelta(seconds=15) + # BOXIM offline-message reads can long-poll for about 20 seconds. + and cursor.last_polled_at + >= datetime.utcnow() - timedelta(seconds=BOXIM_STATUS_FRESH_SECONDS) ): status, message = "ready", "BOXIM 已连接,收到私聊消息 3 秒后自动回复" else: diff --git a/digital-avatar-app/backend/tests/test_takeover_api.py b/digital-avatar-app/backend/tests/test_takeover_api.py index 9d93033..2215e41 100644 --- a/digital-avatar-app/backend/tests/test_takeover_api.py +++ b/digital-avatar-app/backend/tests/test_takeover_api.py @@ -1,6 +1,6 @@ """Tests for takeover configuration and BOXIM connection status.""" -from datetime import datetime +from datetime import datetime, timedelta from fastapi.testclient import TestClient @@ -192,6 +192,28 @@ def test_takeover_status_reports_ready_pending_count_and_errors(authorization_co assert ready["pendingCount"] == 1 assert ready["lastPolledAt"] + db = SessionLocal() + try: + cursor = db.query(TakeoverCursor).filter(TakeoverCursor.avatar_id == avatar_id).one() + cursor.last_polled_at = datetime.utcnow() - timedelta(seconds=30) + db.commit() + finally: + db.close() + + long_polling = client.get(endpoint, headers=context["owner_headers"]).json()["data"] + assert long_polling["status"] == "ready" + + db = SessionLocal() + try: + cursor = db.query(TakeoverCursor).filter(TakeoverCursor.avatar_id == avatar_id).one() + cursor.last_polled_at = datetime.utcnow() - timedelta(seconds=61) + db.commit() + finally: + db.close() + + stale = client.get(endpoint, headers=context["owner_headers"]).json()["data"] + assert stale["status"] == "connecting" + db = SessionLocal() try: cursor = db.query(TakeoverCursor).filter(TakeoverCursor.avatar_id == avatar_id).one()