From d2afecafcfd3cf19b95a6b459c8393efcef6482b Mon Sep 17 00:00:00 2001 From: James Magahern Date: Mon, 15 Apr 2024 19:38:40 -0700 Subject: [PATCH] Try only synchronizing messages after last GUID --- backend/chat-cache-test | Bin 32768 -> 32768 bytes backend/chat-cache-test.lock | Bin 1728 -> 1728 bytes .../backend/db/CachedChatDatabase.kt | 18 ++++++++++++++++-- .../backend/db/model/Conversation.kt | 16 +++++++++------- .../kordophone/backend/model/Conversation.kt | 7 +++++-- .../backend/server/ChatRepository.kt | 10 ++++------ .../kordophone/backend/BackendTests.kt | 14 ++++++++++---- .../buzzert/kordophone/backend/MockServer.kt | 15 +++++++++++++-- 8 files changed, 57 insertions(+), 23 deletions(-) diff --git a/backend/chat-cache-test b/backend/chat-cache-test index ccbf1ede010fab1f62342d41adb511164ada4ae3..650c92949dca635c0f848db56b0864cd6d25c1c8 100644 GIT binary patch literal 32768 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 literal 32768 zcmeHPO>i4WcJ9IN5FkKMq(sQ0l7V7Kig-A_@tx; zpmwMUP5(N@>j{ROLZ3c=T;mmkKd#muudV*l`TVb(Cj+Fw*yO77Z2fWd@v5`3zBYiw z1lC|+N7?r3^Oa|=Q+x3A`O5l$?rajvv@Ta+;hFo{WA|6bn#G6@$T7qcDaH~)K9Cpw zd?k(f9{QNC>}PrjZAwAF)SlME)JmG}BU(xRN%cCQ-m)ZN6dKi|?5@+YZ?)S`)vNxX zAJ*7{Z_&5p+we7gn`lY>F)3a`Aler1-K7_5OPFZ&v=7l556VOjdO&zeU+~W%O6vC^ zV{xlzJR0+bgoV~Hwk=_$KdOFD^-~qpxhH8X&>&FtqwkbxTy%l{O?Tm8^l#nW7^oPW z2xC{*+?AU9OhT^~Z=9xo&icAjU4G)Otbh26KY#d&3MZ;PCj_F!dw7-12w)O%TM21e6{qz3MN~NTYt#no9Kd zv7jDQa7osye!xR7_X7uk!$2aK3eKV>^}}R&>4ILF_wLdQEl8MX_O$=r^m2#uPNRur z%JJ1SmgE@(P!W(N^pfkO>Zj0BZhl>}{5$AN@Hk_O8jIj`V^J1^P&CaK zVcO(BG@7lzMXm@R_<1xK4IKmQ2Rl2H^Z%PN7BVO z+D?yLz?zTFy47EW>eQcD?YxOr{D2Sp*+#e--U}!6ls*dt z;fan@DWnx07j(+HV43jf7h2?0sRj0d?Dye-bJUdWlwK}NSP3vFNU;8MRJE6A2t3fB z@2VetrzGbCeQoGH`g#ZY30>tH%C2)2Wj9!iYblFyHDxibrwkiG(gB~EK0=V7i@60B ze3ri)YLC!31aGnpwg-(P7)O8LzG%+p@kr|9A$ZhMj4goH67niCEgSJ#!gu0)nFX^Cj^O_J?11(@(FZLmsA~sb`sZ_2 zy#*PK#-GPNC`T3}8=x;?tr1~g{~n&2gr&Z1Mtb#aklwT;ze*4K^@ik0>HK=rj`Zlw zThN>1T60V5*PE5vV<$!Y(0Y}kVjcuTo+DztHp8ag(Djk_h(7wU^W>>$Pk6CzODqZh zcZ+SZLw^dVlB-jH@H&$H_!plLMS|7(nHWP$G1frYLhc~rkFVb1Knr&z5W-*;L9p>h< zMW>dl8tF7X(8x9%*Qyw~qFbm{YV}O6U@|*XGwW%$V7U288jbR%;pEe{k;}Q6YSpe3 zv-LEy3r;dLeIA^0k_g%Q$Jn%7Vo-CY-P3t$N<9u{_Diw5o=a z&SAKG9uv=CbSqOSf?21 zh2)QQklHQQV;=iPADtb2DeWPO$S2E>*HZX%QtR&8`c3vjgNY9ua}g?GFQUp0ku5qc z@3AGWhv*k6{afLkVKR*aIr%o?TX2(w+)8r%*XcXNU88=3`KAL_ncGA=3TVm_Sc0R7RJWe1Wwl= zc4(N5!Nu|O{VC@kYJj#%Y8<})T07E!A)t1kqaBh_Kq8pVW7@lv2qyDF<*Vnk_G~CW z#%shbP6X?ZSDe%*v>s%~`u%lFt~Yd)r} z4G3&NU<1*hzy<|2D6m0+4Msx(8xq)%z=i}i6b%b(SYX2f8y47bR2NuXV0D4j1y+xa z2<(W!jtK0Cz>cJ7y&(G-+3WqlPOuz0ve{;IcWiq?*g@5f>~_EH-et4Q8cmP`$^Ajt z?^w1D1CE1(`aP2VU>j?$l^8P-3@joyka5Oy`@Ky#e5b7ZLE6_dfGH6j90fC(w3{=F z^&IS+?UDgD5ud;!xtU@n@8q2djP^2ZjDS)Jopw|C)Bj>^5)3TPq{>3Wn}>`Mxm`6dLG1|hz{r?x2%0D>`xOGkP-8{P~b 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 bJPCLb@Fd_#z>|O{0Z#&+1Uw16Mgso_j1UB5 diff --git a/backend/chat-cache-test.lock b/backend/chat-cache-test.lock index 4b8f81e5226419049e0287337c73a5bf47fbafd5..ccc2fcbd6717cdf9be093931d886762cde487c66 100644 GIT binary patch literal 1728 zcmZS7Fkld8;$vWBU;tx5AdL(JkU3B`NG%LZfHAPp)K-VZia{-e?0;e$imVmo5utbhN`n*hY6snV}S`n)otL0381QDg$XM_7#1Qh z0aSHtFkz^=3UQbKsyeuHpz3x=VOPfi6Lx?wG?ZWhsOG_g0jf?x1-m+U7&k!VSGXe7 zA+zAY-~bWj&_l=~hchos7^-fCIZOc6ef%)t1_;B!1tx&14xS&O>Nfa5)Pd|owils$ Llr+23D{Tv2Y=o z$+ur7yR(pBwJ}K;nZTImHLao?6ZycobumgLp7?3c^NF8Ea{uovRQk5>zTRgQAMsTM z)37%?VhTl%qP@#{AuxOQHh}h;!0g3+0PVGa*}Dz^wC6sP(R?X3CD+%%>+GFo0J>fm zn7uRs(4K1pd-2@wx$Uucd*Qk5`HGr, conversation: ModelConversation, outgoing: Boolean = false) { + if (messages.isEmpty()) { + return + } + val dbConversation = getManagedConversationByGuid(conversation.guid) realm.writeBlocking { messages @@ -128,8 +133,17 @@ class CachedChatDatabase (private val realmConfig: RealmConfiguration) { .map { copyToRealm(it, updatePolicy = UpdatePolicy.ALL) } findLatest(dbConversation)?.let { - it.lastMessagePreview = messages.last().displayText - it.date = messages.last().date.toInstant().toRealmInstant() + val lastMessage = messages.maxByOrNull { it.date }!! + + val lastMessageDate = lastMessage.date.toInstant().toRealmInstant() + if (lastMessageDate > it.date) { + it.lastMessageGUID = lastMessage.guid + it.lastMessagePreview = lastMessage.displayText + + // This will cause sort order to change. I think this ends + // up getting updated whenever we get conversation changes anyway. + // it.date = lastMessageDate + } } } } diff --git a/backend/src/main/java/net/buzzert/kordophone/backend/db/model/Conversation.kt b/backend/src/main/java/net/buzzert/kordophone/backend/db/model/Conversation.kt index 0c455db..0cf3dfb 100644 --- a/backend/src/main/java/net/buzzert/kordophone/backend/db/model/Conversation.kt +++ b/backend/src/main/java/net/buzzert/kordophone/backend/db/model/Conversation.kt @@ -1,17 +1,13 @@ package net.buzzert.kordophone.backend.db.model -import io.realm.kotlin.Realm import io.realm.kotlin.ext.realmListOf -import io.realm.kotlin.ext.realmSetOf import io.realm.kotlin.ext.toRealmList import io.realm.kotlin.types.RealmInstant import io.realm.kotlin.types.RealmList import io.realm.kotlin.types.RealmObject -import io.realm.kotlin.types.RealmSet import io.realm.kotlin.types.annotations.PrimaryKey import net.buzzert.kordophone.backend.model.GUID import org.mongodb.kbson.ObjectId -import java.time.Instant import net.buzzert.kordophone.backend.model.Conversation as ModelConversation import java.util.Date @@ -24,6 +20,7 @@ open class Conversation( var date: RealmInstant, var unreadCount: Int, + var lastMessageGUID: String?, var lastMessagePreview: String?, ): RealmObject { @@ -35,10 +32,11 @@ open class Conversation( date = RealmInstant.now(), unreadCount = 0, lastMessagePreview = null, + lastMessageGUID = null, ) fun toConversation(): ModelConversation { - val conversation = ModelConversation( + return ModelConversation( displayName = displayName, participants = participants.toList(), date = Date.from(date.toInstant()), @@ -46,9 +44,8 @@ open class Conversation( guid = guid, lastMessagePreview = lastMessagePreview, lastMessage = null, + lastFetchedMessageGUID = lastMessageGUID ) - - return conversation } override fun equals(other: Any?): Boolean { @@ -57,6 +54,10 @@ open class Conversation( val o = other as Conversation return guid == o.guid } + + override fun hashCode(): Int { + return guid.hashCode() + } } fun ModelConversation.toDatabaseConversation(): Conversation { @@ -67,6 +68,7 @@ fun ModelConversation.toDatabaseConversation(): Conversation { date = from.date.toInstant().toRealmInstant() unreadCount = from.unreadCount lastMessagePreview = from.lastMessagePreview + lastMessageGUID = from.lastFetchedMessageGUID guid = from.guid } } diff --git a/backend/src/main/java/net/buzzert/kordophone/backend/model/Conversation.kt b/backend/src/main/java/net/buzzert/kordophone/backend/model/Conversation.kt index 2ed7bfe..3af38a4 100644 --- a/backend/src/main/java/net/buzzert/kordophone/backend/model/Conversation.kt +++ b/backend/src/main/java/net/buzzert/kordophone/backend/model/Conversation.kt @@ -27,6 +27,8 @@ data class Conversation( @SerializedName("lastMessage") var lastMessage: Message?, + + var lastFetchedMessageGUID: String?, ) { companion object { fun generate(): Conversation { @@ -38,6 +40,7 @@ data class Conversation( unreadCount = 0, lastMessagePreview = null, lastMessage = null, + lastFetchedMessageGUID = null, ) } } @@ -59,7 +62,7 @@ data class Conversation( participants == o.participants && displayName == o.displayName && unreadCount == o.unreadCount && - lastMessagePreview == o.lastMessagePreview + lastFetchedMessageGUID == o.lastFetchedMessageGUID ) } @@ -69,8 +72,8 @@ data class Conversation( result = 31 * result + participants.hashCode() result = 31 * result + (displayName?.hashCode() ?: 0) result = 31 * result + unreadCount - result = 31 * result + (lastMessagePreview?.hashCode() ?: 0) result = 31 * result + (lastMessage?.hashCode() ?: 0) + result = 31 * result + (lastFetchedMessageGUID?.hashCode() ?: 0) return result } } diff --git a/backend/src/main/java/net/buzzert/kordophone/backend/server/ChatRepository.kt b/backend/src/main/java/net/buzzert/kordophone/backend/server/ChatRepository.kt index 6d06522..4181c84 100644 --- a/backend/src/main/java/net/buzzert/kordophone/backend/server/ChatRepository.kt +++ b/backend/src/main/java/net/buzzert/kordophone/backend/server/ChatRepository.kt @@ -182,9 +182,7 @@ class ChatRepository( } suspend fun synchronizeConversation(conversation: Conversation, limit: Int = 15) = withErrorChannelHandling { - // TODO: Should only fetch messages after the last GUID we know about. - // But keep in mind that outgoing message GUIDs are fake... - val messages = fetchMessages(conversation, limit = limit) + val messages = fetchMessages(conversation, limit = limit, afterGUID = conversation.lastFetchedMessageGUID) database.writeMessages(messages, conversation) } @@ -233,10 +231,10 @@ class ChatRepository( private suspend fun fetchMessages( conversation: Conversation, limit: Int? = null, - before: Message? = null, - after: Message? = null, + beforeGUID: String? = null, + afterGUID: String? = null, ): List { - return apiInterface.getMessages(conversation.guid, limit, before?.guid, after?.guid) + return apiInterface.getMessages(conversation.guid, limit, beforeGUID, afterGUID) .bodyOnSuccessOrThrow() .onEach { it.conversation = conversation } } diff --git a/backend/src/test/java/net/buzzert/kordophone/backend/BackendTests.kt b/backend/src/test/java/net/buzzert/kordophone/backend/BackendTests.kt index 3d294c6..d4cb2cb 100644 --- a/backend/src/test/java/net/buzzert/kordophone/backend/BackendTests.kt +++ b/backend/src/test/java/net/buzzert/kordophone/backend/BackendTests.kt @@ -9,6 +9,7 @@ import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext import net.buzzert.kordophone.backend.db.CachedChatDatabase import net.buzzert.kordophone.backend.model.Message +import net.buzzert.kordophone.backend.model.OutgoingMessage import net.buzzert.kordophone.backend.server.APIClient import net.buzzert.kordophone.backend.server.APIInterface import net.buzzert.kordophone.backend.server.Authentication @@ -85,13 +86,18 @@ class BackendTests { val (repository, mockServer) = mockRepository() val conversation = mockServer.addTestConversations(1).first() - val outgoingMessage = MockServer.generateMessage(conversation) + val generatedMessage = MockServer.generateMessage(conversation) + val outgoingMessage = OutgoingMessage( + body = generatedMessage.text, + conversation = conversation, + attachmentUris = setOf(), + attachmentDataSource = { null }, + ) - val guid = repository.enqueueOutgoingMessage(outgoingMessage, conversation) + repository.enqueueOutgoingMessage(outgoingMessage) val event = repository.messageDeliveredChannel.first() - assertEquals(event.requestGuid, guid) - assertEquals(event.message.text, outgoingMessage.text) + assertEquals(event.message.text, outgoingMessage.body) repository.close() } diff --git a/backend/src/test/java/net/buzzert/kordophone/backend/MockServer.kt b/backend/src/test/java/net/buzzert/kordophone/backend/MockServer.kt index 782a0b0..38230af 100644 --- a/backend/src/test/java/net/buzzert/kordophone/backend/MockServer.kt +++ b/backend/src/test/java/net/buzzert/kordophone/backend/MockServer.kt @@ -18,18 +18,19 @@ import net.buzzert.kordophone.backend.server.AuthenticationRequest import net.buzzert.kordophone.backend.server.AuthenticationResponse import net.buzzert.kordophone.backend.server.SendMessageRequest import net.buzzert.kordophone.backend.server.SendMessageResponse +import net.buzzert.kordophone.backend.server.UploadAttachmentResponse import net.buzzert.kordophone.backend.server.authenticatedWebSocketURL import okhttp3.HttpUrl import okhttp3.MediaType.Companion.toMediaType import okhttp3.OkHttpClient import okhttp3.Request +import okhttp3.RequestBody import okhttp3.ResponseBody import okhttp3.ResponseBody.Companion.toResponseBody import okhttp3.WebSocket import okhttp3.WebSocketListener import okhttp3.mockwebserver.MockResponse import okhttp3.mockwebserver.MockWebServer -import retrofit2.Call import retrofit2.Response import java.util.Date import java.util.UUID @@ -66,7 +67,8 @@ class MockServer { unreadCount = 0, lastMessagePreview = null, lastMessage = null, - guid = UUID.randomUUID().toString() + guid = UUID.randomUUID().toString(), + lastFetchedMessageGUID = null, ) } } @@ -166,6 +168,8 @@ class MockServerClient(private val server: MockServer): APIClient, WebSocketList private var updateWatchJob: Job? = null private val gson: Gson = Gson() + override val isConfigured: Boolean = true + override fun getAPIInterface(): APIInterface { return MockServerInterface(server) } @@ -268,6 +272,13 @@ class MockServerInterface(private val server: MockServer): APIInterface { TODO("Not yet implemented") } + override suspend fun uploadAttachment( + filename: String, + body: RequestBody + ): Response { + TODO("Not yet implemented") + } + override suspend fun authenticate(request: AuthenticationRequest): Response { // Anything goes! val response = AuthenticationResponse(