This commit is contained in:
2026-03-09 14:05:00 +08:00
commit 754e720ba7
105 changed files with 5890 additions and 0 deletions

View File

@@ -0,0 +1,56 @@
"""
Configuration for Sign-in Executor Service
"""
import os
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
"""Sign-in Executor settings"""
# Server settings
HOST: str = os.getenv("HOST", "0.0.0.0")
PORT: int = int(os.getenv("PORT", 8000))
DEBUG: bool = os.getenv("DEBUG", "False").lower() == "true"
# Database settings
DATABASE_URL: str = os.getenv(
"DATABASE_URL",
"mysql+aiomysql://weibo:123456789@118.195.133.163/weibo"
)
REDIS_URL: str = os.getenv("REDIS_URL", "redis://redis:6379")
# External service URLs
PROXY_POOL_URL: str = os.getenv("PROXY_POOL_URL", "http://proxy-pool:8080")
BROWSER_AUTOMATION_URL: str = os.getenv("BROWSER_AUTOMATION_URL", "http://browser-automation:3001")
TASK_SCHEDULER_URL: str = os.getenv("TASK_SCHEDULER_URL", "http://task-scheduler:8000")
# Weibo API settings
WEIBO_LOGIN_URL: str = "https://weibo.com/login.php"
WEIBO_SUPER_TOPIC_URL: str = "https://weibo.com/p/aj/general/button"
# Anti-bot protection settings
RANDOM_DELAY_MIN: float = float(os.getenv("RANDOM_DELAY_MIN", "1.0"))
RANDOM_DELAY_MAX: float = float(os.getenv("RANDOM_DELAY_MAX", "3.0"))
USER_AGENT_ROTATION: bool = os.getenv("USER_AGENT_ROTATION", "True").lower() == "true"
# Cookie and session settings
COOKIE_ENCRYPTION_KEY: str = os.getenv("COOKIE_ENCRYPTION_KEY", "your-cookie-encryption-key")
SESSION_TIMEOUT_MINUTES: int = int(os.getenv("SESSION_TIMEOUT_MINUTES", "30"))
# Browser automation settings
BROWSER_HEADLESS: bool = os.getenv("BROWSER_HEADLESS", "True").lower() == "true"
BROWSER_TIMEOUT_SECONDS: int = int(os.getenv("BROWSER_TIMEOUT_SECONDS", "30"))
# Task execution settings
MAX_CONCURRENT_SIGNIN: int = int(os.getenv("MAX_CONCURRENT_SIGNIN", "5"))
TASK_TIMEOUT_SECONDS: int = int(os.getenv("TASK_TIMEOUT_SECONDS", "300"))
# Logging
LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO")
class Config:
case_sensitive = True
env_file = ".env"
settings = Settings()

View 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"
)

View File

