mirror of
https://github.com/anten-ka/gotelegram_pro.git
synced 2026-05-19 17:56:07 +00:00
v2.5.0: add shared 443 and per-user traffic
This commit is contained in:
@@ -105,6 +105,7 @@ logger = logging.getLogger(__name__)
|
||||
GOTELEGRAM_VERSION = "2.5.0"
|
||||
GOTELEGRAM_CONFIG = "/opt/gotelegram/config.json"
|
||||
DISABLED_USERS_FILE = "/opt/gotelegram/disabled_users.json"
|
||||
USER_STATS_HISTORY = "/opt/gotelegram/user_stats_history.csv"
|
||||
USER_LOCK_FILE = "/run/gotelegram/admin-users.lock"
|
||||
TELEMT_CONFIG = "/etc/telemt/config.toml"
|
||||
TELEMT_SERVICE = "telemt"
|
||||
@@ -124,6 +125,17 @@ ENV_FILE = "/opt/gotelegram-bot/.env"
|
||||
ADMIN_WEB_SERVICE = "gotelegram-admin"
|
||||
ADMIN_WEB_PORT = 1984
|
||||
|
||||
|
||||
def format_bytes_human(value: int) -> str:
|
||||
value = max(0, int(value or 0))
|
||||
if value < 1024:
|
||||
return f"{value} B"
|
||||
if value < 1024 * 1024:
|
||||
return f"{value / 1024:.1f} KB"
|
||||
if value < 1024 * 1024 * 1024:
|
||||
return f"{value / 1024 / 1024:.1f} MB"
|
||||
return f"{value / 1024 / 1024 / 1024:.1f} GB"
|
||||
|
||||
# ── Загрузка ALLOWED_IDS ────────────────────────────────────────────────────
|
||||
# Поддерживает запятую, пробел, или их комбинацию как разделитель
|
||||
ALLOWED_IDS: set = set()
|
||||
@@ -1568,6 +1580,42 @@ def _extract_traffic_value(data: Any, keys: List[str]) -> int:
|
||||
return 0
|
||||
|
||||
|
||||
def user_traffic_history_summary(name: str) -> str:
|
||||
rows: List[Dict[str, int]] = []
|
||||
try:
|
||||
with open(USER_STATS_HISTORY, "r", encoding="utf-8", errors="ignore") as f:
|
||||
reader = csv.DictReader(f)
|
||||
previous = None
|
||||
for row in reader:
|
||||
if row.get("user") != name:
|
||||
continue
|
||||
try:
|
||||
item = {
|
||||
"epoch": int(row.get("epoch") or 0),
|
||||
"total_octets": int(row.get("total_octets") or 0),
|
||||
}
|
||||
except ValueError:
|
||||
continue
|
||||
item["total_delta"] = max(0, item["total_octets"] - previous["total_octets"]) if previous else 0
|
||||
rows.append(item)
|
||||
previous = item
|
||||
except Exception:
|
||||
rows = []
|
||||
|
||||
if not rows:
|
||||
return "\n<i>История по ключу пока не накоплена.</i>"
|
||||
|
||||
latest = max(row["epoch"] for row in rows)
|
||||
periods = [("15 мин", 15 * 60), ("1 час", 60 * 60), ("24 часа", 24 * 60 * 60), ("Месяц", 30 * 24 * 60 * 60)]
|
||||
lines = ["\n<b>История трафика:</b>", "<pre>", f"{'Период':<8} │ {'Трафик':>10}", "─" * 23]
|
||||
for label, seconds in periods:
|
||||
window = [row for row in rows if row["epoch"] >= latest - seconds]
|
||||
total = sum(max(0, row.get("total_delta", 0)) for row in window)
|
||||
lines.append(f"{label:<8} │ {format_bytes_human(total):>10}")
|
||||
lines.append("</pre>")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
async def get_proxy_link_for_secret(secret: str) -> Optional[str]:
|
||||
"""Generate a fake-TLS proxy link for an arbitrary telemt user secret."""
|
||||
config = load_json(GOTELEGRAM_CONFIG) or {}
|
||||
@@ -1747,16 +1795,16 @@ async def _user_detail_text(name: str, secret: str, enabled: bool = True) -> str
|
||||
details = ""
|
||||
if api:
|
||||
data = api.get("data", api)
|
||||
up = _extract_traffic_value(data, ["upload_bytes", "uplink_bytes", "tx_bytes", "sent_bytes", "up"])
|
||||
down = _extract_traffic_value(data, ["download_bytes", "downlink_bytes", "rx_bytes", "received_bytes", "down"])
|
||||
active_ips = _extract_traffic_value(data, ["active_ips", "unique_ips"])
|
||||
total = int(data.get("total_octets") or 0) if isinstance(data, dict) else 0
|
||||
conns = int(data.get("current_connections") or 0) if isinstance(data, dict) else 0
|
||||
active_ips = int(data.get("active_unique_ips") or 0) if isinstance(data, dict) else 0
|
||||
recent_ips = int(data.get("recent_unique_ips") or 0) if isinstance(data, dict) else 0
|
||||
parts = []
|
||||
if up:
|
||||
parts.append(f"↑ {up} B")
|
||||
if down:
|
||||
parts.append(f"↓ {down} B")
|
||||
if active_ips:
|
||||
parts.append(f"active IPs: {active_ips}")
|
||||
parts.append(f"Трафик всего: <b>{format_bytes_human(total)}</b>")
|
||||
parts.append(f"Подключения: <code>{conns}</code>")
|
||||
parts.append(f"Активные IP: <code>{active_ips}</code>")
|
||||
if recent_ips:
|
||||
parts.append(f"Недавние IP: <code>{recent_ips}</code>")
|
||||
if parts:
|
||||
details = "\n" + "\n".join(parts)
|
||||
else:
|
||||
@@ -1766,6 +1814,7 @@ async def _user_detail_text(name: str, secret: str, enabled: bool = True) -> str
|
||||
details = "\n<i>Runtime API недоступен. Новые установки goTelegram Pro включают его автоматически.</i>"
|
||||
else:
|
||||
details = "\n<i>Ключ отключён и сейчас не принимается telemt.</i>"
|
||||
details += user_traffic_history_summary(name)
|
||||
|
||||
link_line = html.escape(link) if link else "link unavailable"
|
||||
status_line = "🟢 enabled" if enabled else "⏸ disabled"
|
||||
|
||||
Reference in New Issue
Block a user