fix(dm): MESSAGE 선도착 ACK 처리를 보정한다
This commit is contained in:
@@ -51,6 +51,7 @@ class DmChatRoomViewModel(
|
||||
private var localMessageSequence: Long = 0L
|
||||
private var requestSequence: Long = 0L
|
||||
private val pendingRequestLocalIds = mutableMapOf<String, String>()
|
||||
private val recentFailedRequestLocalIds = mutableMapOf<String, String>()
|
||||
private val pendingTimeoutDisposables = mutableMapOf<String, Disposable>()
|
||||
private val mainHandler = Handler(Looper.getMainLooper())
|
||||
|
||||
@@ -137,6 +138,7 @@ class DmChatRoomViewModel(
|
||||
if (currentRoomId <= 0L) return
|
||||
val requestId = nextRequestId()
|
||||
|
||||
removeRecentFailedRequests(localId)
|
||||
currentMessages = currentMessages.map {
|
||||
if (it.localId == localId) it.copy(requestId = requestId, status = DmChatMessageStatus.SENDING) else it
|
||||
}
|
||||
@@ -148,9 +150,7 @@ class DmChatRoomViewModel(
|
||||
}
|
||||
|
||||
fun onRealtimeMessage(message: DmChatMessageResponse) {
|
||||
val item = message.toUiItem() ?: return
|
||||
currentMessages = currentMessages.mergeByMessageId(listOf(item))
|
||||
emitContent()
|
||||
handleRealtimeMessage(requestId = null, message = message)
|
||||
}
|
||||
|
||||
fun syncLatestMessagesAfterReconnect() {
|
||||
@@ -364,7 +364,7 @@ class DmChatRoomViewModel(
|
||||
isRealtimeConnected = true
|
||||
syncLatestMessagesAfterReconnect(token = token)
|
||||
}
|
||||
is DmChatSocketEvent.Message -> onRealtimeMessage(event.message)
|
||||
is DmChatSocketEvent.Message -> handleRealtimeMessage(event.requestId, event.message)
|
||||
is DmChatSocketEvent.SendAck -> handleSendAck(event.requestId, event.message)
|
||||
is DmChatSocketEvent.Error -> event.requestId?.let { markPendingMessageFailed(it) }
|
||||
DmChatSocketEvent.Pong -> Unit
|
||||
@@ -372,7 +372,9 @@ class DmChatRoomViewModel(
|
||||
}
|
||||
|
||||
private fun handleSendAck(requestId: String, message: DmChatMessageResponse) {
|
||||
val localId = pendingRequestLocalIds.remove(requestId) ?: return
|
||||
val localId = pendingRequestLocalIds.remove(requestId)
|
||||
?: recentFailedRequestLocalIds.remove(requestId)
|
||||
?: return
|
||||
pendingTimeoutDisposables.remove(requestId)?.dispose()
|
||||
val sentItem = message.toUiItem()
|
||||
if (sentItem == null) {
|
||||
@@ -380,12 +382,28 @@ class DmChatRoomViewModel(
|
||||
return
|
||||
}
|
||||
|
||||
removeRecentFailedRequests(localId)
|
||||
currentMessages = currentMessages.map {
|
||||
if (it.localId == localId) sentItem.copy(localId = localId) else it
|
||||
}.deduplicateSentMessage(sentItem.messageId).sortByCreatedAtAndMessageId()
|
||||
emitContent()
|
||||
}
|
||||
|
||||
private fun removeRecentFailedRequests(localId: String) {
|
||||
recentFailedRequestLocalIds.entries.removeAll { it.value == localId }
|
||||
}
|
||||
|
||||
private fun handleRealtimeMessage(requestId: String?, message: DmChatMessageResponse) {
|
||||
if (requestId != null && pendingRequestLocalIds.containsKey(requestId)) {
|
||||
handleSendAck(requestId, message)
|
||||
return
|
||||
}
|
||||
|
||||
val item = message.toUiItem() ?: return
|
||||
currentMessages = currentMessages.mergeByMessageId(listOf(item))
|
||||
emitContent()
|
||||
}
|
||||
|
||||
private fun List<DmChatMessageUiItem>.deduplicateSentMessage(messageId: Long?): List<DmChatMessageUiItem> {
|
||||
if (messageId == null) return this
|
||||
var found = false
|
||||
@@ -399,6 +417,7 @@ class DmChatRoomViewModel(
|
||||
|
||||
private fun markPendingMessageFailed(requestId: String) {
|
||||
val localId = pendingRequestLocalIds.remove(requestId) ?: return
|
||||
recentFailedRequestLocalIds[requestId] = localId
|
||||
pendingTimeoutDisposables.remove(requestId)?.dispose()
|
||||
markLocalMessageFailed(localId)
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ data class DmChatSocketSendTextPayload(
|
||||
|
||||
@Keep
|
||||
data class DmChatSocketMessagePayload(
|
||||
@SerializedName("requestId") val requestId: String?,
|
||||
@SerializedName("message") val message: DmChatMessageResponse
|
||||
)
|
||||
|
||||
@@ -51,7 +52,10 @@ enum class DmChatSocketClientType(val value: String) {
|
||||
|
||||
sealed class DmChatSocketEvent {
|
||||
data object Joined : DmChatSocketEvent()
|
||||
data class Message(val message: DmChatMessageResponse) : DmChatSocketEvent()
|
||||
data class Message(
|
||||
val requestId: String?,
|
||||
val message: DmChatMessageResponse
|
||||
) : DmChatSocketEvent()
|
||||
data class SendAck(
|
||||
val requestId: String,
|
||||
val message: DmChatMessageResponse
|
||||
@@ -85,7 +89,10 @@ class DmChatSocketParser(private val gson: Gson) {
|
||||
|
||||
private fun parseMessage(payload: JsonObject?): DmChatSocketEvent.Message? {
|
||||
val messagePayload = gson.fromJson(payload, DmChatSocketMessagePayload::class.java) ?: return null
|
||||
return DmChatSocketEvent.Message(messagePayload.message)
|
||||
return DmChatSocketEvent.Message(
|
||||
requestId = messagePayload.requestId,
|
||||
message = messagePayload.message
|
||||
)
|
||||
}
|
||||
|
||||
private fun parseSendAck(payload: JsonObject?): DmChatSocketEvent.SendAck? {
|
||||
|
||||
Reference in New Issue
Block a user