@@ -0,0 +1,89 @@
"""
Data models for Sign-in Executor Service
"""
from pydantic import BaseModel, Field
from typing import Optional, Dict, Any, List
from datetime import datetime
from uuid import UUID
class SignInRequest(BaseModel):
"""Request model for sign-in task execution"""
task_id: str = Field(..., description="Unique task identifier")
account_id: str = Field(..., description="Weibo account identifier")
timestamp: Optional[datetime] = Field(default_factory=datetime.now, description="Request timestamp")
requested_by: Optional[str] = Field(default="task_scheduler", description="Request source")
class SignInResult(BaseModel):
"""Result model for sign-in task execution"""
task_id: str = Field(..., description="Task identifier")
account_id: str = Field(..., description="Account identifier")
status: str = Field(..., description="Task status: accepted, running, success, failed")
message: str = Field(..., description="Human readable result message")
started_at: datetime = Field(..., description="Task start timestamp")
completed_at: Optional[datetime] = Field(None, description="Task completion timestamp")
estimated_completion: Optional[datetime] = Field(None, description="Estimated completion time")
reward_info: Optional[Dict[str, Any]] = Field(None, description="Reward details like exp, credits")
error_message: Optional[str] = Field(None, description="Error details if failed")
signed_topics: Optional[List[str]] = Field(None, description="List of successfully signed topics")
total_topics: Optional[int] = Field(None, description="Total number of topics attempted")
class TaskStatus(BaseModel):
"""Status model for tracking sign-in task progress"""
task_id: str = Field(..., description="Task identifier")
account_id: str = Field(..., description="Account identifier")
status: str = Field(..., description="Current status: pending, running, success, failed")
progress_percentage: int = Field(default=0, ge=0, le=100, description="Progress percentage")
current_step: Optional[str] = Field(None, description="Current execution step")
steps_completed: List[str] = Field(default_factory=list, description="Completed steps")
steps_remaining: List[str] = Field(default_factory=list, description="Remaining steps")
started_at: datetime = Field(..., description="Start timestamp")
updated_at: datetime = Field(default_factory=datetime.now, description="Last update timestamp")
estimated_completion: Optional[datetime] = Field(None, description="Estimated completion")
class WeiboAccount(BaseModel):
"""Weibo account information for sign-in"""
id: UUID = Field(..., description="Account UUID")
user_id: UUID = Field(..., description="Owner user UUID")
weibo_user_id: str = Field(..., description="Weibo user ID")
remark: Optional[str] = Field(None, description="User remark")
encrypted_cookies: str = Field(..., description="Encrypted Weibo cookies")
iv: str = Field(..., description="Encryption initialization vector")
status: str = Field(default="active", description="Account status: active, invalid_cookie, banned")
last_checked_at: Optional[datetime] = Field(None, description="Last validation timestamp")
class SignInLog(BaseModel):
"""Sign-in operation log entry"""
id: Optional[int] = Field(None, description="Log entry ID")
account_id: UUID = Field(..., description="Account UUID")
topic_title: Optional[str] = Field(None, description="Signed topic title")
status: str = Field(..., description="Sign-in status")
reward_info: Optional[Dict[str, Any]] = Field(None, description="Reward information")
error_message: Optional[str] = Field(None, description="Error details")
signed_at: datetime = Field(default_factory=datetime.now, description="Sign-in timestamp")
execution_time_ms: Optional[int] = Field(None, description="Execution time in milliseconds")
class WeiboSuperTopic(BaseModel):
"""Weibo super topic information"""
id: str = Field(..., description="Topic ID")
title: str = Field(..., description="Topic title")
url: str = Field(..., description="Topic URL")
is_signed: bool = Field(default=False, description="Whether already signed")
sign_url: Optional[str] = Field(None, description="Sign-in API URL")
reward_exp: Optional[int] = Field(None, description="Experience points reward")
reward_credit: Optional[int] = Field(None, description="Credit points reward")
class AntiBotConfig(BaseModel):
"""Anti-bot protection configuration"""
random_delay_min: float = Field(default=1.0, description="Minimum random delay seconds")
random_delay_max: float = Field(default=3.0, description="Maximum random delay seconds")
user_agent_rotation: bool = Field(default=True, description="Enable user agent rotation")
proxy_enabled: bool = Field(default=True, description="Enable proxy usage")
fingerprint_simulation: bool = Field(default=True, description="Enable browser fingerprint simulation")
class BrowserAutomationRequest(BaseModel):
"""Request for browser automation service"""
target_url: str = Field(..., description="Target URL to automate")
action_type: str = Field(..., description="Action type: signin, extract, click")
context_data: Optional[Dict[str, Any]] = Field(None, description="Additional context data")
timeout_seconds: int = Field(default=30, description="Operation timeout")

View File

