Compare commits
20
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a31b0ebc95 | ||
|
|
fe86d786f4 | ||
|
|
c48404e3bb | ||
|
|
5daec7195f | ||
|
|
533675b367 | ||
|
|
e547895a9c | ||
|
|
42b7163f5b | ||
|
|
2ceacc6916 | ||
|
|
124273e8d7 | ||
|
|
5a36c88875 | ||
|
|
70e6d2ab45 | ||
|
|
2dc8965cdb | ||
|
|
0d997bbe92 | ||
|
|
f88bbb53cb | ||
|
|
2ae3267049 | ||
|
|
62bbd48b33 | ||
|
|
aa131b0705 | ||
|
|
1510e16e50 | ||
|
|
a3b324c72b | ||
|
|
c959ce13a3 |
@@ -56,3 +56,4 @@ hs_err_pid*
|
|||||||
|
|
||||||
neutrino-proxy-vuepress/deploy.sh
|
neutrino-proxy-vuepress/deploy.sh
|
||||||
.NEUTRINO_PROXY_CLIENT_ID
|
.NEUTRINO_PROXY_CLIENT_ID
|
||||||
|
logs
|
||||||
|
|||||||
@@ -154,7 +154,7 @@
|
|||||||
<el-form-item :label="$t('客户端端口')" prop="clientPort">
|
<el-form-item :label="$t('客户端端口')" prop="clientPort">
|
||||||
<el-input v-model="temp.clientPort"></el-input>
|
<el-input v-model="temp.clientPort"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('域名')" prop="subdomain" v-if="temp.protocal === 'HTTP' && domainName && domainName != ''">
|
<el-form-item :label="$t('域名')" prop="subdomain" v-if="(temp.protocal === 'HTTP' || temp.protocal === 'HTTP(S)') && domainName && domainName != ''">
|
||||||
<el-input v-model="temp.subdomain">
|
<el-input v-model="temp.subdomain">
|
||||||
<template slot="append">.{{ domainName }}</template>
|
<template slot="append">.{{ domainName }}</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
|
|||||||
@@ -1,14 +1,22 @@
|
|||||||
package org.dromara.neutrinoproxy.client;
|
package org.dromara.neutrinoproxy.client;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.Level;
|
||||||
|
import ch.qos.logback.classic.Logger;
|
||||||
|
import ch.qos.logback.classic.LoggerContext;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.noear.solon.Solon;
|
import org.noear.solon.Solon;
|
||||||
|
import org.noear.solon.SolonApp;
|
||||||
import org.noear.solon.annotation.SolonMain;
|
import org.noear.solon.annotation.SolonMain;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author: aoshiguchen
|
* @author: aoshiguchen
|
||||||
* @date: 2022/6/16
|
* @date: 2022/6/16
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
@SolonMain
|
@SolonMain
|
||||||
public class ProxyClient {
|
public class ProxyClient {
|
||||||
|
|
||||||
@@ -20,6 +28,8 @@ public class ProxyClient {
|
|||||||
setAlias("neutrino.proxy.client.jksPath", "jksPath");
|
setAlias("neutrino.proxy.client.jksPath", "jksPath");
|
||||||
setAlias("neutrino.proxy.client.keyStorePassword", "keyStorePassword");
|
setAlias("neutrino.proxy.client.keyStorePassword", "keyStorePassword");
|
||||||
setAlias("neutrino.proxy.client.licenseKey", "licenseKey");
|
setAlias("neutrino.proxy.client.licenseKey", "licenseKey");
|
||||||
|
// 设置日志级别
|
||||||
|
setLogLevel(app);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,4 +44,21 @@ public class ProxyClient {
|
|||||||
Solon.cfg().put(key, val);
|
Solon.cfg().put(key, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void setLogLevel(SolonApp app) {
|
||||||
|
String loggerLevel = app.cfg().get("neutrino.proxy.logger.level");
|
||||||
|
if (StringUtils.isBlank(loggerLevel)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Level level = Level.toLevel(loggerLevel);
|
||||||
|
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
|
||||||
|
for (Logger logger : loggerContext.getLoggerList()) {
|
||||||
|
logger.setLevel(level);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("日志级别设置失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
@@ -40,5 +40,13 @@ public class ProxyConfig {
|
|||||||
private String licenseKey;
|
private String licenseKey;
|
||||||
private Integer threadCount;
|
private Integer threadCount;
|
||||||
private String clientId;
|
private String clientId;
|
||||||
|
private Boolean transferLogEnable;
|
||||||
|
private Reconnection reconnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class Reconnection {
|
||||||
|
private Integer intervalSeconds;
|
||||||
|
private Boolean unlimited;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -24,7 +24,7 @@ public class CmdChannelHandler extends SimpleChannelInboundHandler<ProxyMessage>
|
|||||||
@Override
|
@Override
|
||||||
protected void channelRead0(ChannelHandlerContext ctx, ProxyMessage proxyMessage) throws Exception {
|
protected void channelRead0(ChannelHandlerContext ctx, ProxyMessage proxyMessage) throws Exception {
|
||||||
if (ProxyMessage.TYPE_HEARTBEAT != proxyMessage.getType()) {
|
if (ProxyMessage.TYPE_HEARTBEAT != proxyMessage.getType()) {
|
||||||
log.info("Client CmdChannel recieved proxy message, type is {}", proxyMessage.getType());
|
log.debug("Client CmdChannel recieved proxy message, type is {}", proxyMessage.getType());
|
||||||
}
|
}
|
||||||
Solon.context().getBean(Dispatcher.class).dispatch(ctx, proxyMessage);
|
Solon.context().getBean(Dispatcher.class).dispatch(ctx, proxyMessage);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -24,7 +24,7 @@ public class ProxyChannelHandler extends SimpleChannelInboundHandler<ProxyMessag
|
|||||||
@Override
|
@Override
|
||||||
protected void channelRead0(ChannelHandlerContext ctx, ProxyMessage proxyMessage) throws Exception {
|
protected void channelRead0(ChannelHandlerContext ctx, ProxyMessage proxyMessage) throws Exception {
|
||||||
if (ProxyMessage.TYPE_HEARTBEAT != proxyMessage.getType()) {
|
if (ProxyMessage.TYPE_HEARTBEAT != proxyMessage.getType()) {
|
||||||
log.info("Client ProxyChannel recieved proxy message, type is {}", proxyMessage.getType());
|
log.debug("Client ProxyChannel recieved proxy message, type is {}", proxyMessage.getType());
|
||||||
}
|
}
|
||||||
Solon.context().getBean(Dispatcher.class).dispatch(ctx, proxyMessage);
|
Solon.context().getBean(Dispatcher.class).dispatch(ctx, proxyMessage);
|
||||||
}
|
}
|
||||||
@@ -71,7 +71,7 @@ public class ProxyChannelHandler extends SimpleChannelInboundHandler<ProxyMessag
|
|||||||
ctx.channel().writeAndFlush(ProxyMessage.buildHeartbeatMessage());
|
ctx.channel().writeAndFlush(ProxyMessage.buildHeartbeatMessage());
|
||||||
break;
|
break;
|
||||||
case ALL_IDLE:
|
case ALL_IDLE:
|
||||||
log.info("读写超时");
|
log.debug("读写超时");
|
||||||
ctx.close();
|
ctx.close();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-6
@@ -1,6 +1,7 @@
|
|||||||
package org.dromara.neutrinoproxy.client.core;
|
package org.dromara.neutrinoproxy.client.core;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import io.netty.handler.logging.LoggingHandler;
|
||||||
import org.dromara.neutrinoproxy.client.config.ProxyConfig;
|
import org.dromara.neutrinoproxy.client.config.ProxyConfig;
|
||||||
import org.dromara.neutrinoproxy.client.util.ProxyUtil;
|
import org.dromara.neutrinoproxy.client.util.ProxyUtil;
|
||||||
import org.dromara.neutrinoproxy.core.ProxyMessage;
|
import org.dromara.neutrinoproxy.core.ProxyMessage;
|
||||||
@@ -48,10 +49,10 @@ public class ProxyClientService {
|
|||||||
@Inject("realServerBootstrap")
|
@Inject("realServerBootstrap")
|
||||||
private Bootstrap realServerBootstrap;
|
private Bootstrap realServerBootstrap;
|
||||||
private volatile Channel channel;
|
private volatile Channel channel;
|
||||||
/**
|
// /**
|
||||||
* 重连间隔(秒)
|
// * 重连间隔(秒)
|
||||||
*/
|
// */
|
||||||
private static final long RECONNECT_INTERVAL_SECONDS = 5;
|
// private static final long RECONNECT_INTERVAL_SECONDS = 5;
|
||||||
/**
|
/**
|
||||||
* 重连次数
|
* 重连次数
|
||||||
*/
|
*/
|
||||||
@@ -68,7 +69,7 @@ public class ProxyClientService {
|
|||||||
|
|
||||||
@Init
|
@Init
|
||||||
public void init() {
|
public void init() {
|
||||||
this.reconnectExecutor.scheduleWithFixedDelay(this::reconnect, 10, RECONNECT_INTERVAL_SECONDS, TimeUnit.SECONDS);
|
this.reconnectExecutor.scheduleWithFixedDelay(this::reconnect, 10, proxyConfig.getClient().getReconnection().getIntervalSeconds(), TimeUnit.SECONDS);
|
||||||
this.workerGroup = new NioEventLoopGroup(proxyConfig.getClient().getThreadCount());
|
this.workerGroup = new NioEventLoopGroup(proxyConfig.getClient().getThreadCount());
|
||||||
|
|
||||||
realServerBootstrap.group(workerGroup);
|
realServerBootstrap.group(workerGroup);
|
||||||
@@ -119,7 +120,9 @@ public class ProxyClientService {
|
|||||||
if (proxyConfig.getClient().getSslEnable()) {
|
if (proxyConfig.getClient().getSslEnable()) {
|
||||||
ch.pipeline().addLast(createSslHandler());
|
ch.pipeline().addLast(createSslHandler());
|
||||||
}
|
}
|
||||||
// ch.pipeline().addFirst(new LoggingHandler(ProxyClientService.class));
|
if (null != proxyConfig.getClient().getTransferLogEnable() && proxyConfig.getClient().getTransferLogEnable()) {
|
||||||
|
ch.pipeline().addFirst(new LoggingHandler(ProxyClientService.class));
|
||||||
|
}
|
||||||
ch.pipeline().addLast(new ProxyMessageDecoder(proxyConfig.getProtocol().getMaxFrameLength(),
|
ch.pipeline().addLast(new ProxyMessageDecoder(proxyConfig.getProtocol().getMaxFrameLength(),
|
||||||
proxyConfig.getProtocol().getLengthFieldOffset(), proxyConfig.getProtocol().getLengthFieldLength(),
|
proxyConfig.getProtocol().getLengthFieldOffset(), proxyConfig.getProtocol().getLengthFieldLength(),
|
||||||
proxyConfig.getProtocol().getLengthAdjustment(), proxyConfig.getProtocol().getInitialBytesToStrip()));
|
proxyConfig.getProtocol().getLengthAdjustment(), proxyConfig.getProtocol().getInitialBytesToStrip()));
|
||||||
|
|||||||
+7
-1
@@ -1,6 +1,7 @@
|
|||||||
package org.dromara.neutrinoproxy.client.handler;
|
package org.dromara.neutrinoproxy.client.handler;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import org.dromara.neutrinoproxy.client.config.ProxyConfig;
|
||||||
import org.dromara.neutrinoproxy.core.Constants;
|
import org.dromara.neutrinoproxy.core.Constants;
|
||||||
import org.dromara.neutrinoproxy.core.ExceptionEnum;
|
import org.dromara.neutrinoproxy.core.ExceptionEnum;
|
||||||
import org.dromara.neutrinoproxy.core.ProxyMessage;
|
import org.dromara.neutrinoproxy.core.ProxyMessage;
|
||||||
@@ -10,6 +11,7 @@ import io.netty.channel.ChannelHandlerContext;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.noear.solon.Solon;
|
import org.noear.solon.Solon;
|
||||||
import org.noear.solon.annotation.Component;
|
import org.noear.solon.annotation.Component;
|
||||||
|
import org.noear.solon.annotation.Inject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 认证信息处理器
|
* 认证信息处理器
|
||||||
@@ -20,6 +22,8 @@ import org.noear.solon.annotation.Component;
|
|||||||
@Match(type = Constants.ProxyDataTypeName.AUTH)
|
@Match(type = Constants.ProxyDataTypeName.AUTH)
|
||||||
@Component
|
@Component
|
||||||
public class ProxyMessageAuthHandler implements ProxyMessageHandler {
|
public class ProxyMessageAuthHandler implements ProxyMessageHandler {
|
||||||
|
@Inject
|
||||||
|
private ProxyConfig proxyConfig;
|
||||||
@Override
|
@Override
|
||||||
public void handle(ChannelHandlerContext context, ProxyMessage proxyMessage) {
|
public void handle(ChannelHandlerContext context, ProxyMessage proxyMessage) {
|
||||||
String info = proxyMessage.getInfo();
|
String info = proxyMessage.getInfo();
|
||||||
@@ -30,7 +34,9 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler {
|
|||||||
// 客户端认证失败,直接停止服务
|
// 客户端认证失败,直接停止服务
|
||||||
log.info("client auth failed , client stop.");
|
log.info("client auth failed , client stop.");
|
||||||
context.channel().close();
|
context.channel().close();
|
||||||
Solon.stop();
|
if (!proxyConfig.getClient().getReconnection().getUnlimited()) {
|
||||||
|
Solon.stop();
|
||||||
|
}
|
||||||
} else if (ExceptionEnum.CONNECT_FAILED.getCode().equals(code) ||
|
} else if (ExceptionEnum.CONNECT_FAILED.getCode().equals(code) ||
|
||||||
ExceptionEnum.LICENSE_CANNOT_REPEAT_CONNECT.getCode().equals(code)
|
ExceptionEnum.LICENSE_CANNOT_REPEAT_CONNECT.getCode().equals(code)
|
||||||
){
|
){
|
||||||
|
|||||||
@@ -12,13 +12,30 @@ neutrino:
|
|||||||
read-idle-time: 8
|
read-idle-time: 8
|
||||||
write-idle-time: 3
|
write-idle-time: 3
|
||||||
all-idle-time-seconds: 8
|
all-idle-time-seconds: 8
|
||||||
|
logger:
|
||||||
|
# 日志级别
|
||||||
|
level: ${LOG_LEVEL:info}
|
||||||
client:
|
client:
|
||||||
|
# 线程池相关配置,用于技术调优,可忽略
|
||||||
thread-count: 50
|
thread-count: 50
|
||||||
|
# 隧道SSL证书配置
|
||||||
key-store-password: ${STORE_PASS:123456}
|
key-store-password: ${STORE_PASS:123456}
|
||||||
jks-path: ${JKS_PATH:classpath:/test.jks}
|
jks-path: ${JKS_PATH:classpath:/test.jks}
|
||||||
|
# 服务端IP
|
||||||
server-ip: ${SERVER_IP:localhost}
|
server-ip: ${SERVER_IP:localhost}
|
||||||
|
# 服务端端口(对应服务端app.yml中的tunnel.port、tunnel.ssl-port)
|
||||||
server-port: ${SERVER_PORT:9002}
|
server-port: ${SERVER_PORT:9002}
|
||||||
|
# 是否启用SSL(注意:该配置必须和server-port对应上)
|
||||||
ssl-enable: ${SSL_ENABLE:true}
|
ssl-enable: ${SSL_ENABLE:true}
|
||||||
obtain-license-interval: 5
|
# 客户端连接唯一凭证
|
||||||
license-key: ${LICENSE_KEY:}
|
license-key: ${LICENSE_KEY:}
|
||||||
|
# 客户端唯一身份标识(可忽略,若不设置首次启动会自动生成)
|
||||||
client-id: ${CLIENT_ID:}
|
client-id: ${CLIENT_ID:}
|
||||||
|
# 是否开启隧道传输报文日志(日志级别为debug时开启才有效)
|
||||||
|
transfer-log-enable: ${CLIENT_LOG:false}
|
||||||
|
# 重连设置
|
||||||
|
reconnection:
|
||||||
|
# 重连间隔(秒)
|
||||||
|
interval-seconds: 10
|
||||||
|
# 是否开启无限重连(未开启时,客户端license不合法会自动停止应用,开启了则不会,请谨慎开启)
|
||||||
|
unlimited: false
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<property name="LOG_FILE" value="./neutrino-proxy-client.log"/>
|
<property name="LOG_FILE" value="./logs/neutrino-proxy-client.log"/>
|
||||||
<property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{50} - %msg%n"/>
|
<property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{50} - %msg%n"/>
|
||||||
<!-- <property name="ENCODE" value="utf8" />-->
|
<!-- <property name="ENCODE" value="utf8" />-->
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,10 @@
|
|||||||
<groupId>mysql</groupId>
|
<groupId>mysql</groupId>
|
||||||
<artifactId>mysql-connector-java</artifactId>
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mariadb.jdbc</groupId>
|
||||||
|
<artifactId>mariadb-java-client</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.zaxxer</groupId>
|
<groupId>com.zaxxer</groupId>
|
||||||
<artifactId>HikariCP</artifactId>
|
<artifactId>HikariCP</artifactId>
|
||||||
|
|||||||
@@ -1,15 +1,25 @@
|
|||||||
package org.dromara.neutrinoproxy.server;
|
package org.dromara.neutrinoproxy.server;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.Level;
|
||||||
|
import ch.qos.logback.classic.Logger;
|
||||||
|
import ch.qos.logback.classic.LoggerContext;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.dromara.solonplugins.job.annotation.EnableJob;
|
import org.dromara.solonplugins.job.annotation.EnableJob;
|
||||||
import org.noear.solon.Solon;
|
import org.noear.solon.Solon;
|
||||||
|
import org.noear.solon.SolonApp;
|
||||||
import org.noear.solon.annotation.SolonMain;
|
import org.noear.solon.annotation.SolonMain;
|
||||||
import org.noear.solon.web.cors.CrossFilter;
|
import org.noear.solon.web.cors.CrossFilter;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author: aoshiguchen
|
* @author: aoshiguchen
|
||||||
* @date: 2022/6/16
|
* @date: 2022/6/16
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
@EnableJob
|
@EnableJob
|
||||||
@SolonMain
|
@SolonMain
|
||||||
public class ProxyServer {
|
public class ProxyServer {
|
||||||
@@ -18,6 +28,25 @@ public class ProxyServer {
|
|||||||
Solon.start(ProxyServer.class, args, app -> {
|
Solon.start(ProxyServer.class, args, app -> {
|
||||||
// 跨域支持。加-1 优先级更高
|
// 跨域支持。加-1 优先级更高
|
||||||
app.filter(-1, new CrossFilter().allowedOrigins("*"));
|
app.filter(-1, new CrossFilter().allowedOrigins("*"));
|
||||||
|
// 设置日志级别
|
||||||
|
setLogLevel(app);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void setLogLevel(SolonApp app) {
|
||||||
|
String loggerLevel = app.cfg().get("neutrino.proxy.logger.level");
|
||||||
|
if (StringUtils.isBlank(loggerLevel)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Level level = Level.toLevel(loggerLevel);
|
||||||
|
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
|
||||||
|
for (Logger logger : loggerContext.getLoggerList()) {
|
||||||
|
logger.setLevel(level);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("日志级别设置失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-14
@@ -31,7 +31,6 @@ public class DbConfiguration {
|
|||||||
dataSource.setJournalMode(SQLiteConfig.JournalMode.WAL.getValue());
|
dataSource.setJournalMode(SQLiteConfig.JournalMode.WAL.getValue());
|
||||||
return dataSource;
|
return dataSource;
|
||||||
} else if (DbTypeEnum.MYSQL == dbTypeEnum) {
|
} else if (DbTypeEnum.MYSQL == dbTypeEnum) {
|
||||||
HikariDataSource dataSource = new HikariDataSource();
|
|
||||||
String driver = "com.mysql.cj.jdbc.Driver";
|
String driver = "com.mysql.cj.jdbc.Driver";
|
||||||
try {
|
try {
|
||||||
Class.forName(driver);
|
Class.forName(driver);
|
||||||
@@ -39,24 +38,26 @@ public class DbConfiguration {
|
|||||||
// 对类名的判断,异常则说明不存在:
|
// 对类名的判断,异常则说明不存在:
|
||||||
driver = "com.mysql.jdbc.Driver";
|
driver = "com.mysql.jdbc.Driver";
|
||||||
}
|
}
|
||||||
dataSource.setDriverClassName(driver);
|
return newHikariDataSource(dbConfig, driver);
|
||||||
dataSource.setJdbcUrl(dbConfig.getUrl());
|
} else if (DbTypeEnum.MARIADB == dbTypeEnum) {
|
||||||
dataSource.setMinimumIdle(5);
|
return newHikariDataSource(dbConfig, "org.mariadb.jdbc.Driver");
|
||||||
dataSource.setMaximumPoolSize(20);
|
|
||||||
dataSource.setMaxLifetime(60000);
|
|
||||||
// dataSource.setInitialSize(5);
|
|
||||||
// dataSource.setMinIdle(5);
|
|
||||||
// dataSource.setMaxActive(20);
|
|
||||||
// dataSource.setMaxWait(60000);
|
|
||||||
// dataSource.setPoolPreparedStatements(true);
|
|
||||||
dataSource.setUsername(dbConfig.getUsername());
|
|
||||||
dataSource.setPassword(dbConfig.getPassword());
|
|
||||||
return dataSource;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private HikariDataSource newHikariDataSource(DbConfig dbConfig, String driverClass) {
|
||||||
|
HikariDataSource dataSource = new HikariDataSource();
|
||||||
|
dataSource.setDriverClassName(driverClass);
|
||||||
|
dataSource.setJdbcUrl(dbConfig.getUrl());
|
||||||
|
dataSource.setMinimumIdle(5);
|
||||||
|
dataSource.setMaximumPoolSize(20);
|
||||||
|
dataSource.setMaxLifetime(60000);
|
||||||
|
dataSource.setUsername(dbConfig.getUsername());
|
||||||
|
dataSource.setPassword(dbConfig.getPassword());
|
||||||
|
return dataSource;
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public void db1_ext(@Db("db") GlobalConfig globalConfig) {
|
public void db1_ext(@Db("db") GlobalConfig globalConfig) {
|
||||||
MetaObjectHandler metaObjectHandler = new MetaObjectHandlerImpl();
|
MetaObjectHandler metaObjectHandler = new MetaObjectHandlerImpl();
|
||||||
|
|||||||
+2
@@ -49,6 +49,7 @@ public class ProxyConfig {
|
|||||||
private Integer httpsProxyPort;
|
private Integer httpsProxyPort;
|
||||||
private String keyStorePassword;
|
private String keyStorePassword;
|
||||||
private String jksPath;
|
private String jksPath;
|
||||||
|
private Boolean transferLogEnable;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@@ -60,6 +61,7 @@ public class ProxyConfig {
|
|||||||
private String keyStorePassword;
|
private String keyStorePassword;
|
||||||
private String keyManagerPassword;
|
private String keyManagerPassword;
|
||||||
private String jksPath;
|
private String jksPath;
|
||||||
|
private Boolean transferLogEnable;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-1
@@ -4,6 +4,7 @@ import io.netty.bootstrap.ServerBootstrap;
|
|||||||
import io.netty.channel.ChannelInitializer;
|
import io.netty.channel.ChannelInitializer;
|
||||||
import io.netty.channel.socket.SocketChannel;
|
import io.netty.channel.socket.SocketChannel;
|
||||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||||
|
import io.netty.handler.logging.LoggingHandler;
|
||||||
import org.dromara.neutrinoproxy.core.ProxyDataTypeEnum;
|
import org.dromara.neutrinoproxy.core.ProxyDataTypeEnum;
|
||||||
import org.dromara.neutrinoproxy.core.ProxyMessage;
|
import org.dromara.neutrinoproxy.core.ProxyMessage;
|
||||||
import org.dromara.neutrinoproxy.core.ProxyMessageHandler;
|
import org.dromara.neutrinoproxy.core.ProxyMessageHandler;
|
||||||
@@ -12,6 +13,7 @@ import org.dromara.neutrinoproxy.core.dispatcher.Dispatcher;
|
|||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.nio.NioEventLoopGroup;
|
import io.netty.channel.nio.NioEventLoopGroup;
|
||||||
import org.dromara.neutrinoproxy.server.proxy.core.BytesMetricsHandler;
|
import org.dromara.neutrinoproxy.server.proxy.core.BytesMetricsHandler;
|
||||||
|
import org.dromara.neutrinoproxy.server.proxy.core.ProxyTunnelServer;
|
||||||
import org.dromara.neutrinoproxy.server.proxy.core.TcpVisitorChannelHandler;
|
import org.dromara.neutrinoproxy.server.proxy.core.TcpVisitorChannelHandler;
|
||||||
import org.noear.solon.Solon;
|
import org.noear.solon.Solon;
|
||||||
import org.noear.solon.annotation.Bean;
|
import org.noear.solon.annotation.Bean;
|
||||||
@@ -51,13 +53,18 @@ public class ProxyConfiguration implements LifecycleBean {
|
|||||||
|
|
||||||
@Bean("tcpServerBootstrap")
|
@Bean("tcpServerBootstrap")
|
||||||
public ServerBootstrap tcpServerBootstrap(@Inject("serverBossGroup") NioEventLoopGroup serverBossGroup,
|
public ServerBootstrap tcpServerBootstrap(@Inject("serverBossGroup") NioEventLoopGroup serverBossGroup,
|
||||||
@Inject("serverWorkerGroup") NioEventLoopGroup serverWorkerGroup) {
|
@Inject("serverWorkerGroup") NioEventLoopGroup serverWorkerGroup,
|
||||||
|
@Inject ProxyConfig proxyConfig
|
||||||
|
) {
|
||||||
ServerBootstrap bootstrap = new ServerBootstrap();
|
ServerBootstrap bootstrap = new ServerBootstrap();
|
||||||
bootstrap.group(serverBossGroup, serverWorkerGroup)
|
bootstrap.group(serverBossGroup, serverWorkerGroup)
|
||||||
.channel(NioServerSocketChannel.class)
|
.channel(NioServerSocketChannel.class)
|
||||||
.childHandler(new ChannelInitializer<SocketChannel>() {
|
.childHandler(new ChannelInitializer<SocketChannel>() {
|
||||||
@Override
|
@Override
|
||||||
public void initChannel(SocketChannel ch) throws Exception {
|
public void initChannel(SocketChannel ch) throws Exception {
|
||||||
|
if (null != proxyConfig.getServer().getTransferLogEnable() && proxyConfig.getServer().getTransferLogEnable()) {
|
||||||
|
ch.pipeline().addFirst(new LoggingHandler(ProxyTunnelServer.class));
|
||||||
|
}
|
||||||
ch.pipeline().addFirst(new BytesMetricsHandler());
|
ch.pipeline().addFirst(new BytesMetricsHandler());
|
||||||
ch.pipeline().addLast(new TcpVisitorChannelHandler());
|
ch.pipeline().addLast(new TcpVisitorChannelHandler());
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -31,7 +31,7 @@ public class VisitLogInterceptor implements RouterInterceptor {
|
|||||||
} finally {
|
} finally {
|
||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
long elapsedTime = now.getTime() - startTime.getTime();
|
long elapsedTime = now.getTime() - startTime.getTime();
|
||||||
log.info("\n-----------------------------------------------------------------接口请求日志:\n{} url:{} 执行耗时:{}\n请求体参数:{}\n响应结果:{}\n客户端IP:{}\n",
|
log.debug("\n-----------------------------------------------------------------接口请求日志:\n{} url:{} 执行耗时:{}\n请求体参数:{}\n响应结果:{}\n客户端IP:{}\n",
|
||||||
ctx.method(), ctx.path(), getElapsedTimeStr(elapsedTime),
|
ctx.method(), ctx.path(), getElapsedTimeStr(elapsedTime),
|
||||||
JSONObject.toJSONString(ctx.paramMap()),
|
JSONObject.toJSONString(ctx.paramMap()),
|
||||||
JSONObject.toJSONString(JSONObject.toJSONString(ctx.result)),
|
JSONObject.toJSONString(JSONObject.toJSONString(ctx.result)),
|
||||||
|
|||||||
+3
-1
@@ -38,7 +38,9 @@ import java.util.stream.Stream;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum DbTypeEnum {
|
public enum DbTypeEnum {
|
||||||
SQLITE("sqlite"),
|
SQLITE("sqlite"),
|
||||||
MYSQL("mysql");
|
MYSQL("mysql"),
|
||||||
|
MARIADB("mariadb"),
|
||||||
|
;
|
||||||
|
|
||||||
private String type;
|
private String type;
|
||||||
|
|
||||||
|
|||||||
+5
@@ -33,4 +33,9 @@ public enum NetworkProtocolEnum {
|
|||||||
}
|
}
|
||||||
return map.get(desc);
|
return map.get(desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Boolean isHttp(String desc) {
|
||||||
|
NetworkProtocolEnum networkProtocolEnum = of(desc);
|
||||||
|
return NetworkProtocolEnum.HTTP == networkProtocolEnum;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -51,6 +51,7 @@ public class PortMappingController {
|
|||||||
// 目前仅HTTP支持绑定域名
|
// 目前仅HTTP支持绑定域名
|
||||||
req.setSubdomain(null);
|
req.setSubdomain(null);
|
||||||
}
|
}
|
||||||
|
req.setProtocal(networkProtocolEnum.getDesc());
|
||||||
|
|
||||||
return portMappingService.create(req);
|
return portMappingService.create(req);
|
||||||
}
|
}
|
||||||
@@ -74,6 +75,7 @@ public class PortMappingController {
|
|||||||
// 目前仅HTTP支持绑定域名
|
// 目前仅HTTP支持绑定域名
|
||||||
req.setSubdomain(null);
|
req.setSubdomain(null);
|
||||||
}
|
}
|
||||||
|
req.setProtocal(networkProtocolEnum.getDesc());
|
||||||
|
|
||||||
return portMappingService.update(req);
|
return portMappingService.update(req);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -17,6 +17,6 @@ public class DemoJob implements IJobHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(String param) throws Exception {
|
public void execute(String param) throws Exception {
|
||||||
System.out.println("DemoJob execute param:" + param);
|
log.debug("DemoJob execute param: {}", param);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -127,7 +127,7 @@ public class ProxyTunnelChannelHandler extends SimpleChannelInboundHandler<Proxy
|
|||||||
switch (event.state()) {
|
switch (event.state()) {
|
||||||
case READER_IDLE:
|
case READER_IDLE:
|
||||||
// 读超时,断开连接
|
// 读超时,断开连接
|
||||||
log.info("读超时");
|
log.debug("读超时");
|
||||||
ctx.channel().close();
|
ctx.channel().close();
|
||||||
break;
|
break;
|
||||||
case WRITER_IDLE:
|
case WRITER_IDLE:
|
||||||
|
|||||||
+4
-1
@@ -1,5 +1,6 @@
|
|||||||
package org.dromara.neutrinoproxy.server.proxy.core;
|
package org.dromara.neutrinoproxy.server.proxy.core;
|
||||||
|
|
||||||
|
import io.netty.handler.logging.LoggingHandler;
|
||||||
import org.dromara.neutrinoproxy.core.ProxyMessageDecoder;
|
import org.dromara.neutrinoproxy.core.ProxyMessageDecoder;
|
||||||
import org.dromara.neutrinoproxy.core.ProxyMessageEncoder;
|
import org.dromara.neutrinoproxy.core.ProxyMessageEncoder;
|
||||||
import org.dromara.neutrinoproxy.core.util.FileUtil;
|
import org.dromara.neutrinoproxy.core.util.FileUtil;
|
||||||
@@ -111,7 +112,9 @@ public class ProxyTunnelServer implements EventListener<AppLoadEndEvent> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void proxyServerCommonInitHandler(SocketChannel ch) {
|
private void proxyServerCommonInitHandler(SocketChannel ch) {
|
||||||
// ch.pipeline().addFirst(new LoggingHandler(ProxyServerRunner.class));
|
if (null != proxyConfig.getTunnel().getTransferLogEnable() && proxyConfig.getTunnel().getTransferLogEnable()) {
|
||||||
|
ch.pipeline().addFirst(new LoggingHandler(ProxyTunnelServer.class));
|
||||||
|
}
|
||||||
ch.pipeline().addLast(new ProxyMessageDecoder(proxyConfig.getProtocol().getMaxFrameLength(),
|
ch.pipeline().addLast(new ProxyMessageDecoder(proxyConfig.getProtocol().getMaxFrameLength(),
|
||||||
proxyConfig.getProtocol().getLengthFieldOffset(), proxyConfig.getProtocol().getLengthFieldLength(),
|
proxyConfig.getProtocol().getLengthFieldOffset(), proxyConfig.getProtocol().getLengthFieldLength(),
|
||||||
proxyConfig.getProtocol().getLengthAdjustment(), proxyConfig.getProtocol().getInitialBytesToStrip()));
|
proxyConfig.getProtocol().getLengthAdjustment(), proxyConfig.getProtocol().getInitialBytesToStrip()));
|
||||||
|
|||||||
+6
-1
@@ -6,9 +6,11 @@ import io.netty.channel.*;
|
|||||||
import io.netty.channel.nio.NioEventLoopGroup;
|
import io.netty.channel.nio.NioEventLoopGroup;
|
||||||
import io.netty.channel.socket.SocketChannel;
|
import io.netty.channel.socket.SocketChannel;
|
||||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||||
|
import io.netty.handler.logging.LoggingHandler;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.dromara.neutrinoproxy.server.base.proxy.ProxyConfig;
|
import org.dromara.neutrinoproxy.server.base.proxy.ProxyConfig;
|
||||||
import org.dromara.neutrinoproxy.server.proxy.core.BytesMetricsHandler;
|
import org.dromara.neutrinoproxy.server.proxy.core.BytesMetricsHandler;
|
||||||
|
import org.dromara.neutrinoproxy.server.proxy.core.ProxyTunnelServer;
|
||||||
import org.noear.solon.annotation.Component;
|
import org.noear.solon.annotation.Component;
|
||||||
import org.noear.solon.annotation.Inject;
|
import org.noear.solon.annotation.Inject;
|
||||||
import org.noear.solon.core.event.AppLoadEndEvent;
|
import org.noear.solon.core.event.AppLoadEndEvent;
|
||||||
@@ -40,12 +42,15 @@ public class HttpProxy implements EventListener<AppLoadEndEvent> {
|
|||||||
.channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {
|
.channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {
|
||||||
@Override
|
@Override
|
||||||
public void initChannel(SocketChannel ch) throws Exception {
|
public void initChannel(SocketChannel ch) throws Exception {
|
||||||
|
if (null != proxyConfig.getServer().getTransferLogEnable() && proxyConfig.getServer().getTransferLogEnable()) {
|
||||||
|
ch.pipeline().addFirst(new LoggingHandler(ProxyTunnelServer.class));
|
||||||
|
}
|
||||||
ch.pipeline().addFirst(new BytesMetricsHandler());
|
ch.pipeline().addFirst(new BytesMetricsHandler());
|
||||||
ch.pipeline().addLast(new HttpVisitorChannelHandler(proxyConfig.getServer().getDomainName()));
|
ch.pipeline().addLast(new HttpVisitorChannelHandler(proxyConfig.getServer().getDomainName()));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
bootstrap.bind("0.0.0.0", proxyConfig.getServer().getHttpProxyPort()).sync();
|
bootstrap.bind("0.0.0.0", proxyConfig.getServer().getHttpProxyPort()).sync();
|
||||||
log.info("Http代理服务启动成功!");
|
log.info("Http代理服务启动成功!port:{}", proxyConfig.getServer().getHttpProxyPort());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("http proxy start err!", e);
|
log.error("http proxy start err!", e);
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -68,11 +68,11 @@ public class HttpVisitorChannelHandler extends SimpleChannelInboundHandler<ByteB
|
|||||||
ctx.channel().config().setOption(ChannelOption.AUTO_READ, false);
|
ctx.channel().config().setOption(ChannelOption.AUTO_READ, false);
|
||||||
|
|
||||||
String host = getHost(bytes);
|
String host = getHost(bytes);
|
||||||
|
log.debug("HttpProxy host: {}", host);
|
||||||
if (StringUtils.isBlank(host)) {
|
if (StringUtils.isBlank(host)) {
|
||||||
ctx.channel().close();
|
ctx.channel().close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log.debug("HttpProxy host: {}", host);
|
|
||||||
if (!host.endsWith(domainName)) {
|
if (!host.endsWith(domainName)) {
|
||||||
ctx.channel().close();
|
ctx.channel().close();
|
||||||
return;
|
return;
|
||||||
@@ -163,7 +163,8 @@ public class HttpVisitorChannelHandler extends SimpleChannelInboundHandler<ByteB
|
|||||||
}
|
}
|
||||||
// 域名
|
// 域名
|
||||||
String domain = line.substring(6);
|
String domain = line.substring(6);
|
||||||
return domain;
|
// 去掉域名后面的端口号
|
||||||
|
return domain.replaceAll(":.*", "");
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-1
@@ -6,12 +6,14 @@ import io.netty.channel.*;
|
|||||||
import io.netty.channel.nio.NioEventLoopGroup;
|
import io.netty.channel.nio.NioEventLoopGroup;
|
||||||
import io.netty.channel.socket.SocketChannel;
|
import io.netty.channel.socket.SocketChannel;
|
||||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||||
|
import io.netty.handler.logging.LoggingHandler;
|
||||||
import io.netty.handler.ssl.SslHandler;
|
import io.netty.handler.ssl.SslHandler;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.dromara.neutrinoproxy.core.util.FileUtil;
|
import org.dromara.neutrinoproxy.core.util.FileUtil;
|
||||||
import org.dromara.neutrinoproxy.server.base.proxy.ProxyConfig;
|
import org.dromara.neutrinoproxy.server.base.proxy.ProxyConfig;
|
||||||
import org.dromara.neutrinoproxy.server.proxy.core.BytesMetricsHandler;
|
import org.dromara.neutrinoproxy.server.proxy.core.BytesMetricsHandler;
|
||||||
|
import org.dromara.neutrinoproxy.server.proxy.core.ProxyTunnelServer;
|
||||||
import org.noear.solon.annotation.Component;
|
import org.noear.solon.annotation.Component;
|
||||||
import org.noear.solon.annotation.Inject;
|
import org.noear.solon.annotation.Inject;
|
||||||
import org.noear.solon.core.event.AppLoadEndEvent;
|
import org.noear.solon.core.event.AppLoadEndEvent;
|
||||||
@@ -48,13 +50,16 @@ public class HttpsProxy implements EventListener<AppLoadEndEvent> {
|
|||||||
.channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {
|
.channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {
|
||||||
@Override
|
@Override
|
||||||
public void initChannel(SocketChannel ch) throws Exception {
|
public void initChannel(SocketChannel ch) throws Exception {
|
||||||
|
if (null != proxyConfig.getServer().getTransferLogEnable() && proxyConfig.getServer().getTransferLogEnable()) {
|
||||||
|
ch.pipeline().addFirst(new LoggingHandler(ProxyTunnelServer.class));
|
||||||
|
}
|
||||||
ch.pipeline().addLast(createSslHandler());
|
ch.pipeline().addLast(createSslHandler());
|
||||||
ch.pipeline().addFirst(new BytesMetricsHandler());
|
ch.pipeline().addFirst(new BytesMetricsHandler());
|
||||||
ch.pipeline().addLast(new HttpVisitorChannelHandler(proxyConfig.getServer().getDomainName()));
|
ch.pipeline().addLast(new HttpVisitorChannelHandler(proxyConfig.getServer().getDomainName()));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
bootstrap.bind("0.0.0.0", proxyConfig.getServer().getHttpsProxyPort()).sync();
|
bootstrap.bind("0.0.0.0", proxyConfig.getServer().getHttpsProxyPort()).sync();
|
||||||
log.info("Https代理服务启动成功!");
|
log.info("Https代理服务启动成功!port:{}", proxyConfig.getServer().getHttpsProxyPort());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("https proxy start err!", e);
|
log.error("https proxy start err!", e);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -61,7 +61,7 @@ public class JobLogService implements IJobCallback {
|
|||||||
String msg = "";
|
String msg = "";
|
||||||
if (null == throwable) {
|
if (null == throwable) {
|
||||||
msg = "执行成功";
|
msg = "执行成功";
|
||||||
log.info("job[id={},name={}]执行完毕", jobInfo.getId(), jobInfo.getName());
|
log.debug("job[id={},name={}]执行完毕", jobInfo.getId(), jobInfo.getName());
|
||||||
} else {
|
} else {
|
||||||
log.error("job[id={},name={}]执行异常", jobInfo.getId(), jobInfo.getName(), throwable);
|
log.error("job[id={},name={}]执行异常", jobInfo.getId(), jobInfo.getName(), throwable);
|
||||||
msg = "执行异常:\r\n" + ExceptionUtils.getStackTrace(throwable);
|
msg = "执行异常:\r\n" + ExceptionUtils.getStackTrace(throwable);
|
||||||
|
|||||||
+34
-50
@@ -8,6 +8,8 @@ import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
|||||||
import com.github.pagehelper.Page;
|
import com.github.pagehelper.Page;
|
||||||
import com.github.pagehelper.PageHelper;
|
import com.github.pagehelper.PageHelper;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
import ma.glasnost.orika.MapperFacade;
|
||||||
|
import org.apache.ibatis.solon.annotation.Db;
|
||||||
import org.dromara.neutrinoproxy.server.base.db.DBInitialize;
|
import org.dromara.neutrinoproxy.server.base.db.DBInitialize;
|
||||||
import org.dromara.neutrinoproxy.server.base.page.PageInfo;
|
import org.dromara.neutrinoproxy.server.base.page.PageInfo;
|
||||||
import org.dromara.neutrinoproxy.server.base.page.PageQuery;
|
import org.dromara.neutrinoproxy.server.base.page.PageQuery;
|
||||||
@@ -31,14 +33,10 @@ import org.dromara.neutrinoproxy.server.dal.entity.PortMappingDO;
|
|||||||
import org.dromara.neutrinoproxy.server.dal.entity.PortPoolDO;
|
import org.dromara.neutrinoproxy.server.dal.entity.PortPoolDO;
|
||||||
import org.dromara.neutrinoproxy.server.dal.entity.UserDO;
|
import org.dromara.neutrinoproxy.server.dal.entity.UserDO;
|
||||||
import org.dromara.neutrinoproxy.server.util.ParamCheckUtil;
|
import org.dromara.neutrinoproxy.server.util.ParamCheckUtil;
|
||||||
import ma.glasnost.orika.MapperFacade;
|
|
||||||
import org.apache.ibatis.solon.annotation.Db;
|
|
||||||
import org.dromara.neutrinoproxy.server.controller.res.proxy.*;
|
|
||||||
import org.dromara.neutrinoproxy.server.util.ProxyUtil;
|
import org.dromara.neutrinoproxy.server.util.ProxyUtil;
|
||||||
import org.noear.solon.annotation.Component;
|
import org.noear.solon.annotation.Component;
|
||||||
import org.noear.solon.annotation.Init;
|
import org.noear.solon.annotation.Init;
|
||||||
import org.noear.solon.annotation.Inject;
|
import org.noear.solon.annotation.Inject;
|
||||||
import org.noear.solon.core.Lifecycle;
|
|
||||||
import org.noear.solon.core.bean.LifecycleBean;
|
import org.noear.solon.core.bean.LifecycleBean;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -51,25 +49,25 @@ import java.util.stream.Collectors;
|
|||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
public class PortMappingService implements LifecycleBean {
|
public class PortMappingService implements LifecycleBean {
|
||||||
@Inject
|
@Inject
|
||||||
private MapperFacade mapperFacade;
|
private MapperFacade mapperFacade;
|
||||||
@Db
|
@Db
|
||||||
private PortMappingMapper portMappingMapper;
|
private PortMappingMapper portMappingMapper;
|
||||||
@Db
|
@Db
|
||||||
private LicenseMapper licenseMapper;
|
private LicenseMapper licenseMapper;
|
||||||
@Db
|
@Db
|
||||||
private UserMapper userMapper;
|
private UserMapper userMapper;
|
||||||
@Db
|
@Db
|
||||||
private PortPoolMapper portPoolMapper;
|
private PortPoolMapper portPoolMapper;
|
||||||
@Inject
|
@Inject
|
||||||
private VisitorChannelService visitorChannelService;
|
private VisitorChannelService visitorChannelService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private PortPoolService portPoolService;
|
private PortPoolService portPoolService;
|
||||||
@Inject
|
@Inject
|
||||||
private ProxyConfig proxyConfig;
|
private ProxyConfig proxyConfig;
|
||||||
@Inject
|
@Inject
|
||||||
private DBInitialize dbInitialize;
|
private DBInitialize dbInitialize;
|
||||||
|
|
||||||
public PageInfo<PortMappingListRes> page(PageQuery pageQuery, PortMappingListReq req) {
|
public PageInfo<PortMappingListRes> page(PageQuery pageQuery, PortMappingListReq req) {
|
||||||
Page<PortMappingListRes> result = PageHelper.startPage(pageQuery.getCurrent(), pageQuery.getSize());
|
Page<PortMappingListRes> result = PageHelper.startPage(pageQuery.getCurrent(), pageQuery.getSize());
|
||||||
@@ -77,6 +75,13 @@ public class PortMappingService implements LifecycleBean {
|
|||||||
//描述字段为模糊查询,在应用层处理,否则sqlite不支持
|
//描述字段为模糊查询,在应用层处理,否则sqlite不支持
|
||||||
req.setDescription("%" + req.getDescription() + "%");
|
req.setDescription("%" + req.getDescription() + "%");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 协议名称转换
|
||||||
|
if (StringUtils.isNotBlank(req.getProtocal())) {
|
||||||
|
NetworkProtocolEnum networkProtocolEnum = NetworkProtocolEnum.of(req.getProtocal());
|
||||||
|
req.setProtocal(networkProtocolEnum.getDesc());
|
||||||
|
}
|
||||||
|
|
||||||
List<PortMappingDO> list = portMappingMapper.selectPortMappingByCondition(req);
|
List<PortMappingDO> list = portMappingMapper.selectPortMappingByCondition(req);
|
||||||
List<PortMappingListRes> respList = mapperFacade.mapAsList(list, PortMappingListRes.class);
|
List<PortMappingListRes> respList = mapperFacade.mapAsList(list, PortMappingListRes.class);
|
||||||
if (CollectionUtils.isEmpty(list)) {
|
if (CollectionUtils.isEmpty(list)) {
|
||||||
@@ -113,10 +118,7 @@ public class PortMappingService implements LifecycleBean {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
//sorted [userId asc] [licenseId asc] [createTime asc]
|
//sorted [userId asc] [licenseId asc] [createTime asc]
|
||||||
respList = respList.stream().sorted(Comparator.comparing(PortMappingListRes::getUserId)
|
respList = respList.stream().sorted(Comparator.comparing(PortMappingListRes::getUserId).thenComparing(PortMappingListRes::getLicenseId).thenComparing(PortMappingListRes::getCreateTime)).collect(Collectors.toList());
|
||||||
.thenComparing(PortMappingListRes::getLicenseId)
|
|
||||||
.thenComparing(PortMappingListRes::getCreateTime))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
|
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,9 +151,7 @@ public class PortMappingService implements LifecycleBean {
|
|||||||
// 更新VisitorChannel
|
// 更新VisitorChannel
|
||||||
visitorChannelService.addVisitorChannelByPortMapping(portMappingDO);
|
visitorChannelService.addVisitorChannelByPortMapping(portMappingDO);
|
||||||
// 更新域名映射
|
// 更新域名映射
|
||||||
if (NetworkProtocolEnum.HTTP.getDesc().equals(portMappingDO.getProtocal()) &&
|
if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) && StrUtil.isNotBlank(proxyConfig.getServer().getDomainName()) && StrUtil.isNotBlank(portMappingDO.getSubdomain())) {
|
||||||
StrUtil.isNotBlank(proxyConfig.getServer().getDomainName()) &&
|
|
||||||
StrUtil.isNotBlank(portMappingDO.getSubdomain())) {
|
|
||||||
ProxyUtil.setSubdomainToServerPort(portMappingDO.getSubdomain(), portMappingDO.getServerPort());
|
ProxyUtil.setSubdomainToServerPort(portMappingDO.getSubdomain(), portMappingDO.getServerPort());
|
||||||
}
|
}
|
||||||
return new PortMappingCreateRes();
|
return new PortMappingCreateRes();
|
||||||
@@ -188,14 +188,11 @@ public class PortMappingService implements LifecycleBean {
|
|||||||
// 更新VisitorChannel
|
// 更新VisitorChannel
|
||||||
visitorChannelService.updateVisitorChannelByPortMapping(oldPortMappingDO, portMappingDO);
|
visitorChannelService.updateVisitorChannelByPortMapping(oldPortMappingDO, portMappingDO);
|
||||||
// 删除老的域名映射
|
// 删除老的域名映射
|
||||||
if (NetworkProtocolEnum.HTTP.getDesc().equals(oldPortMappingDO.getProtocal()) &&
|
if (NetworkProtocolEnum.isHttp(oldPortMappingDO.getProtocal()) && StrUtil.isNotBlank(oldPortMappingDO.getSubdomain())) {
|
||||||
StrUtil.isNotBlank(oldPortMappingDO.getSubdomain())) {
|
|
||||||
ProxyUtil.removeSubdomainToServerPort(oldPortMappingDO.getSubdomain());
|
ProxyUtil.removeSubdomainToServerPort(oldPortMappingDO.getSubdomain());
|
||||||
}
|
}
|
||||||
// 更新域名映射
|
// 更新域名映射
|
||||||
if (NetworkProtocolEnum.HTTP.getDesc().equals(portMappingDO.getProtocal()) &&
|
if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) && StrUtil.isNotBlank(proxyConfig.getServer().getDomainName()) && StrUtil.isNotBlank(portMappingDO.getSubdomain())) {
|
||||||
StrUtil.isNotBlank(proxyConfig.getServer().getDomainName()) &&
|
|
||||||
StrUtil.isNotBlank(portMappingDO.getSubdomain())) {
|
|
||||||
ProxyUtil.setSubdomainToServerPort(portMappingDO.getSubdomain(), portMappingDO.getServerPort());
|
ProxyUtil.setSubdomainToServerPort(portMappingDO.getSubdomain(), portMappingDO.getServerPort());
|
||||||
}
|
}
|
||||||
return new PortMappingUpdateRes();
|
return new PortMappingUpdateRes();
|
||||||
@@ -206,16 +203,7 @@ public class PortMappingService implements LifecycleBean {
|
|||||||
if (null == portMappingDO) {
|
if (null == portMappingDO) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
PortMappingDetailRes res = new PortMappingDetailRes()
|
PortMappingDetailRes res = new PortMappingDetailRes().setId(portMappingDO.getId()).setLicenseId(portMappingDO.getLicenseId()).setServerPort(portMappingDO.getServerPort()).setClientIp(portMappingDO.getClientIp()).setClientPort(portMappingDO.getClientPort()).setIsOnline(portMappingDO.getIsOnline()).setEnable(portMappingDO.getEnable()).setCreateTime(portMappingDO.getCreateTime()).setUpdateTime(portMappingDO.getUpdateTime());
|
||||||
.setId(portMappingDO.getId())
|
|
||||||
.setLicenseId(portMappingDO.getLicenseId())
|
|
||||||
.setServerPort(portMappingDO.getServerPort())
|
|
||||||
.setClientIp(portMappingDO.getClientIp())
|
|
||||||
.setClientPort(portMappingDO.getClientPort())
|
|
||||||
.setIsOnline(portMappingDO.getIsOnline())
|
|
||||||
.setEnable(portMappingDO.getEnable())
|
|
||||||
.setCreateTime(portMappingDO.getCreateTime())
|
|
||||||
.setUpdateTime(portMappingDO.getUpdateTime());
|
|
||||||
|
|
||||||
LicenseDO license = licenseMapper.findById(portMappingDO.getLicenseId());
|
LicenseDO license = licenseMapper.findById(portMappingDO.getLicenseId());
|
||||||
if (null != license) {
|
if (null != license) {
|
||||||
@@ -268,8 +256,7 @@ public class PortMappingService implements LifecycleBean {
|
|||||||
// 更新VisitorChannel
|
// 更新VisitorChannel
|
||||||
visitorChannelService.removeVisitorChannelByPortMapping(portMappingDO);
|
visitorChannelService.removeVisitorChannelByPortMapping(portMappingDO);
|
||||||
// 更新域名映射
|
// 更新域名映射
|
||||||
if (NetworkProtocolEnum.HTTP.getDesc().equals(portMappingDO.getProtocal()) &&
|
if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) && StrUtil.isNotBlank(portMappingDO.getSubdomain())) {
|
||||||
StrUtil.isNotBlank(portMappingDO.getSubdomain())) {
|
|
||||||
ProxyUtil.removeSubdomainToServerPort(portMappingDO.getSubdomain());
|
ProxyUtil.removeSubdomainToServerPort(portMappingDO.getSubdomain());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -295,10 +282,7 @@ public class PortMappingService implements LifecycleBean {
|
|||||||
if (StrUtil.isBlank(proxyConfig.getServer().getDomainName())) {
|
if (StrUtil.isBlank(proxyConfig.getServer().getDomainName())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
List<PortMappingDO> portMappingDOList = portMappingMapper.selectList(new LambdaQueryWrapper<PortMappingDO>()
|
List<PortMappingDO> portMappingDOList = portMappingMapper.selectList(new LambdaQueryWrapper<PortMappingDO>().eq(PortMappingDO::getProtocal, NetworkProtocolEnum.HTTP.getDesc()).isNotNull(PortMappingDO::getSubdomain));
|
||||||
.eq(PortMappingDO::getProtocal, NetworkProtocolEnum.HTTP.getDesc())
|
|
||||||
.isNotNull(PortMappingDO::getSubdomain)
|
|
||||||
);
|
|
||||||
if (CollectionUtil.isEmpty(portMappingDOList)) {
|
if (CollectionUtil.isEmpty(portMappingDOList)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
server:
|
server:
|
||||||
|
# 服务端web端口,用于支持HTTP接口,管理后台页面访问
|
||||||
port: ${WEB_PORT:8888}
|
port: ${WEB_PORT:8888}
|
||||||
|
|
||||||
neutrino:
|
neutrino:
|
||||||
@@ -12,28 +13,48 @@ neutrino:
|
|||||||
read-idle-time: 30
|
read-idle-time: 30
|
||||||
write-idle-time: 5
|
write-idle-time: 5
|
||||||
all-idle-time-seconds: 0
|
all-idle-time-seconds: 0
|
||||||
|
logger:
|
||||||
|
# 日志级别
|
||||||
|
level: ${LOG_LEVEL:info}
|
||||||
|
# 隧道相关配置-用于维持服务端与客户端的通信
|
||||||
tunnel:
|
tunnel:
|
||||||
|
# 线程池相关配置,用于技术调优,可忽略
|
||||||
boss-thread-count: 2
|
boss-thread-count: 2
|
||||||
work-thread-count: 10
|
work-thread-count: 10
|
||||||
|
# 隧道非SSL端口
|
||||||
port: ${OPEN_PORT:9000}
|
port: ${OPEN_PORT:9000}
|
||||||
|
# 隧道SSL端口
|
||||||
ssl-port: ${SSL_PORT:9002}
|
ssl-port: ${SSL_PORT:9002}
|
||||||
|
# 隧道SSL证书配置
|
||||||
key-store-password: ${STORE_PASS:123456}
|
key-store-password: ${STORE_PASS:123456}
|
||||||
key-manager-password: ${MGR_PASS:123456}
|
key-manager-password: ${MGR_PASS:123456}
|
||||||
jks-path: ${JKS_PATH:classpath:/test.jks}
|
jks-path: ${JKS_PATH:classpath:/test.jks}
|
||||||
|
# 是否开启隧道传输报文日志(日志级别为debug时开启才有效)
|
||||||
|
transfer-log-enable: ${TUNNEL_LOG:false}
|
||||||
server:
|
server:
|
||||||
|
# 线程池相关配置,用于技术调优,可忽略
|
||||||
boss-thread-count: 5
|
boss-thread-count: 5
|
||||||
work-thread-count: 20
|
work-thread-count: 20
|
||||||
|
# http代理端口,默认80
|
||||||
http-proxy-port: ${HTTP_PROXY_PORT:80}
|
http-proxy-port: ${HTTP_PROXY_PORT:80}
|
||||||
|
# https代理端口,默认443 (需要配置域名、证书)
|
||||||
https-proxy-port: ${HTTPS_PROXY_PORT:443}
|
https-proxy-port: ${HTTPS_PROXY_PORT:443}
|
||||||
# 如果不配置,则不支持域名映射
|
# 如果不配置,则不支持域名映射
|
||||||
domain-name: ${DOMAIN_NAME:}
|
domain-name: ${DOMAIN_NAME:}
|
||||||
|
# https证书配置
|
||||||
key-store-password: ${HTTPS_STORE_PASS:}
|
key-store-password: ${HTTPS_STORE_PASS:}
|
||||||
jks-path: ${HTTPS_JKS_PATH:}
|
jks-path: ${HTTPS_JKS_PATH:}
|
||||||
|
# 是否开启代理服务报文日志(日志级别为debug时开启才有效)
|
||||||
|
transfer-log-enable: ${SERVER_LOG:false}
|
||||||
data:
|
data:
|
||||||
db:
|
db:
|
||||||
|
# 数据库类型,目前支持sqlite、mysql、mariadb
|
||||||
type: ${DB_TYPE:sqlite}
|
type: ${DB_TYPE:sqlite}
|
||||||
|
# 数据库连接URL
|
||||||
url: ${DB_URL:jdbc:sqlite:data.db}
|
url: ${DB_URL:jdbc:sqlite:data.db}
|
||||||
|
# 数据库用户名
|
||||||
username: ${DB_USER:}
|
username: ${DB_USER:}
|
||||||
|
# 数据库密码
|
||||||
password: ${DB_PASSWORD:}
|
password: ${DB_PASSWORD:}
|
||||||
|
|
||||||
#添加MIME印射(如果有需要?)
|
#添加MIME印射(如果有需要?)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<property name="LOG_FILE" value="./neutrino-proxy-server.log"/>
|
<property name="LOG_FILE" value="./logs/neutrino-proxy-server.log"/>
|
||||||
<property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{50} - %msg%n"/>
|
<property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{50} - %msg%n"/>
|
||||||
<!-- <property name="ENCODE" value="utf8" />-->
|
<!-- <property name="ENCODE" value="utf8" />-->
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,207 @@
|
|||||||
|
#############################系统管理相关表#############################
|
||||||
|
#用户表
|
||||||
|
CREATE TABLE IF NOT EXISTS `user` (
|
||||||
|
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`name` varchar(50) NOT NULL COMMENT '用户名',
|
||||||
|
`login_name` varchar(50) NOT NULL COMMENT '登录名',
|
||||||
|
`login_password` varchar(255) NOT NULL COMMENT '登录密码',
|
||||||
|
`enable` int NOT NULL COMMENT '是否启用(1、启用 2、禁用)',
|
||||||
|
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
|
||||||
|
`update_time` datetime(3) NOT NULL COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `I_user_login_name` (`login_name`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
#用户token表
|
||||||
|
CREATE TABLE IF NOT EXISTS `user_token` (
|
||||||
|
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`token` varchar(50) NOT NULL COMMENT 'token',
|
||||||
|
`user_id` int NOT NULL COMMENT '用户ID',
|
||||||
|
`expiration_time` datetime(3) NOT NULL COMMENT '过期时间',
|
||||||
|
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
|
||||||
|
`update_time` datetime(3) NOT NULL COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `I_user_token_user_id` (`user_id`),
|
||||||
|
KEY `I_user_token_token` (`token`),
|
||||||
|
KEY `I_user_token_expiration_time` (`expiration_time`) USING BTREE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
#端口池
|
||||||
|
CREATE TABLE IF NOT EXISTS `port_pool` (
|
||||||
|
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`group_id` int NOT NULL DEFAULT 1 COMMENT '分组ID',
|
||||||
|
`port` int NOT NULL COMMENT '端口',
|
||||||
|
`enable` int NOT NULL COMMENT '是否启用(1、启用 2、禁用)',
|
||||||
|
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
|
||||||
|
`update_time` datetime(3) NOT NULL COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `I_port_pool_port` (`port`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
#端口分组
|
||||||
|
CREATE TABLE IF NOT EXISTS `port_group` (
|
||||||
|
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`name` varchar(255) NOT NULL COMMENT '分组名称',
|
||||||
|
`possessor_type` int NOT NULL DEFAULT '0' COMMENT '所有者类型 (0、全局共享 1、用户所有 2License所有) ',
|
||||||
|
`possessor_id` int NOT NULL DEFAULT '-1' COMMENT '所有者id(当type为0时 固定为-1、当type为1时为用户id 、当type为2时为licenseid)',
|
||||||
|
`enable` int NOT NULL COMMENT '是否启用(1、启用 2、禁用)',
|
||||||
|
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
|
||||||
|
`update_time` datetime(3) NOT NULL COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
#############################代理配置相关表#############################
|
||||||
|
#license表
|
||||||
|
CREATE TABLE IF NOT EXISTS `license` (
|
||||||
|
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`name` varchar(50) NOT NULL COMMENT 'license名称',
|
||||||
|
`key` varchar(100) NOT NULL COMMENT 'license key',
|
||||||
|
`user_id` int NOT NULL COMMENT '用户ID',
|
||||||
|
`is_online` int NOT NULL COMMENT '是否在线(1、在线 2、离线)',
|
||||||
|
`enable` int NOT NULL COMMENT '是否启用(1、启用 2、禁用)',
|
||||||
|
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
|
||||||
|
`update_time` datetime(3) NOT NULL COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
KEY `I_license_key` (`key`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
#端口映射表
|
||||||
|
CREATE TABLE IF NOT EXISTS `port_mapping` (
|
||||||
|
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`license_id` int NOT NULL COMMENT 'licenseID',
|
||||||
|
`protocal` varchar(10) NOT NULL DEFAULT 'TCP' COMMENT '协议',
|
||||||
|
`subdomain` varchar(50) DEFAULT NULL COMMENT '子域名(仅HTTP时有效)',
|
||||||
|
`server_port` int NOT NULL COMMENT '服务端端口',
|
||||||
|
`client_ip` varchar(20) NOT NULL COMMENT '客户端IP',
|
||||||
|
`client_port` int NOT NULL COMMENT '客户端端口',
|
||||||
|
`is_online` int NOT NULL COMMENT '是否在线(1、在线 2、离线)',
|
||||||
|
`description` varchar(100) DEFAULT NULL COMMENT '描述',
|
||||||
|
`enable` int NOT NULL COMMENT '是否启用(1、启用 2、禁用)',
|
||||||
|
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
|
||||||
|
`update_time` datetime(3) NOT NULL COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `I_port_mapping_server_port` (`server_port`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
#############################日志管理相关表#############################
|
||||||
|
#用户登录记录表
|
||||||
|
CREATE TABLE IF NOT EXISTS `user_login_record` (
|
||||||
|
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`user_id` int NOT NULL COMMENT '用户ID',
|
||||||
|
`ip` varchar(50) NOT NULL COMMENT 'IP',
|
||||||
|
`token` varchar(100) NOT NULL COMMENT 'token',
|
||||||
|
`type` int NOT NULL COMMENT '类型(1、登录 2、登出)',
|
||||||
|
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
#客户端连接记录表
|
||||||
|
CREATE TABLE IF NOT EXISTS `client_connect_record` (
|
||||||
|
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`ip` varchar(50) NOT NULL COMMENT 'IP',
|
||||||
|
`license_id` int NOT NULL COMMENT 'licenseId',
|
||||||
|
`type` int NOT NULL COMMENT '类型(1、连接 2、断开连接)',
|
||||||
|
`msg` varchar(512) DEFAULT NULL COMMENT '消息',
|
||||||
|
`code` int NOT NULL COMMENT '结果 (1、成功 2、失败)',
|
||||||
|
`err` text DEFAULT NULL COMMENT '异常信息',
|
||||||
|
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
#############################调度管理相关表#############################
|
||||||
|
#触发器信息表
|
||||||
|
CREATE TABLE IF NOT EXISTS `job_info` (
|
||||||
|
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`desc` varchar(255) NOT NULL COMMENT '描述',
|
||||||
|
`handler` varchar(255) NOT NULL COMMENT '处理器',
|
||||||
|
`cron` varchar(128) NOT NULL COMMENT 'cron',
|
||||||
|
`param` varchar(512) DEFAULT NULL COMMENT '参数',
|
||||||
|
`alarm_email` varchar(255) DEFAULT NULL COMMENT '报警邮箱',
|
||||||
|
`alarm_ding` varchar(255) DEFAULT NULL COMMENT '报警钉钉配置',
|
||||||
|
`enable` int NOT NULL COMMENT '是否启用(1、启用 2、禁用)',
|
||||||
|
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
|
||||||
|
`update_time` datetime(3) NOT NULL COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `I_job_info_handler` (`handler`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
#触发器日志表
|
||||||
|
CREATE TABLE IF NOT EXISTS `job_log` (
|
||||||
|
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`job_id` int NOT NULL COMMENT 'JobId',
|
||||||
|
`handler` varchar(255) NOT NULL COMMENT '处理器',
|
||||||
|
`param` varchar(512) DEFAULT NULL COMMENT '参数',
|
||||||
|
`code` int NOT NULL COMMENT '结果(1、成功 2、失败)',
|
||||||
|
`msg` text COMMENT '消息',
|
||||||
|
`alarm_status` int NOT NULL COMMENT '报警状态(1、未报警 2、已报警)',
|
||||||
|
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
KEY `I_job_log_create_time` (`create_time`) USING BTREE,
|
||||||
|
KEY `I_job_log_code` (`code`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
#############################报表管理相关表#############################
|
||||||
|
#流量统计报表-分钟(保留24小时)
|
||||||
|
CREATE TABLE IF NOT EXISTS `flow_report_minute` (
|
||||||
|
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`user_id` int NOT NULL COMMENT '用户ID',
|
||||||
|
`license_id` int NOT NULL COMMENT 'licenseId',
|
||||||
|
`write_bytes` int NOT NULL COMMENT '写入流量',
|
||||||
|
`read_bytes` int NOT NULL COMMENT '读取流量',
|
||||||
|
`date` datetime(3) NOT NULL COMMENT '时间',
|
||||||
|
`date_str` varchar(20) NOT NULL COMMENT '时间 yyyy-MM-dd HH:mm',
|
||||||
|
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `I_flow_report_minute_create_time` (`create_time`) USING BTREE,
|
||||||
|
KEY `I_flow_report_minute_date` (`date`) USING BTREE,
|
||||||
|
KEY `I_flow_report_minute_user_id` (`user_id`),
|
||||||
|
KEY `I_flow_report_minute_license_id` (`license_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
#流量统计报表-小时(保留60天)
|
||||||
|
CREATE TABLE IF NOT EXISTS `flow_report_hour` (
|
||||||
|
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`user_id` int NOT NULL COMMENT '用户ID',
|
||||||
|
`license_id` int NOT NULL COMMENT 'licenseId',
|
||||||
|
`write_bytes` int NOT NULL COMMENT '写入流量',
|
||||||
|
`read_bytes` int NOT NULL COMMENT '读取流量',
|
||||||
|
`date` datetime(3) NOT NULL COMMENT '时间',
|
||||||
|
`date_str` varchar(20) NOT NULL COMMENT '时间 yyyy-MM-dd HH',
|
||||||
|
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `I_flow_report_hour_create_time` (`create_time`) USING BTREE,
|
||||||
|
KEY `I_flow_report_hour_date` (`date`) USING BTREE,
|
||||||
|
KEY `I_flow_report_hour_user_id` (`user_id`),
|
||||||
|
KEY `I_flow_report_hour_license_id` (`license_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
#流量统计报表-天(保留1年)
|
||||||
|
CREATE TABLE IF NOT EXISTS `flow_report_day` (
|
||||||
|
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`user_id` int NOT NULL COMMENT '用户ID',
|
||||||
|
`license_id` int NOT NULL COMMENT 'licenseId',
|
||||||
|
`write_bytes` int NOT NULL COMMENT '写入流量',
|
||||||
|
`read_bytes` int NOT NULL COMMENT '读取流量',
|
||||||
|
`date` datetime(3) NOT NULL COMMENT '时间',
|
||||||
|
`date_str` varchar(20) NOT NULL COMMENT '时间 yyyy-MM-dd',
|
||||||
|
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `I_flow_report_day_create_time` (`create_time`) USING BTREE,
|
||||||
|
KEY `I_flow_report_day_date` (`date`) USING BTREE,
|
||||||
|
KEY `I_flow_report_day_user_id` (`user_id`),
|
||||||
|
KEY `I_flow_report_day_license_id` (`license_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
#流量统计报表-月(全量保留)
|
||||||
|
CREATE TABLE IF NOT EXISTS `flow_report_month` (
|
||||||
|
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`user_id` int NOT NULL COMMENT '用户ID',
|
||||||
|
`license_id` int NOT NULL COMMENT 'licenseId',
|
||||||
|
`write_bytes` int NOT NULL COMMENT '写入流量',
|
||||||
|
`read_bytes` int NOT NULL COMMENT '读取流量',
|
||||||
|
`date` datetime(3) NOT NULL COMMENT '时间',
|
||||||
|
`date_str` varchar(20) NOT NULL COMMENT '时间 yyyy-MM',
|
||||||
|
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `I_flow_report_month_create_time` (`create_time`) USING BTREE,
|
||||||
|
KEY `I_flow_report_month_date` (`date`) USING BTREE,
|
||||||
|
KEY `I_flow_report_month_user_id` (`user_id`),
|
||||||
|
KEY `I_flow_report_month_license_id` (`license_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#job_qrtz_trigger_info
|
||||||
|
INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(1, '示例Job', 'DemoJob', '0/10 * * * * ?', '{"a":101}', 1, now(), now());
|
||||||
|
INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(2, '数据清理任务', 'DataCleanJob', '0 0 1 * * ?', '', 1, now(), now());
|
||||||
|
INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(3, '流量统计报表-分钟', 'FlowReportForMinuteJob', '0 */1 * * * ?', '', 1, now(), now());
|
||||||
|
INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(4, '流量统计报表-小时', 'FlowReportForHourJob', '0 0 */1 * * ?', '', 1, now(), now());
|
||||||
|
INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(5, '流量统计报表-天', 'FlowReportForDayJob', '0 0 1 * * ?', '', 1, now(), now());
|
||||||
|
INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(6, '流量统计报表-月', 'FlowReportForMonthJob', '0 30 1 1 * ?', '', 1, now(), now());
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#license
|
||||||
|
INSERT INTO license(`id`, `name`, `key`, `user_id`, `is_online`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(1, '我的mac', 'b0a907332b474b25897c4dcb31fc7eb6', 1, 2, 1, now(), now());
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#port_group
|
||||||
|
INSERT INTO `port_group`(`id`,`name`,`possessor_type`,`possessor_id`,`enable`,`create_time`,`update_time`) VALUES
|
||||||
|
(1, '全局(默认)', 0, -1, 1, now(), now());
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#port_mapping
|
||||||
|
INSERT INTO port_mapping(`id`, `license_id`, `server_port`, `protocal`, `subdomain`, `client_ip`, `client_port`, `is_online`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(1, 1, 9101, 'HTTP', 'test1', '127.0.0.1', 8080, 2, 1, now(), now());
|
||||||
|
INSERT INTO port_mapping(`id`, `license_id`, `server_port`, `protocal`, `subdomain`, `client_ip`, `client_port`, `is_online`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(2, 1, 9102, 'TCP', '', '127.0.0.1', 3306, 2, 1, now(), now());
|
||||||
|
INSERT INTO port_mapping(`id`, `license_id`, `server_port`, `protocal`, `subdomain`, `client_ip`, `client_port`, `is_online`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(3, 1, 9103, 'HTTP', 'test2', '127.0.0.1', 8081, 2, 1, now(), now());
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
#端口池
|
||||||
|
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(1, 1, 9101, 1, now(), now());
|
||||||
|
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(2, 1, 9102, 1, now(), now());
|
||||||
|
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(3, 1, 9103, 1, now(), now());
|
||||||
|
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(4, 1, 9104, 1, now(), now());
|
||||||
|
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(5, 1, 9105, 1, now(), now());
|
||||||
|
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(6, 1, 9106, 1, now(), now());
|
||||||
|
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(7, 1, 9107, 1, now(), now());
|
||||||
|
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(8, 1, 9108, 1, now(), now());
|
||||||
|
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(9, 1, 9109, 1, now(), now());
|
||||||
|
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(10, 1, 9110, 1, now(), now());
|
||||||
|
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(11, 1, 9111, 1, now(), now());
|
||||||
|
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(12, 1, 9112, 1, now(), now());
|
||||||
|
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(13, 1, 9113, 1, now(), now());
|
||||||
|
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(14, 1, 9114, 1, now(), now());
|
||||||
|
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(15, 1, 9115, 1, now(), now());
|
||||||
|
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(16, 1, 9116, 1, now(), now());
|
||||||
|
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(17, 1, 9117, 1, now(), now());
|
||||||
|
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(18, 1, 9118, 1, now(), now());
|
||||||
|
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(19, 1, 9119, 1, now(), now());
|
||||||
|
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||||
|
(20, 1, 9120, 1, now(), now());
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#用户表 6613b92b77056faeb72068f184ed4c4f
|
||||||
|
INSERT INTO `user`(`id`, `name`,`login_name`,`login_password`,`enable`,`create_time`, `update_time`) VALUES
|
||||||
|
(1, '管理员', 'admin', 'e10adc3949ba59abbe56e057f20f883e', 1, now(), now());
|
||||||
|
INSERT INTO `user`(`id`, `name`,`login_name`,`login_password`,`enable`,`create_time`, `update_time`) VALUES
|
||||||
|
(2, '游客', 'visitor', 'e10adc3949ba59abbe56e057f20f883e', 1, now(), now());
|
||||||
@@ -7,7 +7,7 @@ article: false
|
|||||||
|
|
||||||
## 1、 部署服务端
|
## 1、 部署服务端
|
||||||
### 1.1、 Docker一键部署
|
### 1.1、 Docker一键部署
|
||||||
> 当前最新版本为1.8.2,下面的脚本中,可以使用:`registry.cn-hangzhou.aliyuncs.com/asgc/neutrino-proxy:1.8.2` 指定版本安装,推荐使用`latest`直接安装最新版。
|
> 当前最新版本为1.8.4,下面的脚本中,可以使用:`registry.cn-hangzhou.aliyuncs.com/asgc/neutrino-proxy:1.8.4` 指定版本安装,推荐使用`latest`直接安装最新版。
|
||||||
|
|
||||||
#### 使用默认sqlite数据库
|
#### 使用默认sqlite数据库
|
||||||
```shell
|
```shell
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ server:
|
|||||||
|
|
||||||
neutrino:
|
neutrino:
|
||||||
proxy:
|
proxy:
|
||||||
|
logger:
|
||||||
|
# 日志级别
|
||||||
|
level: ${LOG_LEVEL:info}
|
||||||
# 隧道相关配置-用于维持服务端与客户端的通信
|
# 隧道相关配置-用于维持服务端与客户端的通信
|
||||||
tunnel:
|
tunnel:
|
||||||
# 线程池相关配置,用于技术调优,可忽略
|
# 线程池相关配置,用于技术调优,可忽略
|
||||||
@@ -32,7 +35,8 @@ neutrino:
|
|||||||
key-store-password: ${STORE_PASS:123456}
|
key-store-password: ${STORE_PASS:123456}
|
||||||
key-manager-password: ${MGR_PASS:123456}
|
key-manager-password: ${MGR_PASS:123456}
|
||||||
jks-path: ${JKS_PATH:classpath:/test.jks}
|
jks-path: ${JKS_PATH:classpath:/test.jks}
|
||||||
# 代理服务相关配置
|
# 是否开启隧道传输报文日志(日志级别为debug时开启才有效)
|
||||||
|
transfer-log-enable: ${TUNNEL_LOG:false}
|
||||||
server:
|
server:
|
||||||
# 线程池相关配置,用于技术调优,可忽略
|
# 线程池相关配置,用于技术调优,可忽略
|
||||||
boss-thread-count: 5
|
boss-thread-count: 5
|
||||||
@@ -46,9 +50,11 @@ neutrino:
|
|||||||
# https证书配置
|
# https证书配置
|
||||||
key-store-password: ${HTTPS_STORE_PASS:}
|
key-store-password: ${HTTPS_STORE_PASS:}
|
||||||
jks-path: ${HTTPS_JKS_PATH:}
|
jks-path: ${HTTPS_JKS_PATH:}
|
||||||
|
# 是否开启代理服务报文日志(日志级别为debug时开启才有效)
|
||||||
|
transfer-log-enable: ${SERVER_LOG:false}
|
||||||
data:
|
data:
|
||||||
db:
|
db:
|
||||||
# 数据库类型,目前支持sqlite、mysql两种
|
# 数据库类型,目前支持sqlite、mysql、mariadb
|
||||||
type: ${DB_TYPE:sqlite}
|
type: ${DB_TYPE:sqlite}
|
||||||
# 数据库连接URL
|
# 数据库连接URL
|
||||||
url: ${DB_URL:jdbc:sqlite:data.db}
|
url: ${DB_URL:jdbc:sqlite:data.db}
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
title: 客户端配置
|
||||||
|
date: 2023-06-09 21:15:35
|
||||||
|
permalink: /pages/50ce10/
|
||||||
|
---
|
||||||
|
|
||||||
|
# 以下是最新的客户端配置格式(app.yml)
|
||||||
|
```yml
|
||||||
|
neutrino:
|
||||||
|
proxy:
|
||||||
|
logger:
|
||||||
|
# 日志级别
|
||||||
|
level: ${LOG_LEVEL:info}
|
||||||
|
client:
|
||||||
|
# 线程池相关配置,用于技术调优,可忽略
|
||||||
|
thread-count: 50
|
||||||
|
# 隧道SSL证书配置
|
||||||
|
key-store-password: ${STORE_PASS:123456}
|
||||||
|
jks-path: ${JKS_PATH:classpath:/test.jks}
|
||||||
|
# 服务端IP
|
||||||
|
server-ip: ${SERVER_IP:localhost}
|
||||||
|
# 服务端端口(对应服务端app.yml中的tunnel.port、tunnel.ssl-port)
|
||||||
|
server-port: ${SERVER_PORT:9002}
|
||||||
|
# 是否启用SSL(注意:该配置必须和server-port对应上)
|
||||||
|
ssl-enable: ${SSL_ENABLE:true}
|
||||||
|
# 客户端连接唯一凭证
|
||||||
|
license-key: ${LICENSE_KEY:}
|
||||||
|
# 客户端唯一身份标识(可忽略,若不设置首次启动会自动生成)
|
||||||
|
client-id: ${CLIENT_ID:}
|
||||||
|
# 是否开启隧道传输报文日志(日志级别为debug时开启才有效)
|
||||||
|
transfer-log-enable: ${CLIENT_LOG:false}
|
||||||
|
# 重连设置
|
||||||
|
reconnection:
|
||||||
|
# 重连间隔(秒)
|
||||||
|
interval-seconds: 10
|
||||||
|
# 是否开启无限重连(未开启时,客户端license不合法会自动停止应用,开启了则不会,请谨慎开启)
|
||||||
|
unlimited: false
|
||||||
|
```
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
title: 2023年
|
||||||
|
date: 2023-06-09 21:33:17
|
||||||
|
permalink: /pages/cded59/
|
||||||
|
---
|
||||||
|
|
||||||
|
| 日期 | 渠道 | 金额 |昵称| 备注 |
|
||||||
|
|:-----------|:---|:---|:-|:--------|
|
||||||
|
| 2023-06-09 |Gitee捐助| 10 |失败女神| 感谢您的开源项目! |
|
||||||
|
| 2023-06-09 |Gitee捐助| 50 |Admin| 感谢您的开源项目! |
|
||||||
|
| 2023-06-09 |微信红包| 50 |李阳| 开源无限好 |
|
||||||
|
| 2023-06-09 |Gitee捐助| 50 |罗宾| 感谢您的开源项目!|
|
||||||
|
| 2023-06-07 |Gitee捐助| 50 |罗宾| 感谢您的开源项目!|
|
||||||
|
| 2023-06-03 |Gitee捐助| 50 |Admin| 感谢您的开源项目!|
|
||||||
|
| 2023-05-29 |微信红包| 20 |TYY| |
|
||||||
|
| 2023-05-29 |Gitee捐助| 10 |笑看| 感谢您的开源项目!|
|
||||||
|
| 2023-05-26 |微信红包| 50 |至少还有满天星光照耀你| |
|
||||||
|
| 2023-02-23 |Gitee捐助| 10 |Yohanes|感谢您的开源项目! |
|
||||||
|
| 2023-02-23 |Gitee捐助| 20 |jam_lee|感谢您的开源项目!希望能支持域名映射|
|
||||||
|
| 2023-02-10 |Gitee捐助| 5 |实习两年半|感谢您的开源项目!|
|
||||||
|
| 2023-02-02 |Gitee捐助| 10 |阳光很暖|感谢您的开源项目!|
|
||||||
@@ -97,6 +97,11 @@
|
|||||||
<artifactId>mysql-connector-java</artifactId>
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
<version>5.1.49</version>
|
<version>5.1.49</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mariadb.jdbc</groupId>
|
||||||
|
<artifactId>mariadb-java-client</artifactId>
|
||||||
|
<version>2.7.4</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.zaxxer</groupId>
|
<groupId>com.zaxxer</groupId>
|
||||||
<artifactId>HikariCP</artifactId>
|
<artifactId>HikariCP</artifactId>
|
||||||
|
|||||||
+15
@@ -1,3 +1,16 @@
|
|||||||
|
# 1.x规划
|
||||||
|
- Bug
|
||||||
|
- 优化
|
||||||
|
- 心跳日志开关
|
||||||
|
- 客户端启动无限重连开关
|
||||||
|
- UDP支持
|
||||||
|
- 官网文档完善
|
||||||
|
- 常见问题汇总
|
||||||
|
- HTTPS配置说明
|
||||||
|
- 协议重构
|
||||||
|
- 代码重构
|
||||||
|
- [x] 适配mariadb
|
||||||
|
|
||||||
# Bug
|
# Bug
|
||||||
- 指令通达被close的问题,org.dromara.neutrinoproxy.server.proxy.core.ProxyTunnelChannelHandler.channelInactive
|
- 指令通达被close的问题,org.dromara.neutrinoproxy.server.proxy.core.ProxyTunnelChannelHandler.channelInactive
|
||||||
- windows环境下直接运行发布版的jar包,日志输出乱码
|
- windows环境下直接运行发布版的jar包,日志输出乱码
|
||||||
@@ -17,6 +30,8 @@
|
|||||||
- [ ] 支持调整服务端端口、证书
|
- [ ] 支持调整服务端端口、证书
|
||||||
- [ ] 服务端版本、协议版本、客户端版本管理
|
- [ ] 服务端版本、协议版本、客户端版本管理
|
||||||
- [ ] 服务端日志
|
- [ ] 服务端日志
|
||||||
|
- [ ] 支持持管理后台动态调整日志级别。
|
||||||
|
- [ ] 动态调整转发、报文、心跳输出
|
||||||
- client+计划启动
|
- client+计划启动
|
||||||
- [ ] 安卓客户端
|
- [ ] 安卓客户端
|
||||||
- [ ] 基于electron-egg的多平台客户端
|
- [ ] 基于electron-egg的多平台客户端
|
||||||
|
|||||||
Reference in New Issue
Block a user