rottenstuff commited on
Commit
5ee2aab
·
verified ·
1 Parent(s): 34943bb

Upload 12 files

Browse files
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 = 15.0,
181
  print_report: bool = True,
182
  ) -> list[TunnelBenchmarkResult]:
183
  """
184
  Последовательно тестирует провайдеров туннелей и собирает метрики.
185
 
186
- Схема работы:
187
- 1. Находит свободный порт, запускает тестовый HTTP-сервер (бинарник
188
- из папки test_server/).
189
- 2. Поочерёдно вызывает каждого провайдера, замеряя время запуска.
190
- 3. Проверяет доступность полученной ссылки, измеряет RTT.
191
- 4. Гарантированно останавливает тестовый сервер (блок finally).
192
- 5. Выводит форматированный отчёт.
193
 
194
- Последовательный (не параллельный) порядок важен для точности замеров:
195
- параллельный запуск исказил бы время за счёт конкуренции за сеть и CPU.
 
 
 
 
 
 
196
 
197
  Args:
198
- providers: Имена провайдеров для теста. None — все доступные.
199
  timeout_per_provider: Таймаут ожидания ссылки от провайдера (сек).
200
- latency_timeout: Таймаут проверки доступности URL (сек).
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
- names = providers or list(proxies_functions.keys())
214
- unknown = [n for n in names if n not in proxies_functions]
215
- if unknown:
216
- raise ValueError(
217
- f'Неизвестные провайдеры: {unknown}. '
218
- f'Доступные: {list(proxies_functions.keys())}'
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 = proxies_functions[name]
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
- from colab_tunnel._registry import tunnel_provider
 
 
 
7
 
8
- @tunnel_provider('myprovider')
9
- def get_myprovider_url(port: int) -> str:
10
- ...
11
 
12
- После этого провайдер автоматически доступен через get_share_link() и try_all().
 
13
  """
14
  from typing import Callable
15
 
16
- # Заполняется при импорте модулей _tunnels и _ssh через декоратор @tunnel_provider
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
- proxies_functions[name] = func
 
 
 
 
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',