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,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
}