5 Commits

Author SHA1 Message Date
Flowseal
2d1ca21293 Merge pull request #7 from Flowseal/copilot/fix-attribute-error-dict-add
Fix AttributeError when handling 302 redirects: initialize _ws_blacklist as set()
2026-03-05 00:03:17 +03:00
copilot-swe-agent[bot]
0401a4c6bb fix: initialize _ws_blacklist as set() instead of {}
Co-authored-by: Flowseal <50780822+Flowseal@users.noreply.github.com>
2026-03-04 21:00:58 +00:00
copilot-swe-agent[bot]
5228dbbdad Initial plan 2026-03-04 21:00:13 +00:00
Flowseal
98e7b374b2 Update README.md 2026-03-04 20:14:08 +03:00
Flowseal
a57be0971f Tray exit lag fix 2026-03-04 18:04:15 +03:00
3 changed files with 25 additions and 5 deletions

View File

@@ -4,6 +4,8 @@
**Ожидаемый результат аналогичен прокидыванию hosts для Web Telegram**: ускорение загрузки и скачивания файлов, загрузки сообщений и части медиа. **Ожидаемый результат аналогичен прокидыванию hosts для Web Telegram**: ускорение загрузки и скачивания файлов, загрузки сообщений и части медиа.
<img width="529" height="487" alt="image" src="https://github.com/user-attachments/assets/6a4cf683-0df8-43af-86c1-0e8f08682b62" />
## Как это работает ## Как это работает
``` ```
@@ -114,4 +116,4 @@ pyinstaller tg_ws_proxy.spec
## Лицензия ## Лицензия
[MIT License](LICENSE) [MIT License](LICENSE)

View File

@@ -39,7 +39,7 @@ _dc_opt: Dict[int, Optional[str]] = {}
# DCs where WS is known to fail (302 redirect) # DCs where WS is known to fail (302 redirect)
# Raw TCP fallback will be used instead # Raw TCP fallback will be used instead
# Keyed by (dc, is_media) # Keyed by (dc, is_media)
_ws_blacklist: Set[Tuple[int, bool]] = {} _ws_blacklist: Set[Tuple[int, bool]] = set()
# Rate-limit re-attempts per (dc, is_media) # Rate-limit re-attempts per (dc, is_media)
_dc_fail_until: Dict[Tuple[int, bool], float] = {} _dc_fail_until: Dict[Tuple[int, bool], float] = {}
@@ -790,7 +790,14 @@ async def _run(port: int, dc_opt: Dict[int, Optional[str]],
async def wait_stop(): async def wait_stop():
await stop_event.wait() await stop_event.wait()
server.close() server.close()
await server.wait_closed() me = asyncio.current_task()
for task in list(asyncio.all_tasks()):
if task is not me:
task.cancel()
try:
await server.wait_closed()
except asyncio.CancelledError:
pass
asyncio.create_task(wait_stop()) asyncio.create_task(wait_stop())
async with server: async with server:

View File

@@ -51,6 +51,7 @@ _stop_event: Optional[threading.Event] = None
_async_stop: Optional[object] = None _async_stop: Optional[object] = None
_tray_icon: Optional[object] = None _tray_icon: Optional[object] = None
_config: dict = {} _config: dict = {}
_exiting: bool = False
log = logging.getLogger("tg-ws-tray") log = logging.getLogger("tg-ws-tray")
@@ -198,7 +199,7 @@ def stop_proxy():
loop, stop_ev = _async_stop loop, stop_ev = _async_stop
loop.call_soon_threadsafe(stop_ev.set) loop.call_soon_threadsafe(stop_ev.set)
if _proxy_thread: if _proxy_thread:
_proxy_thread.join(timeout=5) _proxy_thread.join(timeout=2)
_proxy_thread = None _proxy_thread = None
log.info("Proxy stopped") log.info("Proxy stopped")
@@ -401,8 +402,18 @@ def _on_open_logs(icon=None, item=None):
def _on_exit(icon=None, item=None): def _on_exit(icon=None, item=None):
global _exiting
if _exiting:
os._exit(0)
return
_exiting = True
log.info("User requested exit") log.info("User requested exit")
stop_proxy()
def _force_exit():
time.sleep(3)
os._exit(0)
threading.Thread(target=_force_exit, daemon=True, name="force-exit").start()
if icon: if icon:
icon.stop() icon.stop()