understanding commited on
Commit
766954d
·
verified ·
1 Parent(s): c37aecc

Update bot/handlers.py

Browse files
Files changed (1) hide show
  1. bot/handlers.py +107 -29
bot/handlers.py CHANGED
@@ -1,5 +1,9 @@
1
  # PATH: bot/handlers.py
2
- import json, re, time
 
 
 
 
3
  from typing import Dict
4
 
5
  from hydrogram import Client, filters
@@ -14,9 +18,23 @@ from bot.core.auth import is_owner_id, require_allowed
14
  from bot.core.progress import SpeedETA, human_bytes, human_eta
15
  from bot.core.tasks import create_task, set_task
16
 
 
 
 
 
 
 
 
 
 
17
  from bot.integrations.cf_worker1 import profile_add, profile_list, profile_set_default
18
  from bot.integrations.cf_worker2 import (
19
- allow_user, disallow_user, pick_profile, access_token, record_upload, stats_today
 
 
 
 
 
20
  )
21
 
22
  from bot.telegram.media import download_to_temp
@@ -32,6 +50,10 @@ from bot.integrations.http import fetch_status
32
  # ---------- in-memory auth state (simple FSM) ----------
33
  _AWAIT_AUTH: Dict[int, str] = {}
34
 
 
 
 
 
35
 
36
  def _pick_login_url(j: dict) -> str:
37
  """Accept login_url from either top-level OR nested {data:{...}} shapes."""
@@ -57,7 +79,6 @@ def _pick_login_url(j: dict) -> str:
57
 
58
 
59
  def setup_handlers(app: Client) -> None:
60
-
61
  @app.on_message(filters.command(["start"]) & filters.private)
62
  async def start_handler(_: Client, m: Message):
63
  await safe_reply(m, texts.START_TEXT)
@@ -71,6 +92,54 @@ def setup_handlers(app: Client) -> None:
71
  uid = m.from_user.id if m.from_user else None
72
  await safe_reply(m, f"👤 Your ID: `{uid}`")
73
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  # -------- OWNER allow/disallow via forward OR id --------
75
  @app.on_message(filters.command(["allow"]) & filters.private)
76
  async def allow_cmd(_: Client, m: Message):
@@ -128,7 +197,7 @@ def setup_handlers(app: Client) -> None:
128
  f"W2={Workers.WORKER2_URL} -> {r2}\n\n"
129
  f"DNS W1 -> {dns_check(Workers.WORKER1_URL)}\n"
130
  f"DNS W2 -> {dns_check(Workers.WORKER2_URL)}\n"
131
- f"DNS google -> {dns_check('https://www.google.com')}\n"
132
  )
133
 
134
  # -------- AUTH UI --------
@@ -184,7 +253,25 @@ def setup_handlers(app: Client) -> None:
184
  await q.answer("OK")
185
 
186
  # message sink for auth states
187
- @app.on_message(filters.private & filters.text & ~filters.command(["start","ping","me","auth","cancel","profiles","stats","allow","disallow","diag"]))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  async def auth_sink(_: Client, m: Message):
189
  uid = m.from_user.id if m.from_user else 0
190
  mode = _AWAIT_AUTH.get(uid)
@@ -294,38 +381,29 @@ def setup_handlers(app: Client) -> None:
294
 
295
  file_path = ""
296
  file_size = 0
 
297
 
298
  try:
299
- # ---------------- Download with ETA ----------------
300
  set_task(task_id, "downloading", "")
301
 
302
- dl_se = SpeedETA()
303
- dl_last_edit = 0.0
 
304
 
305
- async def dl_prog(done: int, total: int):
306
- nonlocal dl_last_edit
307
- snap = dl_se.update(done, total)
308
- if time.time() - dl_last_edit < 2.0 and done < total:
309
- return
310
- dl_last_edit = time.time()
311
- txt = (
312
- f"⬇️ Downloading…\n"
313
- f"{human_bytes(done)}/{human_bytes(total)}\n"
314
- f"speed: {human_bytes(snap['speed_bps'])}/s | eta: {human_eta(snap['eta_sec'])}"
315
- )
316
- await safe_edit(status, txt)
317
 
