feat: Enhance logging in MessageRepository and ChatsListViewModel for better debugging and flow tracking

This commit is contained in:
k1ngsterr1
2026-01-13 23:28:48 +05:00
parent 14ef342e80
commit 2c173bda26
6 changed files with 232 additions and 94 deletions

View File

@@ -75,23 +75,44 @@ class MessageRepository private constructor(private val context: Context) {
INSTANCE ?: MessageRepository(context.applicationContext).also { INSTANCE = it }
}
}
/**
* Генерация детерминированного messageId на основе данных сообщения
* Аналог generateRandomKeyFormSeed из Архива
*/
fun generateMessageId(fromPublicKey: String, toPublicKey: String, timestamp: Long): String {
val seed = fromPublicKey + toPublicKey + timestamp.toString()
val hash = java.security.MessageDigest.getInstance("SHA-256")
.digest(seed.toByteArray())
// Берём первые 16 символов hex-представления
return hash.take(8).joinToString("") { String.format("%02x", it) }
}
}
/**
* Инициализация с текущим аккаунтом
*/
fun initialize(publicKey: String, privateKey: String) {
android.util.Log.d("MessageRepository", "🔐 initialize() called with publicKey: ${publicKey.take(16)}...")
currentAccount = publicKey
currentPrivateKey = privateKey
// Загрузка диалогов
scope.launch {
dialogDao.getDialogsFlow(publicKey).collect { entities ->
android.util.Log.d("MessageRepository", "📋 MessageRepository dialogsFlow emitted: ${entities.size} dialogs")
_dialogs.value = entities.map { it.toDialog() }
}
}
}
/**
* Проверка инициализации
*/
fun isInitialized(): Boolean {
return currentAccount != null && currentPrivateKey != null
}
/**
* Получить поток сообщений для диалога
*/
@@ -210,13 +231,39 @@ class MessageRepository private constructor(private val context: Context) {
* Обработка входящего сообщения
*/
suspend fun handleIncomingMessage(packet: PacketMessage) {
val account = currentAccount ?: return
val privateKey = currentPrivateKey ?: return
android.util.Log.d("MessageRepository", "═══════════════════════════════════════")
android.util.Log.d("MessageRepository", "📩 handleIncomingMessage START")
android.util.Log.d("MessageRepository", " from: ${packet.fromPublicKey.take(20)}...")
// Проверяем, не дубликат ли
if (messageDao.messageExists(account, packet.messageId)) return
// 🔥 Генерируем messageId если он пустой (как в Архиве - generateRandomKeyFormSeed)
val messageId = if (packet.messageId.isBlank()) {
generateMessageId(packet.fromPublicKey, packet.toPublicKey, packet.timestamp)
} else {
packet.messageId
}
android.util.Log.d("MessageRepository", " messageId: $messageId (original: ${packet.messageId})")
android.util.Log.d("MessageRepository", " currentAccount: ${currentAccount?.take(20) ?: "NULL"}...")
android.util.Log.d("MessageRepository", " currentPrivateKey: ${if (currentPrivateKey != null) "SET" else "NULL"}")
val account = currentAccount ?: run {
android.util.Log.e("MessageRepository", "❌ ABORT: currentAccount is NULL!")
return
}
val privateKey = currentPrivateKey ?: run {
android.util.Log.e("MessageRepository", "❌ ABORT: currentPrivateKey is NULL!")
return
}
// Проверяем, не дубликат ли (используем сгенерированный messageId)
val isDuplicate = messageDao.messageExists(account, messageId)
android.util.Log.d("MessageRepository", " isDuplicate: $isDuplicate")
if (isDuplicate) {
android.util.Log.d("MessageRepository", "⚠️ Skipping duplicate message")
return
}
val dialogKey = getDialogKey(packet.fromPublicKey)
android.util.Log.d("MessageRepository", " dialogKey: $dialogKey")
try {
// Расшифровываем
@@ -247,21 +294,25 @@ class MessageRepository private constructor(private val context: Context) {
read = 0,
fromMe = 0,
delivered = DeliveryStatus.DELIVERED.value,
messageId = packet.messageId,
messageId = messageId, // 🔥 Используем сгенерированный messageId!
plainMessage = encryptedPlainMessage, // 🔒 Зашифрованный текст
attachments = attachmentsJson,
dialogKey = dialogKey
)
messageDao.insertMessage(entity)
android.util.Log.d("MessageRepository", "✅ Message saved to DB: ${packet.messageId.take(16)}...")
// Обновляем диалог
android.util.Log.d("MessageRepository", "🔄 Calling updateDialog for ${packet.fromPublicKey.take(16)}...")
updateDialog(packet.fromPublicKey, plainText, packet.timestamp, incrementUnread = true)
android.util.Log.d("MessageRepository", "✅ updateDialog completed!")
// Обновляем кэш
val message = entity.toMessage()
updateMessageCache(dialogKey, message)
} catch (e: Exception) {
android.util.Log.e("MessageRepository", "❌ Error handling incoming message", e)
e.printStackTrace()
}
}
@@ -301,13 +352,20 @@ class MessageRepository private constructor(private val context: Context) {
/**
* Отметить диалог как прочитанный
* 🔥 После обновления messages обновляем диалог через updateDialogFromMessages
*/
suspend fun markDialogAsRead(opponentKey: String) {
val account = currentAccount ?: return
val dialogKey = getDialogKey(opponentKey)
// Отмечаем сообщения как прочитанные
messageDao.markDialogAsRead(account, dialogKey)
dialogDao.clearUnreadCount(account, opponentKey)
// 🔥 КРИТИЧНО: Пересчитываем счетчики из таблицы messages
// чтобы unread_count обновился моментально
dialogDao.updateDialogFromMessages(account, opponentKey)
android.util.Log.d("MessageRepository", "✅ Dialog marked as read and updated from messages")
}
/**
@@ -392,21 +450,42 @@ class MessageRepository private constructor(private val context: Context) {
incrementUnread: Boolean = false
) {
val account = currentAccount ?: return
val privateKey = currentPrivateKey ?: return
val existing = dialogDao.getDialog(account, opponentKey)
if (existing != null) {
dialogDao.updateLastMessage(account, opponentKey, lastMessage, timestamp)
if (incrementUnread) {
dialogDao.incrementUnreadCount(account, opponentKey)
android.util.Log.d("MessageRepository", "📝 Updating dialog for ${opponentKey.take(16)}...")
android.util.Log.d("MessageRepository", " lastMessage: ${lastMessage.take(50)}")
try {
// 🔥 КРИТИЧНО: Сначала считаем реальное количество непрочитанных из messages
val unreadCount = messageDao.getUnreadCountForDialog(account, opponentKey)
android.util.Log.d("MessageRepository", " unreadCount from messages: $unreadCount")
// 🔒 Шифруем lastMessage
val encryptedLastMessage = CryptoManager.encryptWithPassword(lastMessage, privateKey)
// Проверяем существует ли диалог
val existing = dialogDao.getDialog(account, opponentKey)
if (existing != null) {
// Обновляем существующий диалог
android.util.Log.d("MessageRepository", " ✏️ Updating existing dialog...")
dialogDao.updateLastMessage(account, opponentKey, encryptedLastMessage, timestamp)
dialogDao.updateUnreadCount(account, opponentKey, unreadCount)
} else {
// Создаем новый диалог
android.util.Log.d("MessageRepository", " Creating new dialog...")
dialogDao.insertDialog(DialogEntity(
account = account,
opponentKey = opponentKey,
lastMessage = encryptedLastMessage,
lastMessageTimestamp = timestamp,
unreadCount = unreadCount
))
}
} else {
dialogDao.insertDialog(DialogEntity(
account = account,
opponentKey = opponentKey,
lastMessage = lastMessage,
lastMessageTimestamp = timestamp,
unreadCount = if (incrementUnread) 1 else 0
))
android.util.Log.d("MessageRepository", " ✅ Dialog updated successfully!")
} catch (e: Exception) {
android.util.Log.e("MessageRepository", " ❌ Error updating dialog", e)
}
}