코틀린에서 stomp 에서 받은 message 파싱을 하는 함수 parseMessage를 보면 다음과 같다.
private fun parseMessage(data: String?): Message {
if (data.isNullOrBlank())
return Message(Commands.UNKNOWN)
val reader = Scanner(StringReader(data))
reader.useDelimiter("\\n")
val command = reader.next()
val headers = HashMap<String, String>()
while (reader.hasNext(Message.PATTERN_HEADER)) {
val matcher = Message.PATTERN_HEADER.matcher(reader.next())
matcher.find()
headers.put(matcher.group(1), matcher.group(2))
}
reader.skip("\\s")
reader.useDelimiter(Message.TERMINATE_MESSAGE_SYMBOL)
val payload = if (reader.hasNext()) reader.next() else null
return Message(command, headers, payload!!)
}
여기서 종종 에러를 일으키는 개발자 들이 많은데 나도 그런 케이스였다.
그 이유는 stomp을 지원하지 않는 서버 환경에서 websocket으로 수동으로 다 stomp포멧에 맞춰 데이터를 전달해 줘야 했기 때문이다.
자 그럼 하나하나 분석해 보자.
일단 맨위 Message를 받는다.
그 뒤 메세지의 존재 유무를 판단하고, 존재할 경우 분석에 들어간다.
먼저 Scanner라는 함수에 Message로 받은 data를 넣는다.
그 뒤 useDelimiter를 이용하여 해당 \\n 이 있는 부분들을 나누어 준다. 이때, 띄어쓰기 등 정확한 구분으로 받은 데이터가 아니면 에러를 일으키거나 정상 동작하지 않을 수 있다.
그리고 저 next() 는 scanner에서 delimiter나 등 작업 후 커서이동을 시켜주는 것이라고 생각하면 된다.
while에 hasNext는 JSON처럼 짝지어 있는 구분에서 다음 커서로 이동 시켜준다.
while 문 줄에 Message.PATTERN_HEADER 는 구글도, chatGPT도 알려주지 않는 놈이다.
내가 볼땐 받은 문자에 해더 형식이 있나 없나 를 보고 있다면 while문 안의 해더를 분석해서 headers 해쉬에 넣어주는 역할인것 같다.
대망의 reader.skip("\\s") 난 이부분에서 며칠을 해맸다. 계속 에러가 나서 분석해보니 무슨 skip이란 명령어에서 에러가 난단 말인가? 없음 그냥 없이 넘어가면 되는 부분이고, 제공된 코드이니 코드에 오타가 있을리도 없는데 계속 여기서 에러가 났다.
공백, 슬레의 같은 것들 없애주는 기능을 하는데, 없으면 그냥 안없애면 되는거 아닌가? 하면서 계속 뭐가 이상한지 분석해봤다.
- - 근데 없으면 에러가 나는 구조였던거다. 즉, skip('어쩌구')가 있으면 받은 data의 해당 커서에 무조건 '어쩌구가' 있어야한다... 그 다음
TERMINATE_MESSAGE_SYMBOL
이부분, useDelimiter 가 또 나왔는데, TERMINATE_MESSAGE_SYMBOL이란다.. 이건 또 뭔 소리냐..
찾아보니 null 이란다.. 즉, next가 null인지 파악하고 끝낼지 말지 정하는것 같다.
전체 코드를 보니, command와 header가 있는 문자열을 갖고, command와 header를 구분하고 header가 있는지 여부 파악후 마지막 Message(command, headers, payload!!)에 저장하는것 같다.
이 형식에 잘 맞춰 짠 코드가 이거다.
이런식의 데이터를 받는걸로 봐서 이렇게 똑같이 만들어 줬다.
일렇게 원하는 포멧에 맞줘 보내니 잘 된다. 휴..