123
This commit is contained in:
226
backend/signin_executor/app/main.py
Normal file
226
backend/signin_executor/app/main.py
Normal file
@@ -0,0 +1,226 @@
|
||||
"""
|
||||
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"
|
||||
)
|
||||
Reference in New Issue
Block a user