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