Dituon / petpet

根据模板生成图像
http://d2n.moe/petpet/
GNU Affero General Public License v3.0
310 stars 81 forks source link

关于gocq的ws链接 断线重连的提议 #120

Open DeepseaXX opened 2 months ago

DeepseaXX commented 2 months ago

我一直在用cq的ws链接,这种方式在断线后不会自动重新连接。想修改但是我的Java水平实在捉急。提问了一下ChatGPT这是我得到的回答…… 大佬能否帮忙完成这个更改? 另外如果可以的话,还想实现在配置文件里的开关选项和断线重连时间的参数设置………

相对目录

src/main/java/moe/dituon/petpet/websocket/gocq/GoCQAPIWebSocketClient.java

ChatGPT回答如下


你可以通过在 `onClose` 和 `onError` 方法中实现自动重连逻辑。为了实现每5秒自动重连,你可以使用 `ScheduledExecutorService` 来设置定时任务,直到连接成功为止。

这里是修改后的代码:

```java
import moe.dituon.petpet.plugin.PluginPetService;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;

import java.net.URI;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class GoCQAPIWebSocketClient extends WebSocketClient {
    private static final int RECONNECT_INTERVAL_SECONDS = 5; // 每5秒重连一次
    private ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
    public GoCQRequester requester = new GoCQRequester(this);

    public GoCQAPIWebSocketClient(URI serverURI) {
        super(serverURI);
        connect();
    }

    @Override
    public void onOpen(ServerHandshake handshakedata) {
        PluginPetService.LOGGER.info("GoCQ Event WebSocket 连接成功");
        // 如果连接成功,关闭之前的重连任务
        if (!scheduler.isShutdown()) {
            scheduler.shutdownNow();
        }
    }

    @Override
    public void onClose(int code, String reason, boolean remote) {
        PluginPetService.LOGGER.info("GoCQ Event WebSocket 连接关闭 (" + code + "): " + reason);
        // 断开连接后,尝试重新连接
        attemptReconnect();
    }

    @Override
    public void onError(Exception ex) {
        PluginPetService.LOGGER.warning("an error occurred: " + ex);
        // 出现错误后,尝试重新连接
        attemptReconnect();
    }

    @Override
    public void onMessage(String message) {
        try {
            GoCQResponseDTO response = GoCQResponseDTO.parse(message);
            Long id = Long.parseLong(response.getEcho());
            ThreadLockObject<GoCQMemberDTO> lock = requester.getThreadLock(id);
            synchronized (lock) {
                lock.set(response.toGetGroupMemberResponseDTO().getData());
                lock.notify();
            }
        } catch (Exception ignored) {
        }
    }

    // 尝试每5秒重新连接
    private void attemptReconnect() {
        if (!scheduler.isShutdown()) {
            scheduler.shutdownNow();  // 停止之前的调度任务
        }

        scheduler = Executors.newSingleThreadScheduledExecutor();
        scheduler.scheduleAtFixedRate(() -> {
            PluginPetService.LOGGER.info("尝试重新连接 WebSocket...");
            try {
                reconnect();
            } catch (Exception e) {
                PluginPetService.LOGGER.warning("重新连接失败: " + e.getMessage());
            }
        }, RECONNECT_INTERVAL_SECONDS, RECONNECT_INTERVAL_SECONDS, TimeUnit.SECONDS);
    }
}

修改内容:

  1. 引入 ScheduledExecutorService,用于定时任务。
  2. onCloseonError 中,当连接断开或出错时,启动一个定时任务,每5秒尝试调用 reconnect() 进行重新连接。
  3. 在连接成功的 onOpen 方法中,取消定时任务以避免重复重连。

通过这种方式,当 WebSocket 断开或出错时,它会每5秒自动尝试重新连接,直到连接成功。