fix proxy
This commit is contained in:
+11
-1
@@ -255,6 +255,14 @@ class BotInterface:
|
|||||||
await callback.answer()
|
await callback.answer()
|
||||||
|
|
||||||
# === Перезапуск ===
|
# === Перезапуск ===
|
||||||
|
@dp.callback_query(F.data == "reload_proxies")
|
||||||
|
async def cb_reload_proxies(callback: CallbackQuery):
|
||||||
|
if not await require_admin(callback):
|
||||||
|
return
|
||||||
|
count = interface.proxy_manager.reload()
|
||||||
|
await interface._show_status(callback.message, edit=True)
|
||||||
|
await callback.answer(f"✅ Прокси перезагружены: {count} шт.")
|
||||||
|
|
||||||
@dp.callback_query(F.data == "bot_restart_confirm")
|
@dp.callback_query(F.data == "bot_restart_confirm")
|
||||||
async def cb_restart_confirm(callback: CallbackQuery):
|
async def cb_restart_confirm(callback: CallbackQuery):
|
||||||
if not await require_admin(callback):
|
if not await require_admin(callback):
|
||||||
@@ -1685,6 +1693,7 @@ class BotInterface:
|
|||||||
)
|
)
|
||||||
builder = InlineKeyboardBuilder()
|
builder = InlineKeyboardBuilder()
|
||||||
builder.row(InlineKeyboardButton(text="🔄 Обновить", callback_data="menu_status"))
|
builder.row(InlineKeyboardButton(text="🔄 Обновить", callback_data="menu_status"))
|
||||||
|
builder.row(InlineKeyboardButton(text="🔃 Перезагрузить прокси", callback_data="reload_proxies"))
|
||||||
builder.row(InlineKeyboardButton(text="🔁 Перезапустить бота", callback_data="bot_restart_confirm"))
|
builder.row(InlineKeyboardButton(text="🔁 Перезапустить бота", callback_data="bot_restart_confirm"))
|
||||||
builder.row(InlineKeyboardButton(text="🔙 В меню", callback_data="menu_main"))
|
builder.row(InlineKeyboardButton(text="🔙 В меню", callback_data="menu_main"))
|
||||||
await self._edit_or_send(message, text, builder.as_markup(), edit)
|
await self._edit_or_send(message, text, builder.as_markup(), edit)
|
||||||
@@ -2166,7 +2175,8 @@ class BotInterface:
|
|||||||
delay = params.get_delay()
|
delay = params.get_delay()
|
||||||
series_size = params.get_series_size()
|
series_size = params.get_series_size()
|
||||||
logger.info(
|
logger.info(
|
||||||
f"⏳ Next series: {series_size} clicks, "
|
f"⏳ Next series: {series_size} clicks "
|
||||||
|
f"(range {params.min_series}-{params.max_series}), "
|
||||||
f"delay {delay}s ({delay//60}m {delay%60}s), "
|
f"delay {delay}s ({delay//60}m {delay%60}s), "
|
||||||
f"reading {params.min_reading}-{params.max_reading}s, "
|
f"reading {params.min_reading}-{params.max_reading}s, "
|
||||||
f"done {params.successful_visits}/{max_v}"
|
f"done {params.successful_visits}/{max_v}"
|
||||||
|
|||||||
+32
-12
@@ -87,19 +87,23 @@ class Proxy:
|
|||||||
|
|
||||||
line = rest
|
line = rest
|
||||||
|
|
||||||
# Парсим части
|
# Поддержка формата login:pass@ip:port
|
||||||
|
login = password = None
|
||||||
|
if "@" in line:
|
||||||
|
creds, line = line.rsplit("@", 1)
|
||||||
|
if ":" in creds:
|
||||||
|
login, password = creds.split(":", 1)
|
||||||
|
|
||||||
|
# Парсим ip:port или ip:port:login:pass
|
||||||
parts = line.split(":")
|
parts = line.split(":")
|
||||||
|
|
||||||
if len(parts) == 2:
|
if len(parts) == 2:
|
||||||
return cls(ip=parts[0], port=parts[1], proxy_type=proxy_type)
|
return cls(ip=parts[0], port=parts[1], proxy_type=proxy_type,
|
||||||
|
login=login, password=password)
|
||||||
elif len(parts) == 4:
|
elif len(parts) == 4:
|
||||||
return cls(
|
return cls(ip=parts[0], port=parts[1],
|
||||||
ip=parts[0],
|
login=parts[2], password=parts[3],
|
||||||
port=parts[1],
|
proxy_type=proxy_type)
|
||||||
login=parts[2],
|
|
||||||
password=parts[3],
|
|
||||||
proxy_type=proxy_type
|
|
||||||
)
|
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -294,9 +298,12 @@ class ProxyManager:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
working = self._working_status.get(proxy.id, True)
|
working = self._working_status.get(proxy.id, True)
|
||||||
scheme = proxy.proxy_type.value # socks5, http, etc.
|
scheme = proxy.proxy_type.value
|
||||||
creds = f"{proxy.login}:{proxy.password}@" if proxy.login else ""
|
# Формат совместимый с from_line: scheme://ip:port:login:pass
|
||||||
new_line = f"{scheme}://{creds}{proxy.ip}:{proxy.port}"
|
if proxy.login and proxy.password:
|
||||||
|
new_line = f"{scheme}://{proxy.ip}:{proxy.port}:{proxy.login}:{proxy.password}"
|
||||||
|
else:
|
||||||
|
new_line = f"{scheme}://{proxy.ip}:{proxy.port}"
|
||||||
|
|
||||||
if not working:
|
if not working:
|
||||||
new_line = f"!{new_line}"
|
new_line = f"!{new_line}"
|
||||||
@@ -410,6 +417,19 @@ class ProxyManager:
|
|||||||
loop = asyncio.get_running_loop()
|
loop = asyncio.get_running_loop()
|
||||||
await loop.run_in_executor(None, self._save_proxies_file)
|
await loop.run_in_executor(None, self._save_proxies_file)
|
||||||
|
|
||||||
|
def reload(self) -> int:
|
||||||
|
"""Перезагружает прокси из файла. Возвращает количество загруженных."""
|
||||||
|
self._proxies.clear()
|
||||||
|
self._working_status.clear()
|
||||||
|
self._in_use.clear()
|
||||||
|
self._usage_count.clear()
|
||||||
|
self._cooldown_until.clear()
|
||||||
|
self._used_ids.clear()
|
||||||
|
self._needs_detection.clear()
|
||||||
|
self._load_proxies()
|
||||||
|
logger.info(f"Proxies reloaded: {len(self._proxies)}")
|
||||||
|
return len(self._proxies)
|
||||||
|
|
||||||
def get_stats(self) -> dict:
|
def get_stats(self) -> dict:
|
||||||
"""Статистика прокси."""
|
"""Статистика прокси."""
|
||||||
loop = asyncio.get_running_loop()
|
loop = asyncio.get_running_loop()
|
||||||
|
|||||||
@@ -188,16 +188,26 @@ class BrowserService:
|
|||||||
else:
|
else:
|
||||||
return VisitResult(url=url, success=False, error="No proxy available")
|
return VisitResult(url=url, success=False, error="No proxy available")
|
||||||
|
|
||||||
|
# Определяем тип ошибки: ошибка соединения (прокси сломан) vs ошибка загрузки (прокси ok)
|
||||||
|
is_proxy_dead = result.error and any(
|
||||||
|
k in result.error for k in ("502", "Bad Gateway", "SOCKS", "NS_ERROR_PROXY")
|
||||||
|
)
|
||||||
|
is_load_error = result.error and not is_proxy_dead and any(
|
||||||
|
k in result.error for k in ("Timeout", "ERR_", "NS_ERROR_", "Connection")
|
||||||
|
)
|
||||||
|
|
||||||
if proxy:
|
if proxy:
|
||||||
await self.proxy_manager.release_proxy(proxy, result.success)
|
# Таймаут/ошибка загрузки — прокси не виноват, освобождаем без штрафа
|
||||||
|
release_success = True if is_load_error else result.success
|
||||||
|
await self.proxy_manager.release_proxy(proxy, release_success)
|
||||||
if use_socks5:
|
if use_socks5:
|
||||||
await self.socks5_pool.release(proxy)
|
await self.socks5_pool.release(proxy)
|
||||||
|
|
||||||
# Если таймаут или соединение не прошло — помечаем прокси как нерабочий и меняем
|
if is_proxy_dead:
|
||||||
if not result.success and result.error and any(
|
logger.warning(f"Visit attempt {attempt + 1} proxy connection failed, retrying with new")
|
||||||
k in result.error for k in ("Timeout", "ERR_", "Connection", "SOCKS", "NS_ERROR_", "502", "Bad Gateway")
|
continue
|
||||||
):
|
elif is_load_error:
|
||||||
logger.warning(f"Visit attempt {attempt + 1} bad proxy, retrying with new")
|
logger.warning(f"Visit attempt {attempt + 1} page load error (proxy ok), retrying")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|||||||
Reference in New Issue
Block a user