@@ -0,0 +1,271 @@
"""
Core sign-in business logic service
Handles Weibo super topic sign-in operations
"""
import asyncio
import httpx
import logging
import random
from datetime import datetime, timedelta
from typing import Dict, Any, List, Optional
from uuid import UUID
from app.config import settings
from app.models.signin_models import SignInRequest, SignInResult, TaskStatus, WeiboAccount, WeiboSuperTopic, AntiBotConfig
from app.services.weibo_client import WeiboClient
logger = logging.getLogger(__name__)
class SignInService:
"""Main service for handling sign-in operations"""
def __init__(self):
self.weibo_client = WeiboClient()
self.active_tasks: Dict[str, TaskStatus] = {}
self.antibot_config = AntiBotConfig(
random_delay_min=settings.RANDOM_DELAY_MIN,
random_delay_max=settings.RANDOM_DELAY_MAX,
user_agent_rotation=settings.USER_AGENT_ROTATION,
proxy_enabled=True,
fingerprint_simulation=True
)
async def execute_signin_task(self, account_id: str, task_id: str):
"""
Execute complete sign-in workflow for an account
This is the main business logic method
"""
logger.info(f"🎯 Starting sign-in execution for account {account_id}, task {task_id}")
# Initialize task status
task_status = TaskStatus(
task_id=task_id,
account_id=account_id,
status="running",
progress_percentage=0,
current_step="initializing",
steps_completed=[],
steps_remaining=[
"validate_account",
"setup_session",
"get_super_topics",
"execute_signin",
"record_results"
],
started_at=datetime.now()
)
self.active_tasks[task_id] = task_status
try:
# Step 1: Validate account
task_status.current_step = "validate_account"
await self._update_task_progress(task_id, 10)
account = await self._get_account_info(account_id)
if not account or account.status != "active":
raise Exception(f"Account {account_id} not found or inactive")
task_status.steps_completed.append("validate_account")
task_status.steps_remaining.remove("validate_account")
task_status.progress_percentage = 20
# Step 2: Setup session with proxy and fingerprint
task_status.current_step = "setup_session"
await self._apply_anti_bot_protection()
task_status.steps_completed.append("setup_session")
task_status.steps_remaining.remove("setup_session")
task_status.progress_percentage = 30
# Step 3: Get super topics list
task_status.current_step = "get_super_topics"
await self._update_task_progress(task_id, 40)
super_topics = await self._get_super_topics_list(account)
if not super_topics:
logger.warning(f"No super topics found for account {account_id}")
task_status.steps_completed.append("get_super_topics")
task_status.steps_remaining.remove("get_super_topics")
task_status.progress_percentage = 50
# Step 4: Execute signin for each topic
task_status.current_step = "execute_signin"
signin_results = await self._execute_topic_signin(account, super_topics, task_id)
task_status.steps_completed.append("execute_signin")
task_status.steps_remaining.remove("execute_signin")
task_status.progress_percentage = 80
# Step 5: Record results
task_status.current_step = "record_results"
await self._update_task_progress(task_id, 90)
result = SignInResult(
task_id=task_id,
account_id=account_id,
status="success",
message=f"Successfully processed {len(signin_results['signed'])} topics",
started_at=task_status.started_at,
completed_at=datetime.now(),
signed_topics=signin_results['signed'],
total_topics=len(super_topics) if super_topics else 0,
reward_info={
"topics_signed": len(signin_results['signed']),
"topics_already_signed": len(signin_results['already_signed']),
"errors": len(signin_results['errors'])
}
)
task_status.status = "success"
task_status.progress_percentage = 100
task_status.current_step = "completed"
logger.info(f"✅ Sign-in task {task_id} completed successfully")
return result
except Exception as e:
logger.error(f"❌ Sign-in task {task_id} failed: {e}")
# Update task status to failed
if task_id in self.active_tasks:
task_status = self.active_tasks[task_id]
task_status.status = "failed"
task_status.error_message = str(e)
# Return failed result
return SignInResult(
task_id=task_id,
account_id=account_id,
status="failed",
message=f"Sign-in failed: {str(e)}",
started_at=task_status.started_at if task_id in self.active_tasks else datetime.now(),
completed_at=datetime.now(),
error_message=str(e)
)
async def get_task_status(self, task_id: str) -> Optional[TaskStatus]:
"""Get current status of a sign-in task"""
return self.active_tasks.get(task_id)
async def _update_task_progress(self, task_id: str, percentage: int):
"""Update task progress percentage"""
if task_id in self.active_tasks:
self.active_tasks[task_id].progress_percentage = percentage
self.active_tasks[task_id].updated_at = datetime.now()
async def _get_account_info(self, account_id: str) -> Optional[WeiboAccount]:
"""Get Weibo account information from database"""
try:
# Mock implementation - in real system, query database
# For demo, return mock account
return WeiboAccount(
id=UUID(account_id),
user_id=UUID("12345678-1234-5678-9012-123456789012"),
weibo_user_id="1234567890",
remark="Demo Account",
encrypted_cookies="mock_encrypted_cookies",
iv="mock_iv_16_bytes",
status="active",
last_checked_at=datetime.now() - timedelta(hours=1)
)
except Exception as e:
logger.error(f"Error fetching account {account_id}: {e}")
return None
async def _apply_anti_bot_protection(self):
"""Apply anti-bot protection measures"""
# Random delay to mimic human behavior
delay = random.uniform(
self.antibot_config.random_delay_min,
self.antibot_config.random_delay_max
)
logger.debug(f"Applying random delay: {delay:.2f}s")
await asyncio.sleep(delay)
# Additional anti-bot measures would go here:
# - User agent rotation
# - Proxy selection
# - Browser fingerprint simulation
# - Request header randomization
async def _get_super_topics_list(self, account: WeiboAccount) -> List[WeiboSuperTopic]:
"""Get list of super topics for account"""
try:
# Mock implementation - in real system, fetch from Weibo API
# Simulate API call delay
await asyncio.sleep(1)
# Return mock super topics
return [
WeiboSuperTopic(
id="topic_001",
title="Python编程",
url="https://weibo.com/p/100808xxx",
is_signed=False,
sign_url="https://weibo.com/p/aj/general/button",
reward_exp=2,
reward_credit=1
),
WeiboSuperTopic(
id="topic_002",
title="人工智能",
url="https://weibo.com/p/100808yyy",
is_signed=False,
sign_url="https://weibo.com/p/aj/general/button",
reward_exp=2,
reward_credit=1
),
WeiboSuperTopic(
id="topic_003",
title="机器学习",
url="https://weibo.com/p/100808zzz",
is_signed=True, # Already signed
sign_url="https://weibo.com/p/aj/general/button",
reward_exp=2,
reward_credit=1
)
]
except Exception as e:
logger.error(f"Error fetching super topics: {e}")
return []
async def _execute_topic_signin(self, account: WeiboAccount, topics: List[WeiboSuperTopic], task_id: str) -> Dict[str, List[str]]:
"""Execute sign-in for each super topic"""
signed = []
already_signed = []
errors = []
for topic in topics:
try:
# Add small delay between requests
await asyncio.sleep(random.uniform(0.5, 1.5))
if topic.is_signed:
already_signed.append(topic.title)
continue
# Execute signin for this topic
success = await self.weibo_client.sign_super_topic(
account=account,
topic=topic,
task_id=task_id
)
if success:
signed.append(topic.title)
logger.info(f"✅ Successfully signed topic: {topic.title}")
else:
errors.append(f"Failed to sign topic: {topic.title}")
except Exception as e:
error_msg = f"Error signing topic {topic.title}: {str(e)}"
logger.error(error_msg)
errors.append(error_msg)
return {
"signed": signed,
"already_signed": already_signed,
"errors": errors
}

