Files
workphone-sdk/sdk/app/services/account_lifecycle.py

170 lines
5.1 KiB
Python

"""
防封模块 — 账号生命周期管理
管理账号从注册到成熟的各阶段操作限制。
阶段定义:
- 新号期 (0-7天):严格限制,以养号为主
- 成长期 (8-30天):逐步放宽,日常操作
- 成熟期 (30天+):正常使用限制
"""
import logging
import time
from enum import Enum
from typing import Dict, Optional
logger = logging.getLogger(__name__)
_redis = None
_redis_last_check: float = 0.0
_REDIS_CHECK_INTERVAL = 60.0
async def _get_redis():
global _redis, _redis_last_check
now = time.time()
if _redis is not None:
if now - _redis_last_check > _REDIS_CHECK_INTERVAL:
try:
await _redis.ping()
_redis_last_check = now
except Exception:
logger.warning("Redis 连接失效,重置")
_redis = None
if _redis is not None:
return _redis
try:
import redis.asyncio as aioredis
from config import settings
_redis = aioredis.from_url(settings.REDIS_URL, decode_responses=True)
await _redis.ping()
_redis_last_check = now
return _redis
except Exception:
_redis = None
return None
_memory_accounts: Dict[str, dict] = {}
class AccountPhase(str, Enum):
NEW = "new" # 0-7天
GROWING = "growing" # 8-30天
MATURE = "mature" # 30天+
PHASE_RULES = {
AccountPhase.NEW: {
"max_daily_add_friend": 10,
"max_daily_send_message": 20,
"max_daily_post_moments": 2,
"max_daily_group_send": 5,
"required_warm_up": True,
"description": "新号期:严格限制,优先养号",
},
AccountPhase.GROWING: {
"max_daily_add_friend": 30,
"max_daily_send_message": 80,
"max_daily_post_moments": 4,
"max_daily_group_send": 30,
"required_warm_up": False,
"description": "成长期:逐步放宽",
},
AccountPhase.MATURE: {
"max_daily_add_friend": 50,
"max_daily_send_message": 200,
"max_daily_post_moments": 5,
"max_daily_group_send": 50,
"required_warm_up": False,
"description": "成熟期:正常操作",
},
}
class AccountLifecycleManager:
"""账号生命周期管理器(单例)"""
async def register_account(
self, device_id: str, platform: str, register_timestamp: Optional[float] = None
):
"""
注册/绑定一个账号。
device_id+platform 唯一标识。
register_timestamp: 账号注册时间戳,不传则用当前时间。
"""
ts = register_timestamp or time.time()
key = f"acct:{device_id}:{platform}"
data = {"register_ts": ts, "platform": platform, "device_id": device_id}
r = await _get_redis()
if r:
try:
import json
await r.set(key, json.dumps(data), ex=86400 * 365)
return
except Exception:
pass
_memory_accounts[key] = data
async def get_phase(self, device_id: str, platform: str) -> AccountPhase:
key = f"acct:{device_id}:{platform}"
data = None
r = await _get_redis()
if r:
try:
import json
raw = await r.get(key)
if raw:
data = json.loads(raw)
except Exception:
pass
if not data:
data = _memory_accounts.get(key)
if not data:
return AccountPhase.NEW
age_days = (time.time() - data.get("register_ts", 0)) / 86400
if age_days <= 7:
return AccountPhase.NEW
elif age_days <= 30:
return AccountPhase.GROWING
return AccountPhase.MATURE
async def is_new_account(self, device_id: str, platform: str) -> bool:
phase = await self.get_phase(device_id, platform)
return phase == AccountPhase.NEW
async def get_rules(self, device_id: str, platform: str) -> dict:
phase = await self.get_phase(device_id, platform)
return {
"phase": phase.value,
**PHASE_RULES[phase],
}
async def check_allowed(
self, device_id: str, platform: str, action: str
) -> Dict[str, any]:
"""
检查某操作在当前生命周期是否允许(仅做检查,不消耗配额)。
返回 {"allowed": bool, "phase": str, "reason": str}
"""
phase = await self.get_phase(device_id, platform)
rules = PHASE_RULES[phase]
if phase == AccountPhase.NEW and rules.get("required_warm_up"):
high_risk_actions = {
"batch_add_friend", "batch_send", "send_red_packet",
"transfer", "open_mini_program",
}
if action in high_risk_actions:
return {
"allowed": False,
"phase": phase.value,
"reason": f"新号期禁止高风险操作: {action}",
}
return {"allowed": True, "phase": phase.value, "reason": ""}
account_lifecycle = AccountLifecycleManager()