WebSocketFrameDispatcher.java

package sprout.server.websocket;

import sprout.server.websocket.framehandler.FrameHandler;
import sprout.server.websocket.framehandler.FrameProcessingContext;
import sprout.server.websocket.message.MessagePayload;
import sprout.server.websocket.message.WebSocketMessageDispatcher;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

public class WebSocketFrameDispatcher {
    private final FrameHandler handlerChain;
    private final List<WebSocketMessageDispatcher> messageDispatchers;

    public WebSocketFrameDispatcher(List<FrameHandler> handlers, List<WebSocketMessageDispatcher> messageDispatchers) {
        this.messageDispatchers = messageDispatchers;
        this.handlerChain = buildHandlerChain(handlers);
    }

    private FrameHandler buildHandlerChain(List<FrameHandler> handlers) {
        if (handlers == null || handlers.isEmpty()) {
            throw new IllegalStateException("No FrameHandler beans found. Cannot build handler chain.");
        }
        // 리스트의 순서대로 next 핸들러를 설정
        for (int i = 0; i < handlers.size() - 1; i++) {
            handlers.get(i).setNext(handlers.get(i + 1));
        }
        return handlers.get(0); // 체인의 시작점 반환
    }

    public void dispatch(FrameProcessingContext state, WebSocketSession webSocketSession, Map<String, String> pathParameters) throws Exception {
        // 핸들러 체인에 프레임 처리 위임
        boolean messageCompleted = handlerChain.handle(state);

        if (messageCompleted) {
            // 메시지가 완성되면, 실제 비즈니스 로직을 처리할 디스패처에게 위임
            MessagePayload payload = state.createPayload();
            InvocationContext contextWithPayload = new DefaultInvocationContext(webSocketSession, pathParameters, payload, state.getFrame());

            DispatchResult result = null;
            try {
                for (WebSocketMessageDispatcher dispatcher : messageDispatchers) {
                    if (dispatcher.supports(state.getFrame(), contextWithPayload)) {
                        result = dispatcher.dispatch(state.getFrame(), contextWithPayload);
                        if (result.isHandled()) {
                            break;
                        }
                    }
                }
            } finally {
                // 스트림 닫기 및 상태 초기화
                if (result == null || result.shouldCloseStream()) {
                    InputStream stream = contextWithPayload.getFrame().getPayloadStream();
                    if (stream != null) {
                        try { stream.close(); } catch (IOException e) { System.err.println("Failed to close payload input stream: " + e.getMessage()); }
                    }
                }
                state.reset(); // 버퍼 및 분할 메시지 상태 초기화
            }

            if (result == null || !result.isHandled()) {
                System.err.println("No suitable WebSocketMessageDispatcher found for frame: " + state.getFrame().getOpcode() + " (FIN: " + state.getFrame().isFin() + ")");
            }
        }
    }
}