318
- file_path, file_size, file_name, dl_sec = await download_to_temp(
319
- app_, m,
320
- progress=dl_prog,
321
- progress_args=(),
322
- )
323
- dl_avg_bps = int((file_size or 0) / max(dl_sec, 0.001))
324
 
325
  # parse title/desc after download
326
  title, desc = extract_title_description(m, file_name)
327
 
328
- # ---------------- Upload with ETA ----------------
329
  set_task(task_id, "uploading", "")
330
  up_t0 = time.time()
331
 
@@ -355,7 +433,7 @@ def setup_handlers(app: Client) -> None:
355
  )
356
 
357
  up_sec = max(0.001, time.time() - up_t0)
358
- up_avg_bps = int((file_size or 0) / up_sec)
359
 
360
  await record_upload(uid, use_profile_id)
361
 
@@ -366,7 +444,7 @@ def setup_handlers(app: Client) -> None:
366
  f"🎬 {title}\n"
367
  f"🔗 {yt_url}\n\n"
368
  f"⬇️ Download: {human_eta(int(dl_sec))} | avg {human_bytes(dl_avg_bps)}/s\n"
369
- f"⬆️ Upload: {human_eta(int(up_sec))} | avg {human_bytes(up_avg_bps)}/s"
370
  )
371
 
372
  except Exception as e:
 
1
  # PATH: bot/handlers.py
2
+ import asyncio
3
+ import json
4
+ import os
5
+ import re
6
+ import time
7
  from typing import Dict
8
 
9
  from hydrogram import Client, filters
 
18
  from bot.core.progress import SpeedETA, human_bytes, human_eta
19
  from bot.core.tasks import create_task, set_task
20
 
21
+ from bot.core.speedtest import (
22
+ ping_ms,
23
+ net_download_test,
24
+ net_upload_test,
25
+ disk_total_free,
26
+ bytes_to_mb,
27
+ bytes_per_sec_to_mb_s,
28
+ )
29
+
30
  from bot.integrations.cf_worker1 import profile_add, profile_list, profile_set_default
31
  from bot.integrations.cf_worker2 import (
32
+ allow_user,
33
+ disallow_user,
34
+ pick_profile,
35
+ access_token,
36
+ record_upload,
37
+ stats_today,
38
  )
39
 
40
  from bot.telegram.media import download_to_temp
 
50
  # ---------- in-memory auth state (simple FSM) ----------
51
  _AWAIT_AUTH: Dict[int, str] = {}
52
 
53
+ # uptime + speedtest cooldown
54
+ _STARTED_AT = time.time()
55
+ _SPEED_COOLDOWN: dict[int, float] = {}
56
+
57
 
58
  def _pick_login_url(j: dict) -> str:
59
  """Accept login_url from either top-level OR nested {data:{...}} shapes."""
 
79
 
80
 
81
  def setup_handlers(app: Client) -> None:
 
82
  @app.on_message(filters.command(["start"]) & filters.private)
83
  async def start_handler(_: Client, m: Message):
84
  await safe_reply(m, texts.START_TEXT)
 
92
  uid = m.from_user.id if m.from_user else None
93
  await safe_reply(m, f"👤 Your ID: `{uid}`")
94
 
