fix(core): arroyo conversation
Signed-off-by: rhunk <101876869+rhunk@users.noreply.github.com>
This commit is contained in:
@@ -325,7 +325,7 @@ class SnapEnhance {
|
||||
|
||||
MessagingFriendInfo(
|
||||
friendUserId,
|
||||
appContext.database.getConversationLinkFromUserId(friendUserId)?.clientConversationId,
|
||||
it.key,
|
||||
friend.displayName,
|
||||
friend.mutableUsername ?: friend.usernameForSorting!!,
|
||||
friend.bitmojiAvatarId,
|
||||
@@ -344,7 +344,7 @@ class SnapEnhance {
|
||||
return appContext.database.getFriendInfo(uuid)?.let {
|
||||
MessagingFriendInfo(
|
||||
userId = it.userId!!,
|
||||
dmConversationId = appContext.database.getConversationLinkFromUserId(it.userId!!)?.clientConversationId,
|
||||
dmConversationId = null,
|
||||
displayName = it.displayName,
|
||||
mutableUsername = it.mutableUsername!!,
|
||||
bitmojiId = it.bitmojiAvatarId,
|
||||
|
||||
@@ -54,7 +54,6 @@ import me.rhunk.snapenhance.core.ui.ViewAppearanceHelper
|
||||
import me.rhunk.snapenhance.core.util.EvictingMap
|
||||
import me.rhunk.snapenhance.core.util.dataBuilder
|
||||
import me.rhunk.snapenhance.mapper.impl.FriendRelationshipChangerMapper
|
||||
import java.net.URL
|
||||
import java.text.DateFormat
|
||||
import java.util.Date
|
||||
import kotlin.random.Random
|
||||
@@ -184,7 +183,7 @@ class BulkMessagingAction : AbstractAction() {
|
||||
}
|
||||
|
||||
private fun getDMLastMessage(userId: String?): ConversationMessage? {
|
||||
return context.database.getConversationLinkFromUserId(userId ?: return null)?.clientConversationId?.let {
|
||||
return context.database.getDMConversationId(userId ?: return null)?.let {
|
||||
context.database.getMessagesFromConversationId(it, 1)
|
||||
}?.firstOrNull()
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import me.rhunk.snapenhance.common.util.ktx.getInteger
|
||||
import me.rhunk.snapenhance.common.util.ktx.getStringOrNull
|
||||
import me.rhunk.snapenhance.common.util.protobuf.ProtoReader
|
||||
import me.rhunk.snapenhance.core.ModContext
|
||||
import me.rhunk.snapenhance.core.wrapper.impl.toSnapUUID
|
||||
import me.rhunk.snapenhance.nativelib.NativeLib
|
||||
|
||||
|
||||
@@ -30,6 +31,14 @@ class DatabaseAccess(
|
||||
) {
|
||||
private val openedDatabases = mutableMapOf<DatabaseType, SQLiteDatabase>()
|
||||
|
||||
private val hasArroyoConversationTable by lazy {
|
||||
useDatabase(DatabaseType.ARROYO)?.performOperation {
|
||||
safeRawQuery("SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'conversation'")?.use { query ->
|
||||
query.moveToFirst() && query.getStringOrNull("name") == "conversation"
|
||||
}
|
||||
} == true
|
||||
}
|
||||
|
||||
private fun useDatabase(database: DatabaseType, writeMode: Boolean = false): SQLiteDatabase? {
|
||||
// only cache read-only databases
|
||||
if (!writeMode && openedDatabases.containsKey(database) && openedDatabases[database]?.isOpen == true) {
|
||||
@@ -88,7 +97,44 @@ class DatabaseAccess(
|
||||
}.getOrNull()
|
||||
}
|
||||
|
||||
private val friendDMsCache by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
|
||||
getFeedEntries(Int.MAX_VALUE)
|
||||
.filter { it.conversationType == 0 && it.participantsSize == 2 }
|
||||
.associate { it.participants?.firstOrNull { it != myUserId } to it.key }
|
||||
.toMutableMap()
|
||||
}
|
||||
|
||||
private val dmOtherParticipantCache by lazy {
|
||||
if (hasArroyoConversationTable) {
|
||||
return@lazy useDatabase(DatabaseType.ARROYO)?.performOperation {
|
||||
safeRawQuery(
|
||||
"SELECT client_conversation_id, conversation_metadata FROM conversation",
|
||||
)?.use { query ->
|
||||
val result = mutableMapOf<String, String?>()
|
||||
if (!query.moveToFirst()) {
|
||||
return@performOperation null
|
||||
}
|
||||
do {
|
||||
val conversationId = query.getStringOrNull("client_conversation_id") ?: continue
|
||||
val conversationMetadata = ProtoReader(query.getBlobOrNull("conversation_metadata") ?: continue)
|
||||
|
||||
val participants = mutableListOf<String>()
|
||||
conversationMetadata.eachBuffer(3) {
|
||||
participants.add(getByteArray(1, 1)?.toSnapUUID()?.toString() ?: return@eachBuffer)
|
||||
}
|
||||
|
||||
result[conversationId] = if (participants.size == 2) {
|
||||
participants.firstOrNull { it != myUserId }?.also {
|
||||
result[it] = null
|
||||
}
|
||||
} else null
|
||||
} while (query.moveToNext())
|
||||
|
||||
result
|
||||
}
|
||||
}?.toMutableMap() ?: mutableMapOf()
|
||||
}
|
||||
|
||||
(useDatabase(DatabaseType.ARROYO)?.performOperation {
|
||||
safeRawQuery(
|
||||
"SELECT client_conversation_id, conversation_type, user_id FROM user_conversation WHERE user_id != ?",
|
||||
@@ -293,6 +339,10 @@ class DatabaseAccess(
|
||||
}
|
||||
|
||||
fun getConversationType(conversationId: String): Int? {
|
||||
if (hasArroyoConversationTable) {
|
||||
return getFeedEntryByConversationId(conversationId)?.conversationType
|
||||
}
|
||||
|
||||
return useDatabase(DatabaseType.ARROYO)?.performOperation {
|
||||
safeRawQuery(
|
||||
"SELECT conversation_type FROM user_conversation WHERE client_conversation_id = ?",
|
||||
@@ -306,37 +356,68 @@ class DatabaseAccess(
|
||||
}
|
||||
}
|
||||
|
||||
fun getConversationLinkFromUserId(userId: String): UserConversationLink? {
|
||||
fun getDMConversationId(userId: String): String? {
|
||||
if (hasArroyoConversationTable) {
|
||||
return friendDMsCache[userId]
|
||||
}
|
||||
|
||||
return useDatabase(DatabaseType.ARROYO)?.performOperation {
|
||||
readDatabaseObject(
|
||||
UserConversationLink(),
|
||||
"user_conversation",
|
||||
"user_id = ? AND conversation_type = 0",
|
||||
arrayOf(userId)
|
||||
)
|
||||
)?.clientConversationId
|
||||
}
|
||||
}
|
||||
|
||||
private fun getConversationParticipantsRaw(conversationId: String): List<String>? {
|
||||
if (hasArroyoConversationTable) {
|
||||
return useDatabase(DatabaseType.ARROYO)?.performOperation {
|
||||
safeRawQuery(
|
||||
"SELECT conversation_metadata FROM conversation WHERE client_conversation_id = ?",
|
||||
arrayOf(conversationId)
|
||||
)?.use { query ->
|
||||
val participants = mutableListOf<String>()
|
||||
if (!query.moveToFirst()) {
|
||||
return@performOperation null
|
||||
}
|
||||
val conversationMetadata = ProtoReader(query.getBlobOrNull("conversation_metadata") ?: return@performOperation null)
|
||||
|
||||
conversationMetadata.eachBuffer(3) {
|
||||
participants.add(getByteArray(1, 1)?.toSnapUUID()?.toString() ?: return@eachBuffer)
|
||||
}
|
||||
|
||||
participants
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return useDatabase(DatabaseType.ARROYO)?.performOperation {
|
||||
safeRawQuery(
|
||||
"SELECT user_id FROM user_conversation WHERE client_conversation_id = ?",
|
||||
arrayOf(conversationId)
|
||||
)?.use { query ->
|
||||
if (!query.moveToFirst()) {
|
||||
return@performOperation emptyList()
|
||||
}
|
||||
val participants = mutableListOf<String>()
|
||||
do {
|
||||
query.getStringOrNull("user_id")?.let { participants.add(it) }
|
||||
} while (query.moveToNext())
|
||||
participants
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getDMOtherParticipant(conversationId: String): String? {
|
||||
if (dmOtherParticipantCache.containsKey(conversationId)) return dmOtherParticipantCache[conversationId]
|
||||
return useDatabase(DatabaseType.ARROYO)?.performOperation {
|
||||
safeRawQuery(
|
||||
"SELECT user_id FROM user_conversation WHERE client_conversation_id = ? AND conversation_type = 0",
|
||||
arrayOf(conversationId)
|
||||
)?.use { query ->
|
||||
val participants = mutableListOf<String>()
|
||||
if (!query.moveToFirst()) {
|
||||
return@performOperation null
|
||||
}
|
||||
do {
|
||||
participants.add(query.getStringOrNull("user_id")!!)
|
||||
} while (query.moveToNext())
|
||||
participants.firstOrNull { it != myUserId }
|
||||
}.also { dmOtherParticipantCache[conversationId] = it }
|
||||
|
||||
return getConversationParticipantsRaw(conversationId)?.takeIf { it.size == 2 }?.firstOrNull { it != myUserId }.also {
|
||||
dmOtherParticipantCache[conversationId] = it
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun getStoryEntryFromId(storyId: String): StoryEntry? {
|
||||
return useDatabase(DatabaseType.MAIN)?.performOperation {
|
||||
readDatabaseObject(StoryEntry(), "Story", "storyId = ?", arrayOf(storyId))
|
||||
@@ -345,28 +426,10 @@ class DatabaseAccess(
|
||||
|
||||
fun getConversationParticipants(conversationId: String, useCache: Boolean = true): List<String>? {
|
||||
if (dmOtherParticipantCache[conversationId] != null && useCache) return dmOtherParticipantCache[conversationId]?.let { listOf(myUserId, it) }
|
||||
return useDatabase(DatabaseType.ARROYO)?.performOperation {
|
||||
safeRawQuery(
|
||||
"SELECT user_id, conversation_type FROM user_conversation WHERE client_conversation_id = ?",
|
||||
arrayOf(conversationId)
|
||||
)?.use { cursor ->
|
||||
if (!cursor.moveToFirst()) {
|
||||
return@performOperation null
|
||||
}
|
||||
val participants = mutableListOf<String>()
|
||||
var conversationType = -1
|
||||
do {
|
||||
if (conversationType == -1) conversationType = cursor.getInteger("conversation_type")
|
||||
participants.add(cursor.getStringOrNull("user_id")!!)
|
||||
} while (cursor.moveToNext())
|
||||
|
||||
if (!dmOtherParticipantCache.containsKey(conversationId)) {
|
||||
dmOtherParticipantCache[conversationId] = when (conversationType) {
|
||||
0 -> participants.firstOrNull { it != myUserId }
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
participants
|
||||
return getConversationParticipantsRaw(conversationId)?.also {
|
||||
if (!dmOtherParticipantCache.containsKey(conversationId)) {
|
||||
dmOtherParticipantCache[conversationId] = it.firstOrNull { it != myUserId }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,5 +116,5 @@ class CoreMessagingBridge(
|
||||
}
|
||||
}
|
||||
|
||||
override fun getOneToOneConversationId(userId: String) = context.database.getConversationLinkFromUserId(userId)?.clientConversationId
|
||||
override fun getOneToOneConversationId(userId: String) = context.database.getDMConversationId(userId)
|
||||
}
|
||||
Reference in New Issue
Block a user