mirror of
https://github.com/Flowseal/tg-ws-proxy.git
synced 2026-10-21 02:58:45 +00:00
fix socketpair EOF
This commit is contained in:
1 parent
a232472cbe
commit
a0a92f5e7e
6 files changed
+396
-4
No files matched your search
+7
-3
@@ -525,10 +525,14 @@ class _HttpChannel:
|
||||
|
||||
async def _recover(self) -> None:
|
||||
while not self.closed:
|
||||
wakeup = asyncio.create_task(self.recovery_wakeup.wait())
|
||||
try:
|
||||
await asyncio.wait_for(self.recovery_wakeup.wait(), REPLAY_CHECK_SECONDS)
|
||||
except asyncio.TimeoutError:
|
||||
pass
|
||||
# wait_for can swallow cancellation when the wakeup completes
|
||||
# at the same time on Python 3.8-3.11 (CPython #86296).
|
||||
await asyncio.wait((wakeup,), timeout=REPLAY_CHECK_SECONDS)
|
||||
finally:
|
||||
wakeup.cancel()
|
||||
await asyncio.gather(wakeup, return_exceptions=True)
|
||||
self.recovery_wakeup.clear()
|
||||
now = time.monotonic()
|
||||
self.lane.log_wait(now)
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
import asyncio
|
||||
import logging
|
||||
import signal
|
||||
import socket
|
||||
import sys
|
||||
import threading
|
||||
|
||||
|
||||
log = logging.getLogger('tg-mtproto-proxy')
|
||||
|
||||
|
||||
def _replace_self_pipe(loop):
|
||||
reader, writer = socket.socketpair()
|
||||
try:
|
||||
reader.setblocking(False)
|
||||
writer.setblocking(False)
|
||||
if threading.current_thread() is threading.main_thread():
|
||||
previous_fd = signal.set_wakeup_fd(writer.fileno())
|
||||
if previous_fd != loop._csock.fileno():
|
||||
signal.set_wakeup_fd(previous_fd)
|
||||
except BaseException:
|
||||
reader.close()
|
||||
writer.close()
|
||||
raise
|
||||
|
||||
old_reader, old_writer = loop._ssock, loop._csock
|
||||
loop._ssock, loop._csock = reader, writer
|
||||
old_reader.close()
|
||||
old_writer.close()
|
||||
|
||||
|
||||
class _SelfPipeGuard:
|
||||
"""Work around https://github.com/python/cpython/issues/156333"""
|
||||
|
||||
def __init__(self, loop):
|
||||
self.loop = loop
|
||||
self.read_self_pipe = loop._loop_self_reading
|
||||
|
||||
def __call__(self, future=None):
|
||||
loop = self.loop
|
||||
if future is not None:
|
||||
if loop._self_reading_future is not future:
|
||||
return
|
||||
try:
|
||||
data = future.result()
|
||||
except OSError as exc:
|
||||
reason = str(exc)
|
||||
except BaseException:
|
||||
return self.read_self_pipe(future)
|
||||
else:
|
||||
if data:
|
||||
return self.read_self_pipe(future)
|
||||
reason = 'EOF'
|
||||
|
||||
loop._self_reading_future = None
|
||||
self._recover(reason)
|
||||
return
|
||||
return self.read_self_pipe(future)
|
||||
|
||||
def _recover(self, reason):
|
||||
loop = self.loop
|
||||
if loop.is_closed() or loop._self_reading_future is not None:
|
||||
return
|
||||
try:
|
||||
_replace_self_pipe(loop)
|
||||
except OSError as exc:
|
||||
log.warning('Windows event loop wakeup socket recovery failed: %s; '
|
||||
'retry in 1s', exc)
|
||||
loop.call_later(1, self._recover, reason)
|
||||
return
|
||||
log.warning('Windows event loop wakeup socket lost (%s); recreated', reason)
|
||||
self.read_self_pipe()
|
||||
|
||||
|
||||
def install_self_pipe_guard(loop):
|
||||
if sys.platform != 'win32' or not isinstance(loop, asyncio.ProactorEventLoop):
|
||||
return
|
||||
if not isinstance(loop._loop_self_reading, _SelfPipeGuard):
|
||||
guard = _SelfPipeGuard(loop)
|
||||
loop._loop_self_reading = guard
|
||||
future = loop._self_reading_future
|
||||
if future is not None:
|
||||
future.remove_done_callback(guard.read_self_pipe)
|
||||
future.add_done_callback(guard)
|
||||
@@ -29,6 +29,7 @@ from .balancer import balancer
|
||||
from .pool import ws_pool, cf_worker_pool
|
||||
from .cf_h2 import CfH2Pool
|
||||
from .network_debug import log_ws_flow
|
||||
from .event_loop import install_self_pipe_guard
|
||||
from ._aes import Cipher, algorithms, modes
|
||||
|
||||
|
||||
@@ -360,6 +361,7 @@ _client_tasks: Set[asyncio.Task] = set()
|
||||
|
||||
async def _run(stop_event: Optional[asyncio.Event] = None):
|
||||
global _server_instance, _server_stop_event, cf_h2_pool
|
||||
install_self_pipe_guard(asyncio.get_running_loop())
|
||||
_server_stop_event = stop_event
|
||||
|
||||
reset_tcp_backoff()
|
||||
|
||||
Reference in new issue
Block a user