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:
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user