diff --git a/.gitignore b/.gitignore index aa5e1192..d4a4a7ba 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ # Compiled class file *.class data.db* +.neutrino-proxy.license + # Log file *.log diff --git a/config.json b/config.json deleted file mode 100644 index e2a81fa6..00000000 --- a/config.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "environment": "我的Mac", - "clientKey": "79419a1a8691413aa5e845b9e3e90051", - "proxy": [ - { - "serverPort": 9100, - "clientInfo": "127.0.0.1:3306" - }, - { - "serverPort": 9101, - "clientInfo": "rm-uf63ggkfh7zrr08vw.mysql.rds.aliyuncs.com:3306" - }, - { - "serverPort": 9102, - "clientInfo": "127.0.0.1:8080" - } - ] -} diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/base/DefaultDispatcher.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/base/DefaultDispatcher.java index e808f3f8..9e38fb43 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/base/DefaultDispatcher.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/base/DefaultDispatcher.java @@ -99,7 +99,7 @@ public class DefaultDispatcher implements Dispatcher handler = handlerMap.get(type); if (null == handler) { - log.warn("{} 找不到匹配的处理器 type:{}", this.name, type); +// log.debug("{} 找不到匹配的处理器 type:{}", this.name, type); return; } String handlerName = handler.name(); diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/context/ApplicationRunner.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/context/ApplicationRunner.java index 3b43d089..dcd56d82 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/context/ApplicationRunner.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/context/ApplicationRunner.java @@ -30,5 +30,4 @@ package fun.asgc.neutrino.core.context; public interface ApplicationRunner { void run(String[] args) throws Exception; - } diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/context/Environment.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/context/Environment.java index 6dbd0ef5..81dd8e65 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/context/Environment.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/context/Environment.java @@ -22,6 +22,7 @@ package fun.asgc.neutrino.core.context; +import fun.asgc.neutrino.core.util.SystemUtil; import lombok.Data; import lombok.experimental.Accessors; @@ -59,4 +60,8 @@ public class Environment { * 启用job */ private boolean enableJob; + /** + * 运行上下文 + */ + private SystemUtil.RunContext runContext; } diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/context/NeutrinoLauncher.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/context/NeutrinoLauncher.java index 67ae58a2..0a37e1dc 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/context/NeutrinoLauncher.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/context/NeutrinoLauncher.java @@ -61,11 +61,13 @@ public class NeutrinoLauncher { environmentInit(); ApplicationContext context = new ApplicationContext(environment); - context.run(); SystemUtil.RunContext runContext = SystemUtil.waitProcessDestroy(() -> { context.destroy(); log.info("Application already stop."); }); + environment.setRunContext(runContext); + + context.run(); stopWatch.stop(); printLog(environment, stopWatch); diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/util/SystemUtil.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/util/SystemUtil.java index b72a9379..e242d497 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/util/SystemUtil.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/util/SystemUtil.java @@ -112,4 +112,12 @@ public class SystemUtil { String osName = System.getProperty("os.name", "unknown"); return osName.toLowerCase().indexOf("windows") != -1; } + + public static void trySleep(long millis) { + try { + Thread.sleep(millis); + } catch (Exception e) { + // ignore + } + } } diff --git a/neutrino-proxy-client/src/main/java/fun/asgc/neutrino/proxy/client/config/ProxyConfig.java b/neutrino-proxy-client/src/main/java/fun/asgc/neutrino/proxy/client/config/ProxyConfig.java index 5f7a202c..e81feb13 100644 --- a/neutrino-proxy-client/src/main/java/fun/asgc/neutrino/proxy/client/config/ProxyConfig.java +++ b/neutrino-proxy-client/src/main/java/fun/asgc/neutrino/proxy/client/config/ProxyConfig.java @@ -39,6 +39,7 @@ public class ProxyConfig { private Protocol protocol; private Client client; private String licenseKey; + public static volatile boolean authSuccess; @Data public static class Protocol { @@ -72,6 +73,8 @@ public class ProxyConfig { private Integer serverPort; @Value("ssl-enable") private Boolean sslEnable; + @Value("obtain-license-interval") + private Integer obtainLicenseInterval; } @Init diff --git a/neutrino-proxy-client/src/main/java/fun/asgc/neutrino/proxy/client/core/ClientChannelHandler.java b/neutrino-proxy-client/src/main/java/fun/asgc/neutrino/proxy/client/core/ClientChannelHandler.java index 8290de15..8efa858d 100644 --- a/neutrino-proxy-client/src/main/java/fun/asgc/neutrino/proxy/client/core/ClientChannelHandler.java +++ b/neutrino-proxy-client/src/main/java/fun/asgc/neutrino/proxy/client/core/ClientChannelHandler.java @@ -59,7 +59,9 @@ public class ClientChannelHandler extends SimpleChannelInboundHandler { + boolean lock = runLock.tryLock(); + try { + if (lock) { + this.process(args); + } + } finally { + if (runLock.isHeldByCurrentThread()){ + runLock.unlock(); + } + } + }, 0, proxyConfig.getClient().getObtainLicenseInterval(), TimeUnit.SECONDS); + } + + public void stop() { + scheduledExecutor.shutdown(); + log.info("licenseKey获取任务停止"); + } + + public void process(String[] args) { + if (isFirst) { + isFirst = true; + SystemUtil.trySleep(2000); + } + String licenseKey = getLicenseKey(args); + proxyClientRunner.start(licenseKey); + } + + private String getLicenseKey(String[] args) { + String license = ""; + if (null != args && ArrayUtil.notEmpty(args)) { + for (String s : args) { + if (s.startsWith("license=") && s.length() > 8) { + license = s.substring(8).trim(); + } + } + } + if (StringUtil.isEmpty(license)) { + license = FileUtil.readContentAsString("./.neutrino-proxy.license"); + } + + while (StringUtil.isEmpty(license)) { + System.out.print("请输入license:"); + license = scanner.next(); + } + + return license; + } +} diff --git a/neutrino-proxy-client/src/main/java/fun/asgc/neutrino/proxy/client/core/ProxyClientRunner.java b/neutrino-proxy-client/src/main/java/fun/asgc/neutrino/proxy/client/core/ProxyClientRunner.java index 53187fb4..88b3af5f 100644 --- a/neutrino-proxy-client/src/main/java/fun/asgc/neutrino/proxy/client/core/ProxyClientRunner.java +++ b/neutrino-proxy-client/src/main/java/fun/asgc/neutrino/proxy/client/core/ProxyClientRunner.java @@ -27,17 +27,14 @@ import fun.asgc.neutrino.core.annotation.Bean; import fun.asgc.neutrino.core.annotation.Component; import fun.asgc.neutrino.core.annotation.NonIntercept; import fun.asgc.neutrino.core.context.ApplicationRunner; -import fun.asgc.neutrino.core.util.ArrayUtil; +import fun.asgc.neutrino.core.context.Environment; import fun.asgc.neutrino.core.util.FileUtil; import fun.asgc.neutrino.core.util.StringUtil; import fun.asgc.neutrino.proxy.client.config.ProxyConfig; import fun.asgc.neutrino.proxy.client.util.ProxyUtil; import fun.asgc.neutrino.proxy.core.*; import io.netty.bootstrap.Bootstrap; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelFutureListener; -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelInitializer; +import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; @@ -51,6 +48,7 @@ import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import java.io.InputStream; import java.security.KeyStore; +import java.util.Scanner; /** * @@ -60,7 +58,7 @@ import java.security.KeyStore; @Slf4j @NonIntercept @Component -public class ProxyClientRunner implements ApplicationRunner { +public class ProxyClientRunner { @Autowired private ProxyConfig proxyConfig; @Autowired("bootstrap") @@ -68,11 +66,20 @@ public class ProxyClientRunner implements ApplicationRunner { @Autowired("realServerBootstrap") private static Bootstrap realServerBootstrap; private static NioEventLoopGroup workerGroup; + @Autowired + private Environment environment; + private volatile Channel channel; - @Override - public void run(String[] args) { - proxyConfig.setLicenseKey(getLicenseKey(args)); - connectProxyServer(); + public void start(String licenseKey) { + if (StringUtil.isEmpty(licenseKey)) { + return; + } + proxyConfig.setLicenseKey(licenseKey); + if (null == channel || !channel.isActive()) { + connectProxyServer(); + } else { + channel.writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getLicenseKey())); + } } /** @@ -114,6 +121,7 @@ public class ProxyClientRunner implements ApplicationRunner { @Override public void operationComplete(ChannelFuture future) throws Exception { if (future.isSuccess()) { + channel = future.channel(); // 连接成功,向服务器发送客户端认证信息(licenseKey) ProxyUtil.setCmdChannel(future.channel()); future.channel().writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getLicenseKey())); @@ -158,25 +166,4 @@ public class ProxyClientRunner implements ApplicationRunner { public Bootstrap realServerBootstrap() { return new Bootstrap(); } - - private String getLicenseKey(String[] args) { - String license = ""; - if (null != args && ArrayUtil.notEmpty(args)) { - for (String s : args) { - if (s.startsWith("license=") && s.length() > 8) { - license = s.substring(8).trim(); - } - } - } - if (StringUtil.isEmpty(license)) { - license = FileUtil.readContentAsString("./.neutrino-proxy.license"); - } - if (StringUtil.isEmpty(license)) { - log.error("未配置license,执行结束."); - System.exit(-1); - } - FileUtil.write("./.neutrino-proxy.license", license); - - return license; - } } diff --git a/neutrino-proxy-client/src/main/java/fun/asgc/neutrino/proxy/client/handler/ProxyMessageAuthHandler.java b/neutrino-proxy-client/src/main/java/fun/asgc/neutrino/proxy/client/handler/ProxyMessageAuthHandler.java new file mode 100644 index 00000000..9cffebfe --- /dev/null +++ b/neutrino-proxy-client/src/main/java/fun/asgc/neutrino/proxy/client/handler/ProxyMessageAuthHandler.java @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2022 aoshiguchen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package fun.asgc.neutrino.proxy.client.handler; + +import com.alibaba.fastjson.JSONObject; +import fun.asgc.neutrino.core.annotation.Autowired; +import fun.asgc.neutrino.core.annotation.Component; +import fun.asgc.neutrino.core.annotation.Match; +import fun.asgc.neutrino.core.annotation.NonIntercept; +import fun.asgc.neutrino.core.util.FileUtil; +import fun.asgc.neutrino.proxy.client.config.ProxyConfig; +import fun.asgc.neutrino.proxy.client.core.LicenseObtainService; +import fun.asgc.neutrino.proxy.core.Constants; +import fun.asgc.neutrino.proxy.core.ExceptionEnum; +import fun.asgc.neutrino.proxy.core.ProxyMessage; +import fun.asgc.neutrino.proxy.core.ProxyMessageHandler; +import io.netty.channel.ChannelHandlerContext; +import lombok.extern.slf4j.Slf4j; + +/** + * + * @author: aoshiguchen + * @date: 2022/9/4 + */ +@Slf4j +@NonIntercept +@Match(type = Constants.ProxyDataTypeName.AUTH) +@Component +public class ProxyMessageAuthHandler implements ProxyMessageHandler { + @Autowired + private LicenseObtainService licenseObtainService; + + @Override + public void handle(ChannelHandlerContext context, ProxyMessage proxyMessage) { + String info = proxyMessage.getInfo(); + JSONObject data = JSONObject.parseObject(info); + Integer code = data.getInteger("code"); + String licenseKey = data.getString("licenseKey"); + log.info("认证结果:{}", info); + if (ExceptionEnum.SUCCESS.getCode().equals(code)) { + ProxyConfig.authSuccess = true; + FileUtil.write("./.neutrino-proxy.license", licenseKey); + licenseObtainService.stop(); + } + } +} diff --git a/neutrino-proxy-client/src/main/resources/application.yml b/neutrino-proxy-client/src/main/resources/application.yml index 9d134d81..0fc6fc51 100644 --- a/neutrino-proxy-client/src/main/resources/application.yml +++ b/neutrino-proxy-client/src/main/resources/application.yml @@ -18,3 +18,4 @@ neutrino: server-ip: localhost server-port: 9002 ssl-enable: true + obtain-license-interval: 5 diff --git a/neutrino-proxy-core/src/main/java/fun/asgc/neutrino/proxy/core/ExceptionEnum.java b/neutrino-proxy-core/src/main/java/fun/asgc/neutrino/proxy/core/ExceptionEnum.java index ec1cc0f5..23434bb7 100644 --- a/neutrino-proxy-core/src/main/java/fun/asgc/neutrino/proxy/core/ExceptionEnum.java +++ b/neutrino-proxy-core/src/main/java/fun/asgc/neutrino/proxy/core/ExceptionEnum.java @@ -33,7 +33,7 @@ import lombok.Getter; @Getter @AllArgsConstructor public enum ExceptionEnum { - + SUCCESS(0, "成功"), AUTH_FAILED(1, "认证失败"), CONNECT_FAILED(2, "连接失败"); diff --git a/neutrino-proxy-core/src/main/java/fun/asgc/neutrino/proxy/core/ProxyMessage.java b/neutrino-proxy-core/src/main/java/fun/asgc/neutrino/proxy/core/ProxyMessage.java index 6308df48..d17432da 100644 --- a/neutrino-proxy-core/src/main/java/fun/asgc/neutrino/proxy/core/ProxyMessage.java +++ b/neutrino-proxy-core/src/main/java/fun/asgc/neutrino/proxy/core/ProxyMessage.java @@ -106,6 +106,15 @@ public class ProxyMessage { .setInfo(info); } + public static ProxyMessage buildAuthResultMessage(Integer code, String msg, String licenseKey) { + JSONObject data = new JSONObject(); + data.put("code", code); + data.put("msg", msg); + data.put("licenseKey", licenseKey); + return create().setType(TYPE_AUTH) + .setInfo(data.toJSONString()); + } + public static ProxyMessage buildConnectMessage(String info) { return create().setType(TYPE_CONNECT) .setInfo(info); diff --git a/neutrino-proxy-server/src/main/java/fun/asgc/neutrino/proxy/server/proxy/handler/ProxyMessageAuthHandler.java b/neutrino-proxy-server/src/main/java/fun/asgc/neutrino/proxy/server/proxy/handler/ProxyMessageAuthHandler.java index e0189e78..f1afecfb 100644 --- a/neutrino-proxy-server/src/main/java/fun/asgc/neutrino/proxy/server/proxy/handler/ProxyMessageAuthHandler.java +++ b/neutrino-proxy-server/src/main/java/fun/asgc/neutrino/proxy/server/proxy/handler/ProxyMessageAuthHandler.java @@ -85,44 +85,45 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler { public void handle(ChannelHandlerContext ctx, ProxyMessage proxyMessage) { String licenseKey = proxyMessage.getInfo(); if (StringUtil.isEmpty(licenseKey)) { - ctx.channel().writeAndFlush(ProxyMessage.buildErrMessage(ExceptionEnum.AUTH_FAILED, "license不能为空!")); - ctx.channel().close(); + ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "license不能为空!", licenseKey)); +// ctx.channel().close(); return; } LicenseDO licenseDO = licenseService.findByKey(licenseKey); if (null == licenseDO) { - ctx.channel().writeAndFlush(ProxyMessage.buildErrMessage(ExceptionEnum.AUTH_FAILED, "license不存在!")); - ctx.channel().close(); + ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "license不存在!", licenseKey)); +// ctx.channel().close(); return; } if (EnableStatusEnum.DISABLE.getStatus().equals(licenseDO.getEnable())) { - ctx.channel().writeAndFlush(ProxyMessage.buildErrMessage(ExceptionEnum.AUTH_FAILED, "当前license已被禁用!")); - ctx.channel().close(); + ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "当前license已被禁用!", licenseKey)); +// ctx.channel().close(); return; } UserDO userDO = userService.findById(licenseDO.getId()); if (null == userDO || EnableStatusEnum.DISABLE.getStatus().equals(userDO.getEnable())) { - ctx.channel().writeAndFlush(ProxyMessage.buildErrMessage(ExceptionEnum.AUTH_FAILED, "当前license无效!")); - ctx.channel().close(); - return; - } - List portMappingList = portMappingService.findEnableListByLicenseId(licenseDO.getId()); - // 没有端口映射仍然保持连接 - if (CollectionUtil.isEmpty(portMappingList)) { + ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "当前license无效!", licenseKey)); +// ctx.channel().close(); return; } Channel cmdChannel = ProxyUtil.getCmdChannelByLicenseId(licenseDO.getId()); if (null != cmdChannel) { - ctx.channel().writeAndFlush(ProxyMessage.buildErrMessage(ExceptionEnum.AUTH_FAILED, "当前license已被另一节点使用!")); - ctx.channel().close(); + ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "当前license已被另一节点使用!", licenseKey)); +// ctx.channel().close(); return; } + // 发送认证成功消息 + ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.SUCCESS.getCode(), "认证成功!", licenseKey)); - ProxyUtil.initProxyInfo(licenseDO.getId(), ProxyMapping.buildList(portMappingList)); + List portMappingList = portMappingService.findEnableListByLicenseId(licenseDO.getId()); + // 没有端口映射仍然保持连接 + if (!CollectionUtil.isEmpty(portMappingList)) { + ProxyUtil.initProxyInfo(licenseDO.getId(), ProxyMapping.buildList(portMappingList)); - ProxyUtil.addCmdChannel(licenseDO.getId(), ctx.channel(), portMappingList.stream().map(PortMappingDO::getServerPort).collect(Collectors.toSet())); + ProxyUtil.addCmdChannel(licenseDO.getId(), ctx.channel(), portMappingList.stream().map(PortMappingDO::getServerPort).collect(Collectors.toSet())); - startUserPortServer(ProxyUtil.getAttachInfo(ctx.channel()), portMappingList); + startUserPortServer(ProxyUtil.getAttachInfo(ctx.channel()), portMappingList); + } } @Override