fix proxy
This commit is contained in:
+11
-1
@@ -255,6 +255,14 @@ class BotInterface:
|
||||
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")
|
||||
async def cb_restart_confirm(callback: CallbackQuery):
|
||||
if not await require_admin(callback):
|
||||
@@ -1685,6 +1693,7 @@ class BotInterface:
|
||||
)
|
||||
builder = InlineKeyboardBuilder()
|
||||
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="menu_main"))
|
||||
await self._edit_or_send(message, text, builder.as_markup(), edit)
|
||||
@@ -2166,7 +2175,8 @@ class BotInterface:
|
||||
delay = params.get_delay()
|
||||
series_size = params.get_series_size()
|
||||
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"reading {params.min_reading}-{params.max_reading}s, "
|
||||
f"done {params.successful_visits}/{max_v}"
|
||||
|
||||
+32
-12
@@ -87,19 +87,23 @@ class Proxy:
|
||||
|
||||
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(":")
|
||||
|
||||
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:
|
||||
return cls(
|
||||
ip=parts[0],
|
||||
port=parts[1],
|
||||
login=parts[2],
|
||||
password=parts[3],
|
||||
proxy_type=proxy_type
|
||||
)
|
||||
return cls(ip=parts[0], port=parts[1],
|
||||
login=parts[2], password=parts[3],
|
||||
proxy_type=proxy_type)
|
||||
|
||||
return None
|
||||
|
||||
@@ -294,9 +298,12 @@ class ProxyManager:
|
||||
continue
|
||||
|
||||
working = self._working_status.get(proxy.id, True)
|
||||
scheme = proxy.proxy_type.value # socks5, http, etc.
|
||||
creds = f"{proxy.login}:{proxy.password}@" if proxy.login else ""
|
||||
new_line = f"{scheme}://{creds}{proxy.ip}:{proxy.port}"
|
||||
scheme = proxy.proxy_type.value
|
||||
# Формат совместимый с from_line: scheme://ip:port:login:pass
|
||||
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:
|
||||
new_line = f"!{new_line}"
|
||||
@@ -410,6 +417,19 @@ class ProxyManager:
|
||||
loop = asyncio.get_running_loop()
|
||||
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:
|
||||
"""Статистика прокси."""
|
||||
loop = asyncio.get_running_loop()
|
||||
|
||||
@@ -188,16 +188,26 @@ class BrowserService:
|
||||
else:
|
||||
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:
|
||||
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:
|
||||
await self.socks5_pool.release(proxy)
|
||||
|
||||
# Если таймаут или соединение не прошло — помечаем прокси как нерабочий и меняем
|
||||
if not result.success and result.error and any(
|
||||
k in result.error for k in ("Timeout", "ERR_", "Connection", "SOCKS", "NS_ERROR_", "502", "Bad Gateway")
|
||||
):
|
||||
logger.warning(f"Visit attempt {attempt + 1} bad proxy, retrying with new")
|
||||
if is_proxy_dead:
|
||||
logger.warning(f"Visit attempt {attempt + 1} proxy connection failed, retrying with new")
|
||||
continue
|
||||
elif is_load_error:
|
||||
logger.warning(f"Visit attempt {attempt + 1} page load error (proxy ok), retrying")
|
||||
continue
|
||||
|
||||
return result
|
||||
|
||||
Reference in New Issue
Block a user