feat(dm): WebSocket 클라이언트를 추가한다
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
package kr.co.vividnext.sodalive.v2.main.chat.dm.data
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonObject
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import okhttp3.WebSocket
|
||||
import okhttp3.WebSocketListener
|
||||
|
||||
class DmChatSocketClient(
|
||||
private val okHttpClient: OkHttpClient,
|
||||
private val gson: Gson,
|
||||
private val baseUrl: String,
|
||||
private val webSocketFactory: (Request, WebSocketListener) -> WebSocket = okHttpClient::newWebSocket
|
||||
) {
|
||||
interface Listener {
|
||||
fun onEvent(event: DmChatSocketEvent)
|
||||
fun onFailure(throwable: Throwable)
|
||||
}
|
||||
|
||||
private val parser = DmChatSocketParser(gson)
|
||||
private var webSocket: WebSocket? = null
|
||||
|
||||
@Volatile
|
||||
private var listener: Listener? = null
|
||||
|
||||
@Volatile
|
||||
private var activeSocket: WebSocket? = null
|
||||
|
||||
@Synchronized
|
||||
fun connect(token: String, listener: Listener) {
|
||||
close()
|
||||
this.listener = listener
|
||||
|
||||
val socketUrl = socketUrl()
|
||||
val request = Request.Builder()
|
||||
.url(socketUrl)
|
||||
.tag(String::class.java, socketUrl)
|
||||
.header(HEADER_AUTHORIZATION, bearer(token))
|
||||
.build()
|
||||
val socketListener = object : WebSocketListener() {
|
||||
override fun onMessage(webSocket: WebSocket, text: String) {
|
||||
if (webSocket != activeSocket) return
|
||||
parser.parse(text)?.let { event -> this@DmChatSocketClient.listener?.onEvent(event) }
|
||||
}
|
||||
|
||||
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
|
||||
if (webSocket != activeSocket) return
|
||||
this@DmChatSocketClient.listener?.onFailure(t)
|
||||
}
|
||||
}
|
||||
|
||||
webSocket = webSocketFactory(request, socketListener).also { activeSocket = it }
|
||||
}
|
||||
|
||||
fun sendJoinRoom(roomId: Long): Boolean = send(
|
||||
type = DmChatSocketClientType.JOIN_ROOM,
|
||||
payload = DmChatSocketRoomPayload(roomId = roomId)
|
||||
)
|
||||
|
||||
fun sendLeaveRoom(roomId: Long): Boolean = send(
|
||||
type = DmChatSocketClientType.LEAVE_ROOM,
|
||||
payload = DmChatSocketRoomPayload(roomId = roomId)
|
||||
)
|
||||
|
||||
fun sendText(
|
||||
roomId: Long,
|
||||
requestId: String,
|
||||
textMessage: String
|
||||
): Boolean = send(
|
||||
type = DmChatSocketClientType.SEND_TEXT,
|
||||
payload = DmChatSocketSendTextPayload(
|
||||
roomId = roomId,
|
||||
requestId = requestId,
|
||||
textMessage = textMessage
|
||||
)
|
||||
)
|
||||
|
||||
fun sendPing(): Boolean = send(
|
||||
type = DmChatSocketClientType.PING,
|
||||
payload = JsonObject()
|
||||
)
|
||||
|
||||
@Synchronized
|
||||
fun close() {
|
||||
val socket = webSocket ?: return
|
||||
webSocket = null
|
||||
activeSocket = null
|
||||
listener = null
|
||||
socket.close(NORMAL_CLOSE_CODE, null)
|
||||
}
|
||||
|
||||
private fun send(
|
||||
type: DmChatSocketClientType,
|
||||
payload: Any
|
||||
): Boolean {
|
||||
val socket = webSocket ?: return false
|
||||
return socket.send(gson.toJson(DmChatSocketOutboundEnvelope(type = type.value, payload = payload)))
|
||||
}
|
||||
|
||||
private fun socketUrl(): String = baseUrl
|
||||
.trimEnd('/')
|
||||
.replacePrefix(oldValue = "https://", newValue = "wss://")
|
||||
.replacePrefix(oldValue = "http://", newValue = "ws://") + SOCKET_PATH
|
||||
|
||||
private fun bearer(token: String) = "Bearer $token"
|
||||
|
||||
private data class DmChatSocketOutboundEnvelope(
|
||||
val type: String,
|
||||
val payload: Any
|
||||
)
|
||||
|
||||
private companion object {
|
||||
const val HEADER_AUTHORIZATION = "Authorization"
|
||||
const val NORMAL_CLOSE_CODE = 1000
|
||||
const val SOCKET_PATH = "/ws/v2/user-creator-chat"
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.replacePrefix(oldValue: String, newValue: String): String =
|
||||
if (startsWith(oldValue)) newValue + removePrefix(oldValue) else this
|
||||
Reference in New Issue
Block a user