Added autodelete of backup messsges

This commit is contained in:
Corrado Mulas
2026-06-19 17:21:57 +02:00
parent 5d15de651a
commit c4a99d24e7

View File

@@ -1,5 +1,6 @@
import logging import logging
import asyncio import asyncio
import re
from typing import Awaitable, Callable, List, Optional from typing import Awaitable, Callable, List, Optional
from telethon import functions, types from telethon import functions, types
@@ -20,6 +21,10 @@ from src.utils.qr_backup import build_qr_image
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
StatusCallback = Callable[[str], Awaitable[object]] StatusCallback = Callable[[str], Awaitable[object]]
GROUPHELP_IMPORT_STATUS_RE = re.compile(r"🔀\s*Importazione Backup", re.IGNORECASE)
GROUPHELP_QR_DELETE_DELAY_SECONDS = 5
GROUPHELP_IMPORT_CLEANUP_WINDOW_SECONDS = 30
GROUPHELP_IMPORT_CLEANUP_POLL_SECONDS = 3
class GroupService: class GroupService:
"""Service class for group creation and management""" """Service class for group creation and management"""
@@ -36,6 +41,90 @@ class GroupService:
return await status_callback(message) return await status_callback(message)
return None return None
def _sent_message_ids(self, sent_message) -> List[int]:
if not sent_message:
return []
messages = sent_message if isinstance(sent_message, list) else [sent_message]
return [message.id for message in messages if getattr(message, "id", None)]
def _message_text(self, message) -> str:
return (
getattr(message, "raw_text", None)
or getattr(message, "text", None)
or getattr(message, "message", None)
or ""
)
def _is_grouphelp_import_status(self, message) -> bool:
return bool(GROUPHELP_IMPORT_STATUS_RE.search(self._message_text(message)))
async def _delete_messages_safely(self, target_group, message_ids: List[int], reason: str) -> int:
if not message_ids:
return 0
try:
await self.client.delete_messages(target_group, message_ids, revoke=True)
logger.info("Deleted %s message(s): %s", reason, message_ids)
return len(message_ids)
except Exception as e:
logger.warning("Failed to delete %s message(s) %s: %s", reason, message_ids, e)
return 0
async def _cleanup_grouphelp_import_artifacts(self, target_group, sent_message, qr_group: str):
sent_ids = self._sent_message_ids(sent_message)
min_message_id = min(sent_ids) if sent_ids else 0
await asyncio.sleep(GROUPHELP_QR_DELETE_DELAY_SECONDS)
await self._delete_messages_safely(target_group, sent_ids, "GroupHelp QR import")
deleted_status_ids = set()
deadline = asyncio.get_running_loop().time() + GROUPHELP_IMPORT_CLEANUP_WINDOW_SECONDS
while asyncio.get_running_loop().time() < deadline:
status_ids = []
try:
async for message in self.client.iter_messages(target_group, limit=20):
message_id = getattr(message, "id", None)
if not message_id or message_id in deleted_status_ids:
continue
if min_message_id and message_id < min_message_id:
continue
if self._is_grouphelp_import_status(message):
status_ids.append(message_id)
except Exception as e:
logger.warning("Failed to scan GroupHelp import status messages for %s: %s", qr_group, e)
return
if status_ids:
await self._delete_messages_safely(target_group, status_ids, "GroupHelp import status")
deleted_status_ids.update(status_ids)
await asyncio.sleep(GROUPHELP_IMPORT_CLEANUP_POLL_SECONDS)
def _log_background_task_result(self, task: asyncio.Task):
try:
task.result()
except asyncio.CancelledError:
pass
except Exception as e:
logger.warning("Background GroupHelp cleanup failed: %s", e)
def _schedule_grouphelp_import_cleanup(self, target_group, sent_message, qr_group: str):
task = asyncio.create_task(
self._cleanup_grouphelp_import_artifacts(target_group, sent_message, qr_group),
name=f"grouphelp-import-cleanup-{qr_group}",
)
task.add_done_callback(self._log_background_task_result)
return task
async def _send_grouphelp_qr_import(self, target_group, qr_data: str, qr_group: str = DEFAULT_QR_GROUP):
qr_image = build_qr_image(qr_data)
sent_message = await self.client.send_file(
target_group,
qr_image,
caption=".importbackup",
force_document=False,
)
return self._schedule_grouphelp_import_cleanup(target_group, sent_message, qr_group)
async def _edit_status(self, status_message, message: str): async def _edit_status(self, status_message, message: str):
if hasattr(status_message, "edit"): if hasattr(status_message, "edit"):
await status_message.edit(message) await status_message.edit(message)
@@ -288,13 +377,7 @@ class GroupService:
qr_data = get_qr_data() qr_data = get_qr_data()
if qr_data: if qr_data:
logger.info("Sending GroupHelp QR backup import image") logger.info("Sending GroupHelp QR backup import image")
qr_image = build_qr_image(qr_data) await self._send_grouphelp_qr_import(target_group, qr_data)
await self.client.send_file(
target_group,
qr_image,
caption=".importbackup",
force_document=False,
)
qr_imported = True qr_imported = True
if staff_chat_id: if staff_chat_id:
await self.client.send_message(staff_chat_id, "✅ GroupHelp QR backup image sent to the new group.") await self.client.send_message(staff_chat_id, "✅ GroupHelp QR backup image sent to the new group.")
@@ -357,6 +440,7 @@ class GroupService:
skipped = 0 skipped = 0
errors = [] errors = []
owned_groups = [] owned_groups = []
cleanup_tasks = []
assignments = get_qr_group_assignments() assignments = get_qr_group_assignments()
async for dialog in self.client.iter_dialogs(): async for dialog in self.client.iter_dialogs():
@@ -390,12 +474,8 @@ class GroupService:
try: try:
logger.info("Sending stored GroupHelp QR backup %s to owned group %s", group, group_name) logger.info("Sending stored GroupHelp QR backup %s to owned group %s", group, group_name)
qr_image = build_qr_image(qr_data) cleanup_tasks.append(
await self.client.send_file( await self._send_grouphelp_qr_import(dialog.entity, qr_data, qr_group=group)
dialog.entity,
qr_image,
caption=".importbackup",
force_document=False,
) )
sent += 1 sent += 1
await self._notify( await self._notify(
@@ -412,6 +492,9 @@ class GroupService:
if index < matched - 1: if index < matched - 1:
await asyncio.sleep(delay_seconds) await asyncio.sleep(delay_seconds)
if cleanup_tasks:
await asyncio.gather(*cleanup_tasks, return_exceptions=True)
await self._notify( await self._notify(
status_callback, status_callback,
f"✅ GroupHelp QR sync for `{group}` complete. Sent: {sent}, failed: {failed}, owned groups: {matched}.", f"✅ GroupHelp QR sync for `{group}` complete. Sent: {sent}, failed: {failed}, owned groups: {matched}.",