实现了完整的Nextcloud Talk聊天适配器,包含以下核心功能: 1. 基础客户端通信与认证 2. 会话路由与聊天类型解析 3. 消息分块与格式转换 4. 用户配对与权限校验 5. 轮询式消息监听 6. 配置验证与诊断工具 7. 安全策略与去重缓存 8. 指标统计与状态快照 新增配套的配对用户缓存文件与模块导出入口。
79 lines
3.2 KiB
Python
79 lines
3.2 KiB
Python
from __future__ import annotations
|
|
|
|
import time
|
|
from collections import deque
|
|
from typing import Any
|
|
|
|
|
|
class NextcloudTalkMetrics:
|
|
def __init__(self, max_latency_samples: int = 100):
|
|
self._max_latency_samples = max_latency_samples
|
|
self._send_latencies: deque[float] = deque(maxlen=max_latency_samples)
|
|
self._receive_latencies: deque[float] = deque(maxlen=max_latency_samples)
|
|
self._send_count: int = 0
|
|
self._receive_count: int = 0
|
|
self._send_error_count: int = 0
|
|
self._receive_error_count: int = 0
|
|
self._circuit_breaker_trips: int = 0
|
|
self._started_at: float = time.time()
|
|
|
|
def record_send_success(self, latency_s: float) -> None:
|
|
self._send_latencies.append(latency_s)
|
|
self._send_count += 1
|
|
|
|
def record_send_error(self) -> None:
|
|
self._send_error_count += 1
|
|
|
|
def record_receive_success(self, latency_s: float) -> None:
|
|
self._receive_latencies.append(latency_s)
|
|
self._receive_count += 1
|
|
|
|
def record_receive_error(self) -> None:
|
|
self._receive_error_count += 1
|
|
|
|
def record_circuit_breaker_trip(self) -> None:
|
|
self._circuit_breaker_trips += 1
|
|
|
|
def snapshot(self) -> dict[str, Any]:
|
|
uptime_s = time.time() - self._started_at
|
|
|
|
send_latencies = list(self._send_latencies)
|
|
recv_latencies = list(self._receive_latencies)
|
|
|
|
avg_send = sum(send_latencies) / len(send_latencies) if send_latencies else None
|
|
avg_recv = sum(recv_latencies) / len(recv_latencies) if recv_latencies else None
|
|
|
|
return {
|
|
"uptime_seconds": round(uptime_s, 1),
|
|
"send": {
|
|
"count": self._send_count,
|
|
"error_count": self._send_error_count,
|
|
"avg_latency_ms": round(avg_send * 1000, 1) if avg_send is not None else None,
|
|
"p50_latency_ms": round(_percentile(send_latencies, 50) * 1000, 1) if send_latencies else None,
|
|
"p95_latency_ms": round(_percentile(send_latencies, 95) * 1000, 1) if send_latencies else None,
|
|
"p99_latency_ms": round(_percentile(send_latencies, 99) * 1000, 1) if send_latencies else None,
|
|
},
|
|
"receive": {
|
|
"count": self._receive_count,
|
|
"error_count": self._receive_error_count,
|
|
"avg_latency_ms": round(avg_recv * 1000, 1) if avg_recv is not None else None,
|
|
"p50_latency_ms": round(_percentile(recv_latencies, 50) * 1000, 1) if recv_latencies else None,
|
|
"p95_latency_ms": round(_percentile(recv_latencies, 95) * 1000, 1) if recv_latencies else None,
|
|
"p99_latency_ms": round(_percentile(recv_latencies, 99) * 1000, 1) if recv_latencies else None,
|
|
},
|
|
"circuit_breaker": {
|
|
"trip_count": self._circuit_breaker_trips,
|
|
},
|
|
}
|
|
|
|
|
|
def _percentile(data: list[float], percentile: float) -> float:
|
|
if not data:
|
|
return 0.0
|
|
sorted_data = sorted(data)
|
|
k = (len(sorted_data) - 1) * percentile / 100.0
|
|
f = int(k)
|
|
c = k - f
|
|
if f + 1 < len(sorted_data):
|
|
return sorted_data[f] + c * (sorted_data[f + 1] - sorted_data[f])
|
|
return sorted_data[f] |