mirror of
https://github.com/Flowseal/tg-ws-proxy.git
synced 2026-05-17 00:25:51 +03:00
remove cf priority flag, cf worker ui setup
This commit is contained in:
@@ -49,7 +49,6 @@ tg-ws-proxy [--port PORT] [--host HOST] [--dc-ip DC:IP ...] [-v]
|
|||||||
| `--no-cfproxy` | `false` | Отключить попытку [проксирования через Cloudflare](./CfProxy.md) |
|
| `--no-cfproxy` | `false` | Отключить попытку [проксирования через Cloudflare](./CfProxy.md) |
|
||||||
| `--cfproxy-domain` | | Указать свой домен для проксирования через Cloudflare. [Подробнее](./CfProxy.md) |
|
| `--cfproxy-domain` | | Указать свой домен для проксирования через Cloudflare. [Подробнее](./CfProxy.md) |
|
||||||
| `--cfproxy-worker-domain` | | Домен Cloudflare Worker [Подробнее](./CfWorker.md) |
|
| `--cfproxy-worker-domain` | | Домен Cloudflare Worker [Подробнее](./CfWorker.md) |
|
||||||
| `--cfproxy-priority` | `true` | Пробовать проксировать через Cloudflare перед прямым TCP подключением |
|
|
||||||
| `--fake-tls-domain` | | Включить маскировку Fake TLS (ee-secret) с указанным SNI-доменом |
|
| `--fake-tls-domain` | | Включить маскировку Fake TLS (ee-secret) с указанным SNI-доменом |
|
||||||
| `--proxy-protocol` | выкл. | Принимать HAProxy PROXY protocol v1 (для работы за nginx/haproxy с `proxy_protocol on`) |
|
| `--proxy-protocol` | выкл. | Принимать HAProxy PROXY protocol v1 (для работы за nginx/haproxy с `proxy_protocol on`) |
|
||||||
| `--buf-kb` | `256` | Размер буфера в КБ |
|
| `--buf-kb` | `256` | Размер буфера в КБ |
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ Tray-приложение хранит данные в:
|
|||||||
"log_max_mb": 5.0,
|
"log_max_mb": 5.0,
|
||||||
"check_updates": true,
|
"check_updates": true,
|
||||||
"cfproxy": true,
|
"cfproxy": true,
|
||||||
"cfproxy_priority": true,
|
|
||||||
"cfproxy_user_domain": "",
|
"cfproxy_user_domain": "",
|
||||||
"cfproxy_worker_domain": "",
|
"cfproxy_worker_domain": "",
|
||||||
"appearance": "auto"
|
"appearance": "auto"
|
||||||
|
|||||||
43
macos.py
43
macos.py
@@ -41,6 +41,8 @@ _app: Optional[object] = None
|
|||||||
_config: dict = {}
|
_config: dict = {}
|
||||||
_exiting: bool = False
|
_exiting: bool = False
|
||||||
|
|
||||||
|
_CFWORKER_HELP_URL = "https://github.com/Flowseal/tg-ws-proxy/blob/main/docs/CfWorker.md"
|
||||||
|
|
||||||
# osascript dialogs
|
# osascript dialogs
|
||||||
|
|
||||||
|
|
||||||
@@ -109,6 +111,32 @@ def _osascript_input(prompt: str, default: str, title: str = "TG WS Proxy") -> O
|
|||||||
return r.stdout.rstrip("\r\n")
|
return r.stdout.rstrip("\r\n")
|
||||||
|
|
||||||
|
|
||||||
|
def _ask_cfworker_domain(default: str) -> Optional[str]:
|
||||||
|
value = default
|
||||||
|
while True:
|
||||||
|
script = (
|
||||||
|
f'set d to display dialog "{_esc("Cloudflare Worker домен (например, name.account.workers.dev):")}" '
|
||||||
|
f'default answer "{_esc(value)}" '
|
||||||
|
f'with title "TG WS Proxy" '
|
||||||
|
f'buttons {{"Закрыть", "?", "OK"}} '
|
||||||
|
f'default button "OK" cancel button "Закрыть"\n'
|
||||||
|
f'return (button returned of d) & "\\n" & (text returned of d)'
|
||||||
|
)
|
||||||
|
r = subprocess.run(["osascript", "-e", script], capture_output=True, text=True)
|
||||||
|
if r.returncode != 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
out_lines = r.stdout.splitlines()
|
||||||
|
button = out_lines[0].strip() if out_lines else ""
|
||||||
|
value = out_lines[1].strip() if len(out_lines) > 1 else value
|
||||||
|
|
||||||
|
if button == "?":
|
||||||
|
webbrowser.open(_CFWORKER_HELP_URL)
|
||||||
|
continue
|
||||||
|
if button == "OK":
|
||||||
|
return value.strip()
|
||||||
|
|
||||||
|
|
||||||
# menubar icon
|
# menubar icon
|
||||||
|
|
||||||
|
|
||||||
@@ -396,13 +424,6 @@ def _edit_config_dialog() -> None:
|
|||||||
if cfproxy is None:
|
if cfproxy is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
cfproxy_priority = True
|
|
||||||
if cfproxy:
|
|
||||||
cfproxy_priority_result = _ask_yes_no_close("Приоритет CfProxy (пробовать раньше прямого TCP)?")
|
|
||||||
if cfproxy_priority_result is None:
|
|
||||||
return
|
|
||||||
cfproxy_priority = cfproxy_priority_result
|
|
||||||
|
|
||||||
cfproxy_domain = _osascript_input(
|
cfproxy_domain = _osascript_input(
|
||||||
"Свой CF-домен (оставьте пустым для автоматического выбора):\n"
|
"Свой CF-домен (оставьте пустым для автоматического выбора):\n"
|
||||||
"DNS записи kws1-kws5,kws203 должны указывать на IP датацентров Telegram через Cloudflare.",
|
"DNS записи kws1-kws5,kws203 должны указывать на IP датацентров Telegram через Cloudflare.",
|
||||||
@@ -412,6 +433,12 @@ def _edit_config_dialog() -> None:
|
|||||||
return
|
return
|
||||||
cfproxy_domain = cfproxy_domain.strip()
|
cfproxy_domain = cfproxy_domain.strip()
|
||||||
|
|
||||||
|
cfworker_domain = _ask_cfworker_domain(
|
||||||
|
cfg.get("cfproxy_worker_domain", DEFAULT_CONFIG.get("cfproxy_worker_domain", ""))
|
||||||
|
)
|
||||||
|
if cfworker_domain is None:
|
||||||
|
return
|
||||||
|
|
||||||
new_cfg = {
|
new_cfg = {
|
||||||
"host": host,
|
"host": host,
|
||||||
"port": port,
|
"port": port,
|
||||||
@@ -423,8 +450,8 @@ def _edit_config_dialog() -> None:
|
|||||||
"log_max_mb": adv.get("log_max_mb", cfg.get("log_max_mb", DEFAULT_CONFIG["log_max_mb"])),
|
"log_max_mb": adv.get("log_max_mb", cfg.get("log_max_mb", DEFAULT_CONFIG["log_max_mb"])),
|
||||||
"check_updates": cfg.get("check_updates", True),
|
"check_updates": cfg.get("check_updates", True),
|
||||||
"cfproxy": cfproxy,
|
"cfproxy": cfproxy,
|
||||||
"cfproxy_priority": cfproxy_priority,
|
|
||||||
"cfproxy_user_domain": cfproxy_domain,
|
"cfproxy_user_domain": cfproxy_domain,
|
||||||
|
"cfproxy_worker_domain": cfworker_domain,
|
||||||
}
|
}
|
||||||
save_config(new_cfg)
|
save_config(new_cfg)
|
||||||
log.info("Config saved: %s", new_cfg)
|
log.info("Config saved: %s", new_cfg)
|
||||||
|
|||||||
@@ -132,15 +132,16 @@ async def do_fallback(reader, writer, relay_init, label,
|
|||||||
ctx: CryptoCtx, splitter=None):
|
ctx: CryptoCtx, splitter=None):
|
||||||
fallback_dst = DC_DEFAULT_IPS.get(dc)
|
fallback_dst = DC_DEFAULT_IPS.get(dc)
|
||||||
use_cf = proxy_config.fallback_cfproxy
|
use_cf = proxy_config.fallback_cfproxy
|
||||||
cf_first = proxy_config.fallback_cfproxy_priority
|
|
||||||
worker_domain = proxy_config.cfproxy_worker_domain
|
worker_domain = proxy_config.cfproxy_worker_domain
|
||||||
|
|
||||||
methods: List[str] = ['tcp']
|
methods: List[str] = []
|
||||||
|
|
||||||
|
if worker_domain and fallback_dst:
|
||||||
|
methods.append('cf_worker')
|
||||||
if use_cf:
|
if use_cf:
|
||||||
methods.insert(0 if cf_first else 1, 'cf')
|
methods.append('cf')
|
||||||
if worker_domain:
|
if fallback_dst:
|
||||||
methods.insert(0, 'cf_worker')
|
methods.append('tcp')
|
||||||
|
|
||||||
for method in methods:
|
for method in methods:
|
||||||
if method == 'cf_worker' and fallback_dst:
|
if method == 'cf_worker' and fallback_dst:
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ class ProxyConfig:
|
|||||||
buffer_size: int = 256 * 1024
|
buffer_size: int = 256 * 1024
|
||||||
pool_size: int = 4
|
pool_size: int = 4
|
||||||
fallback_cfproxy: bool = True
|
fallback_cfproxy: bool = True
|
||||||
fallback_cfproxy_priority: bool = True
|
|
||||||
cfproxy_user_domain: str = ''
|
cfproxy_user_domain: str = ''
|
||||||
cfproxy_worker_domain: str = ''
|
cfproxy_worker_domain: str = ''
|
||||||
fake_tls_domain: str = ''
|
fake_tls_domain: str = ''
|
||||||
|
|||||||
@@ -587,9 +587,8 @@ async def _run(stop_event: Optional[asyncio.Event] = None):
|
|||||||
ip = proxy_config.dc_redirects.get(dc)
|
ip = proxy_config.dc_redirects.get(dc)
|
||||||
log.info(" DC%d: %s", dc, ip)
|
log.info(" DC%d: %s", dc, ip)
|
||||||
if proxy_config.fallback_cfproxy:
|
if proxy_config.fallback_cfproxy:
|
||||||
prio = 'CF first' if proxy_config.fallback_cfproxy_priority else 'TCP first'
|
|
||||||
user_domain = "user" if proxy_config.cfproxy_user_domain else "auto"
|
user_domain = "user" if proxy_config.cfproxy_user_domain else "auto"
|
||||||
log.info(" CF proxy: enabled (%s | %s)", prio, user_domain)
|
log.info(" CF proxy: enabled (%s)", user_domain)
|
||||||
if proxy_config.cfproxy_worker_domain:
|
if proxy_config.cfproxy_worker_domain:
|
||||||
log.info(" CF worker: enabled (%s)",
|
log.info(" CF worker: enabled (%s)",
|
||||||
proxy_config.cfproxy_worker_domain)
|
proxy_config.cfproxy_worker_domain)
|
||||||
@@ -654,16 +653,6 @@ def run_proxy(stop_event: Optional[asyncio.Event] = None):
|
|||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
def _parse_bool(value: str) -> bool:
|
|
||||||
lowered = value.strip().lower()
|
|
||||||
if lowered == 'true':
|
|
||||||
return True
|
|
||||||
if lowered == 'false':
|
|
||||||
return False
|
|
||||||
raise argparse.ArgumentTypeError(
|
|
||||||
"Expected boolean value: true or false",
|
|
||||||
)
|
|
||||||
|
|
||||||
ap = argparse.ArgumentParser(
|
ap = argparse.ArgumentParser(
|
||||||
description='Telegram MTProto WebSocket Bridge Proxy')
|
description='Telegram MTProto WebSocket Bridge Proxy')
|
||||||
ap.add_argument('--port', type=int, default=1443,
|
ap.add_argument('--port', type=int, default=1443,
|
||||||
@@ -696,8 +685,6 @@ def main():
|
|||||||
'(tried before other fallback methods)')
|
'(tried before other fallback methods)')
|
||||||
ap.add_argument('--no-cfproxy', action='store_true',
|
ap.add_argument('--no-cfproxy', action='store_true',
|
||||||
help='Disable Cloudflare proxy fallback')
|
help='Disable Cloudflare proxy fallback')
|
||||||
ap.add_argument('--cfproxy-priority', type=_parse_bool, default=True,
|
|
||||||
help='Try cfproxy before tcp fallback (default: true)')
|
|
||||||
ap.add_argument('--fake-tls-domain', type=str, default='',
|
ap.add_argument('--fake-tls-domain', type=str, default='',
|
||||||
metavar='DOMAIN',
|
metavar='DOMAIN',
|
||||||
help='Enable Fake TLS (ee-secret) masking with the given '
|
help='Enable Fake TLS (ee-secret) masking with the given '
|
||||||
@@ -737,7 +724,6 @@ def main():
|
|||||||
proxy_config.buffer_size = max(4, args.buf_kb) * 1024
|
proxy_config.buffer_size = max(4, args.buf_kb) * 1024
|
||||||
proxy_config.pool_size = max(0, args.pool_size)
|
proxy_config.pool_size = max(0, args.pool_size)
|
||||||
proxy_config.fallback_cfproxy = not args.no_cfproxy
|
proxy_config.fallback_cfproxy = not args.no_cfproxy
|
||||||
proxy_config.fallback_cfproxy_priority = args.cfproxy_priority
|
|
||||||
proxy_config.cfproxy_user_domain = args.cfproxy_domain.strip()
|
proxy_config.cfproxy_user_domain = args.cfproxy_domain.strip()
|
||||||
proxy_config.cfproxy_worker_domain = args.cfproxy_worker_domain.strip()
|
proxy_config.cfproxy_worker_domain = args.cfproxy_worker_domain.strip()
|
||||||
proxy_config.fake_tls_domain = args.fake_tls_domain.strip()
|
proxy_config.fake_tls_domain = args.fake_tls_domain.strip()
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import webbrowser
|
import webbrowser
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
@@ -17,6 +18,8 @@ from ui.ctk_theme import (
|
|||||||
)
|
)
|
||||||
from ui.ctk_tooltip import attach_ctk_tooltip, attach_tooltip_to_widgets
|
from ui.ctk_tooltip import attach_ctk_tooltip, attach_tooltip_to_widgets
|
||||||
|
|
||||||
|
log = logging.getLogger('tg-mtproto-proxy')
|
||||||
|
|
||||||
_TIP_HOST = (
|
_TIP_HOST = (
|
||||||
"Адрес, на котором прокси принимает подключения.\n"
|
"Адрес, на котором прокси принимает подключения.\n"
|
||||||
"Обычно 127.0.0.1 — локальная сеть, 0.0.0.0 - все интерфейсы"
|
"Обычно 127.0.0.1 — локальная сеть, 0.0.0.0 - все интерфейсы"
|
||||||
@@ -55,9 +58,6 @@ _TIP_CHECK_UPDATES = "При запуске проверять наличие о
|
|||||||
_TIP_CFPROXY = (
|
_TIP_CFPROXY = (
|
||||||
"Использовать Cloudflare прокси для недоступных датацентров"
|
"Использовать Cloudflare прокси для недоступных датацентров"
|
||||||
)
|
)
|
||||||
_TIP_CFPROXY_PRIORITY = (
|
|
||||||
"Пробовать CF-прокси раньше прямого TCP-подключения"
|
|
||||||
)
|
|
||||||
_TIP_CFPROXY_DOMAIN = (
|
_TIP_CFPROXY_DOMAIN = (
|
||||||
"Ваш собственный домен, проксируемый через Cloudflare, для WS-подключения.\n"
|
"Ваш собственный домен, проксируемый через Cloudflare, для WS-подключения.\n"
|
||||||
"Если не указан — выбирается автоматически из поддерживаемых доменов"
|
"Если не указан — выбирается автоматически из поддерживаемых доменов"
|
||||||
@@ -65,14 +65,27 @@ _TIP_CFPROXY_DOMAIN = (
|
|||||||
_TIP_CFPROXY_USER_DOMAIN_CB = (
|
_TIP_CFPROXY_USER_DOMAIN_CB = (
|
||||||
"Указать свой домен вместо автоматического выбора"
|
"Указать свой домен вместо автоматического выбора"
|
||||||
)
|
)
|
||||||
|
_TIP_CFWORKER_DOMAIN = (
|
||||||
|
"Домен Cloudflare Worker (например, name.account.workers.dev).\n"
|
||||||
|
"Прокси передает через него подключение к Telegram DC по IP"
|
||||||
|
)
|
||||||
_TIP_SAVE = "Сохранить настройки"
|
_TIP_SAVE = "Сохранить настройки"
|
||||||
_TIP_CANCEL = "Закрыть окно без сохранения изменений"
|
_TIP_CANCEL = "Закрыть окно без сохранения изменений"
|
||||||
|
|
||||||
_CFPROXY_HELP_URL = "https://github.com/Flowseal/tg-ws-proxy/blob/main/docs/CfProxy.md"
|
_CFPROXY_HELP_URL = "https://github.com/Flowseal/tg-ws-proxy/blob/main/docs/CfProxy.md"
|
||||||
|
_CFWORKER_HELP_URL = "https://github.com/Flowseal/tg-ws-proxy/blob/main/docs/CfWorker.md"
|
||||||
_CFPROXY_TEST_DCS = [1, 2, 3, 4, 5, 203]
|
_CFPROXY_TEST_DCS = [1, 2, 3, 4, 5, 203]
|
||||||
|
_CFWORKER_TEST_DST = {
|
||||||
|
1: '149.154.175.50',
|
||||||
|
2: '149.154.167.51',
|
||||||
|
3: '149.154.175.100',
|
||||||
|
4: '149.154.167.91',
|
||||||
|
5: '149.154.171.5',
|
||||||
|
203: '91.105.192.100',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def _run_cfproxy_connectivity_test(domain: str) -> dict:
|
def _run_connectivity_test(cases: list) -> dict:
|
||||||
import base64
|
import base64
|
||||||
import ssl
|
import ssl
|
||||||
import socket as _socket
|
import socket as _socket
|
||||||
@@ -81,15 +94,14 @@ def _run_cfproxy_connectivity_test(domain: str) -> dict:
|
|||||||
ctx.check_hostname = False
|
ctx.check_hostname = False
|
||||||
ctx.verify_mode = ssl.CERT_NONE
|
ctx.verify_mode = ssl.CERT_NONE
|
||||||
results = {}
|
results = {}
|
||||||
for dc in _CFPROXY_TEST_DCS:
|
for dc, connect_host, sni_host, req_host, path in cases:
|
||||||
host = f"kws{dc}.{domain}"
|
|
||||||
try:
|
try:
|
||||||
with _socket.create_connection((host, 443), timeout=5) as raw:
|
with _socket.create_connection((connect_host, 443), timeout=5) as raw:
|
||||||
with ctx.wrap_socket(raw, server_hostname=host) as ssock:
|
with ctx.wrap_socket(raw, server_hostname=sni_host) as ssock:
|
||||||
ws_key = base64.b64encode(os.urandom(16)).decode()
|
ws_key = base64.b64encode(os.urandom(16)).decode()
|
||||||
req = (
|
req = (
|
||||||
f"GET /apiws HTTP/1.1\r\n"
|
f"GET {path} HTTP/1.1\r\n"
|
||||||
f"Host: {host}\r\n"
|
f"Host: {req_host}\r\n"
|
||||||
f"Upgrade: websocket\r\n"
|
f"Upgrade: websocket\r\n"
|
||||||
f"Connection: Upgrade\r\n"
|
f"Connection: Upgrade\r\n"
|
||||||
f"Sec-WebSocket-Key: {ws_key}\r\n"
|
f"Sec-WebSocket-Key: {ws_key}\r\n"
|
||||||
@@ -120,6 +132,23 @@ def _run_cfproxy_connectivity_test(domain: str) -> dict:
|
|||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
def _run_cfproxy_connectivity_test(domain: str) -> dict:
|
||||||
|
cases = []
|
||||||
|
for dc in _CFPROXY_TEST_DCS:
|
||||||
|
host = f"kws{dc}.{domain}"
|
||||||
|
cases.append((dc, host, host, host, "/apiws"))
|
||||||
|
return _run_connectivity_test(cases)
|
||||||
|
|
||||||
|
|
||||||
|
def _run_cfworker_connectivity_test(domain: str) -> dict:
|
||||||
|
cases = []
|
||||||
|
for dc in _CFPROXY_TEST_DCS:
|
||||||
|
dst = _CFWORKER_TEST_DST[dc]
|
||||||
|
path = f"/apiws?dst={dst}&dc={dc}&media=0"
|
||||||
|
cases.append((dc, domain, domain, domain, path))
|
||||||
|
return _run_connectivity_test(cases)
|
||||||
|
|
||||||
|
|
||||||
def _run_cfproxy_auto_test(domains: list) -> tuple:
|
def _run_cfproxy_auto_test(domains: list) -> tuple:
|
||||||
merged: dict = {}
|
merged: dict = {}
|
||||||
best_domain = None
|
best_domain = None
|
||||||
@@ -136,49 +165,39 @@ def _run_cfproxy_auto_test(domains: list) -> tuple:
|
|||||||
return best_domain, merged
|
return best_domain, merged
|
||||||
|
|
||||||
|
|
||||||
def _cfproxy_show_test_results(domain: str, results: dict) -> None:
|
def _show_connectivity_results(title_base: str, results: dict,
|
||||||
|
domain: str = '', label_prefix: str = 'DC',
|
||||||
|
auto_mode: bool = False,
|
||||||
|
unavailable_message: str = '') -> None:
|
||||||
import tkinter as _tk
|
import tkinter as _tk
|
||||||
from tkinter import messagebox as _mb
|
from tkinter import messagebox as _mb
|
||||||
|
|
||||||
ok = [dc for dc, v in results.items() if v is True]
|
ok = [dc for dc, v in results.items() if v is True]
|
||||||
fail = [(dc, v) for dc, v in results.items() if v is not True]
|
if auto_mode:
|
||||||
if len(ok) == len(_CFPROXY_TEST_DCS):
|
if domain:
|
||||||
title = "CF-прокси: всё работает"
|
title = f"{title_base}: доступен"
|
||||||
msg = f"\u2713 Все {len(_CFPROXY_TEST_DCS)} серверов доступны через {domain}."
|
msg = f"\u2713 {title_base} работает. {len(ok)} из {len(_CFPROXY_TEST_DCS)} серверов доступны."
|
||||||
elif not ok:
|
else:
|
||||||
title = "CF-прокси: недоступен"
|
title = f"{title_base}: недоступен"
|
||||||
msg = f"\u2717 Ни один сервер не отвечает через {domain}.\n\nОшибки:\n"
|
msg = unavailable_message
|
||||||
msg += "\n".join(f" kws{dc}: {v}" for dc, v in fail)
|
|
||||||
else:
|
else:
|
||||||
title = "CF-прокси: частично работает"
|
fail = [(dc, v) for dc, v in results.items() if v is not True]
|
||||||
msg = (
|
if len(ok) == len(_CFPROXY_TEST_DCS):
|
||||||
f"Домен: {domain}\n\n"
|
title = f"{title_base}: всё работает"
|
||||||
f"\u2713 Работают: {', '.join(f'kws{dc}' for dc in ok)}\n\n"
|
msg = f"\u2713 Все {len(_CFPROXY_TEST_DCS)} серверов доступны через {domain}."
|
||||||
f"\u2717 Недоступны:\n"
|
elif not ok:
|
||||||
+ "\n".join(f" kws{dc}: {v}" for dc, v in fail)
|
title = f"{title_base}: недоступен"
|
||||||
)
|
msg = f"\u2717 Ни один сервер не отвечает через {domain}.\n\nОшибки:\n"
|
||||||
root = _tk.Tk()
|
msg += "\n".join(f" {label_prefix}{dc}: {v}" for dc, v in fail)
|
||||||
root.withdraw()
|
else:
|
||||||
try:
|
title = f"{title_base}: частично работает"
|
||||||
root.attributes("-topmost", True)
|
msg = (
|
||||||
except Exception:
|
f"Домен: {domain}\n\n"
|
||||||
pass
|
f"\u2713 Работают: {', '.join(f'{label_prefix}{dc}' for dc in ok)}\n\n"
|
||||||
_mb.showinfo(title, msg, parent=root)
|
f"\u2717 Недоступны:\n"
|
||||||
root.destroy()
|
+ "\n".join(f" {label_prefix}{dc}: {v}" for dc, v in fail)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _cfproxy_show_auto_test_results(ok_domain, results: dict) -> None:
|
|
||||||
import tkinter as _tk
|
|
||||||
from tkinter import messagebox as _mb
|
|
||||||
|
|
||||||
if ok_domain is not None:
|
|
||||||
title = "CF-прокси: доступен"
|
|
||||||
ok = [dc for dc, v in results.items() if v is True]
|
|
||||||
msg = f"\u2713 CF-прокси работает. {len(ok)} из {len(_CFPROXY_TEST_DCS)} серверов доступны."
|
|
||||||
else:
|
|
||||||
title = "CF-прокси: недоступен"
|
|
||||||
msg = "\u2717 Ни один из автоматических CF-доменов не отвечает.\n"
|
|
||||||
msg += "Возможно, блокировка или проблемы с сетью."
|
|
||||||
root = _tk.Tk()
|
root = _tk.Tk()
|
||||||
root.withdraw()
|
root.withdraw()
|
||||||
try:
|
try:
|
||||||
@@ -296,8 +315,8 @@ class TrayConfigFormWidgets:
|
|||||||
autostart_var: Optional[Any]
|
autostart_var: Optional[Any]
|
||||||
check_updates_var: Optional[Any]
|
check_updates_var: Optional[Any]
|
||||||
cfproxy_var: Optional[Any] = None
|
cfproxy_var: Optional[Any] = None
|
||||||
cfproxy_priority_var: Optional[Any] = None
|
|
||||||
cfproxy_user_domain_var: Optional[Any] = None
|
cfproxy_user_domain_var: Optional[Any] = None
|
||||||
|
cfproxy_worker_domain_var: Optional[Any] = None
|
||||||
appearance_var: Optional[Any] = None
|
appearance_var: Optional[Any] = None
|
||||||
|
|
||||||
|
|
||||||
@@ -428,13 +447,6 @@ def install_tray_config_form(
|
|||||||
cf_cb.pack(side="left", padx=(0, 16))
|
cf_cb.pack(side="left", padx=(0, 16))
|
||||||
attach_ctk_tooltip(cf_cb, _TIP_CFPROXY)
|
attach_ctk_tooltip(cf_cb, _TIP_CFPROXY)
|
||||||
|
|
||||||
cfproxy_priority_var = ctk.BooleanVar(
|
|
||||||
value=cfg.get("cfproxy_priority", default_config.get("cfproxy_priority", True))
|
|
||||||
)
|
|
||||||
cf_prio_cb = _checkbox(ctk, cf_row, theme, "Приоритет", cfproxy_priority_var)
|
|
||||||
cf_prio_cb.pack(side="left")
|
|
||||||
attach_ctk_tooltip(cf_prio_cb, _TIP_CFPROXY_PRIORITY)
|
|
||||||
|
|
||||||
_cf_test_btn = [None]
|
_cf_test_btn = [None]
|
||||||
|
|
||||||
def _on_cf_test():
|
def _on_cf_test():
|
||||||
@@ -448,7 +460,12 @@ def install_tray_config_form(
|
|||||||
try:
|
try:
|
||||||
res = _run_cfproxy_connectivity_test(user_domain)
|
res = _run_cfproxy_connectivity_test(user_domain)
|
||||||
if btn:
|
if btn:
|
||||||
btn.after(0, lambda: _cfproxy_show_test_results(user_domain, res))
|
btn.after(
|
||||||
|
0,
|
||||||
|
lambda: _show_connectivity_results(
|
||||||
|
"CF-прокси", res, domain=user_domain, label_prefix='kws',
|
||||||
|
),
|
||||||
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
log.error("CF proxy test failed: %s", exc)
|
log.error("CF proxy test failed: %s", exc)
|
||||||
finally:
|
finally:
|
||||||
@@ -460,7 +477,17 @@ def install_tray_config_form(
|
|||||||
try:
|
try:
|
||||||
ok_domain, res = _run_cfproxy_auto_test(balancer.domains)
|
ok_domain, res = _run_cfproxy_auto_test(balancer.domains)
|
||||||
if btn:
|
if btn:
|
||||||
btn.after(0, lambda: _cfproxy_show_auto_test_results(ok_domain, res))
|
btn.after(
|
||||||
|
0,
|
||||||
|
lambda: _show_connectivity_results(
|
||||||
|
"CF-прокси", res,
|
||||||
|
domain=ok_domain or '',
|
||||||
|
auto_mode=True,
|
||||||
|
unavailable_message=(
|
||||||
|
"\u2717 Ни один из автоматических CF-доменов не отвечает."
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
log.error("CF proxy auto-test failed: %s", exc)
|
log.error("CF proxy auto-test failed: %s", exc)
|
||||||
finally:
|
finally:
|
||||||
@@ -512,6 +539,80 @@ def install_tray_config_form(
|
|||||||
cf_custom_cb_var.trace_add("write", _sync_domain_entry)
|
cf_custom_cb_var.trace_add("write", _sync_domain_entry)
|
||||||
_sync_domain_entry()
|
_sync_domain_entry()
|
||||||
|
|
||||||
|
cf_worker_inner = _config_section(ctk, frame, theme, "Cloudflare Worker")
|
||||||
|
|
||||||
|
cf_worker_row = ctk.CTkFrame(cf_worker_inner, fg_color="transparent")
|
||||||
|
cf_worker_row.pack(fill="x", pady=(0, 4))
|
||||||
|
cf_worker_lbl = _label(ctk, cf_worker_row, theme, "Cloudflare Worker домен", size=11)
|
||||||
|
cf_worker_lbl.pack(anchor="w", pady=(0, 2))
|
||||||
|
|
||||||
|
cf_worker_input = ctk.CTkFrame(cf_worker_inner, fg_color="transparent")
|
||||||
|
cf_worker_input.pack(fill="x")
|
||||||
|
|
||||||
|
cfproxy_worker_domain_var = ctk.StringVar(
|
||||||
|
value=cfg.get("cfproxy_worker_domain", default_config.get("cfproxy_worker_domain", ""))
|
||||||
|
)
|
||||||
|
cf_worker_entry = _entry(
|
||||||
|
ctk, cf_worker_input, theme, var=cfproxy_worker_domain_var,
|
||||||
|
height=32, radius=8,
|
||||||
|
)
|
||||||
|
cf_worker_entry.pack(side="left", fill="x", expand=True, padx=(0, 6))
|
||||||
|
attach_tooltip_to_widgets([cf_worker_lbl, cf_worker_entry], _TIP_CFWORKER_DOMAIN)
|
||||||
|
|
||||||
|
_cfworker_test_btn = [None]
|
||||||
|
|
||||||
|
def _sync_cfworker_test_button(*_):
|
||||||
|
btn = _cfworker_test_btn[0]
|
||||||
|
if btn is None:
|
||||||
|
return
|
||||||
|
enabled = bool(cfproxy_worker_domain_var.get().strip())
|
||||||
|
btn.configure(state="normal" if enabled else "disabled")
|
||||||
|
|
||||||
|
def _on_cfworker_test():
|
||||||
|
domain = cfproxy_worker_domain_var.get().strip()
|
||||||
|
btn = _cfworker_test_btn[0]
|
||||||
|
if not domain or btn is None:
|
||||||
|
return
|
||||||
|
btn.configure(text="...", state="disabled")
|
||||||
|
import threading as _threading
|
||||||
|
|
||||||
|
def _worker():
|
||||||
|
try:
|
||||||
|
res = _run_cfworker_connectivity_test(domain)
|
||||||
|
btn.after(
|
||||||
|
0,
|
||||||
|
lambda: _show_connectivity_results(
|
||||||
|
"CF Worker", res, domain=domain, label_prefix='DC',
|
||||||
|
),
|
||||||
|
)
|
||||||
|
except Exception as exc:
|
||||||
|
log.error("CF worker test failed: %s", exc)
|
||||||
|
finally:
|
||||||
|
btn.after(0, lambda: btn.configure(text="Тест"))
|
||||||
|
btn.after(0, _sync_cfworker_test_button)
|
||||||
|
|
||||||
|
_threading.Thread(target=_worker, daemon=True).start()
|
||||||
|
|
||||||
|
ctk.CTkButton(
|
||||||
|
cf_worker_input, text="?", width=28, height=32,
|
||||||
|
font=(theme.ui_font_family, 14), corner_radius=8,
|
||||||
|
fg_color=theme.tg_blue, hover_color=theme.tg_blue_hover,
|
||||||
|
text_color="#ffffff", border_width=1, border_color=theme.field_border,
|
||||||
|
command=lambda: webbrowser.open(_CFWORKER_HELP_URL),
|
||||||
|
).pack(side="right")
|
||||||
|
|
||||||
|
_cfworker_test_widget = ctk.CTkButton(
|
||||||
|
cf_worker_input, text="Тест", width=56, height=32,
|
||||||
|
font=(theme.ui_font_family, 13), corner_radius=8,
|
||||||
|
fg_color=theme.tg_blue, hover_color=theme.tg_blue_hover,
|
||||||
|
text_color="#ffffff", border_width=1, border_color=theme.field_border,
|
||||||
|
command=_on_cfworker_test,
|
||||||
|
)
|
||||||
|
_cfworker_test_widget.pack(side="right", padx=(0, 6))
|
||||||
|
_cfworker_test_btn[0] = _cfworker_test_widget
|
||||||
|
cfproxy_worker_domain_var.trace_add("write", _sync_cfworker_test_button)
|
||||||
|
_sync_cfworker_test_button()
|
||||||
|
|
||||||
log_inner = _config_section(ctk, frame, theme, "Логи и производительность")
|
log_inner = _config_section(ctk, frame, theme, "Логи и производительность")
|
||||||
|
|
||||||
verbose_var = ctk.BooleanVar(value=cfg.get("verbose", False))
|
verbose_var = ctk.BooleanVar(value=cfg.get("verbose", False))
|
||||||
@@ -601,8 +702,8 @@ def install_tray_config_form(
|
|||||||
adv_entries=adv_entries, adv_keys=adv_keys,
|
adv_entries=adv_entries, adv_keys=adv_keys,
|
||||||
autostart_var=autostart_var, check_updates_var=check_updates_var,
|
autostart_var=autostart_var, check_updates_var=check_updates_var,
|
||||||
cfproxy_var=cfproxy_var,
|
cfproxy_var=cfproxy_var,
|
||||||
cfproxy_priority_var=cfproxy_priority_var,
|
|
||||||
cfproxy_user_domain_var=cfproxy_user_domain_var,
|
cfproxy_user_domain_var=cfproxy_user_domain_var,
|
||||||
|
cfproxy_worker_domain_var=cfproxy_worker_domain_var,
|
||||||
appearance_var=appearance_var,
|
appearance_var=appearance_var,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -682,10 +783,10 @@ def validate_config_form(
|
|||||||
new_cfg["check_updates"] = bool(widgets.check_updates_var.get())
|
new_cfg["check_updates"] = bool(widgets.check_updates_var.get())
|
||||||
if widgets.cfproxy_var is not None:
|
if widgets.cfproxy_var is not None:
|
||||||
new_cfg["cfproxy"] = bool(widgets.cfproxy_var.get())
|
new_cfg["cfproxy"] = bool(widgets.cfproxy_var.get())
|
||||||
if widgets.cfproxy_priority_var is not None:
|
|
||||||
new_cfg["cfproxy_priority"] = bool(widgets.cfproxy_priority_var.get())
|
|
||||||
if widgets.cfproxy_user_domain_var is not None:
|
if widgets.cfproxy_user_domain_var is not None:
|
||||||
new_cfg["cfproxy_user_domain"] = widgets.cfproxy_user_domain_var.get().strip()
|
new_cfg["cfproxy_user_domain"] = widgets.cfproxy_user_domain_var.get().strip()
|
||||||
|
if widgets.cfproxy_worker_domain_var is not None:
|
||||||
|
new_cfg["cfproxy_worker_domain"] = widgets.cfproxy_worker_domain_var.get().strip()
|
||||||
if widgets.appearance_var is not None:
|
if widgets.appearance_var is not None:
|
||||||
new_cfg["appearance"] = _APPEARANCE_TO_CFG.get(widgets.appearance_var.get(), "auto")
|
new_cfg["appearance"] = _APPEARANCE_TO_CFG.get(widgets.appearance_var.get(), "auto")
|
||||||
return new_cfg
|
return new_cfg
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ _TRAY_DEFAULTS_COMMON: Dict[str, Any] = {
|
|||||||
"buf_kb": 256,
|
"buf_kb": 256,
|
||||||
"pool_size": 4,
|
"pool_size": 4,
|
||||||
"cfproxy": True,
|
"cfproxy": True,
|
||||||
"cfproxy_priority": True,
|
|
||||||
"cfproxy_user_domain": "",
|
"cfproxy_user_domain": "",
|
||||||
"cfproxy_worker_domain": "",
|
"cfproxy_worker_domain": "",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -271,7 +271,6 @@ def apply_proxy_config(cfg: dict) -> bool:
|
|||||||
pc.buffer_size = max(4, cfg.get("buf_kb", DEFAULT_CONFIG["buf_kb"])) * 1024
|
pc.buffer_size = max(4, cfg.get("buf_kb", DEFAULT_CONFIG["buf_kb"])) * 1024
|
||||||
pc.pool_size = max(0, cfg.get("pool_size", DEFAULT_CONFIG["pool_size"]))
|
pc.pool_size = max(0, cfg.get("pool_size", DEFAULT_CONFIG["pool_size"]))
|
||||||
pc.fallback_cfproxy = cfg.get("cfproxy", DEFAULT_CONFIG["cfproxy"])
|
pc.fallback_cfproxy = cfg.get("cfproxy", DEFAULT_CONFIG["cfproxy"])
|
||||||
pc.fallback_cfproxy_priority = cfg.get("cfproxy_priority", DEFAULT_CONFIG["cfproxy_priority"])
|
|
||||||
pc.cfproxy_user_domain = cfg.get("cfproxy_user_domain", DEFAULT_CONFIG["cfproxy_user_domain"])
|
pc.cfproxy_user_domain = cfg.get("cfproxy_user_domain", DEFAULT_CONFIG["cfproxy_user_domain"])
|
||||||
pc.cfproxy_worker_domain = cfg.get("cfproxy_worker_domain", DEFAULT_CONFIG["cfproxy_worker_domain"])
|
pc.cfproxy_worker_domain = cfg.get("cfproxy_worker_domain", DEFAULT_CONFIG["cfproxy_worker_domain"])
|
||||||
return True
|
return True
|
||||||
|
|||||||
Reference in New Issue
Block a user