mirror of
https://github.com/Flowseal/tg-ws-proxy.git
synced 2026-10-21 16:24:10 +03:00
89 lines
3.7 KiB
Python
89 lines
3.7 KiB
Python
import logging
|
|
import time
|
|
from collections import defaultdict
|
|
|
|
log = logging.getLogger('tg-mtproto-proxy')
|
|
|
|
|
|
class WsActivity:
|
|
active = set()
|
|
|
|
def __init__(self, label, dc):
|
|
self.label, self.dc = label, dc
|
|
self.started = time.monotonic()
|
|
self.native_up = self.ws_up = self.ws_down = self.native_down = 0
|
|
self.first_input = self.first_reply = self.last_rx = self.last_tx = None
|
|
self.awaiting_rx = self.sending = self.writing_native = None
|
|
self.max_rx_gap = self.max_send = self.max_native_write = 0.0
|
|
self.sample = (self.started, 0, 0, 0, 0)
|
|
self.active.add(self)
|
|
log.debug('[%s] WS OPEN %s', self.label, self.dc)
|
|
|
|
def input(self, length):
|
|
self.native_up += length
|
|
if self.first_input is None:
|
|
self.first_input = time.monotonic()
|
|
|
|
def send_started(self):
|
|
self.sending = time.monotonic()
|
|
|
|
def sent(self, length):
|
|
now = time.monotonic()
|
|
self.ws_up += length
|
|
if self.sending is not None:
|
|
self.max_send = max(self.max_send, now - self.sending)
|
|
if self.awaiting_rx is None and (self.last_rx is None or self.last_rx < self.sending):
|
|
self.awaiting_rx = self.sending
|
|
self.last_tx, self.sending = now, None
|
|
|
|
def received(self, length):
|
|
now = time.monotonic()
|
|
self.ws_down += length
|
|
self.last_rx = now
|
|
if self.awaiting_rx is not None:
|
|
self.max_rx_gap = max(self.max_rx_gap, now - self.awaiting_rx)
|
|
if self.first_reply is None and self.first_input is not None:
|
|
self.first_reply = now - self.first_input
|
|
self.awaiting_rx = None
|
|
self.writing_native = now
|
|
|
|
def delivered(self, length):
|
|
self.native_down += length
|
|
if self.writing_native is not None:
|
|
self.max_native_write = max(self.max_native_write, time.monotonic() - self.writing_native)
|
|
self.writing_native = None
|
|
|
|
def summary(self, now):
|
|
current = (now, self.native_up, self.ws_up, self.ws_down, self.native_down)
|
|
previous, self.sample = self.sample, current
|
|
return ('client=%s window_ms=%.0f native_up=%d ws_up=%d ws_down=%d native_down=%d '
|
|
'rx_gap_ms=%.0f last_rx_ms=%.0f ws_write_ms=%.0f native_write_ms=%.0f' % (
|
|
self.label, (now - previous[0]) * 1000,
|
|
*(current[index] - previous[index] for index in range(1, 5)),
|
|
0 if self.awaiting_rx is None else (now - self.awaiting_rx) * 1000,
|
|
-1 if self.last_rx is None else (now - self.last_rx) * 1000,
|
|
0 if self.sending is None else (now - self.sending) * 1000,
|
|
0 if self.writing_native is None else (now - self.writing_native) * 1000))
|
|
|
|
def close(self):
|
|
now = time.monotonic()
|
|
self.active.discard(self)
|
|
log.debug('WS END %s %s first_reply_ms=%.0f max_rx_gap_ms=%.0f '
|
|
'max_ws_write_ms=%.0f max_native_write_ms=%.0f',
|
|
self.dc, self.summary(now),
|
|
-1 if self.first_reply is None else self.first_reply * 1000,
|
|
self.max_rx_gap * 1000, self.max_send * 1000, self.max_native_write * 1000)
|
|
|
|
|
|
def log_ws_flow(now):
|
|
if not log.isEnabledFor(logging.DEBUG):
|
|
return
|
|
groups = defaultdict(list)
|
|
for activity in WsActivity.active:
|
|
groups[activity.dc].append(activity)
|
|
for dc, activities in sorted(groups.items()):
|
|
activities.sort(key=lambda item: item.label)
|
|
for offset in range(0, len(activities), 8):
|
|
log.debug('WS FLOW %s [%s]', dc,
|
|
'; '.join(item.summary(now) for item in activities[offset:offset + 8]))
|