Update send message to account for guid returned by servers
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package net.buzzert.kordophone.backend.db
|
||||
|
||||
import android.util.Log
|
||||
import io.realm.kotlin.MutableRealm
|
||||
import io.realm.kotlin.Realm
|
||||
import io.realm.kotlin.RealmConfiguration
|
||||
@@ -15,6 +16,7 @@ import net.buzzert.kordophone.backend.db.model.toDatabaseConversation
|
||||
import net.buzzert.kordophone.backend.db.model.toDatabaseMessage
|
||||
import net.buzzert.kordophone.backend.db.model.toRealmInstant
|
||||
import net.buzzert.kordophone.backend.model.GUID
|
||||
import net.buzzert.kordophone.backend.server.REPO_LOG
|
||||
import java.lang.IllegalArgumentException
|
||||
import net.buzzert.kordophone.backend.model.Conversation as ModelConversation
|
||||
import net.buzzert.kordophone.backend.model.Message as ModelMessage
|
||||
@@ -41,7 +43,15 @@ class CachedChatDatabase (private val realmConfig: RealmConfiguration) {
|
||||
}
|
||||
}
|
||||
|
||||
private val realm = Realm.open(realmConfig)
|
||||
private val realm = runCatching {
|
||||
Realm.open(realmConfig)
|
||||
}.recover {
|
||||
// We're just a caching layer, so in the event of a migration error, just delete and start over.
|
||||
Log.d(REPO_LOG, "Error opening (${it.message}). Recovering by deleting database.")
|
||||
Realm.deleteRealm(realmConfig)
|
||||
|
||||
return@recover Realm.open(realmConfig)
|
||||
}.getOrThrow()
|
||||
|
||||
// Flow for watching changes to the database
|
||||
val conversationChanges: Flow<List<ModelConversation>>
|
||||
@@ -122,16 +132,6 @@ class CachedChatDatabase (private val realmConfig: RealmConfiguration) {
|
||||
}
|
||||
}
|
||||
|
||||
fun clearOutgoingMessages() {
|
||||
realm.query(Message::class, "isOutgoing == true").find().forEach { message ->
|
||||
realm.writeBlocking {
|
||||
findLatest(message)?.let {
|
||||
delete(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun fetchMessages(conversation: ModelConversation): List<ModelMessage> {
|
||||
val dbConversation = getConversationByGuid(conversation.guid)
|
||||
return dbConversation.messages.map { it.toMessage(dbConversation.toConversation()) }
|
||||
|
||||
@@ -22,7 +22,6 @@ open class Message(
|
||||
var date: RealmInstant,
|
||||
|
||||
var conversationGUID: GUID,
|
||||
var isOutgoing: Boolean,
|
||||
): RealmObject
|
||||
{
|
||||
constructor() : this(
|
||||
@@ -31,7 +30,6 @@ open class Message(
|
||||
sender = null,
|
||||
date = RealmInstant.now(),
|
||||
conversationGUID = ObjectId().toString(),
|
||||
isOutgoing = false,
|
||||
)
|
||||
|
||||
fun toMessage(parentConversation: ModelConversation): ModelMessage {
|
||||
@@ -53,6 +51,5 @@ fun ModelMessage.toDatabaseMessage(outgoing: Boolean = false): Message {
|
||||
sender = from.sender
|
||||
date = from.date.toInstant().toRealmInstant()
|
||||
conversationGUID = from.conversation.guid
|
||||
isOutgoing = outgoing
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import net.buzzert.kordophone.backend.model.GUID
|
||||
import net.buzzert.kordophone.backend.model.Message
|
||||
|
||||
data class MessageDeliveredEvent(
|
||||
val guid: GUID,
|
||||
val message: Message,
|
||||
val conversation: Conversation,
|
||||
val requestGuid: GUID,
|
||||
)
|
||||
|
||||
@@ -25,6 +25,11 @@ data class SendMessageRequest(
|
||||
val transferGUIDs: List<String>?,
|
||||
)
|
||||
|
||||
data class SendMessageResponse(
|
||||
@SerializedName("guid")
|
||||
val sentMessageGUID: String,
|
||||
)
|
||||
|
||||
interface APIInterface {
|
||||
@GET("/version")
|
||||
suspend fun getVersion(): ResponseBody
|
||||
@@ -41,7 +46,7 @@ interface APIInterface {
|
||||
): Response<List<Message>>
|
||||
|
||||
@POST("/sendMessage")
|
||||
suspend fun sendMessage(@Body request: SendMessageRequest): Response<Void>
|
||||
suspend fun sendMessage(@Body request: SendMessageRequest): Response<SendMessageResponse>
|
||||
}
|
||||
|
||||
class ResponseDecodeError(val response: ResponseBody): Exception()
|
||||
|
||||
@@ -65,7 +65,7 @@ class ChatRepository(
|
||||
private data class OutgoingMessageInfo (
|
||||
val message: Message,
|
||||
val conversation: Conversation,
|
||||
val guid: GUID,
|
||||
val requestGuid: GUID,
|
||||
)
|
||||
|
||||
private val apiInterface = apiClient.getAPIInterface()
|
||||
@@ -133,12 +133,6 @@ class ChatRepository(
|
||||
val serverConversations = fetchConversations()
|
||||
database.updateConversations(serverConversations)
|
||||
|
||||
// Delete outgoing conversations
|
||||
// This is an unfortunate limitation in that we don't know what outgoing GUIDs are going to
|
||||
// be before we send them.
|
||||
// TODO: Keep this in mind when syncing messages after a certain GUID. The outgoing GUIDs are fake.
|
||||
database.clearOutgoingMessages()
|
||||
|
||||
// Sync top N number of conversations' message content
|
||||
Log.d(REPO_LOG, "Synchronizing messages")
|
||||
val sortedConversations = conversations.sortedBy { it.date }.reversed()
|
||||
@@ -198,23 +192,39 @@ class ChatRepository(
|
||||
while (true) {
|
||||
val outgoingMessageRequest = outgoingMessageQueue.poll()?.let {
|
||||
runBlocking {
|
||||
val guid = it.guid
|
||||
val message = it.message
|
||||
val outgoingMessage = it.message
|
||||
val conversation = it.conversation
|
||||
val requestGuid = it.requestGuid
|
||||
|
||||
Log.d(REPO_LOG, "Sending message to $conversation: $message")
|
||||
Log.d(REPO_LOG, "Sending message to $conversation: $outgoingMessage")
|
||||
|
||||
val result = apiInterface.sendMessage(
|
||||
SendMessageRequest(
|
||||
conversationGUID = conversation.guid,
|
||||
body = message.text,
|
||||
body = outgoingMessage.text,
|
||||
transferGUIDs = null,
|
||||
)
|
||||
)
|
||||
|
||||
if (result.isSuccessful) {
|
||||
Log.d(REPO_LOG, "Successfully sent message.")
|
||||
_messageDeliveredChannel.emit(MessageDeliveredEvent(guid, message, conversation))
|
||||
val messageGuid = result.body()?.sentMessageGUID ?: outgoingMessage.guid
|
||||
Log.d(REPO_LOG, "Successfully sent message: $messageGuid")
|
||||
|
||||
val newMessage = Message(
|
||||
guid = messageGuid,
|
||||
text = outgoingMessage.text,
|
||||
sender = null,
|
||||
conversation = it.conversation,
|
||||
date = outgoingMessage.date
|
||||
)
|
||||
|
||||
_messageDeliveredChannel.emit(
|
||||
MessageDeliveredEvent(
|
||||
newMessage,
|
||||
conversation,
|
||||
requestGuid
|
||||
)
|
||||
)
|
||||
} else {
|
||||
Log.e(REPO_LOG, "Error sending message. Enqueuing for retry.")
|
||||
outgoingMessageQueue.add(it)
|
||||
|
||||
Reference in New Issue
Block a user