95
+ # -------------------- SPEEDTEST (any user) --------------------
96
+ @app.on_message(filters.command(["speedtest"]) & filters.private)
97
+ async def speedtest_cmd(_: Client, m: Message):
98
+ uid = m.from_user.id if m.from_user else 0
99
+
100
+ now = time.time()
101
+ last = _SPEED_COOLDOWN.get(uid, 0.0)
102
+ if now - last < 30:
103
+ return await safe_reply(m, "⏳ Wait 30s then try again.")
104
+ _SPEED_COOLDOWN[uid] = now
105
+
106
+ msg = await safe_reply(m, "⚡ Running speedtest…")
107
+
108
+ # uptime
109
+ up_sec = int(max(0, time.time() - _STARTED_AT))
110
+ up_txt = human_eta(up_sec)
111
+
112
+ # disk
113
+ d = disk_total_free("/")
114
+ total_gb = d["total"] / (1024**3)
115
+ free_gb = d["free"] / (1024**3)
116
+
117
+ # run parallel
118
+ dl_task = asyncio.create_task(net_download_test())
119
+ up_task = asyncio.create_task(net_upload_test())
120
+ p_task = asyncio.create_task(ping_ms())
121
+
122
+ dl = await dl_task
123
+ up = await up_task
124
+ p = await p_task
125
+
126
+ ping_line = f"{p:.0f} ms" if p is not None else "N/A"
127
+
128
+ dl_mb_s = bytes_per_sec_to_mb_s(dl["bps"])
129
+ up_mb_s = bytes_per_sec_to_mb_s(up["bps"])
130
+
131
+ txt = (
132
+ "⚡ **Speedtest**\n\n"
133
+ f"🕒 Uptime: **{up_txt}**\n"
134
+ f"📶 Ping: **{ping_line}**\n"
135
+ f"💾 Disk: **{total_gb:.1f} GB total**, **{free_gb:.1f} GB free**\n\n"
136
+ f"⬇️ Download: **{dl_mb_s:.2f} MB/s** "
137
+ f"({bytes_to_mb(dl['bytes']):.2f} MB in {dl['seconds']:.2f}s)\n"
138
+ f"⬆️ Upload: **{up_mb_s:.2f} MB/s** "
139
+ f"({bytes_to_mb(up['bytes']):.2f} MB in {up['seconds']:.2f}s)\n"
140
+ )
141
+ await safe_edit(msg, txt)
142
+
143
  # -------- OWNER allow/disallow via forward OR id --------
144
  @app.on_message(filters.command(["allow"]) & filters.private)
145
  async def allow_cmd(_: Client, m: Message):
 
197
  f"W2={Workers.WORKER2_URL} -> {r2}\n\n"
198
  f"DNS W1 -> {dns_check(Workers.WORKER1_URL)}\n"
199
  f"DNS W2 -> {dns_check(Workers.WORKER2_URL)}\n"
200
+ f"DNS google -> {dns_check('https://www.google.com')}\n",
201
  )
202
 
203
  # -------- AUTH UI --------
 
253
  await q.answer("OK")
254
 
255
  # message sink for auth states
256
+ @app.on_message(
257
+ filters.private
258
+ & filters.text
259
+ & ~filters.command(
260
+ [
261
+ "start",
262
+ "ping",
263
+ "me",
264
+ "auth",
265
+ "cancel",
266
+ "profiles",
267
+ "speedtest",
268
+ "stats",
269
+ "allow",
270
+ "disallow",
271
+ "diag",
272
+ ]
273
+ )
274
+ )
275
  async def auth_sink(_: Client, m: Message):
276
  uid = m.from_user.id if m.from_user else 0
277
  mode = _AWAIT_AUTH.get(uid)
 
381
 
382
  file_path = ""
383
  file_size = 0
384
+ file_name = "video.bin"
385
 
386
  try:
387
+ # ---------------- Download (Telegram) ----------------
388
  set_task(task_id, "downloading", "")
389
 
390
+ dl_t0 = time.time()
391
+ file_path, file_size, file_name = await download_to_temp(app_, m)
392
+ dl_sec = max(0.001, time.time() - dl_t0)
393
 
394
+ # fallback size from disk if TG didn't give it
395
+ if not file_size and file_path and os.path.exists(file_path):
396
+ try:
397
+ file_size = os.path.getsize(file_path)
398
+ except Exception:
399
+ file_size = 0
 
 
 
 
 
 
400
 
401
+ dl_avg_bps = int((file_size or 0) / dl_sec) if file_size else 0
 
 
 
 
 
402
 
403
  # parse title/desc after download
404
  title, desc = extract_title_description(m, file_name)
405
 
406
+ # ---------------- Upload (YouTube) ----------------
407
  set_task(task_id, "uploading", "")
408
  up_t0 = time.time()
409
 
 
433
  )
434
 
435
  up_sec = max(0.001, time.time() - up_t0)
436
+ up_avg_bps = int((file_size or 0) / up_sec) if file_size else 0
437
 
438
  await record_upload(uid, use_profile_id)
439
 
 
444
  f"🎬 {title}\n"
445
  f"🔗 {yt_url}\n\n"
446
  f"⬇️ Download: {human_eta(int(dl_sec))} | avg {human_bytes(dl_avg_bps)}/s\n"
447
+ f"⬆️ Upload: {human_eta(int(up_sec))} | avg {human_bytes(up_avg_bps)}/s",
448
  )
449
 
450
  except Exception as e: