from __future__ import annotations import logging import time from dataclasses import dataclass, field from typing import Any from yuxi.channel.extensions.qqbot.types import KnownUser logger = logging.getLogger(__name__) class KnownUsersStore: def __init__(self): self._users: dict[str, KnownUser] = {} def _make_key(self, account_id: str, openid: str, user_type: str, group_openid: str | None = None) -> str: base = f"{account_id}:{openid}:{user_type}" if group_openid: base += f":{group_openid}" return base async def record_known_user(self, user: KnownUser) -> None: key = self._make_key(user.account_id, user.openid, user.type, user.group_openid) now = time.time() if key in self._users: existing = self._users[key] existing.last_seen_at = now existing.interaction_count += 1 if user.nickname: existing.nickname = user.nickname else: user.first_seen_at = now user.last_seen_at = now user.interaction_count = 1 self._users[key] = user async def get_known_user( self, account_id: str, openid: str, user_type: str, group_openid: str | None = None ) -> KnownUser | None: key = self._make_key(account_id, openid, user_type, group_openid) return self._users.get(key) async def list_known_users(self, account_id: str | None = None) -> list[KnownUser]: users = list(self._users.values()) if account_id: users = [u for u in users if u.account_id == account_id] return sorted(users, key=lambda u: u.last_seen_at, reverse=True) async def get_stats(self, account_id: str | None = None) -> dict: users = await self.list_known_users(account_id) now = time.time() c2c_count = sum(1 for u in users if u.type == "c2c") group_count = sum(1 for u in users if u.type == "group") active_24h = sum(1 for u in users if now - u.last_seen_at < 86400) active_7d = sum(1 for u in users if now - u.last_seen_at < 604800) return { "total_users": len(users), "c2c_users": c2c_count, "group_users": group_count, "active_in_24h": active_24h, "active_in_7d": active_7d, } def clear(self) -> None: self._users.clear()