Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a31b0ebc95 | ||
|
|
fe86d786f4 | ||
|
|
c48404e3bb | ||
|
|
5daec7195f | ||
|
|
533675b367 | ||
|
|
e547895a9c | ||
|
|
42b7163f5b | ||
|
|
2ceacc6916 | ||
|
|
124273e8d7 | ||
|
|
5a36c88875 | ||
|
|
70e6d2ab45 |
@@ -1,14 +1,22 @@
|
||||
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 lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.noear.solon.Solon;
|
||||
import org.noear.solon.SolonApp;
|
||||
import org.noear.solon.annotation.SolonMain;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
@Slf4j
|
||||
@SolonMain
|
||||
public class ProxyClient {
|
||||
|
||||
@@ -20,6 +28,8 @@ public class ProxyClient {
|
||||
setAlias("neutrino.proxy.client.jksPath", "jksPath");
|
||||
setAlias("neutrino.proxy.client.keyStorePassword", "keyStorePassword");
|
||||
setAlias("neutrino.proxy.client.licenseKey", "licenseKey");
|
||||
// 设置日志级别
|
||||
setLogLevel(app);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -34,4 +44,21 @@ public class ProxyClient {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
@@ -41,5 +41,12 @@ public class ProxyConfig {
|
||||
private Integer threadCount;
|
||||
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
|
||||
protected void channelRead0(ChannelHandlerContext ctx, ProxyMessage proxyMessage) throws Exception {
|
||||
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);
|
||||
}
|
||||
|
||||
+2
-2
@@ -24,7 +24,7 @@ public class ProxyChannelHandler extends SimpleChannelInboundHandler<ProxyMessag
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, ProxyMessage proxyMessage) throws Exception {
|
||||
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);
|
||||
}
|
||||
@@ -71,7 +71,7 @@ public class ProxyChannelHandler extends SimpleChannelInboundHandler<ProxyMessag
|
||||
ctx.channel().writeAndFlush(ProxyMessage.buildHeartbeatMessage());
|
||||
break;
|
||||
case ALL_IDLE:
|
||||
log.info("读写超时");
|
||||
log.debug("读写超时");
|
||||
ctx.close();
|
||||
break;
|
||||
}
|
||||
|
||||
+5
-5
@@ -49,10 +49,10 @@ public class ProxyClientService {
|
||||
@Inject("realServerBootstrap")
|
||||
private Bootstrap realServerBootstrap;
|
||||
private volatile Channel channel;
|
||||
/**
|
||||
* 重连间隔(秒)
|
||||
*/
|
||||
private static final long RECONNECT_INTERVAL_SECONDS = 5;
|
||||
// /**
|
||||
// * 重连间隔(秒)
|
||||
// */
|
||||
// private static final long RECONNECT_INTERVAL_SECONDS = 5;
|
||||
/**
|
||||
* 重连次数
|
||||
*/
|
||||
@@ -69,7 +69,7 @@ public class ProxyClientService {
|
||||
|
||||
@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());
|
||||
|
||||
realServerBootstrap.group(workerGroup);
|
||||
|
||||
+7
-1
@@ -1,6 +1,7 @@
|
||||
package org.dromara.neutrinoproxy.client.handler;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.dromara.neutrinoproxy.client.config.ProxyConfig;
|
||||
import org.dromara.neutrinoproxy.core.Constants;
|
||||
import org.dromara.neutrinoproxy.core.ExceptionEnum;
|
||||
import org.dromara.neutrinoproxy.core.ProxyMessage;
|
||||
@@ -10,6 +11,7 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.noear.solon.Solon;
|
||||
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)
|
||||
@Component
|
||||
public class ProxyMessageAuthHandler implements ProxyMessageHandler {
|
||||
@Inject
|
||||
private ProxyConfig proxyConfig;
|
||||
@Override
|
||||
public void handle(ChannelHandlerContext context, ProxyMessage proxyMessage) {
|
||||
String info = proxyMessage.getInfo();
|
||||
@@ -30,7 +34,9 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler {
|
||||
// 客户端认证失败,直接停止服务
|
||||
log.info("client auth failed , client stop.");
|
||||
context.channel().close();
|
||||
Solon.stop();
|
||||
if (!proxyConfig.getClient().getReconnection().getUnlimited()) {
|
||||
Solon.stop();
|
||||
}
|
||||
} else if (ExceptionEnum.CONNECT_FAILED.getCode().equals(code) ||
|
||||
ExceptionEnum.LICENSE_CANNOT_REPEAT_CONNECT.getCode().equals(code)
|
||||
){
|
||||
|
||||
@@ -12,14 +12,30 @@ neutrino:
|
||||
read-idle-time: 8
|
||||
write-idle-time: 3
|
||||
all-idle-time-seconds: 8
|
||||
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}
|
||||
obtain-license-interval: 5
|
||||
# 客户端连接唯一凭证
|
||||
license-key: ${LICENSE_KEY:}
|
||||
# 客户端唯一身份标识(可忽略,若不设置首次启动会自动生成)
|
||||
client-id: ${CLIENT_ID:}
|
||||
# 是否开启隧道传输报文日志(日志级别为debug时开启才有效)
|
||||
transfer-log-enable: ${CLIENT_LOG:false}
|
||||
# 重连设置
|
||||
reconnection:
|
||||
# 重连间隔(秒)
|
||||
interval-seconds: 10
|
||||
# 是否开启无限重连(未开启时,客户端license不合法会自动停止应用,开启了则不会,请谨慎开启)
|
||||
unlimited: false
|
||||
|
||||
@@ -1,15 +1,25 @@
|
||||
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.noear.solon.Solon;
|
||||
import org.noear.solon.SolonApp;
|
||||
import org.noear.solon.annotation.SolonMain;
|
||||
import org.noear.solon.web.cors.CrossFilter;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/6/16
|
||||
*/
|
||||
@Slf4j
|
||||
@EnableJob
|
||||
@SolonMain
|
||||
public class ProxyServer {
|
||||
@@ -18,6 +28,25 @@ public class ProxyServer {
|
||||
Solon.start(ProxyServer.class, args, app -> {
|
||||
// 跨域支持。加-1 优先级更高
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ public class VisitLogInterceptor implements RouterInterceptor {
|
||||
} finally {
|
||||
Date now = new Date();
|
||||
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),
|
||||
JSONObject.toJSONString(ctx.paramMap()),
|
||||
JSONObject.toJSONString(JSONObject.toJSONString(ctx.result)),
|
||||
|
||||
+1
-1
@@ -17,6 +17,6 @@ public class DemoJob implements IJobHandler {
|
||||
|
||||
@Override
|
||||
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()) {
|
||||
case READER_IDLE:
|
||||
// 读超时,断开连接
|
||||
log.info("读超时");
|
||||
log.debug("读超时");
|
||||
ctx.channel().close();
|
||||
break;
|
||||
case WRITER_IDLE:
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ public class HttpProxy implements EventListener<AppLoadEndEvent> {
|
||||
}
|
||||
});
|
||||
bootstrap.bind("0.0.0.0", proxyConfig.getServer().getHttpProxyPort()).sync();
|
||||
log.info("Http代理服务启动成功!");
|
||||
log.info("Http代理服务启动成功!port:{}", proxyConfig.getServer().getHttpProxyPort());
|
||||
} catch (Exception e) {
|
||||
log.error("http proxy start err!", e);
|
||||
}
|
||||
|
||||
+2
-1
@@ -163,7 +163,8 @@ public class HttpVisitorChannelHandler extends SimpleChannelInboundHandler<ByteB
|
||||
}
|
||||
// 域名
|
||||
String domain = line.substring(6);
|
||||
return domain;
|
||||
// 去掉域名后面的端口号
|
||||
return domain.replaceAll(":.*", "");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ public class HttpsProxy implements EventListener<AppLoadEndEvent> {
|
||||
}
|
||||
});
|
||||
bootstrap.bind("0.0.0.0", proxyConfig.getServer().getHttpsProxyPort()).sync();
|
||||
log.info("Https代理服务启动成功!");
|
||||
log.info("Https代理服务启动成功!port:{}", proxyConfig.getServer().getHttpsProxyPort());
|
||||
} catch (Exception e) {
|
||||
log.error("https proxy start err!", e);
|
||||
}
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ public class JobLogService implements IJobCallback {
|
||||
String msg = "";
|
||||
if (null == throwable) {
|
||||
msg = "执行成功";
|
||||
log.info("job[id={},name={}]执行完毕", jobInfo.getId(), jobInfo.getName());
|
||||
log.debug("job[id={},name={}]执行完毕", jobInfo.getId(), jobInfo.getName());
|
||||
} else {
|
||||
log.error("job[id={},name={}]执行异常", jobInfo.getId(), jobInfo.getName(), 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.PageHelper;
|
||||
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.page.PageInfo;
|
||||
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.UserDO;
|
||||
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.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Init;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
import org.noear.solon.core.Lifecycle;
|
||||
import org.noear.solon.core.bean.LifecycleBean;
|
||||
|
||||
import java.util.*;
|
||||
@@ -51,25 +49,25 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
@Component
|
||||
public class PortMappingService implements LifecycleBean {
|
||||
@Inject
|
||||
private MapperFacade mapperFacade;
|
||||
@Db
|
||||
private PortMappingMapper portMappingMapper;
|
||||
@Db
|
||||
private LicenseMapper licenseMapper;
|
||||
@Db
|
||||
private UserMapper userMapper;
|
||||
@Db
|
||||
private PortPoolMapper portPoolMapper;
|
||||
@Inject
|
||||
private VisitorChannelService visitorChannelService;
|
||||
@Inject
|
||||
private MapperFacade mapperFacade;
|
||||
@Db
|
||||
private PortMappingMapper portMappingMapper;
|
||||
@Db
|
||||
private LicenseMapper licenseMapper;
|
||||
@Db
|
||||
private UserMapper userMapper;
|
||||
@Db
|
||||
private PortPoolMapper portPoolMapper;
|
||||
@Inject
|
||||
private VisitorChannelService visitorChannelService;
|
||||
|
||||
@Inject
|
||||
private PortPoolService portPoolService;
|
||||
@Inject
|
||||
private ProxyConfig proxyConfig;
|
||||
@Inject
|
||||
private DBInitialize dbInitialize;
|
||||
@Inject
|
||||
private PortPoolService portPoolService;
|
||||
@Inject
|
||||
private ProxyConfig proxyConfig;
|
||||
@Inject
|
||||
private DBInitialize dbInitialize;
|
||||
|
||||
public PageInfo<PortMappingListRes> page(PageQuery pageQuery, PortMappingListReq req) {
|
||||
Page<PortMappingListRes> result = PageHelper.startPage(pageQuery.getCurrent(), pageQuery.getSize());
|
||||
@@ -77,6 +75,13 @@ public class PortMappingService implements LifecycleBean {
|
||||
//描述字段为模糊查询,在应用层处理,否则sqlite不支持
|
||||
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<PortMappingListRes> respList = mapperFacade.mapAsList(list, PortMappingListRes.class);
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
@@ -113,10 +118,7 @@ public class PortMappingService implements LifecycleBean {
|
||||
}
|
||||
});
|
||||
//sorted [userId asc] [licenseId asc] [createTime asc]
|
||||
respList = respList.stream().sorted(Comparator.comparing(PortMappingListRes::getUserId)
|
||||
.thenComparing(PortMappingListRes::getLicenseId)
|
||||
.thenComparing(PortMappingListRes::getCreateTime))
|
||||
.collect(Collectors.toList());
|
||||
respList = respList.stream().sorted(Comparator.comparing(PortMappingListRes::getUserId).thenComparing(PortMappingListRes::getLicenseId).thenComparing(PortMappingListRes::getCreateTime)).collect(Collectors.toList());
|
||||
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
|
||||
}
|
||||
|
||||
@@ -149,9 +151,7 @@ public class PortMappingService implements LifecycleBean {
|
||||
// 更新VisitorChannel
|
||||
visitorChannelService.addVisitorChannelByPortMapping(portMappingDO);
|
||||
// 更新域名映射
|
||||
if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) &&
|
||||
StrUtil.isNotBlank(proxyConfig.getServer().getDomainName()) &&
|
||||
StrUtil.isNotBlank(portMappingDO.getSubdomain())) {
|
||||
if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) && StrUtil.isNotBlank(proxyConfig.getServer().getDomainName()) && StrUtil.isNotBlank(portMappingDO.getSubdomain())) {
|
||||
ProxyUtil.setSubdomainToServerPort(portMappingDO.getSubdomain(), portMappingDO.getServerPort());
|
||||
}
|
||||
return new PortMappingCreateRes();
|
||||
@@ -188,14 +188,11 @@ public class PortMappingService implements LifecycleBean {
|
||||
// 更新VisitorChannel
|
||||
visitorChannelService.updateVisitorChannelByPortMapping(oldPortMappingDO, portMappingDO);
|
||||
// 删除老的域名映射
|
||||
if (NetworkProtocolEnum.isHttp(oldPortMappingDO.getProtocal()) &&
|
||||
StrUtil.isNotBlank(oldPortMappingDO.getSubdomain())) {
|
||||
if (NetworkProtocolEnum.isHttp(oldPortMappingDO.getProtocal()) && StrUtil.isNotBlank(oldPortMappingDO.getSubdomain())) {
|
||||
ProxyUtil.removeSubdomainToServerPort(oldPortMappingDO.getSubdomain());
|
||||
}
|
||||
// 更新域名映射
|
||||
if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) &&
|
||||
StrUtil.isNotBlank(proxyConfig.getServer().getDomainName()) &&
|
||||
StrUtil.isNotBlank(portMappingDO.getSubdomain())) {
|
||||
if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) && StrUtil.isNotBlank(proxyConfig.getServer().getDomainName()) && StrUtil.isNotBlank(portMappingDO.getSubdomain())) {
|
||||
ProxyUtil.setSubdomainToServerPort(portMappingDO.getSubdomain(), portMappingDO.getServerPort());
|
||||
}
|
||||
return new PortMappingUpdateRes();
|
||||
@@ -206,16 +203,7 @@ public class PortMappingService implements LifecycleBean {
|
||||
if (null == portMappingDO) {
|
||||
return null;
|
||||
}
|
||||
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());
|
||||
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());
|
||||
|
||||
LicenseDO license = licenseMapper.findById(portMappingDO.getLicenseId());
|
||||
if (null != license) {
|
||||
@@ -268,8 +256,7 @@ public class PortMappingService implements LifecycleBean {
|
||||
// 更新VisitorChannel
|
||||
visitorChannelService.removeVisitorChannelByPortMapping(portMappingDO);
|
||||
// 更新域名映射
|
||||
if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) &&
|
||||
StrUtil.isNotBlank(portMappingDO.getSubdomain())) {
|
||||
if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) && StrUtil.isNotBlank(portMappingDO.getSubdomain())) {
|
||||
ProxyUtil.removeSubdomainToServerPort(portMappingDO.getSubdomain());
|
||||
}
|
||||
}
|
||||
@@ -295,10 +282,7 @@ public class PortMappingService implements LifecycleBean {
|
||||
if (StrUtil.isBlank(proxyConfig.getServer().getDomainName())) {
|
||||
return;
|
||||
}
|
||||
List<PortMappingDO> portMappingDOList = portMappingMapper.selectList(new LambdaQueryWrapper<PortMappingDO>()
|
||||
.eq(PortMappingDO::getProtocal, NetworkProtocolEnum.HTTP.getDesc())
|
||||
.isNotNull(PortMappingDO::getSubdomain)
|
||||
);
|
||||
List<PortMappingDO> portMappingDOList = portMappingMapper.selectList(new LambdaQueryWrapper<PortMappingDO>().eq(PortMappingDO::getProtocal, NetworkProtocolEnum.HTTP.getDesc()).isNotNull(PortMappingDO::getSubdomain));
|
||||
if (CollectionUtil.isEmpty(portMappingDOList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
server:
|
||||
# 服务端web端口,用于支持HTTP接口,管理后台页面访问
|
||||
port: ${WEB_PORT:8888}
|
||||
|
||||
neutrino:
|
||||
@@ -12,30 +13,48 @@ neutrino:
|
||||
read-idle-time: 30
|
||||
write-idle-time: 5
|
||||
all-idle-time-seconds: 0
|
||||
logger:
|
||||
# 日志级别
|
||||
level: ${LOG_LEVEL:info}
|
||||
# 隧道相关配置-用于维持服务端与客户端的通信
|
||||
tunnel:
|
||||
# 线程池相关配置,用于技术调优,可忽略
|
||||
boss-thread-count: 2
|
||||
work-thread-count: 10
|
||||
# 隧道非SSL端口
|
||||
port: ${OPEN_PORT:9000}
|
||||
# 隧道SSL端口
|
||||
ssl-port: ${SSL_PORT:9002}
|
||||
# 隧道SSL证书配置
|
||||
key-store-password: ${STORE_PASS:123456}
|
||||
key-manager-password: ${MGR_PASS:123456}
|
||||
jks-path: ${JKS_PATH:classpath:/test.jks}
|
||||
# 是否开启隧道传输报文日志(日志级别为debug时开启才有效)
|
||||
transfer-log-enable: ${TUNNEL_LOG:false}
|
||||
server:
|
||||
# 线程池相关配置,用于技术调优,可忽略
|
||||
boss-thread-count: 5
|
||||
work-thread-count: 20
|
||||
# http代理端口,默认80
|
||||
http-proxy-port: ${HTTP_PROXY_PORT:80}
|
||||
# https代理端口,默认443 (需要配置域名、证书)
|
||||
https-proxy-port: ${HTTPS_PROXY_PORT:443}
|
||||
# 如果不配置,则不支持域名映射
|
||||
domain-name: ${DOMAIN_NAME:}
|
||||
# https证书配置
|
||||
key-store-password: ${HTTPS_STORE_PASS:}
|
||||
jks-path: ${HTTPS_JKS_PATH:}
|
||||
# 是否开启代理服务报文日志(日志级别为debug时开启才有效)
|
||||
transfer-log-enable: ${SERVER_LOG:false}
|
||||
data:
|
||||
db:
|
||||
# 数据库类型,目前支持sqlite、mysql、mariadb
|
||||
type: ${DB_TYPE:sqlite}
|
||||
# 数据库连接URL
|
||||
url: ${DB_URL:jdbc:sqlite:data.db}
|
||||
# 数据库用户名
|
||||
username: ${DB_USER:}
|
||||
# 数据库密码
|
||||
password: ${DB_PASSWORD:}
|
||||
|
||||
#添加MIME印射(如果有需要?)
|
||||
|
||||
@@ -7,7 +7,7 @@ article: false
|
||||
|
||||
## 1、 部署服务端
|
||||
### 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数据库
|
||||
```shell
|
||||
|
||||
@@ -19,6 +19,9 @@ server:
|
||||
|
||||
neutrino:
|
||||
proxy:
|
||||
logger:
|
||||
# 日志级别
|
||||
level: ${LOG_LEVEL:info}
|
||||
# 隧道相关配置-用于维持服务端与客户端的通信
|
||||
tunnel:
|
||||
# 线程池相关配置,用于技术调优,可忽略
|
||||
@@ -32,7 +35,8 @@ neutrino:
|
||||
key-store-password: ${STORE_PASS:123456}
|
||||
key-manager-password: ${MGR_PASS:123456}
|
||||
jks-path: ${JKS_PATH:classpath:/test.jks}
|
||||
# 代理服务相关配置
|
||||
# 是否开启隧道传输报文日志(日志级别为debug时开启才有效)
|
||||
transfer-log-enable: ${TUNNEL_LOG:false}
|
||||
server:
|
||||
# 线程池相关配置,用于技术调优,可忽略
|
||||
boss-thread-count: 5
|
||||
@@ -46,9 +50,11 @@ neutrino:
|
||||
# https证书配置
|
||||
key-store-password: ${HTTPS_STORE_PASS:}
|
||||
jks-path: ${HTTPS_JKS_PATH:}
|
||||
# 是否开启代理服务报文日志(日志级别为debug时开启才有效)
|
||||
transfer-log-enable: ${SERVER_LOG:false}
|
||||
data:
|
||||
db:
|
||||
# 数据库类型,目前支持sqlite、mysql两种
|
||||
# 数据库类型,目前支持sqlite、mysql、mariadb
|
||||
type: ${DB_TYPE:sqlite}
|
||||
# 数据库连接URL
|
||||
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 |阳光很暖|感谢您的开源项目!|
|
||||
@@ -30,6 +30,8 @@
|
||||
- [ ] 支持调整服务端端口、证书
|
||||
- [ ] 服务端版本、协议版本、客户端版本管理
|
||||
- [ ] 服务端日志
|
||||
- [ ] 支持持管理后台动态调整日志级别。
|
||||
- [ ] 动态调整转发、报文、心跳输出
|
||||
- client+计划启动
|
||||
- [ ] 安卓客户端
|
||||
- [ ] 基于electron-egg的多平台客户端
|
||||
|
||||
Reference in New Issue
Block a user