This commit is contained in:
本间白猫 2025-01-07 14:15:56 +08:00
parent 1ac5de3e54
commit 70282a7793

View File

@ -44,6 +44,9 @@ class AsyncProxyServer:
self.buffer_size = 256 * 1024 self.buffer_size = 256 * 1024
self.proxy_cache = {} self.proxy_cache = {}
self.proxy_cache_ttl = 10 self.proxy_cache_ttl = 10
self.last_switch_attempt = 0
self.switch_cooldown = 3
self.switching_proxy = False
async def get_next_proxy(self): async def get_next_proxy(self):
if self.mode == 'load_balance': if self.mode == 'load_balance':
@ -193,26 +196,50 @@ class AsyncProxyServer:
dst_port = struct.unpack('!H', await reader.readexactly(2))[0] dst_port = struct.unpack('!H', await reader.readexactly(2))[0]
proxy = await self.get_next_proxy() retry_count = 2
proxy_type, proxy_addr = proxy.split('://') while retry_count > 0:
proxy_auth, proxy_host_port = self._split_proxy_auth(proxy_addr) try:
proxy_host, proxy_port = proxy_host_port.split(':') proxy = await self.get_next_proxy()
proxy_port = int(proxy_port) proxy_type, proxy_addr = proxy.split('://')
proxy_auth, proxy_host_port = self._split_proxy_auth(proxy_addr)
proxy_host, proxy_port = proxy_host_port.split(':')
proxy_port = int(proxy_port)
remote_reader, remote_writer = await asyncio.open_connection(proxy_host, proxy_port) remote_reader, remote_writer = await asyncio.wait_for(
asyncio.open_connection(proxy_host, proxy_port),
timeout=10
)
if proxy_type == 'socks5': if proxy_type == 'socks5':
await self._initiate_socks5(remote_reader, remote_writer, dst_addr, dst_port) await self._initiate_socks5(remote_reader, remote_writer, dst_addr, dst_port)
elif proxy_type in ['http', 'https']: elif proxy_type in ['http', 'https']:
await self._initiate_http(remote_reader, remote_writer, dst_addr, dst_port, proxy_auth) await self._initiate_http(remote_reader, remote_writer, dst_addr, dst_port, proxy_auth)
writer.write(b'\x05\x00\x00\x01\x00\x00\x00\x00\x00\x00') writer.write(b'\x05\x00\x00\x01\x00\x00\x00\x00\x00\x00')
await writer.drain()
await asyncio.gather(
self._pipe(reader, remote_writer),
self._pipe(remote_reader, writer)
)
self.proxy_fail_count = 0
return
except (asyncio.TimeoutError, ConnectionRefusedError, ConnectionResetError):
logging.warning(get_message('request_retry', self.language, retry_count-1))
await self.handle_proxy_failure()
retry_count -= 1
if retry_count > 0:
await asyncio.sleep(1)
continue
except Exception as e:
logging.error(get_message('socks5_connection_error', self.language, e))
await self.handle_proxy_failure()
break
writer.write(b'\x05\x01\x00\x01\x00\x00\x00\x00\x00\x00')
await writer.drain() await writer.drain()
await asyncio.gather(
self._pipe(reader, remote_writer),
self._pipe(remote_reader, writer)
)
except Exception as e: except Exception as e:
logging.error(get_message('socks5_connection_error', self.language, e)) logging.error(get_message('socks5_connection_error', self.language, e))
writer.write(b'\x05\x01\x00\x01\x00\x00\x00\x00\x00\x00') writer.write(b'\x05\x01\x00\x01\x00\x00\x00\x00\x00\x00')
@ -502,6 +529,11 @@ class AsyncProxyServer:
return False return False
async def handle_proxy_failure(self): async def handle_proxy_failure(self):
current_time = time.time()
if self.switching_proxy or (current_time - self.last_switch_attempt) < self.switch_cooldown:
return
if await self.check_current_proxy(): if await self.check_current_proxy():
self.proxy_fail_count += 1 self.proxy_fail_count += 1
if self.proxy_fail_count >= self.max_fail_count: if self.proxy_fail_count >= self.max_fail_count:
@ -512,12 +544,24 @@ class AsyncProxyServer:
await self.force_switch_proxy() await self.force_switch_proxy()
async def force_switch_proxy(self): async def force_switch_proxy(self):
self.proxy_failed = True current_time = time.time()
self.proxy_fail_count = 0
old_proxy = self.current_proxy if self.switching_proxy or (current_time - self.last_switch_attempt) < self.switch_cooldown:
await self.get_proxy() return
self.last_switch_time = time.time()
logging.info(get_message('proxy_switched', self.language, old_proxy, self.current_proxy)) try:
self.switching_proxy = True
self.last_switch_attempt = current_time
self.proxy_failed = True
self.proxy_fail_count = 0
old_proxy = self.current_proxy
await self.get_proxy()
self.last_switch_time = current_time
logging.info(get_message('proxy_switched', self.language, old_proxy, self.current_proxy))
self.proxy_failed = False
finally:
self.switching_proxy = False
async def check_proxy(self, proxy): async def check_proxy(self, proxy):
current_time = time.time() current_time = time.time()