저번 글을 작성하고 SSFAY 수료, 면접 등 여러 일이 겹치면서 2편을 작성하지 못했다. 지금이나마 2편을 작성해야겠다는 생각이 들어 포스팅을 시작한다.
STMOP 연결에 성공했다면 특정 topic에 구독 요청을 해야한다.
val newChatMessage: Flow<StompFrame.Message> = stompSession.subscribe(
StompSubscribeHeaders(
destination = "${subscribe을 위한 url}",
customHeaders = mapOf(
"Authorization" to "${token}"
)
)
)
지난 글에서 연결에 성공한 StompSession의 subscribe 함수를 사용한다.
파라미터로는 StompSubscribeHeaders를 사용했다.
StompSubscribeHeaders에 구독을 위한 custom stomp header를 포함시킬 수 있다.
위의 newChatMessage는 Flow이기 때문에 collect를 통해서 데이터를 수집해야한다.
newChatMessage.collect {
val chatMessage = moshi.adapter(Chat::class.java).fromJson(it.bodyAsText)
intent { copy(chatList = chatList + chatMessage!!) }
}
수신하는 데이터의 타입은 StompFrame이다.
클래스 내부를 보면
val bodyAsText: String by lazy { body?.asText(headers.contentType) ?: "" }
과 같이 해당 Frame의 body를 String 타입으로 변환한 bodyAsText 라는 멤버가 존재한다.
또한 내가 정의한 Chat data class는 다음과 같다
data class Chat(
val memberId: Long,
val memberName: String,
val memberImageUrl: String,
val content: String,
val sendDateTime: Long,
val readCount: Int = 1
)
이는 서버 개발자와의 규약으로 StompFrame의 body는 Chat의 정보가 담겨져 넘어온다.
자 그럼 다시
newChatMessage.collect {
val chatMessage = moshi.adapter(Chat::class.java).fromJson(it.bodyAsText)
intent { copy(chatList = chatList + chatMessage!!) }
}
이 코드를 보면 새로운 채팅을 수신하면 이를 moshi를 사용해 자체 데이터 클래스인 Chat으로 변환하고 List<Chat>
타입인 chatList에 수신한 채팅을 추가하고 intent를 사용해 UI 상태를 갱신시킨다.
본인은 Compose + MVI 패턴을 사용했기 때문에 위와 같이 개발했지만 MVVM등 다른 패턴을 사용하는 경우에는 상태에 맞게 View에서 감지만 하면 될 것이다.
viewModelScope.launch {
stompSession.withMoshi(moshi).convertAndSend(
StompSendHeaders(
destination = SEND_URL,
customHeaders = mapOf(
HEADER_AUTHORIZATION to tkn
)
),
ChatMessage(roomId, userInfo.photo, message)
)
}
}
우선 suspend fun 이니 Coroutine Scope 내에서 함수를 호출하면 된다.
StompSession의 convertAndSend 함수를 살펴보면
suspend inline fun <reified T> TypedStompSession.convertAndSend(headers: StompSendHeaders, body: T): StompReceipt? =
convertAndSend(headers, body, typeRefOf())
StompSendHeader와 body를 파라미터로 받는다.
본인은 채팅을 보낼 때 token을 헤더에 담아 보내야 했기 때문에 위와 같이 사용했지만, 상황에 따라 목적지 url과 body만 받을 수도 있고, url만 받을 수도 있다.
body는 규약된 데이터 클래스를 잘 사용하면 될 것이다.
채팅을 화면에 그리는 것은 나보다 더 잘 정리한 사람들이 많기 때문에 UI관련 로직은 다루지 않고, STOMP를 사용하는 방법에 초점을 맞춰 글을 작성했다.
혹시 전체 코드를 참고하려면 github에서 feature -> student -> home -> chatting 안에 있는 코드를 확인하면 될 것이다.
역시 사람들이 많이 사용하지 않는 것에는 이유가 있다는 것을 느꼈고, 하지만 라이브러리를 샅샅이 뜯어보고 내 상황에 맞게 사용하는 능력을 향상시키는데 많은 도움이 되었던 경험이었다.
참고가 많이 되었습니다! 감사합니다:)