Upload 12 files
Browse files- colab_tunnel/__init__.py +4 -1
- colab_tunnel/_diagnostics.py +48 -26
- colab_tunnel/_registry.py +72 -10
- colab_tunnel/_tunnels.py +1 -1
colab_tunnel/__init__.py
CHANGED
|
@@ -25,7 +25,7 @@ from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
| 25 |
|
| 26 |
from ._config import WORK_FOLDER
|
| 27 |
from ._logger import logger
|
| 28 |
-
from ._registry import proxies_functions, tunnel_provider
|
| 29 |
from ._utils import run, download
|
| 30 |
|
| 31 |
# Импорт модулей регистрирует провайдеров через @tunnel_provider
|
|
@@ -63,6 +63,9 @@ __all__ = [
|
|
| 63 |
'benchmark',
|
| 64 |
'TunnelBenchmarkResult',
|
| 65 |
# Реестр (для расширения)
|
|
|
|
|
|
|
|
|
|
| 66 |
'proxies_functions',
|
| 67 |
'tunnel_provider',
|
| 68 |
# Провайдеры (прямой доступ)
|
|
|
|
| 25 |
|
| 26 |
from ._config import WORK_FOLDER
|
| 27 |
from ._logger import logger
|
| 28 |
+
from ._registry import proxies_functions, tunnel_provider, list_providers, enable_provider, disable_provider
|
| 29 |
from ._utils import run, download
|
| 30 |
|
| 31 |
# Импорт модулей регистрирует провайдеров через @tunnel_provider
|
|
|
|
| 63 |
'benchmark',
|
| 64 |
'TunnelBenchmarkResult',
|
| 65 |
# Реестр (для расширения)
|
| 66 |
+
'disable_provider',
|
| 67 |
+
'enable_provider',
|
| 68 |
+
'list_providers',
|
| 69 |
'proxies_functions',
|
| 70 |
'tunnel_provider',
|
| 71 |
# Провайдеры (прямой доступ)
|
colab_tunnel/_diagnostics.py
CHANGED
|
@@ -177,46 +177,51 @@ def _print_report(results: list[TunnelBenchmarkResult]) -> None:
|
|
| 177 |
def benchmark(
|
| 178 |
providers: list[str] | None = None,
|
| 179 |
timeout_per_provider: float = 30.0,
|
| 180 |
-
latency_timeout: float =
|
| 181 |
print_report: bool = True,
|
| 182 |
) -> list[TunnelBenchmarkResult]:
|
| 183 |
"""
|
| 184 |
Последовательно тестирует провайдеров туннелей и собирает метрики.
|
| 185 |
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
из папки test_server/).
|
| 189 |
-
2. Поочерёдно вызывает каждого провайдера, замеряя время запуска.
|
| 190 |
-
3. Проверяет доступность полученной ссылки, измеряет RTT.
|
| 191 |
-
4. Гарантированно останавливает тестовый сервер (блок finally).
|
| 192 |
-
5. Выводит форматированный отчёт.
|
| 193 |
|
| 194 |
-
|
| 195 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 196 |
|
| 197 |
Args:
|
| 198 |
-
providers: Имена провайдеров
|
| 199 |
timeout_per_provider: Таймаут ожидания ссылки от провайдера (сек).
|
| 200 |
-
latency_timeout: Таймаут проверки
|
| 201 |
-
print_report: Вывести
|
| 202 |
|
| 203 |
Returns:
|
| 204 |
-
Список TunnelBenchmarkResult
|
| 205 |
-
|
| 206 |
-
Raises:
|
| 207 |
-
FileNotFoundError: Бинарник тестового сервера не найден.
|
| 208 |
-
ValueError: Указан несуществующий провайдер.
|
| 209 |
"""
|
| 210 |
server_bin = _find_test_server_bin()
|
| 211 |
port = find_free_port()
|
| 212 |
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
if
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 220 |
|
| 221 |
print(f'Бенчмарк: {len(names)} провайдеров, порт {port}.')
|
| 222 |
_start_test_server(server_bin, port)
|
|
@@ -225,8 +230,9 @@ def benchmark(
|
|
| 225 |
results: list[TunnelBenchmarkResult] = []
|
| 226 |
|
| 227 |
try:
|
|
|
|
| 228 |
for name in names:
|
| 229 |
-
func =
|
| 230 |
print(f'[{name:<12}] запуск...', end=' ', flush=True)
|
| 231 |
result = TunnelBenchmarkResult(name=name)
|
| 232 |
t_start = time.time()
|
|
@@ -252,6 +258,21 @@ def benchmark(
|
|
| 252 |
|
| 253 |
results.append(result)
|
| 254 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 255 |
finally:
|
| 256 |
print()
|
| 257 |
_stop_test_server(server_bin)
|
|
@@ -261,3 +282,4 @@ def benchmark(
|
|
| 261 |
_print_report(results)
|
| 262 |
|
| 263 |
return results
|
|
|
|
|
|
| 177 |
def benchmark(
|
| 178 |
providers: list[str] | None = None,
|
| 179 |
timeout_per_provider: float = 30.0,
|
| 180 |
+
latency_timeout: float = 10.0,
|
| 181 |
print_report: bool = True,
|
| 182 |
) -> list[TunnelBenchmarkResult]:
|
| 183 |
"""
|
| 184 |
Последовательно тестирует провайдеров туннелей и собирает метрики.
|
| 185 |
|
| 186 |
+
По умолчанию тестирует только активных провайдеров (из proxies_functions).
|
| 187 |
+
Передать список имён явно — включая отключённых — можно через параметр providers.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 188 |
|
| 189 |
+
Схема работы:
|
| 190 |
+
1. Запускает тестовый HTTP-сервер.
|
| 191 |
+
2. Последовательно запускает каждого провайдера, измеряя время старта.
|
| 192 |
+
3. Сразу проверяет RTT полученного URL.
|
| 193 |
+
4. После всех провайдеров — второй проход RTT для тех, кто не ответил
|
| 194 |
+
с первого раза (cloudflared, tunnelite: маршрут распространяется 10–15с).
|
| 195 |
+
5. Останавливает тестовый сервер (блок finally).
|
| 196 |
+
6. Выводит форматированный отчёт.
|
| 197 |
|
| 198 |
Args:
|
| 199 |
+
providers: Имена провайдеров. None — все активные.
|
| 200 |
timeout_per_provider: Таймаут ожидания ссылки от провайдера (сек).
|
| 201 |
+
latency_timeout: Таймаут проверки RTT (сек).
|
| 202 |
+
print_report: Вывести таблицу результатов.
|
| 203 |
|
| 204 |
Returns:
|
| 205 |
+
Список TunnelBenchmarkResult.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 206 |
"""
|
| 207 |
server_bin = _find_test_server_bin()
|
| 208 |
port = find_free_port()
|
| 209 |
|
| 210 |
+
# Если провайдеры переданы явно — ищем в _all_providers (включая отключённых).
|
| 211 |
+
# Если нет — берём только активных из proxies_functions.
|
| 212 |
+
if providers is not None:
|
| 213 |
+
from ._registry import _all_providers
|
| 214 |
+
unknown = [n for n in providers if n not in _all_providers]
|
| 215 |
+
if unknown:
|
| 216 |
+
raise ValueError(
|
| 217 |
+
f'Неизвестные провайдеры: {unknown}. '
|
| 218 |
+
f'Все зарегистрированные: {list(_all_providers)}'
|
| 219 |
+
)
|
| 220 |
+
names = providers
|
| 221 |
+
func_map = _all_providers
|
| 222 |
+
else:
|
| 223 |
+
names = list(proxies_functions.keys())
|
| 224 |
+
func_map = proxies_functions
|
| 225 |
|
| 226 |
print(f'Бенчмарк: {len(names)} провайдеров, порт {port}.')
|
| 227 |
_start_test_server(server_bin, port)
|
|
|
|
| 230 |
results: list[TunnelBenchmarkResult] = []
|
| 231 |
|
| 232 |
try:
|
| 233 |
+
# ── Основной проход: запуск + первая проверка RTT ────────────────
|
| 234 |
for name in names:
|
| 235 |
+
func = func_map[name]
|
| 236 |
print(f'[{name:<12}] запуск...', end=' ', flush=True)
|
| 237 |
result = TunnelBenchmarkResult(name=name)
|
| 238 |
t_start = time.time()
|
|
|
|
| 258 |
|
| 259 |
results.append(result)
|
| 260 |
|
| 261 |
+
# ── Второй проход: RTT для провайдеров с warmup-задержкой ────────
|
| 262 |
+
# К этому моменту прошло достаточно времени (пока тестировались
|
| 263 |
+
# остальные провайдеры), чтобы маршруты cloudflared/tunnelite
|
| 264 |
+
# успели распространиться по сети провайдера.
|
| 265 |
+
needs_recheck = [
|
| 266 |
+
r for r in results
|
| 267 |
+
if r.success and r.latency is None and r.name != 'native'
|
| 268 |
+
]
|
| 269 |
+
if needs_recheck:
|
| 270 |
+
print(f'\nПовторная проверка RTT ({len(needs_recheck)} провайдеров)...')
|
| 271 |
+
for r in needs_recheck:
|
| 272 |
+
r.latency = _check_url_latency(r.url, timeout=latency_timeout) # type: ignore[arg-type]
|
| 273 |
+
status = f'RTT {r.latency * 1000:.0f}мс' if r.latency else 'всё ещё недоступен'
|
| 274 |
+
print(f' [{r.name:<12}] {status}')
|
| 275 |
+
|
| 276 |
finally:
|
| 277 |
print()
|
| 278 |
_stop_test_server(server_bin)
|
|
|
|
| 282 |
_print_report(results)
|
| 283 |
|
| 284 |
return results
|
| 285 |
+
|
colab_tunnel/_registry.py
CHANGED
|
@@ -1,25 +1,87 @@
|
|
| 1 |
"""
|
| 2 |
Реестр провайдеров туннелей.
|
| 3 |
|
| 4 |
-
|
|
|
|
|
|
|
| 5 |
|
| 6 |
-
|
|
|
|
|
|
|
|
|
|
| 7 |
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
...
|
| 11 |
|
| 12 |
-
Пос
|
|
|
|
| 13 |
"""
|
| 14 |
from typing import Callable
|
| 15 |
|
| 16 |
-
#
|
| 17 |
proxies_functions: dict[str, Callable[[int], str]] = {}
|
| 18 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
|
| 20 |
-
def tunnel_provider(name: str) -> Callable:
|
| 21 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
def decorator(func: Callable[[int], str]) -> Callable[[int], str]:
|
| 23 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
return func
|
| 25 |
return decorator
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
"""
|
| 2 |
Реестр провайдеров туннелей.
|
| 3 |
|
| 4 |
+
Регистрация нового провайдера:
|
| 5 |
+
@tunnel_provider('myprovider')
|
| 6 |
+
def get_myprovider_url(port: int) -> str: ...
|
| 7 |
|
| 8 |
+
Отключить провайдера (сервис временно недоступен):
|
| 9 |
+
@tunnel_provider('tunwg', enabled=False)
|
| 10 |
+
# или в рантайме:
|
| 11 |
+
disable_provider('tunwg')
|
| 12 |
|
| 13 |
+
Включить обратно:
|
| 14 |
+
enable_provider('tunwg')
|
|
|
|
| 15 |
|
| 16 |
+
Посмотреть статус всех:
|
| 17 |
+
list_providers()
|
| 18 |
"""
|
| 19 |
from typing import Callable
|
| 20 |
|
| 21 |
+
# Активные провайдеры — используются get_share_link(), try_all(), benchmark()
|
| 22 |
proxies_functions: dict[str, Callable[[int], str]] = {}
|
| 23 |
|
| 24 |
+
# Все зарегистрированные провайдеры (активные + отключённые)
|
| 25 |
+
_all_providers: dict[str, Callable[[int], str]] = {}
|
| 26 |
+
|
| 27 |
+
# Имена отключённых провайдеров
|
| 28 |
+
_disabled_providers: set[str] = set()
|
| 29 |
+
|
| 30 |
|
| 31 |
+
def tunnel_provider(name: str, *, enabled: bool = True) -> Callable:
|
| 32 |
+
"""
|
| 33 |
+
Декоратор регистрации провайдера туннеля.
|
| 34 |
+
|
| 35 |
+
Args:
|
| 36 |
+
name: Уникальное имя провайдера.
|
| 37 |
+
enabled: False — провайдер зарегистрирован, но не активен.
|
| 38 |
+
Включить позднее через enable_provider(name).
|
| 39 |
+
"""
|
| 40 |
def decorator(func: Callable[[int], str]) -> Callable[[int], str]:
|
| 41 |
+
_all_providers[name] = func
|
| 42 |
+
if enabled:
|
| 43 |
+
proxies_functions[name] = func
|
| 44 |
+
else:
|
| 45 |
+
_disabled_providers.add(name)
|
| 46 |
return func
|
| 47 |
return decorator
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def disable_provider(name: str) -> None:
|
| 51 |
+
"""
|
| 52 |
+
Деактивирует провайдера: убирает из активного реестра.
|
| 53 |
+
Функция сохраняется — включить обратно через enable_provider().
|
| 54 |
+
|
| 55 |
+
Raises:
|
| 56 |
+
KeyError: Провайдер с таким именем не зарегистрирован.
|
| 57 |
+
"""
|
| 58 |
+
if name not in _all_providers:
|
| 59 |
+
raise KeyError(f'Провайдер "{name}" не зарегистрирован. Доступные: {list(_all_providers)}')
|
| 60 |
+
proxies_functions.pop(name, None)
|
| 61 |
+
_disabled_providers.add(name)
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def enable_provider(name: str) -> None:
|
| 65 |
+
"""
|
| 66 |
+
Активирует ранее отключённого провайдера.
|
| 67 |
+
|
| 68 |
+
Raises:
|
| 69 |
+
KeyError: Провайдер с таким именем не зарегистрирован.
|
| 70 |
+
"""
|
| 71 |
+
if name not in _all_providers:
|
| 72 |
+
raise KeyError(f'Провайдер "{name}" не зарегистрирован. Доступные: {list(_all_providers)}')
|
| 73 |
+
_disabled_providers.discard(name)
|
| 74 |
+
proxies_functions[name] = _all_providers[name]
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
def list_providers() -> dict[str, bool]:
|
| 78 |
+
"""
|
| 79 |
+
Возвращает статус всех зарегистрированных провайдеров.
|
| 80 |
+
|
| 81 |
+
Returns:
|
| 82 |
+
Словарь {имя: активен}, в порядке регистрации.
|
| 83 |
+
|
| 84 |
+
Пример вывода:
|
| 85 |
+
{'cloudflared': True, 'tunwg': False, 'bore': True, ...}
|
| 86 |
+
"""
|
| 87 |
+
return {name: (name not in _disabled_providers) for name in _all_providers}
|
colab_tunnel/_tunnels.py
CHANGED
|
@@ -169,7 +169,7 @@ def get_tmole_url(port: int) -> str:
|
|
| 169 |
)
|
| 170 |
|
| 171 |
|
| 172 |
-
@tunnel_provider('tunwg')
|
| 173 |
def get_tunwg_url(port: int) -> str:
|
| 174 |
return get_revproxy_url(
|
| 175 |
bin_url='https://github.com/ntnj/tunwg/releases/latest/download/tunwg',
|
|
|
|
| 169 |
)
|
| 170 |
|
| 171 |
|
| 172 |
+
@tunnel_provider('tunwg', enabled=False) # Сервис недоступен с 2026-06-16, включить: enable_provider('tunwg')
|
| 173 |
def get_tunwg_url(port: int) -> str:
|
| 174 |
return get_revproxy_url(
|
| 175 |
bin_url='https://github.com/ntnj/tunwg/releases/latest/download/tunwg',
|