PLUS: проверка API понимает заглушку провайдера, переоткрытий не больше 5
Browse files- plus/serve_muscriptor.py +32 -7
plus/serve_muscriptor.py
CHANGED
|
@@ -22,6 +22,7 @@ import subprocess
|
|
| 22 |
import sys
|
| 23 |
import threading
|
| 24 |
import time
|
|
|
|
| 25 |
import urllib.request
|
| 26 |
|
| 27 |
LINKS_FILE = "muscriptor_links.txt"
|
|
@@ -280,15 +281,31 @@ BROWSER_UA = ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
|
|
| 280 |
"(KHTML, like Gecko) Chrome/128.0 Safari/537.36")
|
| 281 |
|
| 282 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 283 |
def probe_api(url: str, timeout: float = 10.0) -> tuple[bool, str]:
|
| 284 |
-
"""API через туннель:
|
|
|
|
| 285 |
try:
|
| 286 |
-
with urllib.request.urlopen(
|
| 287 |
-
|
| 288 |
-
|
| 289 |
-
|
|
|
|
| 290 |
except Exception as problem:
|
| 291 |
return False, "API не ответил (%s)" % type(problem).__name__
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 292 |
names = data.get("instruments") if isinstance(data, dict) else None
|
| 293 |
if not names:
|
| 294 |
return False, "API отдал пустой список инструментов"
|
|
@@ -612,6 +629,8 @@ def main(argv: list[str] | None = None) -> int:
|
|
| 612 |
if tunnel.url and SUBDOMAIN and SUBDOMAIN not in tunnel.url:
|
| 613 |
say(" провайдер выдал другой адрес (свой поддомен занят): %s" % tunnel.url)
|
| 614 |
if tunnel.url:
|
|
|
|
|
|
|
| 615 |
ttfb, total, size = speed_probe(tunnel.url)
|
| 616 |
if ttfb >= 0:
|
| 617 |
say(" скорость ссылки: первый байт %.1f с, страница %.1f с"
|
|
@@ -624,6 +643,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
| 624 |
|
| 625 |
started, beat = time.time(), time.time()
|
| 626 |
public_fails, checked = 0, time.time()
|
|
|
|
| 627 |
try:
|
| 628 |
while True:
|
| 629 |
time.sleep(10)
|
|
@@ -655,14 +675,19 @@ def main(argv: list[str] | None = None) -> int:
|
|
| 655 |
else:
|
| 656 |
public_fails += 1
|
| 657 |
say(" ссылка снаружи: %s (%d подряд)" % (note, public_fails))
|
| 658 |
-
if public_fails >=
|
| 659 |
-
|
|
|
|
|
|
|
| 660 |
tunnel.kill()
|
| 661 |
tunnel = open_tunnel(proxy_port, order)
|
| 662 |
write_link(tunnel.url or "", args.port, proxy_port)
|
| 663 |
if tunnel.url:
|
| 664 |
say(">>> OPEN THIS LINK: " + tunnel.url)
|
| 665 |
public_fails = 0
|
|
|
|
|
|
|
|
|
|
| 666 |
if tunnel is not None and not tunnel.alive():
|
| 667 |
say("туннель умер, открываю новый")
|
| 668 |
tunnel.kill()
|
|
|
|
| 22 |
import sys
|
| 23 |
import threading
|
| 24 |
import time
|
| 25 |
+
import urllib.error
|
| 26 |
import urllib.request
|
| 27 |
|
| 28 |
LINKS_FILE = "muscriptor_links.txt"
|
|
|
|
| 281 |
"(KHTML, like Gecko) Chrome/128.0 Safari/537.36")
|
| 282 |
|
| 283 |
|
| 284 |
+
BYPASS_HEADERS = {"serveo-skip-browser-warning": "true"}
|
| 285 |
+
PAGE_MARKS = ("continue to", "continue to site", "proceed", "phishing",
|
| 286 |
+
"browser warning", "serveo")
|
| 287 |
+
|
| 288 |
+
|
| 289 |
def probe_api(url: str, timeout: float = 10.0) -> tuple[bool, str]:
|
| 290 |
+
"""API через туннель: JSON со списком инструментов, заглушка — не поломка."""
|
| 291 |
+
request = urllib.request.Request(url + "/instruments", headers=BYPASS_HEADERS)
|
| 292 |
try:
|
| 293 |
+
with urllib.request.urlopen(request, timeout=timeout) as answer:
|
| 294 |
+
status = answer.status
|
| 295 |
+
body = answer.read().decode("utf-8", "ignore")
|
| 296 |
+
except urllib.error.HTTPError as problem:
|
| 297 |
+
return False, "API код %d" % problem.code
|
| 298 |
except Exception as problem:
|
| 299 |
return False, "API не ответил (%s)" % type(problem).__name__
|
| 300 |
+
if status != 200:
|
| 301 |
+
return False, "API код %d" % status
|
| 302 |
+
try:
|
| 303 |
+
data = json.loads(body)
|
| 304 |
+
except Exception:
|
| 305 |
+
low = body.lower()
|
| 306 |
+
if any(mark in low for mark in PAGE_MARKS):
|
| 307 |
+
return True, "API за страницей-предупреждением провайдера"
|
| 308 |
+
return False, "API отдал не JSON"
|
| 309 |
names = data.get("instruments") if isinstance(data, dict) else None
|
| 310 |
if not names:
|
| 311 |
return False, "API отдал пустой список инструментов"
|
|
|
|
| 629 |
if tunnel.url and SUBDOMAIN and SUBDOMAIN not in tunnel.url:
|
| 630 |
say(" провайдер выдал другой адрес (свой поддомен занят): %s" % tunnel.url)
|
| 631 |
if tunnel.url:
|
| 632 |
+
api_ok, api_note = probe_api(tunnel.url)
|
| 633 |
+
say(" API снаружи: %s" % api_note)
|
| 634 |
ttfb, total, size = speed_probe(tunnel.url)
|
| 635 |
if ttfb >= 0:
|
| 636 |
say(" скорость ссылки: первый байт %.1f с, страница %.1f с"
|
|
|
|
| 643 |
|
| 644 |
started, beat = time.time(), time.time()
|
| 645 |
public_fails, checked = 0, time.time()
|
| 646 |
+
reopens = 0
|
| 647 |
try:
|
| 648 |
while True:
|
| 649 |
time.sleep(10)
|
|
|
|
| 675 |
else:
|
| 676 |
public_fails += 1
|
| 677 |
say(" ссылка снаружи: %s (%d подряд)" % (note, public_fails))
|
| 678 |
+
if public_fails >= 3 and reopens < 5:
|
| 679 |
+
reopens += 1
|
| 680 |
+
say(" переоткрываю туннель: снаружи не отвечает"
|
| 681 |
+
" (раз %d из 5)" % reopens)
|
| 682 |
tunnel.kill()
|
| 683 |
tunnel = open_tunnel(proxy_port, order)
|
| 684 |
write_link(tunnel.url or "", args.port, proxy_port)
|
| 685 |
if tunnel.url:
|
| 686 |
say(">>> OPEN THIS LINK: " + tunnel.url)
|
| 687 |
public_fails = 0
|
| 688 |
+
elif public_fails >= 3:
|
| 689 |
+
say(" переоткрытий уже 5, оставляю этот туннель:"
|
| 690 |
+
" проблема не в нём")
|
| 691 |
if tunnel is not None and not tunnel.alive():
|
| 692 |
say("туннель умер, открываю новый")
|
| 693 |
tunnel.kill()
|