This commit is contained in:
Yuriy Yuriev
2026-05-18 21:19:05 +07:00
parent 88bd8bfefa
commit 0102461e78
4 changed files with 173 additions and 75 deletions
+52 -31
View File
@@ -165,17 +165,19 @@ class TwitchIRCClient:
return False
async def listen_for_messages(
self,
on_url_found: Callable[[str, str], Awaitable[None]],
duration: int,
allowed_domains: Optional[List[str]] = None,
is_active: Callable[[], bool] = None, # Функция проверки активности
) -> dict:
self,
on_url_found: Callable[[str, str], Awaitable[None]],
duration: int,
allowed_domains: Optional[List[str]] = None,
is_active: Callable[[], bool] = None,
on_drain_fail: Callable[[], Awaitable[None]] = None,
) -> dict:
stats = {"links_found": 0, "messages": 0, "reconnects": 0}
start_time = datetime.now()
last_message_time = datetime.now()
drain_errors = 0
if not await self.connect():
raise ConnectionError(f"IRC connect failed for #{self.channel}")
@@ -194,28 +196,47 @@ class TwitchIRCClient:
# === ПЕРЕПОДКЛЮЧЕНИЕ КАЖДЫЕ 30 СЕКУНД ===
if (datetime.now() - last_message_time).seconds > 30:
logger.info("🔄 Reconnecting (30s)...")
# Сначала читаем всё что осталось
try:
while True:
line = await asyncio.wait_for(self._reader.readline(), timeout=1.0)
if not line:
break
decoded = line.decode('utf-8', errors='ignore').strip()
if 'PRIVMSG' in decoded:
msg = self._parse_message(decoded)
if msg:
stats["messages"] += 1
for url in self._extract_urls(msg['message']):
if self._is_domain_allowed(url, allowed_domains):
stats["links_found"] += 1
try:
await on_url_found(url, msg['display_name'])
except Exception as e:
logger.warning(f"URL callback error: {e}")
except Exception as e:
logger.warning(f"Error draining IRC data: {e}")
# Сначала читаем всё что осталось (с retry)
drain_ok = False
for attempt in range(3):
try:
while True:
line = await asyncio.wait_for(self._reader.readline(), timeout=1.0)
if not line:
break
decoded = line.decode('utf-8', errors='ignore').strip()
if 'PRIVMSG' in decoded:
msg = self._parse_message(decoded)
if msg:
stats["messages"] += 1
for url in self._extract_urls(msg['message']):
if self._is_domain_allowed(url, allowed_domains):
stats["links_found"] += 1
try:
await on_url_found(url, msg['display_name'])
except Exception as e:
logger.warning(f"URL callback error: {e}")
drain_ok = True
break
except asyncio.TimeoutError:
drain_ok = True
break
except Exception as e:
logger.warning(f"Error draining IRC data (attempt {attempt + 1}/3): {e}")
await asyncio.sleep(2)
if not drain_ok:
drain_errors += 1
logger.error(f"IRC drain failed 3 times, total failures: {drain_errors}")
if drain_errors >= 3:
logger.error("IRC drain failed 3 consecutive times — pausing task")
if on_drain_fail:
await on_drain_fail()
return stats
else:
drain_errors = 0
# Переподключаемся
try:
await self.disconnect()
@@ -223,7 +244,7 @@ class TwitchIRCClient:
logger.warning(f"Disconnect error: {e}")
await asyncio.sleep(1)
await self.connect()
stats["reconnects"] += 1
last_message_time = datetime.now()
continue