Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions macos.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
LOG_FILE, acquire_lock, apply_proxy_config, ensure_dirs, load_config,
log, release_lock, save_config, setup_logging, stop_proxy, tg_proxy_url,
)
from utils.diagnostics import diagnose_listen_error

MENUBAR_ICON_PATH = APP_DIR / "menubar_icon.png"

Expand Down Expand Up @@ -184,13 +185,9 @@ def _run_proxy_thread() -> None:
loop.run_until_complete(_run(stop_event=stop_ev))
except Exception as exc:
log.error("Proxy thread crashed: %s", exc)
if "Address already in use" in str(exc):
_show_error(
"Не удалось запустить прокси:\n"
"Порт уже используется другим приложением.\n\n"
"Закройте приложение, использующее этот порт, "
"или измените порт в настройках прокси и перезапустите."
)
msg = diagnose_listen_error(exc)
if msg:
_show_error(msg)
finally:
loop.close()
_async_stop = None
Expand Down
55 changes: 55 additions & 0 deletions utils/diagnostics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from __future__ import annotations

import errno

from typing import Optional


MSG_PORT_BUSY = (
"Не удалось запустить прокси:\n"
"Порт уже используется другим приложением.\n\n"
"Закройте приложение, использующее этот порт, "
"или измените порт в настройках прокси и перезапустите."
)

MSG_PERMISSION = (
"Не удалось запустить прокси:\n"
"Доступ к адресу/порту запрещён "
"(брандмауэр, антивирус или права доступа).\n\n"
"Измените порт на случайный в диапазоне 10000–50000 в настройках, "
"проверьте брандмауэр/антивирус и перезапустите."
)

MSG_BAD_ADDRESS = (
"Не удалось запустить прокси:\n"
"Некорректный или недоступный адрес для прослушивания.\n\n"
"Проверьте host и порт в настройках прокси и перезапустите."
)

# Windows WinSock error codes (exc.winerror); errno may differ from POSIX.
_WSA_EACCES = 10013
_WSA_EFAULT = 10014
_WSA_EADDRINUSE = 10048
_WSA_EADDRNOTAVAIL = 10049


def diagnose_listen_error(exc: BaseException) -> Optional[str]:
"""Map a listen-socket bind failure to a user-facing message.

Returns None when the exception is not a recognizable bind failure,
so callers can fall back to generic handling.
"""
if not isinstance(exc, OSError):
return None

err = exc.errno
winerror = getattr(exc, "winerror", None)

if err == errno.EADDRINUSE or winerror == _WSA_EADDRINUSE:
return MSG_PORT_BUSY
if err == errno.EACCES or winerror == _WSA_EACCES:
return MSG_PERMISSION
if (winerror in (_WSA_EFAULT, _WSA_EADDRNOTAVAIL)
or err in (errno.EADDRNOTAVAIL, errno.EFAULT)):
return MSG_BAD_ADDRESS
return None
11 changes: 4 additions & 7 deletions utils/tray_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from proxy import __version__, get_link_host, parse_dc_ip_list, proxy_config, coerce_domain_list
from proxy.tg_ws_proxy import _run
from utils.default_config import default_tray_config
from utils.diagnostics import diagnose_listen_error

log = logging.getLogger("tg-ws-tray")

Expand Down Expand Up @@ -243,13 +244,9 @@ def _run_proxy_thread(on_port_busy: Callable[[str], None]) -> None:
loop.run_until_complete(_run(stop_event=stop_ev))
except Exception as exc:
log.error("Proxy thread crashed: %s", repr(exc))
if "Address already in use" in str(exc) or "10048" in str(exc):
on_port_busy(
"Не удалось запустить прокси:\n"
"Порт уже используется другим приложением.\n\n"
"Закройте приложение, использующее этот порт, "
"или измените порт в настройках прокси и перезапустите."
)
msg = diagnose_listen_error(exc)
if msg:
on_port_busy(msg)
finally:
loop.close()
_async_stop = None
Expand Down