R2turnTrue / chzzk4j

Unofficial Java API library of CHZZK (치지직, the video streaming service of Naver)
MIT License
30 stars 6 forks source link

채팅 이벤트가 많이 발생하지 않으면 연결이 끊어지는 문제에 대해... #6

Closed beramo14 closed 3 months ago

beramo14 commented 6 months ago

안녕하세요. 글이 길어질거 같아 이곳에 작성해 봅니다.

에러

채팅이 많이 올라오지 않는 채널에서 1분 후 채팅 커넥션이 끊기는 문제

내용

해당 현상이 일어나고부터 혹시 api에 변경점이 있나 싶어 크롬 DevTools에서 chat 웹 소켓 통신 기록을 보니 채팅이 없는 경우(?) 클라이언트에서 한 번씩 특정 패턴으로 생존 확인용 핑 {"ver": "2","cmd": 0} 을 보내는 것을 확인했습니다.

그래서 테스트로 라이브러리 코드를 받아 치지직 채팅이 연결된 시점에서 20초 간격으로 핑 데이터를 보내게 수정하여 적용한 결과 약 20분 넘게 커넥션이 살아있는 것을 확인했습니다.

치지직 채팅 생존 확인용 핑 전송 패턴

1분이상 채팅이 없거나 핑이 없는 경우 커넥션이 끊어짐 << 현재 상황

코드

public class ChatWebsocketClient extends WebSocketClient {

    private ChzzkChat chat;
    private Gson gson;
    private String sid;
    private ScheduledExecutorService executor; //[수정]

    public ChatWebsocketClient(ChzzkChat chat, URI websocketUri) {
        super(websocketUri);
        this.chat = chat;
        this.gson = new Gson()
                .newBuilder()
                .disableHtmlEscaping()
                .create();
        this.executor = Executors.newSingleThreadScheduledExecutor();  //[수정]
    }
/*...........생략...........*/
@Override
    public void onMessage(String message) {

        try {

            if (chat.chzzk.isDebug) System.out.println("Message: " + message);

            JsonObject parsedMessage = JsonParser.parseString(message)
                    .getAsJsonObject();

            var cmdId = parsedMessage
                    .get("cmd")
                    .getAsInt();

            var messageClass = getClientboundMessageClass(cmdId);

            if (messageClass == WsMessageClientboundConnected.class) {
                // handle connected message
                WsMessageClientboundConnected msg = gson.fromJson(parsedMessage, WsMessageClientboundConnected.class);
                if (msg.retCode == 0) {
                    if (chat.chzzk.isDebug) System.out.println("Successfully connected!");
                    sid = msg.bdy.sid;
                    for (ChatEventListener listener : chat.listeners) {
                        listener.onConnect(chat, chat.reconnecting);
                    }

                    Runnable task = () -> {  //[수정]
                        System.out.println("작업 실행: " + System.currentTimeMillis() / 1000);
                        this.send(gson.toJson(new WsMessageServerboundPing()));
                    };

                    executor.scheduleAtFixedRate(task, 0, 20, TimeUnit.SECONDS);  //[수정]

                } else {
                    throw new ChatFailedConnectException(msg.retCode, msg.retMsg);
                }
            } else if (cmdId == WsMessageTypes.Commands.PING) {
/*...........생략...........*/

20초마다 코드를 실행하는 부분은 테스트 목적으로 chatGPT에 도움을 받아 끼워 맞춘 거라.... 더 좋은 방법이 있을 거라 생각됩니다...... 글을 잘 못쓰기도하고 졸면서 작성한 글이라 엉망인점 죄송합니다......

R2turnTrue commented 6 months ago

안녕하세요! 일단 무엇이 됐든, 기여 감사합니다!

우선 해당 문제와 작성해주신 해결 코드 모두 확인하였고, 해당 코드를 라이브러리 코드에 맞게 잘 수정해서 실제 버전에 적용해보도록 하겠습니다.

감사합니다!

R2turnTrue commented 3 months ago

9 를 통해 해결되었습니다.