React Redux-Saga 환경에서 Stomp Client & Spring boot kotlin 설정

ChodingSense·2022년 4월 28일
0

React

목록 보기
1/2

React + typescript + redux-saga 환경에서 stomp client를 개발한 경험을 공유합니다.

의존성 추가

yarn add react-stomp @stomp/stompjs sockjs-client @types/sockjs-client

saga

initializeStompChannel 을 호출하여 stomp 연결

function* initializeStompChannel(): any {
    yield startStomp();
}

function* startStomp(): any {

   	const stompClient = yield call(createStompConnection)

   
   	channel = yield call(createEventChannel, stompClient);

    let isRunning = true
  
    while (isRunning) {
    
        const { message, timeout } = yield race({
            timeout: delay(6 * 10000),
            message : take(channel),
        });

        if (timeout) isRunning = false;
    
        yield put(receivedStompMsg(message));
    }
}

Stomp 연결 설정

function createStompConnection() {

    const stompUrl: string = {URL}

    return new Promise((resolve, reject) => {

        const initConnection = () => {

          	const stompClient = new Client({
                webSocketFactory : function () {
                    return new SockJS(stompUrl)
                }
            })


            stompClient.reconnectDelay = 5000
            stompClient.heartbeatIncoming = 4000
            stompClient.heartbeatOutgoing = 4000

            const header = {
                login: "",
                password: "",
                priority: '9'
            }

            const connectionCallback = () => { 
              resolve(stompClient); 
            }

            stompClient.onConnect = connectionCallback
          
          	stompClient.activate()
        }

        initConnection();
        
    });
}

Redux-Saga 에서 특정 이벤트가 발생했을 때 처리를 위해 EventChannel을 사용

function createEventChannel(stompClient: CompatClient) {

    return eventChannel(emit => {

        const onReceivedMessage = (iMessage: IMessage) => { emit(iMessage); }

        const subscribeMessage = () => {
             stompClient.subscribe('{topic}', onReceivedMessage)
        };

        subscribeMessage();

        return function unsubscribe() {
          	stompClient.deactivate()
        };
  },  buffers.expanding(1000) || buffers.none());
}

actions

...
export const receivedStompMsg = (message: object) => ({
    type: RECEIVED_STOMP_MSG,
    payload: message
})
...

메시지 송신

startStomp에 writeTask 추가

function* startStomp(): any {
  ...
  	const stompClient = yield call(createStompConnection)

    lastWriteTask = yield fork(sendStomp, stompClient)
  ...
}

send 구현
아래에서는 json object 를 string 으로 변환해 전송

function* sendStomp(stompClient: CompatClient) {

    while (true) {

        const { payload } = yield take(SEND_STOMP_MSG)

        const data: Idata = {
            type: "test data",
            data: `$payload`
        }
      
        stompClient.publish({
            destination: `{url}`,
            body: JSON.stringify(data),
            headers: header
        })
    }
}


# types.ts
export interface Idata {
    type: string,
    data: string
}

spring boot

gradle 의존성 추가
작성 기준 2.6.6 버전 사용

dependencies {
...
	implementation("org.springframework.boot:spring-boot-starter-web")
	implementation("org.springframework.boot:spring-boot-starter-websocket")
}

WebSocketConfig 추가

@Configuration
@EnableWebSocketMessageBroker
class WebSocketConfig: WebSocketMessageBrokerConfigurer {

    override fun registerStompEndpoints(registry: StompEndpointRegistry) {
        registry.addEndpoint("/message").setAllowedOrigins("localhost:3000").withSockJS();
    }

    override fun configureMessageBroker(registry: MessageBrokerRegistry) {
        registry.enableSimpleBroker("/topic", "/queue")
        registry.setApplicationDestinationPrefixes("/app")

    }
}

SocketController 추가

@RestController
@Component
class SocketController(private val simpleMessageTemplate: SimpMessagingTemplate) {

    @MessageMapping("/message")
    fun sendMessage(@Payload messageData: MessageData, @DestinationVariable id: Int) {      
    	this.simpleMessageTemplate.convertAndSend("{topic}", messageData)
    }
    
}

data class MessageData(
    val type: String,
    val data: String
)

필요에 따라 WebSocketEventListener 추가

@Component
class WebSocketEventListener() {

    @EventListener
    fun handleWebSocketConnectListener(event: SessionConnectEvent) {
    }

    @EventListener
    fun handleWebSocketDisconnectListener(event: SessionDisconnectEvent) {
    }
}
profile
물고기를 좋아합니다.

0개의 댓글