View File

@@ -0,0 +1,167 @@
"""
Weibo API Client
Handles all interactions with Weibo.com, including login, sign-in, and data fetching
"""
import httpx
import asyncio
import logging
import random
from typing import Dict, Any, Optional, List
from app.config import settings
from app.models.signin_models import WeiboAccount, WeiboSuperTopic
logger = logging.getLogger(__name__)
class WeiboClient:
"""Client for interacting with Weibo API"""
def __init__(self):
self.base_headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
"Accept": "application/json, text/plain, */*",
"Accept-Language": "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7",
"Connection": "keep-alive",
"Referer": "https://weibo.com/"
}
async def verify_cookies(self, account: WeiboAccount) -> bool:
"""Verify if Weibo cookies are still valid"""
try:
# Decrypt cookies
cookies = self._decrypt_cookies(account.encrypted_cookies, account.iv)
async with httpx.AsyncClient(cookies=cookies, headers=self.base_headers) as client:
response = await client.get("https://weibo.com/mygroups", follow_redirects=True)
if response.status_code == 200 and "我的首页" in response.text:
logger.info(f"Cookies for account {account.weibo_user_id} are valid")
return True
else:
logger.warning(f"Cookies for account {account.weibo_user_id} are invalid")
return False
except Exception as e:
logger.error(f"Error verifying cookies: {e}")
return False
async def get_super_topics(self, account: WeiboAccount) -> List[WeiboSuperTopic]:
"""Get list of super topics for an account"""
try:
# Mock implementation - in real system, this would involve complex API calls
# Simulate API call delay
await asyncio.sleep(random.uniform(1.0, 2.0))
# Return mock data
return [
WeiboSuperTopic(id="topic_001", title="Python编程", url="...", is_signed=False),
WeiboSuperTopic(id="topic_002", title="人工智能", url="...", is_signed=False),
WeiboSuperTopic(id="topic_003", title="机器学习", url="...", is_signed=True)
]
except Exception as e:
logger.error(f"Error fetching super topics: {e}")
return []
async def sign_super_topic(self, account: WeiboAccount, topic: WeiboSuperTopic, task_id: str) -> bool:
"""
Execute sign-in for a single super topic
"""
try:
# Decrypt cookies
cookies = self._decrypt_cookies(account.encrypted_cookies, account.iv)
# Prepare request payload
payload = {
"ajwvr": "6",
"api": "http://i.huati.weibo.com/aj/super/checkin",
"id": topic.id,
"location": "page_100808_super_index",
"refer_flag": "100808_-_1",
"refer_lflag": "100808_-_1",
"ua": self.base_headers["User-Agent"],
"is_new": "1",
"is_from_ad": "0",
"ext": "mi_898_1_0_0"
}
# In a real scenario, we might need to call browser automation service
# to get signed parameters or handle JS challenges
# Simulate API call
await asyncio.sleep(random.uniform(0.5, 1.5))
# Mock response - assume success
response_data = {
"code": "100000",
"msg": "签到成功",
"data": {
"tip": "签到成功",
"alert_title": "签到成功",
"alert_subtitle": "恭喜你成为今天第12345位签到的人",
"reward": {"exp": 2, "credit": 1}
}
}
if response_data.get("code") == "100000":
logger.info(f"Successfully signed topic: {topic.title}")
return True
elif response_data.get("code") == "382004":
logger.info(f"Topic {topic.title} already signed today")
return True # Treat as success
else:
logger.error(f"Failed to sign topic {topic.title}: {response_data.get('msg')}")
return False
except Exception as e:
logger.error(f"Exception signing topic {topic.title}: {e}")
return False
def _decrypt_cookies(self, encrypted_cookies: str, iv: str) -> Dict[str, str]:
"""
Decrypt cookies using AES-256-GCM
In a real system, this would use a proper crypto library
"""
try:
# Mock implementation - return dummy cookies
return {
"SUB": "_2A25z...",
"SUBP": "0033Wr...",
"ALF": "16...",
"SSOLoginState": "16...",
"SCF": "...",
"UN": "testuser"
}
except Exception as e:
logger.error(f"Failed to decrypt cookies: {e}")
return {}
async def get_proxy(self) -> Optional[Dict[str, str]]:
"""Get a proxy from the proxy pool service"""
try:
async with httpx.AsyncClient(timeout=5.0) as client:
response = await client.get(f"{settings.PROXY_POOL_URL}/get")
if response.status_code == 200:
proxy_info = response.json()
return {
"http://": f"http://{proxy_info['proxy']}",
"https://": f"https://{proxy_info['proxy']}"
}
else:
return None
except Exception as e:
logger.error(f"Failed to get proxy: {e}")
return None
async def get_browser_fingerprint(self) -> Dict[str, Any]:
"""Get a browser fingerprint from the generator service"""
try:
# Mock implementation
return {
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
"screen_resolution": "1920x1080",
"timezone": "Asia/Shanghai",
"plugins": ["PDF Viewer", "Chrome PDF Viewer", "Native Client"]
}
except Exception as e:
logger.error(f"Failed to get browser fingerprint: {e}")
return {}