""" Weibo-HotSign Sign-in Executor Service Core service that executes sign-in tasks and handles Weibo interactions """ from fastapi import FastAPI, BackgroundTasks, HTTPException, status, Depends, Request from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse import uvicorn import asyncio import httpx import logging from datetime import datetime from typing import Dict, Any, Optional import os from app.config import settings from app.services.signin_service import SignInService from app.services.weibo_client import WeiboClient from app.models.signin_models import SignInRequest, SignInResult, TaskStatus # Initialize FastAPI app app = FastAPI( title="Weibo-HotSign Sign-in Executor", description="Core service for executing Weibo super topic sign-in tasks", version="1.0.0", docs_url="/docs", redoc_url="/redoc" ) # CORS middleware app.add_middleware( CORSMiddleware, allow_origins=["*"], # In production, specify actual origins allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Initialize services signin_service = SignInService() weibo_client = WeiboClient() @app.on_event("startup") async def startup_event(): """Initialize executor service on startup""" print("🚀 Weibo-HotSign Sign-in Executor starting up...") print(f"📡 Service Documentation: http://{settings.HOST}:{settings.PORT}/docs") print("🔧 Ready to process sign-in tasks...") @app.on_event("shutdown") async def shutdown_event(): """Cleanup on shutdown""" print("👋 Weibo-HotSign Sign-in Executor shutting down...") @app.get("/") async def root(): return { "service": "Weibo-HotSign Sign-in Executor", "status": "running", "version": "1.0.0", "description": "Core sign-in execution service for Weibo super topics", "capabilities": [ "Weibo login and verification", "Super topic sign-in automation", "Anti-bot protection handling", "Proxy integration", "Browser fingerprint simulation" ] } @app.get("/health") async def health_check(): """Health check endpoint""" return { "status": "healthy", "service": "signin-executor", "timestamp": datetime.now().isoformat(), "dependencies": { "database": "connected", "redis": "connected", "proxy_pool": f"{settings.PROXY_POOL_URL}", "browser_automation": f"{settings.BROWSER_AUTOMATION_URL}" } } @app.post("/api/v1/signin/execute", response_model=SignInResult) async def execute_signin_task( signin_request: SignInRequest, background_tasks: BackgroundTasks ): """ Execute sign-in task for specified account This endpoint is called by the task scheduler """ try: logger.info(f"🎯 Received sign-in request for account: {signin_request.account_id}") # Execute sign-in in background to avoid timeout background_tasks.add_task( signin_service.execute_signin_task, signin_request.account_id, signin_request.task_id ) # Return immediate response return SignInResult( task_id=signin_request.task_id, account_id=signin_request.account_id, status="accepted", message="Sign-in task accepted and queued for execution", started_at=datetime.now(), estimated_completion=None ) except Exception as e: logger.error(f"❌ Failed to accept sign-in task: {e}") raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Failed to accept sign-in task: {str(e)}" ) @app.get("/api/v1/signin/status/{task_id}", response_model=TaskStatus) async def get_task_status(task_id: str): """Get status of a sign-in task""" try: status_info = await signin_service.get_task_status(task_id) if not status_info: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Task {task_id} not found" ) return status_info except HTTPException: raise except Exception as e: logger.error(f"❌ Error getting task status: {e}") raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Internal server error" ) @app.post("/api/v1/signin/test") async def test_signin_capability(): """Test sign-in service capabilities (for debugging)""" try: # Test basic service connectivity tests = { "weibo_connectivity": await _test_weibo_connectivity(), "proxy_pool_access": await _test_proxy_pool(), "browser_automation": await _test_browser_automation(), "database_connection": await _test_database_connection() } return { "test_timestamp": datetime.now().isoformat(), "tests": tests, "overall_status": "operational" if all(tests.values()) else "degraded" } except Exception as e: logger.error(f"❌ Capability test failed: {e}") raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Capability test failed: {str(e)}" ) async def _test_weibo_connectivity() -> bool: """Test connectivity to Weibo""" try: async with httpx.AsyncClient(timeout=10.0) as client: response = await client.get("https://weibo.com", follow_redirects=True) return response.status_code == 200 except: return False async def _test_proxy_pool() -> bool: """Test proxy pool service availability""" try: async with httpx.AsyncClient(timeout=5.0) as client: response = await client.get(f"{settings.PROXY_POOL_URL}/health", timeout=5.0) return response.status_code == 200 except: return False async def _test_browser_automation() -> bool: """Test browser automation service availability""" try: async with httpx.AsyncClient(timeout=5.0) as client: response = await client.get(f"{settings.BROWSER_AUTOMATION_URL}/health", timeout=5.0) return response.status_code == 200 except: return False async def _test_database_connection() -> bool: """Test database connectivity""" try: # Simple database ping test return True # Simplified for demo except: return False @app.exception_handler(HTTPException) async def http_exception_handler(request: Request, exc: HTTPException): """Global HTTP exception handler""" return JSONResponse( status_code=exc.status_code, content={ "success": False, "data": None, "message": exc.detail, "error": { "code": f"HTTP_{exc.status_code}", "details": [] } } ) if __name__ == "__main__": host = os.getenv("HOST", settings.HOST) port = int(os.getenv("PORT", settings.PORT)) uvicorn.run( app, host=host, port=port, log_level="info" if not settings.DEBUG else "debug" )