""" Event Reporter — 将 Frida Hook 事件上报到 SDK 服务端 职责: - 接收 FridaManager 回调的 hook_event - 格式化为 SDK 服务端 WebSocket 协议 - 通过 Agent 的 WebSocket 连接上报 - 本地缓存(服务端离线时暂存) """ import time import logging import threading from typing import Dict, Any, Optional, Callable, List from collections import deque logger = logging.getLogger(__name__) MAX_BUFFER_SIZE = 500 class EventReporter: """Hook 事件上报器""" def __init__( self, send_fn: Optional[Callable[[Dict[str, Any]], None]] = None, buffer_size: int = MAX_BUFFER_SIZE, ): self._send_fn = send_fn self._buffer: deque = deque(maxlen=buffer_size) self._stats = {"total": 0, "sent": 0, "buffered": 0, "errors": 0} self._lock = threading.Lock() def set_send_fn(self, fn: Callable[[Dict[str, Any]], None]): self._send_fn = fn self._flush_buffer() def on_hook_event(self, payload: Dict[str, Any]): event = { "type": "hook_event", "event_type": payload.get("event_type", "unknown"), "platform": payload.get("platform", "wechat"), "payload": payload.get("payload", {}), "timestamp": payload.get("timestamp") or time.strftime("%Y-%m-%dT%H:%M:%S"), } with self._lock: self._stats["total"] += 1 if self._send_fn: try: self._send_fn(event) with self._lock: self._stats["sent"] += 1 except Exception as e: logger.warning(f"事件上报失败,暂存: {e}") self._buffer.append(event) with self._lock: self._stats["buffered"] += 1 self._stats["errors"] += 1 else: self._buffer.append(event) with self._lock: self._stats["buffered"] += 1 def _flush_buffer(self): if not self._send_fn: return while self._buffer: event = self._buffer.popleft() try: self._send_fn(event) with self._lock: self._stats["sent"] += 1 self._stats["buffered"] = max(0, self._stats["buffered"] - 1) except Exception: self._buffer.appendleft(event) break def get_stats(self) -> Dict[str, Any]: with self._lock: return dict(self._stats) def get_buffered_events(self, limit: int = 50) -> List[Dict[str, Any]]: return list(self._buffer)[:limit]