From e5788822ed50c456094d96a15bec453a85d1ca7e Mon Sep 17 00:00:00 2001 From: Wzp-2008 Date: Wed, 26 Mar 2025 19:12:56 +0800 Subject: [PATCH] feat: add retry configuration and optimization running lifecycle --- .../plugins/configuration/IConfiguration.java | 12 ++-- .../configuration/INetworkConfiguration.java | 38 ++++++++++++ src/main/java/cn/wzpmc/Main.java | 14 ++++- .../cn/wzpmc/configuration/Configuration.java | 9 +-- .../configuration/NetworkConfiguration.java | 38 ++++++++++++ .../java/cn/wzpmc/console/MyBotConsole.java | 6 ++ .../cn/wzpmc/entities/user/bot/MyBot.java | 2 + .../wzpmc/network/HandshakePacketHandler.java | 1 - .../java/cn/wzpmc/network/PacketHandler.java | 8 +++ .../network/WebSocketConnectionHandler.java | 61 +++++++++++++++++-- src/main/java/cn/wzpmc/utils/YamlUtils.java | 4 +- src/main/resources/templates/config.yaml | 6 +- 12 files changed, 177 insertions(+), 22 deletions(-) create mode 100644 mybot-api/src/main/java/cn/wzpmc/plugins/configuration/INetworkConfiguration.java create mode 100644 src/main/java/cn/wzpmc/configuration/NetworkConfiguration.java diff --git a/mybot-api/src/main/java/cn/wzpmc/plugins/configuration/IConfiguration.java b/mybot-api/src/main/java/cn/wzpmc/plugins/configuration/IConfiguration.java index 767830d..a430527 100644 --- a/mybot-api/src/main/java/cn/wzpmc/plugins/configuration/IConfiguration.java +++ b/mybot-api/src/main/java/cn/wzpmc/plugins/configuration/IConfiguration.java @@ -8,13 +8,13 @@ package cn.wzpmc.plugins.configuration; * @since 2024/7/31 上午3:42 */ public interface IConfiguration { - /** - * @return WebSocket连接URL - * @author wzp - * @since 2024/7/31 上午3:48 v0.0.1-dev - */ - String getWebsocket(); + /** + * @author wzp + * @since 2025/3/26 17:29 v1.0.7 + * @return 网络相关配置 + */ + INetworkConfiguration getNetwork(); /** * * @author wzp diff --git a/mybot-api/src/main/java/cn/wzpmc/plugins/configuration/INetworkConfiguration.java b/mybot-api/src/main/java/cn/wzpmc/plugins/configuration/INetworkConfiguration.java new file mode 100644 index 0000000..875e14d --- /dev/null +++ b/mybot-api/src/main/java/cn/wzpmc/plugins/configuration/INetworkConfiguration.java @@ -0,0 +1,38 @@ +package cn.wzpmc.plugins.configuration; + +/** + * @author wzp + * @since 2025/3/26 17:26 + * @version 1.0.7 + */ +public interface INetworkConfiguration { + /** + * @return WebSocket连接URL + * @author wzp + * @since 2025/3/26 17:26 v1.0.7 + */ + String getWebsocket(); + + /** + * @author wzp + * @since 2025/3/26 17:27 v1.0.7 + * @return 是否启用连接重试 + */ + Boolean isRetry(); + + /** + * @author wzp + * @since 2025/3/26 17:27 v1.0.7 + * @return 重试最大次数(-1为无限) + */ + Integer getMaxRetryCount(); + + + /** + * @author wzp + * @since 2025/3/26 17:28 v1.0.7 + * @return 获取重试间隔(单位毫秒) + */ + Long getRetryInterval(); + +} diff --git a/src/main/java/cn/wzpmc/Main.java b/src/main/java/cn/wzpmc/Main.java index 7a3bbb0..ce11c22 100644 --- a/src/main/java/cn/wzpmc/Main.java +++ b/src/main/java/cn/wzpmc/Main.java @@ -18,6 +18,7 @@ import cn.wzpmc.utils.JsonUtils; import cn.wzpmc.utils.ReflectionUtils; import cn.wzpmc.utils.TemplateFileUtils; import cn.wzpmc.utils.YamlUtils; +import com.alibaba.fastjson2.JSONObject; import lombok.SneakyThrows; import lombok.extern.log4j.Log4j2; @@ -52,6 +53,7 @@ public class Main { } log.debug("读取配置文件 {}", configurationFile.getAbsolutePath()); Configuration configuration = YamlUtils.readYamlFile(configurationFile, Configuration.class); + JSONObject fullConfiguration = YamlUtils.readYamlFile(configurationFile, JSONObject.class); Configuration defaultConfiguration = TemplateFileUtils.readDefaultConfig(classLoader, DEFAULT_CONFIGURATION_FILE_PATH, Configuration.class); // 配置文件自动更新 start boolean isChanged = false; @@ -78,6 +80,12 @@ public class Main { configuration.setCommandPrefix(defaultConfiguration.getCommandPrefix()); isChanged = true; } + if (configuration.getNetwork() == null) { + configuration.setNetwork(defaultConfiguration.getNetwork()); + configuration.getNetwork().setWebsocket(fullConfiguration.getString("websocket")); + isChanged = true; + } + // end if (isChanged) { log.warn("已自动升级配置文件,请检查config.yml是否有错误的地方,有则请修改"); YamlUtils.writeYamlFile(configurationFile, configuration); @@ -95,7 +103,7 @@ public class Main { public static URI getUriFromConfiguration(Configuration configuration) { URI uri; try { - uri = new URI(configuration.getWebsocket()); + uri = new URI(configuration.getNetwork().getWebsocket()); } catch (URISyntaxException e) { return null; } @@ -134,8 +142,8 @@ public class Main { } public static WebSocketConnectionHandler createConnection(MyBot myBot, URI uri) { - WebSocketConnectionHandler webSocketConnectionHandler = new WebSocketConnectionHandler(myBot); - webSocketConnectionHandler.connect(uri); + WebSocketConnectionHandler webSocketConnectionHandler = new WebSocketConnectionHandler(myBot, uri); + webSocketConnectionHandler.connect(); return webSocketConnectionHandler; } diff --git a/src/main/java/cn/wzpmc/configuration/Configuration.java b/src/main/java/cn/wzpmc/configuration/Configuration.java index 151c455..cc09e22 100644 --- a/src/main/java/cn/wzpmc/configuration/Configuration.java +++ b/src/main/java/cn/wzpmc/configuration/Configuration.java @@ -12,12 +12,13 @@ import lombok.Data; */ @Data public class Configuration implements IConfiguration { + /** - * WebSocket连接URL - * - * @since 2024/7/30 下午11:48 v0.0.1-dev + * 网络相关配置 + * @since 2025/3/26 17:32 v1.0.7 */ - private String websocket; + private NetworkConfiguration network; + /** * 命令前缀 diff --git a/src/main/java/cn/wzpmc/configuration/NetworkConfiguration.java b/src/main/java/cn/wzpmc/configuration/NetworkConfiguration.java new file mode 100644 index 0000000..b0dda80 --- /dev/null +++ b/src/main/java/cn/wzpmc/configuration/NetworkConfiguration.java @@ -0,0 +1,38 @@ +package cn.wzpmc.configuration; + +import cn.wzpmc.plugins.configuration.INetworkConfiguration; +import lombok.Data; + +/** + * @author wzp + * @since 2025/3/26 17:29 + * @version 1.0.7 + */ +@Data +public class NetworkConfiguration implements INetworkConfiguration { + /** + * WebSocket连接URL + * @since 2025/3/26 17:31 v1.0.7 + */ + private String websocket; + /** + * 是否启用连接重试 + * @since 2025/3/26 17:31 v1.0.7 + */ + private Boolean retry; + /** + * 重试最大次数(-1为无限) + * @since 2025/3/26 17:31 v1.0.7 + */ + private Integer maxRetryCount; + /** + * 获取重试间隔(单位毫秒) + * @since 2025/3/26 17:31 v1.0.7 + */ + private Long retryInterval; + + @Override + public Boolean isRetry() { + return this.retry; + } +} diff --git a/src/main/java/cn/wzpmc/console/MyBotConsole.java b/src/main/java/cn/wzpmc/console/MyBotConsole.java index 43bacc2..60c0c5d 100644 --- a/src/main/java/cn/wzpmc/console/MyBotConsole.java +++ b/src/main/java/cn/wzpmc/console/MyBotConsole.java @@ -1,8 +1,10 @@ package cn.wzpmc.console; +import cn.wzpmc.entities.api.ApiResponseRequired; import cn.wzpmc.entities.user.bot.MyBot; import cn.wzpmc.network.WebSocketConnectionHandler; import cn.wzpmc.plugins.CommandManager; +import cn.wzpmc.utils.json.action.ActionReader; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; @@ -47,12 +49,16 @@ public class MyBotConsole extends SimpleTerminalConsole { @Override public void shutdown() { this.webSocketConnectionHandler.kill(); + for (ApiResponseRequired value : ActionReader.tasks.values()) { + value.getFuture().complete(null); + } running = false; } @Override public void start() { this.bot.setConsole(this); + if (this.bot.isShutdown()) return; super.start(); } } \ No newline at end of file diff --git a/src/main/java/cn/wzpmc/entities/user/bot/MyBot.java b/src/main/java/cn/wzpmc/entities/user/bot/MyBot.java index 10b1bdd..f44b8ce 100644 --- a/src/main/java/cn/wzpmc/entities/user/bot/MyBot.java +++ b/src/main/java/cn/wzpmc/entities/user/bot/MyBot.java @@ -50,6 +50,8 @@ public class MyBot extends IBot { private final Configuration configuration; private final CommandManager commandManager = new CommandManager(this); private final PluginManager pluginManager = new PluginManager(); + @Setter + private boolean shutdown = false; private final IncreasbleHashMap, EventHandlerMethod> events = new IncreasbleHashMap<>(); @Getter private final Ops ops; diff --git a/src/main/java/cn/wzpmc/network/HandshakePacketHandler.java b/src/main/java/cn/wzpmc/network/HandshakePacketHandler.java index 50bf835..af017df 100644 --- a/src/main/java/cn/wzpmc/network/HandshakePacketHandler.java +++ b/src/main/java/cn/wzpmc/network/HandshakePacketHandler.java @@ -37,7 +37,6 @@ public class HandshakePacketHandler extends SimpleChannelInboundHandler { private final IBot bot; private final ExecutorService threadPool = Executors.newFixedThreadPool(4); + private final Runnable retryFunction; + @Override protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame webSocketFrame) { @@ -105,4 +107,10 @@ public class PacketHandler extends SimpleChannelInboundHandler void registerResponse(UUID echo, CompletableFuture> responsePromise, Action request) { ActionReader.tasks.put(echo, new ApiResponseRequired<>(responsePromise, request)); } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + log.info("与服务器断开连接!"); + retryFunction.run(); + } } diff --git a/src/main/java/cn/wzpmc/network/WebSocketConnectionHandler.java b/src/main/java/cn/wzpmc/network/WebSocketConnectionHandler.java index a9435d6..6908797 100644 --- a/src/main/java/cn/wzpmc/network/WebSocketConnectionHandler.java +++ b/src/main/java/cn/wzpmc/network/WebSocketConnectionHandler.java @@ -2,7 +2,11 @@ package cn.wzpmc.network; import cn.wzpmc.api.Action; import cn.wzpmc.api.ActionResponse; -import cn.wzpmc.user.IBot; +import cn.wzpmc.console.MyBotConsole; +import cn.wzpmc.entities.api.ApiResponseRequired; +import cn.wzpmc.entities.user.bot.MyBot; +import cn.wzpmc.plugins.configuration.INetworkConfiguration; +import cn.wzpmc.utils.json.action.ActionReader; import com.alibaba.fastjson2.JSON; import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; @@ -32,26 +36,70 @@ import java.util.concurrent.ExecutionException; @RequiredArgsConstructor public class WebSocketConnectionHandler { private final EventLoopGroup eventLoopGroup = new NioEventLoopGroup(); - private final IBot bot; + private final MyBot bot; + /** + * websocket连接地址 + * @since 2025/3/26 17:56 v1.0.7 + */ + private final URI websocket; private ChannelFuture channelFuture; private PacketHandler packetHandler; private HandshakePacketHandler handshakePacketHandler; + private int currentRetryCount = 0; + + + private void tryReconnect() { + INetworkConfiguration network = bot.getConfiguration().getNetwork(); + if (!network.isRetry()) { + this.quit(); + return; + } + Integer maxRetryCount = network.getMaxRetryCount(); + if (maxRetryCount != 0 && currentRetryCount >= maxRetryCount) { + this.quit(); + return; + } + this.currentRetryCount++; + log.info("尝试重连第{}次", currentRetryCount); + this.connect(); + } + + private void quit() { + for (ApiResponseRequired value : ActionReader.tasks.values()) { + value.getFuture().obtrudeException(new InterruptedException()); + } + this.handshakePacketHandler.getHandshakeFuture().obtrudeException(new InterruptedException()); + MyBotConsole console = bot.getConsole(); + bot.setShutdown(true); + if (console == null) { + this.eventLoopGroup.shutdownGracefully(); + return; + } + console.shutdown(); + } /** * 建立连接 - * - * @param websocket websocket连接地址 * @author wzp * @since 2024/7/30 下午11:55 v0.0.1-dev */ - public void connect(URI websocket) { + public void connect() { log.info("正在连接websocket"); Bootstrap bootstrap = new Bootstrap(); WebSocketClientHandshaker clientHandshaker = WebSocketClientHandshakerFactory.newHandshaker(websocket, WebSocketVersion.V13, null, false, new DefaultHttpHeaders(), 65536 * 100); this.handshakePacketHandler = new HandshakePacketHandler(clientHandshaker); - this.packetHandler = new PacketHandler(this.bot); + this.packetHandler = new PacketHandler(this.bot, this::tryReconnect); bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class).handler(new WebSocketChannelInitializer(this.packetHandler, this.handshakePacketHandler)); this.channelFuture = bootstrap.connect(websocket.getHost(), websocket.getPort()); + this.channelFuture.addListener(future -> { + if (!future.isSuccess()) { + log.info("连接失败!"); + this.tryReconnect(); + } else { + log.info("连接成功!"); + this.currentRetryCount = 0; + } + }); } /** @@ -81,6 +129,7 @@ public class WebSocketConnectionHandler { this.handshakePacketHandler.getHandshakeFuture().get(); } catch (ExecutionException e) { log.error(e); + return null; } CompletableFuture> responsePromise = new CompletableFuture<>(); packetHandler.registerResponse(request.getEcho(), responsePromise, request); diff --git a/src/main/java/cn/wzpmc/utils/YamlUtils.java b/src/main/java/cn/wzpmc/utils/YamlUtils.java index 3c9050b..345a318 100644 --- a/src/main/java/cn/wzpmc/utils/YamlUtils.java +++ b/src/main/java/cn/wzpmc/utils/YamlUtils.java @@ -1,6 +1,7 @@ package cn.wzpmc.utils; import cn.wzpmc.configuration.Configuration; +import com.alibaba.fastjson2.JSONObject; import lombok.extern.log4j.Log4j2; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.Yaml; @@ -30,7 +31,8 @@ public class YamlUtils { */ public static T readYamlStream(InputStream is, Class clazz) { Yaml yaml = new Yaml(); - return yaml.loadAs(is, clazz); + JSONObject json = yaml.loadAs(is, JSONObject.class); + return json.to(clazz); } /** diff --git a/src/main/resources/templates/config.yaml b/src/main/resources/templates/config.yaml index 3586400..589e121 100644 --- a/src/main/resources/templates/config.yaml +++ b/src/main/resources/templates/config.yaml @@ -1,4 +1,8 @@ -websocket: "" +network: + websocket: "" + retry: true + maxRetryCount: 3 + retryInterval: 10000 commandPrefix: "/" authorization: enable: false