diff --git a/src/common/tools.py b/src/common/tools.py index 1b322f3..9ad93c8 100644 --- a/src/common/tools.py +++ b/src/common/tools.py @@ -429,6 +429,44 @@ class Tools: # Возвращаем айдишки return int(message_id), int(last_message_id), message_time + async def collect_bootstrap_history( + self, chatIds, db_pool, senderId, protocol_type="mobile", limit=50, include_favourites=True + ): + """Собирает карту {chatId: [messages...]} для bootstrap-pre-fetch в LOGIN. + + Десктопный MAX в ответе LOGIN ждёт поле `messages` как карту чат→история. + Если карта пустая — клиент полагает, что у него уже есть локальная + история и НЕ запрашивает CHAT_HISTORY (49). В итоге в окне чата + видно только lastMessage из chats[]. + """ + result = {} + + async def _fetch(chat_db_id, key_for_client): + async with db_pool.acquire() as conn: + async with conn.cursor() as cursor: + await cursor.execute( + "SELECT * FROM `messages` WHERE chat_id = %s ORDER BY time DESC LIMIT %s", + (chat_db_id, limit), + ) + rows = await cursor.fetchall() + + if not rows: + return + + messages = [self.build_message_dict(row, protocol_type) for row in rows] + messages.sort(key=lambda m: m["time"]) + result[key_for_client] = messages + + for chatId in chatIds: + await _fetch(chatId, chatId) + + if include_favourites: + # Избранное: в БД хранится как chat_id = -senderId, + # но клиенту отдаётся под id = senderId ^ senderId (= 0) + await _fetch(-senderId, senderId ^ senderId) + + return result + async def get_last_message(self, chatId, db_pool, protocol_type="mobile"): """Получение последнего сообщения в чате""" async with db_pool.acquire() as db_connection: diff --git a/src/oneme/processors/auth.py b/src/oneme/processors/auth.py index da646c1..4120200 100644 --- a/src/oneme/processors/auth.py +++ b/src/oneme/processors/auth.py @@ -603,11 +603,24 @@ class AuthProcessors(BaseProcessor): username=user.get("username"), ) + # Список ID чатов до того как generate_chats затрёт переменную + chat_ids_for_history = list(chats) + # Генерируем список чатов chats = await self.tools.generate_chats( chats, self.db_pool, user.get("id"), protocol_type=self.type ) + # Bootstrap-история: карта {chatId: [messages]}. + # Без неё десктопный MAX считает, что локальная история уже + # синхронизирована, и не запрашивает CHAT_HISTORY (49). + bootstrap_messages = await self.tools.collect_bootstrap_history( + chat_ids_for_history, + self.db_pool, + user.get("id"), + protocol_type=self.type, + ) + # Генерируем список контактов contacts = await self.tools.collect_user_contacts( user.get("id"), self.db_pool, self.config.avatar_base_url @@ -621,8 +634,8 @@ class AuthProcessors(BaseProcessor): payload = { "profile": profile, "chats": chats, - "chatMarker": 0, - "messages": {}, + "chatMarker": int(time.time() * 1000), + "messages": bootstrap_messages, "contacts": contacts, "presence": presence, "config": {