feat: publish workphone SDK deployment and API docs
This commit is contained in:
86
sdk/agent/hook/event_reporter.py
Normal file
86
sdk/agent/hook/event_reporter.py
Normal file
@@ -0,0 +1,86 @@
|
||||
"""
|
||||
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]
|
||||
Reference in New Issue
Block a user