rottenstuff commited on
Commit
81966b1
·
verified ·
1 Parent(s): adf497c

Upload 12 files

Browse files
colab_tunnel/_diagnostics.py CHANGED
@@ -81,23 +81,39 @@ def _stop_test_server(server_bin: Path) -> None:
81
  logger.debug('Тестовый сервер остановлен.')
82
 
83
 
84
- def _check_url_latency(url: str, timeout: float = 15.0) -> Optional[float]:
 
 
 
 
 
85
  """
86
- Делает GET-запрос к публичному URL и возвращает RTT.
 
 
 
 
87
 
88
  Returns:
89
- Время ответа в секундах, или None если URL недоступен.
90
  """
91
- # Убираем строку с IPv4-паролем (если провайдер вернул её как вторую строку)
92
  clean_url = url.split('\n')[0].strip()
93
- try:
94
- t = time.time()
95
- resp = get_url(clean_url, timeout=timeout, allow_redirects=True)
96
- elapsed = round(time.time() - t, 3)
97
- if 200 <= resp.status_code < 400:
98
- return elapsed
99
- except Exception as e:
100
- logger.debug(f'URL недоступен ({clean_url}): {e}')
 
 
 
 
 
 
 
101
  return None
102
 
103
 
@@ -145,6 +161,12 @@ def _print_report(results: list[TunnelBenchmarkResult]) -> None:
145
  if with_lat:
146
  lowest = min(with_lat, key=lambda r: r.latency) # type: ignore[arg-type]
147
  print(f'Минимальная задержка: {lowest.name} ({lowest.latency * 1000:.0f}мс)') # type: ignore[operator]
 
 
 
 
 
 
148
  print()
149
 
150
 
 
81
  logger.debug('Тестовый сервер остановлен.')
82
 
83
 
84
+ def _check_url_latency(
85
+ url: str,
86
+ timeout: float = 10.0,
87
+ warmup_retries: int = 2,
88
+ warmup_delay: float = 5.0,
89
+ ) -> Optional[float]:
90
  """
91
+ Проверяет доступность публичного URL и возвращает RTT.
92
+
93
+ Делает повторные попытки с паузой — некоторые провайдеры (cloudflared,
94
+ tunnelite) анонсируют URL раньше, чем маршрут фактически распространяется
95
+ по их сети. Cloudflared обычно требует 5–10 секунд после старта.
96
 
97
  Returns:
98
+ RTT в секундах, или None если URL недоступен после всех попыток.
99
  """
100
+ # Убираем строку с IPv4-паролем, если провайдер вернул её второй строкой
101
  clean_url = url.split('\n')[0].strip()
102
+
103
+ for attempt in range(warmup_retries):
104
+ if attempt > 0:
105
+ logger.debug(f'Повтор проверки доступности (попытка {attempt + 1}): {clean_url}')
106
+ time.sleep(warmup_delay)
107
+ try:
108
+ t = time.time()
109
+ resp = get_url(clean_url, timeout=timeout, allow_redirects=True)
110
+ elapsed = round(time.time() - t, 3)
111
+ if 200 <= resp.status_code < 400:
112
+ return elapsed
113
+ logger.debug(f'HTTP {resp.status_code} от {clean_url}')
114
+ except Exception as e:
115
+ logger.debug(f'Попытка {attempt + 1}/{warmup_retries} не удалась: {e}')
116
+
117
  return None
118
 
119
 
 
161
  if with_lat:
162
  lowest = min(with_lat, key=lambda r: r.latency) # type: ignore[arg-type]
163
  print(f'Минимальная задержка: {lowest.name} ({lowest.latency * 1000:.0f}мс)') # type: ignore[operator]
164
+
165
+ # Пояснение для native — его URL требует сессионные куки Google Colab
166
+ native_result = next((r for r in results if r.name == 'native'), None)
167
+ if native_result and native_result.success and not native_result.latency:
168
+ print('\n ℹ native: URL работает, но требует Google-авторизации —')
169
+ print(' внешняя проверка без куки браузера всегда будет недоступна.')
170
  print()
