mirror of
https://github.com/Flowseal/tg-ws-proxy.git
synced 2026-05-22 23:41:44 +03:00
multiple domains handling
This commit is contained in:
1
.github/cfproxy-domains.txt
vendored
Normal file
1
.github/cfproxy-domains.txt
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
virkgj.com
|
||||||
9
macos.py
9
macos.py
@@ -404,10 +404,9 @@ def _edit_config_dialog() -> None:
|
|||||||
cfproxy_priority = cfproxy_priority_result
|
cfproxy_priority = cfproxy_priority_result
|
||||||
|
|
||||||
cfproxy_domain = _osascript_input(
|
cfproxy_domain = _osascript_input(
|
||||||
"Домен CF-прокси:\n"
|
"Свой CF-домен (оставьте пустым для автоматического выбора):\n"
|
||||||
"DNS записи kws1-kws5,kws203 должны указывать на IP датацентров Telegram через Cloudflare.\n"
|
"DNS записи kws1-kws5,kws203 должны указывать на IP датацентров Telegram через Cloudflare.",
|
||||||
"pclead.co.uk готовый настроенный домен. Подробнее про настройку читайте в репозитории - docs/CfProxy.md",
|
cfg.get("cfproxy_user_domain", DEFAULT_CONFIG.get("cfproxy_user_domain", "")),
|
||||||
cfg.get("cfproxy_domain", DEFAULT_CONFIG.get("cfproxy_domain", "pclead.co.uk")),
|
|
||||||
)
|
)
|
||||||
if cfproxy_domain is None:
|
if cfproxy_domain is None:
|
||||||
return
|
return
|
||||||
@@ -425,7 +424,7 @@ def _edit_config_dialog() -> None:
|
|||||||
"check_updates": cfg.get("check_updates", True),
|
"check_updates": cfg.get("check_updates", True),
|
||||||
"cfproxy": cfproxy,
|
"cfproxy": cfproxy,
|
||||||
"cfproxy_priority": cfproxy_priority,
|
"cfproxy_priority": cfproxy_priority,
|
||||||
"cfproxy_domain": cfproxy_domain or DEFAULT_CONFIG.get("cfproxy_domain", "pclead.co.uk"),
|
"cfproxy_user_domain": cfproxy_domain,
|
||||||
}
|
}
|
||||||
save_config(new_cfg)
|
save_config(new_cfg)
|
||||||
log.info("Config saved: %s", new_cfg)
|
log.info("Config saved: %s", new_cfg)
|
||||||
|
|||||||
@@ -161,22 +161,33 @@ async def _cfproxy_fallback(reader, writer, relay_init, label,
|
|||||||
clt_decryptor=None, clt_encryptor=None,
|
clt_decryptor=None, clt_encryptor=None,
|
||||||
tg_encryptor=None, tg_decryptor=None,
|
tg_encryptor=None, tg_decryptor=None,
|
||||||
splitter=None):
|
splitter=None):
|
||||||
domain = f'kws{dc}.{proxy_config.fallback_cfproxy_domain}'
|
|
||||||
media_tag = ' media' if is_media else ''
|
media_tag = ' media' if is_media else ''
|
||||||
ws = None
|
|
||||||
|
|
||||||
log.info("[%s] DC%d%s -> CF proxy wss://%s/apiws",
|
active = proxy_config.active_cfproxy_domain
|
||||||
label, dc, media_tag, domain)
|
others = [d for d in proxy_config.cfproxy_domains if d != active]
|
||||||
try:
|
|
||||||
ws = await RawWebSocket.connect(domain, domain,
|
ws = None
|
||||||
timeout=10.0)
|
chosen_domain = None
|
||||||
except Exception as exc:
|
|
||||||
log.warning("[%s] DC%d%s CF proxy %s failed: %s",
|
for base_domain in ([active] + others):
|
||||||
label, dc, media_tag, domain, exc)
|
domain = f'kws{dc}.{base_domain}'
|
||||||
|
log.info("[%s] DC%d%s -> CF proxy wss",
|
||||||
|
label, dc, media_tag)
|
||||||
|
try:
|
||||||
|
ws = await RawWebSocket.connect(domain, domain, timeout=10.0)
|
||||||
|
chosen_domain = base_domain
|
||||||
|
break
|
||||||
|
except Exception as exc:
|
||||||
|
log.warning("[%s] DC%d%s CF proxy failed: %s",
|
||||||
|
label, dc, media_tag, exc)
|
||||||
|
|
||||||
if ws is None:
|
if ws is None:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
if chosen_domain and chosen_domain != proxy_config.active_cfproxy_domain:
|
||||||
|
log.info("[%s] Switching active CF domain", label)
|
||||||
|
proxy_config.active_cfproxy_domain = chosen_domain
|
||||||
|
|
||||||
stats.connections_cfproxy += 1
|
stats.connections_cfproxy += 1
|
||||||
await ws.send(relay_init)
|
await ws.send(relay_init)
|
||||||
await bridge_ws_reencrypt(reader, writer, ws, label,
|
await bridge_ws_reencrypt(reader, writer, ws, label,
|
||||||
|
|||||||
@@ -1,8 +1,36 @@
|
|||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import random
|
||||||
import socket as _socket
|
import socket as _socket
|
||||||
|
import threading
|
||||||
|
|
||||||
from typing import Dict, List
|
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
|
from typing import Dict, List
|
||||||
|
from urllib.request import Request, urlopen
|
||||||
|
|
||||||
|
log = logging.getLogger('tg-mtproto-proxy')
|
||||||
|
|
||||||
|
CFPROXY_DOMAINS_URL = (
|
||||||
|
"https://raw.githubusercontent.com/Flowseal/tg-ws-proxy/main"
|
||||||
|
"/.github/cfproxy-domains.txt"
|
||||||
|
)
|
||||||
|
|
||||||
|
_CFPROXY_ENC: List[str] = ['virkgj.com']
|
||||||
|
_S = ''.join(chr(c) for c in (46, 99, 111, 46, 117, 107))
|
||||||
|
|
||||||
|
|
||||||
|
def _dd(s: str) -> str:
|
||||||
|
"""Only for decoding CF proxy domains"""
|
||||||
|
if not s[-4:] == '.com':
|
||||||
|
return s
|
||||||
|
p, n = s[:-4], sum(c.isalpha() for c in s[:-4])
|
||||||
|
return ''.join(
|
||||||
|
chr((ord(c) - (97 if c > '`' else 65) - n) % 26 + (97 if c > '`' else 65))
|
||||||
|
if c.isalpha() else c for c in p
|
||||||
|
) + _S
|
||||||
|
|
||||||
|
|
||||||
|
CFPROXY_DEFAULT_DOMAINS: List[str] = [_dd(d) for d in _CFPROXY_ENC]
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -15,12 +43,54 @@ class ProxyConfig:
|
|||||||
pool_size: int = 4
|
pool_size: int = 4
|
||||||
fallback_cfproxy: bool = True
|
fallback_cfproxy: bool = True
|
||||||
fallback_cfproxy_priority: bool = True
|
fallback_cfproxy_priority: bool = True
|
||||||
fallback_cfproxy_domain: str = 'pclead.co.uk'
|
cfproxy_user_domain: str = ''
|
||||||
|
cfproxy_domains: List[str] = field(default_factory=lambda: list(CFPROXY_DEFAULT_DOMAINS))
|
||||||
|
active_cfproxy_domain: str = field(default_factory=lambda: random.choice(CFPROXY_DEFAULT_DOMAINS))
|
||||||
|
|
||||||
|
|
||||||
proxy_config = ProxyConfig()
|
proxy_config = ProxyConfig()
|
||||||
|
|
||||||
|
|
||||||
|
def _fetch_cfproxy_domain_list() -> List[str]:
|
||||||
|
try:
|
||||||
|
req = Request(CFPROXY_DOMAINS_URL, headers={'User-Agent': 'tg-ws-proxy'})
|
||||||
|
with urlopen(req, timeout=10) as resp:
|
||||||
|
text = resp.read().decode('utf-8', errors='replace')
|
||||||
|
encoded = [
|
||||||
|
line.strip() for line in text.splitlines()
|
||||||
|
if line.strip() and not line.startswith('#')
|
||||||
|
]
|
||||||
|
return [_dd(d) for d in encoded]
|
||||||
|
except Exception as exc:
|
||||||
|
log.warning("Failed to fetch CF proxy domain list: %s", exc)
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def refresh_cfproxy_domains() -> None:
|
||||||
|
if proxy_config.cfproxy_user_domain:
|
||||||
|
return
|
||||||
|
|
||||||
|
fetched = _fetch_cfproxy_domain_list()
|
||||||
|
|
||||||
|
if fetched:
|
||||||
|
seen = set()
|
||||||
|
pool = [d for d in fetched if not (d in seen or seen.add(d))]
|
||||||
|
log.info("CF proxy domain pool updated from GitHub (%d domains)", len(pool))
|
||||||
|
else:
|
||||||
|
pool = list(proxy_config.cfproxy_domains) or list(CFPROXY_DEFAULT_DOMAINS)
|
||||||
|
|
||||||
|
proxy_config.cfproxy_domains = pool
|
||||||
|
proxy_config.active_cfproxy_domain = random.choice(pool)
|
||||||
|
|
||||||
|
|
||||||
|
def start_cfproxy_domain_refresh() -> None:
|
||||||
|
threading.Thread(
|
||||||
|
target=refresh_cfproxy_domains,
|
||||||
|
daemon=True,
|
||||||
|
name='cfproxy-domains-refresh',
|
||||||
|
).start()
|
||||||
|
|
||||||
|
|
||||||
def parse_dc_ip_list(dc_ip_list: List[str]) -> Dict[int, str]:
|
def parse_dc_ip_list(dc_ip_list: List[str]) -> Dict[int, str]:
|
||||||
dc_redirects: Dict[int, str] = {}
|
dc_redirects: Dict[int, str] = {}
|
||||||
for entry in dc_ip_list:
|
for entry in dc_ip_list:
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import struct
|
import struct
|
||||||
|
import random
|
||||||
import asyncio
|
import asyncio
|
||||||
import hashlib
|
import hashlib
|
||||||
import argparse
|
import argparse
|
||||||
@@ -24,7 +25,7 @@ if __name__ == '__main__' and (__package__ is None or __package__ == ''):
|
|||||||
|
|
||||||
from .utils import *
|
from .utils import *
|
||||||
from .stats import stats
|
from .stats import stats
|
||||||
from .config import proxy_config, parse_dc_ip_list
|
from .config import proxy_config, parse_dc_ip_list, start_cfproxy_domain_refresh, CFPROXY_DEFAULT_DOMAINS
|
||||||
from .bridge import MsgSplitter, do_fallback, bridge_ws_reencrypt
|
from .bridge import MsgSplitter, do_fallback, bridge_ws_reencrypt
|
||||||
from .raw_websocket import RawWebSocket, WsHandshakeError, set_sock_opts
|
from .raw_websocket import RawWebSocket, WsHandshakeError, set_sock_opts
|
||||||
|
|
||||||
@@ -445,6 +446,16 @@ async def _run(stop_event: Optional[asyncio.Event] = None):
|
|||||||
ws_blacklist.clear()
|
ws_blacklist.clear()
|
||||||
dc_fail_until.clear()
|
dc_fail_until.clear()
|
||||||
|
|
||||||
|
if proxy_config.fallback_cfproxy:
|
||||||
|
user = proxy_config.cfproxy_user_domain
|
||||||
|
if user:
|
||||||
|
proxy_config.cfproxy_domains = [user]
|
||||||
|
proxy_config.active_cfproxy_domain = user
|
||||||
|
else:
|
||||||
|
proxy_config.cfproxy_domains = list(CFPROXY_DEFAULT_DOMAINS)
|
||||||
|
proxy_config.active_cfproxy_domain = random.choice(CFPROXY_DEFAULT_DOMAINS)
|
||||||
|
start_cfproxy_domain_refresh()
|
||||||
|
|
||||||
secret_bytes = bytes.fromhex(proxy_config.secret)
|
secret_bytes = bytes.fromhex(proxy_config.secret)
|
||||||
|
|
||||||
def client_cb(r, w):
|
def client_cb(r, w):
|
||||||
@@ -472,8 +483,8 @@ async def _run(stop_event: Optional[asyncio.Event] = None):
|
|||||||
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'
|
prio = 'CF first' if proxy_config.fallback_cfproxy_priority else 'TCP first'
|
||||||
log.info(" CF proxy: %s (%s)",
|
user_domain = "user" if proxy_config.cfproxy_user_domain else "auto"
|
||||||
proxy_config.fallback_cfproxy_domain, prio)
|
log.info(" CF proxy: enabled (%s | %s)", prio, user_domain)
|
||||||
log.info("=" * 60)
|
log.info("=" * 60)
|
||||||
log.info(" Connect link:")
|
log.info(" Connect link:")
|
||||||
log.info(" %s", tg_link)
|
log.info(" %s", tg_link)
|
||||||
@@ -557,10 +568,9 @@ def main():
|
|||||||
help='Socket send/recv buffer size in KB (default 256)')
|
help='Socket send/recv buffer size in KB (default 256)')
|
||||||
ap.add_argument('--pool-size', type=int, default=4, metavar='N',
|
ap.add_argument('--pool-size', type=int, default=4, metavar='N',
|
||||||
help='WS connection pool size per DC (default 4, min 0)')
|
help='WS connection pool size per DC (default 4, min 0)')
|
||||||
ap.add_argument('--cfproxy-domain', type=str, default='pclead.co.uk',
|
ap.add_argument('--cfproxy-domain', type=str, default='',
|
||||||
metavar='DOMAIN',
|
metavar='DOMAIN',
|
||||||
help='Cloudflare-proxied domain for WS fallback '
|
help='User defined Cloudflare-proxied domain for WS fallback')
|
||||||
'(default: pclead.co.uk)')
|
|
||||||
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=bool, default=True,
|
ap.add_argument('--cfproxy-priority', type=bool, default=True,
|
||||||
@@ -598,7 +608,7 @@ def main():
|
|||||||
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.fallback_cfproxy_priority = args.cfproxy_priority
|
||||||
proxy_config.fallback_cfproxy_domain = args.cfproxy_domain
|
proxy_config.cfproxy_user_domain = args.cfproxy_domain
|
||||||
|
|
||||||
log_level = logging.DEBUG if args.verbose else logging.INFO
|
log_level = logging.DEBUG if args.verbose else logging.INFO
|
||||||
log_fmt = logging.Formatter('%(asctime)s %(levelname)-5s %(message)s',
|
log_fmt = logging.Formatter('%(asctime)s %(levelname)-5s %(message)s',
|
||||||
|
|||||||
@@ -6,8 +6,10 @@ from dataclasses import dataclass
|
|||||||
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
||||||
|
|
||||||
from proxy import __version__, get_link_host, parse_dc_ip_list
|
from proxy import __version__, get_link_host, parse_dc_ip_list
|
||||||
|
from proxy.config import CFPROXY_DEFAULT_DOMAINS
|
||||||
from utils.update_check import RELEASES_PAGE_URL, get_status
|
from utils.update_check import RELEASES_PAGE_URL, get_status
|
||||||
|
|
||||||
|
|
||||||
from ui.ctk_theme import (
|
from ui.ctk_theme import (
|
||||||
FIRST_RUN_FRAME_PAD,
|
FIRST_RUN_FRAME_PAD,
|
||||||
CtkTheme,
|
CtkTheme,
|
||||||
@@ -57,7 +59,11 @@ _TIP_CFPROXY_PRIORITY = (
|
|||||||
"Пробовать CF-прокси раньше прямого TCP-подключения"
|
"Пробовать CF-прокси раньше прямого TCP-подключения"
|
||||||
)
|
)
|
||||||
_TIP_CFPROXY_DOMAIN = (
|
_TIP_CFPROXY_DOMAIN = (
|
||||||
"Домен, проксируемый через Cloudflare, для WS-подключения"
|
"Ваш собственный домен, проксируемый через Cloudflare, для WS-подключения.\n"
|
||||||
|
"Если не указан — выбирается автоматически из поддерживаемых доменов"
|
||||||
|
)
|
||||||
|
_TIP_CFPROXY_USER_DOMAIN_CB = (
|
||||||
|
"Указать свой домен вместо автоматического выбора"
|
||||||
)
|
)
|
||||||
_TIP_SAVE = "Сохранить настройки"
|
_TIP_SAVE = "Сохранить настройки"
|
||||||
_TIP_CANCEL = "Закрыть окно без сохранения изменений"
|
_TIP_CANCEL = "Закрыть окно без сохранения изменений"
|
||||||
@@ -114,6 +120,16 @@ def _run_cfproxy_connectivity_test(domain: str) -> dict:
|
|||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
def _run_cfproxy_auto_test(domains: list) -> tuple:
|
||||||
|
last: dict = {}
|
||||||
|
for domain in domains:
|
||||||
|
res = _run_cfproxy_connectivity_test(domain)
|
||||||
|
last = res
|
||||||
|
if any(v is True for v in res.values()):
|
||||||
|
return domain, res
|
||||||
|
return None, last
|
||||||
|
|
||||||
|
|
||||||
def _cfproxy_show_test_results(domain: str, results: dict) -> None:
|
def _cfproxy_show_test_results(domain: str, results: dict) -> None:
|
||||||
import tkinter as _tk
|
import tkinter as _tk
|
||||||
from tkinter import messagebox as _mb
|
from tkinter import messagebox as _mb
|
||||||
@@ -144,6 +160,28 @@ def _cfproxy_show_test_results(domain: str, results: dict) -> None:
|
|||||||
_mb.showinfo(title, msg, parent=root)
|
_mb.showinfo(title, msg, parent=root)
|
||||||
root.destroy()
|
root.destroy()
|
||||||
|
|
||||||
|
|
||||||
|
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.withdraw()
|
||||||
|
try:
|
||||||
|
root.attributes("-topmost", True)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
_mb.showinfo(title, msg, parent=root)
|
||||||
|
root.destroy()
|
||||||
|
|
||||||
_INNER_W = 396
|
_INNER_W = 396
|
||||||
|
|
||||||
_APPEARANCE_OPTIONS = ["Авто", "Светлая", "Тёмная"]
|
_APPEARANCE_OPTIONS = ["Авто", "Светлая", "Тёмная"]
|
||||||
@@ -253,7 +291,7 @@ class TrayConfigFormWidgets:
|
|||||||
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_priority_var: Optional[Any] = None
|
||||||
cfproxy_domain_var: Optional[Any] = None
|
cfproxy_user_domain_var: Optional[Any] = None
|
||||||
appearance_var: Optional[Any] = None
|
appearance_var: Optional[Any] = None
|
||||||
|
|
||||||
|
|
||||||
@@ -363,7 +401,7 @@ def install_tray_config_form(
|
|||||||
cf_inner = _config_section(ctk, frame, theme, "Cloudflare Proxy")
|
cf_inner = _config_section(ctk, frame, theme, "Cloudflare Proxy")
|
||||||
|
|
||||||
cf_row = ctk.CTkFrame(cf_inner, fg_color="transparent")
|
cf_row = ctk.CTkFrame(cf_inner, fg_color="transparent")
|
||||||
cf_row.pack(fill="x", pady=(0, 6))
|
cf_row.pack(fill="x", pady=(0, 4))
|
||||||
|
|
||||||
cfproxy_var = ctk.BooleanVar(
|
cfproxy_var = ctk.BooleanVar(
|
||||||
value=cfg.get("cfproxy", default_config.get("cfproxy", True))
|
value=cfg.get("cfproxy", default_config.get("cfproxy", True))
|
||||||
@@ -375,60 +413,76 @@ def install_tray_config_form(
|
|||||||
cfproxy_priority_var = ctk.BooleanVar(
|
cfproxy_priority_var = ctk.BooleanVar(
|
||||||
value=cfg.get("cfproxy_priority", default_config.get("cfproxy_priority", True))
|
value=cfg.get("cfproxy_priority", default_config.get("cfproxy_priority", True))
|
||||||
)
|
)
|
||||||
cf_prio_cb = _checkbox(ctk, cf_row, theme, "Приоритет CF-прокси", cfproxy_priority_var)
|
cf_prio_cb = _checkbox(ctk, cf_row, theme, "Приоритет", cfproxy_priority_var)
|
||||||
cf_prio_cb.pack(side="left")
|
cf_prio_cb.pack(side="left")
|
||||||
attach_ctk_tooltip(cf_prio_cb, _TIP_CFPROXY_PRIORITY)
|
attach_ctk_tooltip(cf_prio_cb, _TIP_CFPROXY_PRIORITY)
|
||||||
|
|
||||||
cf_domain_row = ctk.CTkFrame(cf_inner, fg_color="transparent")
|
|
||||||
cf_domain_row.pack(fill="x")
|
|
||||||
|
|
||||||
cf_domain_col, cfproxy_domain_var = _labeled_entry(
|
|
||||||
ctk, cf_domain_row, theme, "Домен",
|
|
||||||
cfg.get("cfproxy_domain", default_config.get("cfproxy_domain", "pclead.co.uk")),
|
|
||||||
tip=_TIP_CFPROXY_DOMAIN, width=160, pack_fill=True,
|
|
||||||
)
|
|
||||||
cf_domain_col.pack(side="left", fill="x", expand=True, padx=(0, 10))
|
|
||||||
|
|
||||||
_cf_test_btn = [None]
|
_cf_test_btn = [None]
|
||||||
|
|
||||||
def _on_cf_test():
|
def _on_cf_test():
|
||||||
domain = cfproxy_domain_var.get().strip()
|
user_domain = cfproxy_user_domain_var.get().strip() if cf_custom_cb_var.get() else ""
|
||||||
if not domain:
|
|
||||||
return
|
|
||||||
btn = _cf_test_btn[0]
|
btn = _cf_test_btn[0]
|
||||||
if btn:
|
if btn:
|
||||||
btn.configure(text="...", state="disabled")
|
btn.configure(text="...", state="disabled")
|
||||||
import threading as _threading
|
import threading as _threading
|
||||||
def _worker():
|
if user_domain:
|
||||||
res = _run_cfproxy_connectivity_test(domain)
|
def _worker():
|
||||||
if btn:
|
res = _run_cfproxy_connectivity_test(user_domain)
|
||||||
btn.after(0, lambda: btn.configure(text="Тест", state="normal"))
|
if btn:
|
||||||
btn.after(0, lambda: _cfproxy_show_test_results(domain, res))
|
btn.after(0, lambda: btn.configure(text="Тест", state="normal"))
|
||||||
_threading.Thread(target=_worker, daemon=True).start()
|
btn.after(0, lambda: _cfproxy_show_test_results(user_domain, res))
|
||||||
|
_threading.Thread(target=_worker, daemon=True).start()
|
||||||
|
else:
|
||||||
|
def _worker_auto():
|
||||||
|
ok_domain, res = _run_cfproxy_auto_test(CFPROXY_DEFAULT_DOMAINS)
|
||||||
|
if btn:
|
||||||
|
btn.after(0, lambda: btn.configure(text="Тест", state="normal"))
|
||||||
|
btn.after(0, lambda: _cfproxy_show_auto_test_results(ok_domain, res))
|
||||||
|
_threading.Thread(target=_worker_auto, daemon=True).start()
|
||||||
|
|
||||||
cf_test_col = ctk.CTkFrame(cf_domain_row, fg_color="transparent")
|
|
||||||
cf_test_col.pack(side="left", anchor="s", padx=(0, 6))
|
|
||||||
ctk.CTkLabel(cf_test_col, text="", font=(theme.ui_font_family, 12)).pack(pady=(0, 2))
|
|
||||||
_cf_test_widget = ctk.CTkButton(
|
_cf_test_widget = ctk.CTkButton(
|
||||||
cf_test_col, text="Тест", width=56, height=36,
|
cf_row, text="Тест", width=56, height=28,
|
||||||
font=(theme.ui_font_family, 13), corner_radius=10,
|
font=(theme.ui_font_family, 13), corner_radius=8,
|
||||||
fg_color=theme.tg_blue, hover_color=theme.tg_blue_hover,
|
fg_color=theme.tg_blue, hover_color=theme.tg_blue_hover,
|
||||||
text_color="#ffffff", border_width=1, border_color=theme.field_border,
|
text_color="#ffffff", border_width=1, border_color=theme.field_border,
|
||||||
command=_on_cf_test,
|
command=_on_cf_test,
|
||||||
)
|
)
|
||||||
_cf_test_widget.pack()
|
_cf_test_widget.pack(side="right")
|
||||||
_cf_test_btn[0] = _cf_test_widget
|
_cf_test_btn[0] = _cf_test_widget
|
||||||
|
|
||||||
cf_help_col = ctk.CTkFrame(cf_domain_row, fg_color="transparent")
|
cf_custom_row = ctk.CTkFrame(cf_inner, fg_color="transparent")
|
||||||
cf_help_col.pack(side="left", anchor="s")
|
cf_custom_row.pack(fill="x")
|
||||||
ctk.CTkLabel(cf_help_col, text="", font=(theme.ui_font_family, 12)).pack(pady=(0, 2))
|
|
||||||
|
saved_user_domain = cfg.get("cfproxy_user_domain", default_config.get("cfproxy_user_domain", ""))
|
||||||
|
cf_custom_cb_var = ctk.BooleanVar(value=bool(saved_user_domain))
|
||||||
|
cf_custom_cb = _checkbox(ctk, cf_custom_row, theme, "Свой домен", cf_custom_cb_var)
|
||||||
|
cf_custom_cb.pack(side="left", padx=(0, 10))
|
||||||
|
attach_ctk_tooltip(cf_custom_cb, _TIP_CFPROXY_USER_DOMAIN_CB)
|
||||||
|
|
||||||
ctk.CTkButton(
|
ctk.CTkButton(
|
||||||
cf_help_col, text="?", width=36, height=36,
|
cf_custom_row, text="?", width=28, height=32,
|
||||||
font=(theme.ui_font_family, 18), corner_radius=10,
|
font=(theme.ui_font_family, 14), corner_radius=8,
|
||||||
fg_color=theme.tg_blue, hover_color=theme.tg_blue_hover,
|
fg_color=theme.tg_blue, hover_color=theme.tg_blue_hover,
|
||||||
text_color="#ffffff", border_width=1, border_color=theme.field_border,
|
text_color="#ffffff", border_width=1, border_color=theme.field_border,
|
||||||
command=lambda: webbrowser.open(_CFPROXY_HELP_URL),
|
command=lambda: webbrowser.open(_CFPROXY_HELP_URL),
|
||||||
).pack()
|
).pack(side="right")
|
||||||
|
|
||||||
|
cfproxy_user_domain_var = ctk.StringVar(value=saved_user_domain)
|
||||||
|
cf_domain_entry = _entry(
|
||||||
|
ctk, cf_custom_row, theme, var=cfproxy_user_domain_var,
|
||||||
|
height=32, radius=8,
|
||||||
|
)
|
||||||
|
cf_domain_entry.pack(side="left", fill="x", expand=True, padx=(0, 6))
|
||||||
|
attach_ctk_tooltip(cf_domain_entry, _TIP_CFPROXY_DOMAIN)
|
||||||
|
|
||||||
|
def _sync_domain_entry(*_):
|
||||||
|
state = "normal" if cf_custom_cb_var.get() else "disabled"
|
||||||
|
cf_domain_entry.configure(state=state)
|
||||||
|
if not cf_custom_cb_var.get():
|
||||||
|
cfproxy_user_domain_var.set("")
|
||||||
|
|
||||||
|
cf_custom_cb_var.trace_add("write", _sync_domain_entry)
|
||||||
|
_sync_domain_entry()
|
||||||
|
|
||||||
log_inner = _config_section(ctk, frame, theme, "Логи и производительность")
|
log_inner = _config_section(ctk, frame, theme, "Логи и производительность")
|
||||||
|
|
||||||
@@ -520,7 +574,7 @@ def install_tray_config_form(
|
|||||||
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_priority_var=cfproxy_priority_var,
|
||||||
cfproxy_domain_var=cfproxy_domain_var,
|
cfproxy_user_domain_var=cfproxy_user_domain_var,
|
||||||
appearance_var=appearance_var,
|
appearance_var=appearance_var,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -602,10 +656,8 @@ def validate_config_form(
|
|||||||
new_cfg["cfproxy"] = bool(widgets.cfproxy_var.get())
|
new_cfg["cfproxy"] = bool(widgets.cfproxy_var.get())
|
||||||
if widgets.cfproxy_priority_var is not None:
|
if widgets.cfproxy_priority_var is not None:
|
||||||
new_cfg["cfproxy_priority"] = bool(widgets.cfproxy_priority_var.get())
|
new_cfg["cfproxy_priority"] = bool(widgets.cfproxy_priority_var.get())
|
||||||
if widgets.cfproxy_domain_var is not None:
|
if widgets.cfproxy_user_domain_var is not None:
|
||||||
domain = widgets.cfproxy_domain_var.get().strip()
|
new_cfg["cfproxy_user_domain"] = widgets.cfproxy_user_domain_var.get().strip()
|
||||||
if domain:
|
|
||||||
new_cfg["cfproxy_domain"] = domain
|
|
||||||
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
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ _TRAY_DEFAULTS_COMMON: Dict[str, Any] = {
|
|||||||
"pool_size": 4,
|
"pool_size": 4,
|
||||||
"cfproxy": True,
|
"cfproxy": True,
|
||||||
"cfproxy_priority": True,
|
"cfproxy_priority": True,
|
||||||
"cfproxy_domain": "pclead.co.uk",
|
"cfproxy_user_domain": "",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -271,7 +271,7 @@ def apply_proxy_config(cfg: dict) -> bool:
|
|||||||
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.fallback_cfproxy_priority = cfg.get("cfproxy_priority", DEFAULT_CONFIG["cfproxy_priority"])
|
||||||
pc.fallback_cfproxy_domain = cfg.get("cfproxy_domain", DEFAULT_CONFIG["cfproxy_domain"])
|
pc.cfproxy_user_domain = cfg.get("cfproxy_user_domain", DEFAULT_CONFIG["cfproxy_user_domain"])
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user