feat(logging): improve error handling and logging for file movement

Add retry logic to the `move` function to handle cases where files are locked or in use. Implement comprehensive error handling and logging to provide detailed feedback about file movement operations. Update the `Thon` class to include more informative logging messages for banned account handling and client disconnection. Improve the `ProcessThon` class with proper resource cleanup during disconnection.
This commit is contained in:
2026-03-07 16:07:04 +03:00
parent 865d39d512
commit 5ed6f960d5
3 changed files with 76 additions and 10 deletions

View File

@ -26,8 +26,21 @@ class Thon:
async with ProcessThon(session, self.__options) as thon:
if isinstance(thon, str):
if "Banned" in thon and self.__move_banned_folder:
await move(session.item)
await move(session.json_file)
print(
f"{session.item.name} | Аккаунт забанен, перемещение файлов..."
)
# Перемещаем файлы сессии с обработкой ошибок
success_session = await move(session.item, "banned")
success_json = await move(session.json_file, "banned")
if success_session and success_json:
print(
f"{session.item.name} | Файлы успешно перемещены / Files moved successfully"
)
else:
print(
f"{session.item.name} | Не удалось полностью переместить файлы / Failed to move all files"
)
if self.__callback_error is not None:
self.__callback_error()
continue

View File

@ -59,7 +59,7 @@ class ProcessThon(Data):
def __get_client(self) -> TelegramClient:
__session = str(self.__item) if self.__item else self.string_session
proxy = self.proxy
print(proxy)
self._logger.info(f"{self.session_file} | {proxy}")
client = TelegramClient(
session=__session,
api_id=self.app_id,
@ -169,14 +169,22 @@ class ProcessThon(Data):
return ""
async def disconnect(self):
"""Полное отключение клиента с очисткой ресурсов"""
# Сначала переводим в оффлайн (если есть)
with contextlib.suppress(Exception):
await self.client(UpdateStatusRequest(offline=True))
# Затем отключаем соединение (если есть)
with contextlib.suppress(Exception):
await self.client.disconnect() # type: ignore # ty:ignore[unused-ignore-comment]
await self.client.disconnect()
# Явно удаляем client из памяти
with contextlib.suppress(Exception):
del self.__client
async def __aenter__(self) -> Self | str:
r = await self.check()
print(r)
self._logger.info(f"{self.session_file} | {r}")
if r != "OK":
await self.disconnect()
return r

View File

@ -27,14 +27,59 @@ def extract_verification_code(text: str, regexp: str) -> str | None:
return code if code.isdigit() else None
async def move(path: Path, move_folder_name: str = "banned"):
async def move(
path: Path, move_folder_name: str = "banned", max_retries: int = 5
) -> bool:
"""
Перемещает файл с retry-логикой, если файл занят.
Возвращает True если успешно, False если не удалось.
"""
_folder = Path(f"sessions/{move_folder_name}")
__folder = Path(f"сессии/{move_folder_name}")
if __folder.exists():
_folder = __folder
_folder.mkdir(parents=True, exist_ok=True)
loop = asyncio.get_running_loop()
try:
await loop.run_in_executor(None, os.rename, path, _folder / path.name)
except OSError as e:
print(f"{path.name} | Error moving file / Не удалось переместить файл: {e}")
for attempt in range(max_retries):
try:
# Проверяем, что файл существует и доступен для чтения
if not path.exists():
print(f"{path.name} | Файл не найден / File not found")
return False
if not path.is_file():
print(f"{path.name} | Это не файл / Not a file")
return False
# Попытка переместить файл
await loop.run_in_executor(None, os.rename, path, _folder / path.name)
return True
except OSError:
if attempt < max_retries - 1:
# Ждем перед следующей попыткой (с экспоненциальной задержкой)
wait_time = 0.5 * (2**attempt) # 0.5s, 1s, 2s, 4s...
print(
f"{path.name} | Попытка {attempt + 1}/{max_retries}: файл занят, ждем {wait_time}s..."
)
await asyncio.sleep(wait_time)
else:
# Последняя попытка неудачна - попробуем копию
print(
f"{path.name} | Ошибка перемещения / Failed to move (final attempt), trying copy..."
)
try:
await loop.run_in_executor(
None, os.replace, path, _folder / path.name
)
print(f"{path.name} | Файл перемещен через копию / Moved via copy")
return True
except OSError as e:
print(
f"{path.name} | Не удалось ни переместить, ни скопировать / Failed to move or copy: {e}"
)
return False
return False