171
 
172
 
colab_tunnel/_tunnels.py CHANGED
@@ -36,6 +36,7 @@ def get_revproxy_url(
36
  timeout: float = 20.0,
37
  write_link: bool = False,
38
  stdin_input: str | None = None,
 
39
  ) -> str:
40
  """
41
  Универсальный запуск бинарного туннельного провайдера.
@@ -53,6 +54,8 @@ def get_revproxy_url(
53
  timeout: Максимальное время ожидания URL (сек).
54
  write_link: Сохранять ли ссылку в links.txt.
55
  stdin_input: Строка для отправки в stdin процесса.
 
 
56
 
57
  Returns:
58
  Публичный URL туннеля.
@@ -90,11 +93,18 @@ def get_revproxy_url(
90
 
91
  # ── Завершение предыдущего экземпляра ───────────────────────────────
92
  kill_process_by_name(bin_path.name)
93
-
 
 
 
 
94
  # ── Запуск процесса ──────────────────────────────────────────────────
95
  stdin_flag = PIPE if stdin_input is not None else None
96
- process = Popen(start_commands, stdout=PIPE, stderr=PIPE, stdin=stdin_flag)
97
-
 
 
 
98
  if stdin_input is not None and process.stdin:
99
  try:
100
  process.stdin.write(stdin_input.encode())
@@ -325,6 +335,9 @@ def get_bore_url(port: int) -> str:
325
  read_from_stderr=True, # Rust логи идут в stderr
326
  url_pattern=r'bore\.pub:\d+',
327
  timeout=15.0,
 
 
 
328
  )
329
  return f'http://{raw}/'
330
 
 
36
  timeout: float = 20.0,
37
  write_link: bool = False,
38
  stdin_input: str | None = None,
39
+ extra_env: dict[str, str] | None = None,
40
  ) -> str:
41
  """
42
  Универсальный запуск бинарного туннельного провайдера.
 
54
  timeout: Максимальное время ожидания URL (сек).
55
  write_link: Сохранять ли ссылку в links.txt.
56
  stdin_input: Строка для отправки в stdin процесса.
57
+ extra_env: Дополнительные переменные окружения для процесса.
58
+ Накладываются поверх os.environ (не заменяют его).
59
 
60
  Returns:
61
  Публичный URL туннеля.
 
93
 
94
  # ── Завершение предыдущего экземпляра ───────────────────────────────
95
  kill_process_by_name(bin_path.name)
96
+ # ── Подготовка окружения ─────────────────────────────────────────────
97
+ import os as _os
98
+ proc_env = _os.environ.copy()
99
+ if extra_env:
100
+ proc_env.update(extra_env)
101
  # ── Запуск процесса ──────────────────────────────────────────────────
102
  stdin_flag = PIPE if stdin_input is not None else None
103
+ process = Popen(
104
+ start_commands,
105
+ stdout=PIPE, stderr=PIPE, stdin=stdin_flag,
106
+ env=proc_env, # ← передаём окружение
107
+ )
108
  if stdin_input is not None and process.stdin:
109
  try:
110
  process.stdin.write(stdin_input.encode())
 
335
  read_from_stderr=True, # Rust логи идут в stderr
336
  url_pattern=r'bore\.pub:\d+',
337
  timeout=15.0,
338
+ # Bore использует Rust-крейт `tracing`. Без RUST_LOG=info строка
339
+ # "listening at bore.pub:XXXXX" (INFO-уровень) не выводится совсем.
340
+ extra_env={'RUST_LOG': 'info'},
341
  )
342
  return f'http://{raw}/'
343
 
pyproject.toml CHANGED
@@ -10,7 +10,7 @@ readme = "README.md"
10
  requires-python = ">=3.10"
11
  license = { text = "MIT" }
12
  dependencies = [
13
- "requests",
14
  ]
15
 
16
  [project.optional-dependencies]
 
10
  requires-python = ">=3.10"
11
  license = { text = "MIT" }
12
  dependencies = [
13
+ "requests>=2.32.4",
14
  ]
15
 
16
  [project.optional-dependencies]