diff --git a/app/src/main/java/kr/co/vividnext/sodalive/v2/main/chat/dm/DmChatRoomViewModel.kt b/app/src/main/java/kr/co/vividnext/sodalive/v2/main/chat/dm/DmChatRoomViewModel.kt index ecd82520..4c1b7e7c 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/v2/main/chat/dm/DmChatRoomViewModel.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/v2/main/chat/dm/DmChatRoomViewModel.kt @@ -42,10 +42,12 @@ class DmChatRoomViewModel( private var nextCursor: Long? = null private var isLoadingOlder: Boolean = false private var isSending: Boolean = false + private var isRealtimeJoining: Boolean = false private var isRealtimeConnected: Boolean = false private var shouldReconnectRealtime: Boolean = false private var currentAuthToken: String = "" private var currentRealtimeToken: String = "" + private var currentRealtimeRoomId: Long = 0L private var reconnectDisposable: Disposable? = null private var localMessageSequence: Long = 0L private val mainHandler = Handler(Looper.getMainLooper()) @@ -179,10 +181,14 @@ class DmChatRoomViewModel( private fun connectRealtime(token: String) { val roomId = currentRoomId - if (roomId <= 0L || isRealtimeConnected || !shouldReconnectRealtime && currentRealtimeToken.isNotEmpty()) return + if (roomId <= 0L || isRealtimeConnected && currentRealtimeRoomId == roomId) return + if (isRealtimeJoining && currentRealtimeRoomId == roomId) return + if (!shouldReconnectRealtime && currentRealtimeToken.isNotEmpty() && currentRealtimeRoomId == roomId) return currentRealtimeToken = token - isRealtimeConnected = true + currentRealtimeRoomId = roomId + isRealtimeJoining = true + isRealtimeConnected = false shouldReconnectRealtime = true reconnectDisposable?.dispose() reconnectDisposable = null @@ -195,6 +201,7 @@ class DmChatRoomViewModel( override fun onFailure(throwable: Throwable) { scheduleRealtimeCallback { + isRealtimeJoining = false isRealtimeConnected = false throwable.message?.let { Logger.e(it) } scheduleRealtimeReconnect() @@ -211,6 +218,8 @@ class DmChatRoomViewModel( shouldReconnectRealtime = false currentRealtimeToken = "" + currentRealtimeRoomId = 0L + isRealtimeJoining = false isRealtimeConnected = false reconnectDisposable?.dispose() reconnectDisposable = null @@ -247,6 +256,9 @@ class DmChatRoomViewModel( mainHandler.removeCallbacksAndMessages(null) reconnectDisposable?.dispose() reconnectDisposable = null + currentRealtimeRoomId = 0L + isRealtimeJoining = false + isRealtimeConnected = false repository.closeSocket() super.onCleared() } @@ -329,7 +341,11 @@ class DmChatRoomViewModel( private fun handleSocketEvent(event: DmChatSocketEvent, token: String) { when (event) { - DmChatSocketEvent.Joined -> syncLatestMessagesAfterReconnect(token = token) + DmChatSocketEvent.Joined -> { + isRealtimeJoining = false + isRealtimeConnected = true + syncLatestMessagesAfterReconnect(token = token) + } is DmChatSocketEvent.Message -> onRealtimeMessage(event.message) is DmChatSocketEvent.SendAck -> handleSendAck(event.requestId, event.message) is DmChatSocketEvent.Error -> event.requestId?.let { markLocalMessageFailed(it) } diff --git a/app/src/test/java/kr/co/vividnext/sodalive/v2/main/chat/dm/DmChatRoomViewModelTest.kt b/app/src/test/java/kr/co/vividnext/sodalive/v2/main/chat/dm/DmChatRoomViewModelTest.kt index b3339e7e..ebd6f2a8 100644 --- a/app/src/test/java/kr/co/vividnext/sodalive/v2/main/chat/dm/DmChatRoomViewModelTest.kt +++ b/app/src/test/java/kr/co/vividnext/sodalive/v2/main/chat/dm/DmChatRoomViewModelTest.kt @@ -323,9 +323,11 @@ class DmChatRoomViewModelTest { viewModel.enter(roomId = 10L, creatorId = 0L) viewModel.connectRealtime() + assertEquals(false, viewModel.isRealtimeConnectedForTest()) socketFactory.emitJoined() assertEquals(listOf(RealtimeConnectCall("test-token", 10L)), socketFactory.connectCalls) + assertEquals(true, viewModel.isRealtimeConnectedForTest()) assertEquals(listOf(MessagesCall("Bearer test-token", 10L, null, 20)), api.messagesCalls) val state = viewModel.chatRoomStateLiveData.requireValue() as DmChatRoomUiState.Content assertEquals(listOf(1L, 2L), state.messages.map { it.messageId }) @@ -340,6 +342,8 @@ class DmChatRoomViewModelTest { viewModel.connectRealtime() assertEquals(listOf(RealtimeConnectCall("test-token", 10L)), socketFactory.connectCalls) + assertEquals(1, socketFactory.webSocket.sentTexts.size) + assertEquals("JOIN_ROOM", socketFactory.webSocket.sentJsonAt(0).get("type").asString) } @Test @@ -651,6 +655,12 @@ class DmChatRoomViewModelTest { method.isAccessible = true method.invoke(this) } + + fun DmChatRoomViewModel.isRealtimeConnectedForTest(): Boolean { + val field = DmChatRoomViewModel::class.java.getDeclaredField("isRealtimeConnected") + field.isAccessible = true + return field.getBoolean(this) + } } }