feat(tray): добавлен статус прокси в GUI и обновлены настройки
This commit is contained in:
parent
bd5056a64c
commit
a11b634ba7
13
README.md
13
README.md
|
|
@ -39,13 +39,20 @@ Telegram Desktop → SOCKS5 (127.0.0.1:1080) → TG WS Proxy → WSS → Telegra
|
||||||
**Меню трея:**
|
**Меню трея:**
|
||||||
|
|
||||||
- **Открыть в Telegram** — автоматически настроить прокси через `tg://socks` ссылку
|
- **Открыть в Telegram** — автоматически настроить прокси через `tg://socks` ссылку
|
||||||
|
- **Статус и проверка TCP…** — диалог с фазой прокси (запуск / слушает / ошибка), uptime и локальной проверкой TCP до `host:port`
|
||||||
- **Перезапустить прокси** — перезапуск без выхода из приложения
|
- **Перезапустить прокси** — перезапуск без выхода из приложения
|
||||||
- **Настройки...** — GUI-редактор конфигурации (в т.ч. версия приложения, опциональная проверка обновлений с GitHub)
|
- **Настройки...** — GUI-редактор конфигурации (см. ниже)
|
||||||
- **Открыть логи** — открыть файл логов
|
- **Открыть логи** — открыть файл логов
|
||||||
- **Выход** — остановить прокси и закрыть приложение
|
- **Выход** — остановить прокси и закрыть приложение
|
||||||
|
|
||||||
|
**Иконка в трее:** цветной индикатор на иконке — **зелёный** прокси слушает порт, **красный** — ошибка, **жёлтый** — запуск / остановка / ожидание. Подсказка при наведении: адрес, состояние и при работе — uptime.
|
||||||
|
|
||||||
|
Повторный запуск приложения, пока оно уже работает, блокируется (один экземпляр); при конфликте порта показывается сообщение об ошибке.
|
||||||
|
|
||||||
При первом запуске после старта может появиться запрос об открытии страницы релиза, если на GitHub вышла новая версия (отключается в настройках).
|
При первом запуске после старта может появиться запрос об открытии страницы релиза, если на GitHub вышла новая версия (отключается в настройках).
|
||||||
|
|
||||||
|
**Окно настроек (Windows / Linux):** секция **«Статус»** — цветной индикатор, текст состояния и uptime (обновляется автоматически). Полная проверка TCP и детали — в меню трея **«Статус и проверка TCP…»**. В блоке **«Обновления»** — время последней проверки GitHub; без интернета имеет смысл отключить **«Проверять обновления при запуске»**.
|
||||||
|
|
||||||
### macOS
|
### macOS
|
||||||
|
|
||||||
Перейдите на [страницу релизов](https://github.com/Flowseal/tg-ws-proxy/releases) и скачайте **`TgWsProxy_macos_universal.dmg`** — универсальная сборка для Apple Silicon и Intel.
|
Перейдите на [страницу релизов](https://github.com/Flowseal/tg-ws-proxy/releases) и скачайте **`TgWsProxy_macos_universal.dmg`** — универсальная сборка для Apple Silicon и Intel.
|
||||||
|
|
@ -54,6 +61,8 @@ Telegram Desktop → SOCKS5 (127.0.0.1:1080) → TG WS Proxy → WSS → Telegra
|
||||||
2. Перенести **TG WS Proxy.app** в папку **Applications**
|
2. Перенести **TG WS Proxy.app** в папку **Applications**
|
||||||
3. При первом запуске macOS может попросить подтвердить открытие: **Системные настройки → Конфиденциальность и безопасность → Всё равно открыть**
|
3. При первом запуске macOS может попросить подтвердить открытие: **Системные настройки → Конфиденциальность и безопасность → Всё равно открыть**
|
||||||
|
|
||||||
|
В строке меню доступны те же действия, что и в трее Windows/Linux (в т.ч. статус и проверка TCP); иконка в меню обновляется с цветным индикатором состояния. Настройки на macOS задаются через системные диалоги, не через окно CustomTkinter.
|
||||||
|
|
||||||
### Linux
|
### Linux
|
||||||
|
|
||||||
Для Debian/Ubuntu скачайте со [страницы релизов](https://github.com/Flowseal/tg-ws-proxy/releases) пакет **`TgWsProxy_linux_amd64.deb`**.
|
Для Debian/Ubuntu скачайте со [страницы релизов](https://github.com/Flowseal/tg-ws-proxy/releases) пакет **`TgWsProxy_linux_amd64.deb`**.
|
||||||
|
|
@ -158,7 +167,7 @@ tg-ws-proxy-tray-linux = "linux:main"
|
||||||
|
|
||||||
## Структура исходников (tray)
|
## Структура исходников (tray)
|
||||||
|
|
||||||
Общая логика tray-приложений (пути данных, один экземпляр процесса, конфиг, логирование, поток с прокси, IPv6, фоновая проверка релизов) находится в `utils/tray_*.py`; вспомогательные части UI — в `ui/tray_*.py`. Точки входа по ОС: `windows.py`, `linux.py`, `macos.py`.
|
Общая логика tray-приложений (пути данных, один экземпляр процесса, конфиг, логирование, поток с прокси, состояние для UI, локальная диагностика порта/TCP, IPv6, фоновая проверка релизов) находится в `utils/tray_*.py`; вспомогательные части UI — в `ui/tray_*.py` и `ui/ctk_tray_ui.py`. Точки входа по ОС: `windows.py`, `linux.py`, `macos.py`.
|
||||||
|
|
||||||
Для согласованных окончаний строк в репозитории используются `.editorconfig` и `.gitattributes` (LF).
|
Для согласованных окончаний строк в репозитории используются `.editorconfig` и `.gitattributes` (LF).
|
||||||
|
|
||||||
|
|
|
||||||
1
linux.py
1
linux.py
|
|
@ -275,6 +275,7 @@ def _edit_config_dialog():
|
||||||
cfg,
|
cfg,
|
||||||
DEFAULT_CONFIG,
|
DEFAULT_CONFIG,
|
||||||
show_autostart=False,
|
show_autostart=False,
|
||||||
|
proxy_state=_proxy_state,
|
||||||
)
|
)
|
||||||
|
|
||||||
def on_save():
|
def on_save():
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,8 @@ class CtkTheme:
|
||||||
field_border: str = "#d6d9dc"
|
field_border: str = "#d6d9dc"
|
||||||
text_primary: str = "#000000"
|
text_primary: str = "#000000"
|
||||||
text_secondary: str = "#707579"
|
text_secondary: str = "#707579"
|
||||||
|
status_pill_bg: str = "#f4f6fa"
|
||||||
|
status_pill_border: str = "#e2e6ed"
|
||||||
ui_font_family: str = "Sans"
|
ui_font_family: str = "Sans"
|
||||||
mono_font_family: str = "Monospace"
|
mono_font_family: str = "Monospace"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
||||||
|
|
||||||
import proxy.tg_ws_proxy as tg_ws_proxy
|
import proxy.tg_ws_proxy as tg_ws_proxy
|
||||||
from proxy import __version__
|
from proxy import __version__
|
||||||
|
from ui.tray_icons import badge_rgb_for_phase
|
||||||
|
from utils.tray_proxy_state import format_uptime_short, phase_label_ru
|
||||||
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 (
|
||||||
|
|
@ -138,6 +140,7 @@ def install_tray_config_form(
|
||||||
*,
|
*,
|
||||||
show_autostart: bool = False,
|
show_autostart: bool = False,
|
||||||
autostart_value: bool = False,
|
autostart_value: bool = False,
|
||||||
|
proxy_state: Optional[Any] = None,
|
||||||
) -> TrayConfigFormWidgets:
|
) -> TrayConfigFormWidgets:
|
||||||
"""Поля настроек прокси внутри уже созданного `frame`."""
|
"""Поля настроек прокси внутри уже созданного `frame`."""
|
||||||
header = ctk.CTkFrame(frame, fg_color="transparent")
|
header = ctk.CTkFrame(frame, fg_color="transparent")
|
||||||
|
|
@ -216,6 +219,67 @@ def install_tray_config_form(
|
||||||
port_entry.pack(anchor="w")
|
port_entry.pack(anchor="w")
|
||||||
attach_tooltip_to_widgets([port_lbl, port_entry, port_col], _TIP_PORT)
|
attach_tooltip_to_widgets([port_lbl, port_entry, port_col], _TIP_PORT)
|
||||||
|
|
||||||
|
if proxy_state is not None:
|
||||||
|
stat_inner = _config_section(ctk, frame, theme, "Статус")
|
||||||
|
pill = ctk.CTkFrame(
|
||||||
|
stat_inner,
|
||||||
|
fg_color=theme.status_pill_bg,
|
||||||
|
corner_radius=12,
|
||||||
|
border_width=1,
|
||||||
|
border_color=theme.status_pill_border,
|
||||||
|
)
|
||||||
|
pill.pack(fill="x", pady=(2, 0))
|
||||||
|
row = ctk.CTkFrame(pill, fg_color="transparent")
|
||||||
|
row.pack(fill="x", padx=14, pady=12)
|
||||||
|
dot = ctk.CTkFrame(
|
||||||
|
row,
|
||||||
|
width=12,
|
||||||
|
height=12,
|
||||||
|
corner_radius=6,
|
||||||
|
fg_color="#eab308",
|
||||||
|
)
|
||||||
|
dot.pack(side="left", padx=(0, 12))
|
||||||
|
dot.pack_propagate(False)
|
||||||
|
text_col = ctk.CTkFrame(row, fg_color="transparent")
|
||||||
|
text_col.pack(side="left", fill="x", expand=True)
|
||||||
|
status_main = ctk.CTkLabel(
|
||||||
|
text_col,
|
||||||
|
text="",
|
||||||
|
font=(theme.ui_font_family, 14),
|
||||||
|
text_color=theme.text_primary,
|
||||||
|
anchor="w",
|
||||||
|
)
|
||||||
|
status_main.pack(side="left")
|
||||||
|
status_uptime = ctk.CTkLabel(
|
||||||
|
text_col,
|
||||||
|
text="",
|
||||||
|
font=(theme.ui_font_family, 13),
|
||||||
|
text_color=theme.text_secondary,
|
||||||
|
anchor="w",
|
||||||
|
)
|
||||||
|
status_uptime.pack(side="left")
|
||||||
|
|
||||||
|
def _mini_status_tick() -> None:
|
||||||
|
if not frame.winfo_exists():
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
snap = proxy_state.snapshot()
|
||||||
|
phase = snap["phase"]
|
||||||
|
r, g, b = badge_rgb_for_phase(phase)
|
||||||
|
dot.configure(fg_color=f"#{r:02x}{g:02x}{b:02x}")
|
||||||
|
status_main.configure(text=phase_label_ru(phase))
|
||||||
|
ls = snap.get("listening_since")
|
||||||
|
if phase == "listening" and ls is not None:
|
||||||
|
status_uptime.configure(text=f" · {format_uptime_short(ls)}")
|
||||||
|
else:
|
||||||
|
status_uptime.configure(text="")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if frame.winfo_exists():
|
||||||
|
frame.after(1000, _mini_status_tick)
|
||||||
|
|
||||||
|
_mini_status_tick()
|
||||||
|
|
||||||
dc_inner = _config_section(ctk, frame, theme, "Датацентры Telegram (DC → IP)")
|
dc_inner = _config_section(ctk, frame, theme, "Датацентры Telegram (DC → IP)")
|
||||||
dc_lbl = ctk.CTkLabel(
|
dc_lbl = ctk.CTkLabel(
|
||||||
dc_inner,
|
dc_inner,
|
||||||
|
|
@ -591,7 +655,7 @@ def populate_first_run_window(
|
||||||
"порт занят — другой процесс или старый экземпляр; смените порт в настройках;",
|
"порт занят — другой процесс или старый экземпляр; смените порт в настройках;",
|
||||||
"IPv6 — трафик может идти мимо прокси; см. предупреждение при первом запуске;",
|
"IPv6 — трафик может идти мимо прокси; см. предупреждение при первом запуске;",
|
||||||
"брандмауэр / антивирус — разрешите локальное прослушивание;",
|
"брандмауэр / антивирус — разрешите локальное прослушивание;",
|
||||||
"меню трея: «Статус» — без поиска по логам.",
|
"меню трея: «Статус и проверка TCP…» — без поиска по логам.",
|
||||||
):
|
):
|
||||||
ctk.CTkLabel(
|
ctk.CTkLabel(
|
||||||
frame,
|
frame,
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,6 @@ from typing import Any, List, Tuple
|
||||||
|
|
||||||
from PIL import Image, ImageDraw, ImageFont
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
|
|
||||||
# Подсказка для tooltip (согласована с цветами бейджа)
|
|
||||||
BADGE_TOOLTIP_HINT = (
|
|
||||||
"Бейдж: зелёный — работает, красный — ошибка, жёлтый — запуск/ожидание/остановка"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _resample_lanczos() -> int:
|
def _resample_lanczos() -> int:
|
||||||
try:
|
try:
|
||||||
return Image.Resampling.LANCZOS # type: ignore[attr-defined]
|
return Image.Resampling.LANCZOS # type: ignore[attr-defined]
|
||||||
|
|
|
||||||
|
|
@ -90,8 +90,6 @@ def build_tray_tooltip(
|
||||||
port: int,
|
port: int,
|
||||||
state: ProxyRuntimeState,
|
state: ProxyRuntimeState,
|
||||||
) -> str:
|
) -> str:
|
||||||
from ui.tray_icons import BADGE_TOOLTIP_HINT
|
|
||||||
|
|
||||||
snap = state.snapshot()
|
snap = state.snapshot()
|
||||||
phase = snap["phase"]
|
phase = snap["phase"]
|
||||||
addr = f"{host}:{port}"
|
addr = f"{host}:{port}"
|
||||||
|
|
@ -99,12 +97,10 @@ def build_tray_tooltip(
|
||||||
|
|
||||||
if phase == "listening" and snap["listening_since"] is not None:
|
if phase == "listening" and snap["listening_since"] is not None:
|
||||||
up = format_uptime_short(snap["listening_since"])
|
up = format_uptime_short(snap["listening_since"])
|
||||||
base = f"TG WS Proxy | {addr} | {label} | {up}"
|
return f"TG WS Proxy | {addr} | {label} | {up}"
|
||||||
elif phase == "error" and snap["detail"]:
|
if phase == "error" and snap["detail"]:
|
||||||
short = snap["detail"]
|
short = snap["detail"]
|
||||||
if len(short) > 80:
|
if len(short) > 80:
|
||||||
short = short[:77] + "…"
|
short = short[:77] + "…"
|
||||||
base = f"TG WS Proxy | {addr} | {label}: {short}"
|
return f"TG WS Proxy | {addr} | {label}: {short}"
|
||||||
else:
|
return f"TG WS Proxy | {addr} | {label}"
|
||||||
base = f"TG WS Proxy | {addr} | {label}"
|
|
||||||
return f"{base}\n{BADGE_TOOLTIP_HINT}"
|
|
||||||
|
|
|
||||||
|
|
@ -394,6 +394,7 @@ def _edit_config_dialog():
|
||||||
DEFAULT_CONFIG,
|
DEFAULT_CONFIG,
|
||||||
show_autostart=_supports_autostart(),
|
show_autostart=_supports_autostart(),
|
||||||
autostart_value=cfg.get("autostart", False),
|
autostart_value=cfg.get("autostart", False),
|
||||||
|
proxy_state=_proxy_state,
|
||||||
)
|
)
|
||||||
|
|
||||||
def on_save():
|
def on_save():
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue