feat: add retry configuration and optimization running lifecycle
This commit is contained in:
parent
d9d3bb2a5b
commit
e5788822ed
@ -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
|
||||
|
@ -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();
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
||||
/**
|
||||
* 命令前缀
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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<Class<? extends Event>, EventHandlerMethod> events = new IncreasbleHashMap<>();
|
||||
@Getter
|
||||
private final Ops ops;
|
||||
|
@ -37,7 +37,6 @@ public class HandshakePacketHandler extends SimpleChannelInboundHandler<FullHttp
|
||||
handshaker.finishHandshake(channelHandlerContext.channel(), fullHttpResponse);
|
||||
this.handshakeFuture.complete(true);
|
||||
log.debug("握手成功");
|
||||
log.info("连接服务器成功!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,8 @@ import java.util.concurrent.Executors;
|
||||
public class PacketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
|
||||
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<TextWebSocketFram
|
||||
public <REQUEST, RESPONSE> void registerResponse(UUID echo, CompletableFuture<ActionResponse<RESPONSE>> responsePromise, Action<REQUEST, RESPONSE> request) {
|
||||
ActionReader.tasks.put(echo, new ApiResponseRequired<>(responsePromise, request));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
log.info("与服务器断开连接!");
|
||||
retryFunction.run();
|
||||
}
|
||||
}
|
||||
|
@ -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<ActionResponse<RESPONSE>> responsePromise = new CompletableFuture<>();
|
||||
packetHandler.registerResponse(request.getEcho(), responsePromise, request);
|
||||
|
@ -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> T readYamlStream(InputStream is, Class<T> clazz) {
|
||||
Yaml yaml = new Yaml();
|
||||
return yaml.loadAs(is, clazz);
|
||||
JSONObject json = yaml.loadAs(is, JSONObject.class);
|
||||
return json.to(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,4 +1,8 @@
|
||||
websocket: "<Your WebSocket connection link, e.g: ws://127.0.0.1:3001/>"
|
||||
network:
|
||||
websocket: "<Your WebSocket connection link, e.g: ws://127.0.0.1:3001/>"
|
||||
retry: true
|
||||
maxRetryCount: 3
|
||||
retryInterval: 10000
|
||||
commandPrefix: "/"
|
||||
authorization:
|
||||
enable: false
|
||||
|
Loading…
x
Reference in New Issue
Block a user