代理逻辑优化.

This commit is contained in:
aoshiguchen
2022-09-03 22:37:32 +08:00
parent 3f3b3772bf
commit e93481f082
16 changed files with 153 additions and 42 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
# Compiled class file
*.class
data.db
data.db-wal
# Log file
*.log
@@ -0,0 +1,60 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.core.util;
import io.netty.channel.Channel;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
/**
*
* @author: aoshiguchen
* @date: 2022/9/3
*/
public class ChannelUtil {
/**
* 获取ip地址
* @param channel
* @return
*/
public static String getIP(Channel channel) {
if (null == channel) {
return "";
}
String ip = ((InetSocketAddress)channel.remoteAddress()).getAddress().getHostAddress();
if (ip.equals("127.0.0.1") || ip.equals("0:0:0:0:0:0:0:1")) {
//根据网卡取本机配置的IP
InetAddress inet = null;
try {
inet = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
}
ip = inet.getHostAddress();
}
return ip;
}
}
@@ -19,7 +19,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.util;
package fun.asgc.neutrino.core.util;
import fun.asgc.neutrino.core.web.context.HttpRequestWrapper;
import io.netty.channel.ChannelHandlerContext;
@@ -143,6 +143,7 @@ public class HttpRequestHandler {
}
} catch (Throwable e) {
try {
log.error("请求处理异常:{}", requestParser.getUrl(), e);
postHandle(requestParser.getRoutePath(), null, null);
Object res = exceptionHandler(e);
if (null != res) {
@@ -35,11 +35,12 @@ import java.util.List;
*/
public class InterceptorRegistry {
private final List<InterceptorRegistration> registrations = new ArrayList<InterceptorRegistration>();
private final List<InterceptorRegistration> registrations = new ArrayList<>();
public InterceptorRegistration addInterceptor(HandlerInterceptor interceptor) {
InterceptorRegistration registration = new InterceptorRegistration(interceptor);
this.registrations.add(registration);
Collections.sort(this.registrations, INTERCEPTOR_ORDER_COMPARATOR);
return registration;
}
@@ -47,7 +48,6 @@ public class InterceptorRegistry {
* Return all registered interceptors.
*/
public List<Object> getInterceptors() {
Collections.sort(this.registrations, INTERCEPTOR_ORDER_COMPARATOR);
List<Object> result = new ArrayList<Object>(this.registrations.size());
for (InterceptorRegistration registration : this.registrations) {
result.add(registration.getInterceptor());
@@ -25,7 +25,6 @@ package fun.asgc.neutrino.proxy.client.config;
import fun.asgc.neutrino.core.annotation.Configuration;
import fun.asgc.neutrino.core.annotation.Init;
import fun.asgc.neutrino.core.annotation.Value;
import fun.asgc.neutrino.proxy.core.ProxyClientConfig;
import lombok.Data;
/**
@@ -113,10 +113,10 @@ public class ProxyClientRunner implements ApplicationRunner {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
// 连接成功,向服务器发送客户端认证信息(clientKey
// 连接成功,向服务器发送客户端认证信息(licenseKey
ProxyUtil.setCmdChannel(future.channel());
future.channel().writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getLicenseKey()));
log.info("连接代理服务成功.");
log.info("连接代理服务成功. channelId:{}", future.channel().id().asLongText());
} else {
log.info("连接代理服务失败!");
System.exit(-1);
@@ -48,7 +48,7 @@ public class ProxyMessageDisconnectHandler implements ProxyMessageHandler {
@Override
public void handle(ChannelHandlerContext ctx, ProxyMessage proxyMessage) {
Channel realServerChannel = ctx.channel().attr(Constants.NEXT_CHANNEL).get();
if (realServerChannel != null) {
if (null != realServerChannel) {
ctx.channel().attr(Constants.NEXT_CHANNEL).remove();
ProxyUtil.returnProxyChanel(ctx.channel());
realServerChannel.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
@@ -57,7 +57,7 @@ public class ProxyUtil {
public static void borrowProxyChanel(Bootstrap bootstrap, final ProxyChannelBorrowListener borrowListener) {
Channel channel = proxyChannelPool.poll();
if (channel != null) {
if (null != channel) {
borrowListener.success(channel);
return;
}
@@ -34,7 +34,8 @@ import lombok.Getter;
@AllArgsConstructor
public enum ExceptionEnum {
AUTH_FAILED(1, "认证失败");
AUTH_FAILED(1, "认证失败"),
CONNECT_FAILED(2, "连接失败");
private Integer code;
private String msg;
@@ -22,6 +22,7 @@
package fun.asgc.neutrino.proxy.server.base.rest.interceptor;
import fun.asgc.neutrino.core.util.BeanManager;
import fun.asgc.neutrino.core.util.HttpUtil;
import fun.asgc.neutrino.core.util.StringUtil;
import fun.asgc.neutrino.core.web.context.HttpContextHolder;
import fun.asgc.neutrino.core.web.context.HttpRequestWrapper;
@@ -33,7 +34,6 @@ import fun.asgc.neutrino.proxy.server.constant.EnableStatusEnum;
import fun.asgc.neutrino.proxy.server.constant.ExceptionConstant;
import fun.asgc.neutrino.proxy.server.dal.entity.UserDO;
import fun.asgc.neutrino.proxy.server.service.UserService;
import fun.asgc.neutrino.proxy.server.util.HttpUtil;
import java.lang.reflect.Method;
@@ -42,6 +42,8 @@ public class CorsInterceptor implements HandlerInterceptor {
responseWrapper.headers().add("Access-Control-Allow-Headers", "*");
responseWrapper.headers().add("Access-Control-Allow-Credentials", "true");
responseWrapper.headers().add("XDomainRequestAllowed", "1");
responseWrapper.headers().add("Access-Control-Allow-Headers","Authorize, Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type");
responseWrapper.headers().add("Access-Control-Allow-Credentials", "true");
}
}
@@ -34,4 +34,8 @@ import lombok.experimental.Accessors;
public class UserChannelAttachInfo {
private String userId;
private String lanInfo;
/**
* ip地址
*/
private String ip;
}
@@ -0,0 +1,49 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package fun.asgc.neutrino.proxy.server.service;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.proxy.server.proxy.domain.CmdChannelAttachInfo;
import lombok.extern.slf4j.Slf4j;
/**
* 代理交互服务
* @author: aoshiguchen
* @date: 2022/9/3
*/
@Slf4j
@NonIntercept
@Component
public class ProxyMutualService {
/**
* 绑定服务端端口处理
* @param attachInfo
* @param serverPort
*/
public void bindServerPort(CmdChannelAttachInfo attachInfo, Integer serverPort) {
// TODO
log.info("绑定服务端端口 licenseId:{},ip:{},lanInfo:{},serverPort:{}", attachInfo.getLicenseId(), attachInfo.getIp(), attachInfo.getClientLanInfo(), serverPort);
}
}
@@ -21,10 +21,9 @@
*/
package fun.asgc.neutrino.proxy.server.util;
import fun.asgc.neutrino.core.util.ChannelUtil;
import fun.asgc.neutrino.core.util.CollectionUtil;
import fun.asgc.neutrino.core.util.StringUtil;
import fun.asgc.neutrino.proxy.core.ChannelAttribute;
import fun.asgc.neutrino.proxy.core.Constants;
import fun.asgc.neutrino.proxy.server.proxy.domain.CmdChannelAttachInfo;
import fun.asgc.neutrino.proxy.server.proxy.domain.ProxyMapping;
import fun.asgc.neutrino.proxy.server.proxy.domain.UserChannelAttachInfo;
@@ -47,7 +46,7 @@ public class ProxyUtil {
/**
* license -> 服务端口映射
*/
private static final Map<String, Set<Integer>> licenseToServerPortMap = new HashMap<>();
private static final Map<Integer, Set<Integer>> licenseToServerPortMap = new HashMap<>();
/**
* 代理信息映射
*/
@@ -59,7 +58,7 @@ public class ProxyUtil {
/**
* license -> 指令通道映射
*/
private static Map<String, Channel> licenseToCmdChannelMap = new ConcurrentHashMap<>();
private static Map<Integer, Channel> licenseToCmdChannelMap = new ConcurrentHashMap<>();
/**
* cmdChannelAttachInfo.getUserChannelMap() 读写锁
@@ -68,30 +67,24 @@ public class ProxyUtil {
/**
* 初始化代理信息
* @param licenseKey 客户端licenseKey
* @param licenseId 客户端licenseId
* @param proxyMappingList 代理映射集合
*/
public static void initProxyInfo(String licenseKey, List<ProxyMapping> proxyMappingList) {
if (StringUtil.isEmpty(licenseKey)) {
return;
}
licenseToServerPortMap.put(licenseKey, new HashSet<>());
if (CollectionUtil.isEmpty(proxyMappingList)) {
return;
}
public static void initProxyInfo(Integer licenseId, List<ProxyMapping> proxyMappingList) {
licenseToServerPortMap.put(licenseId, new HashSet<>());
for (ProxyMapping proxyMapping : proxyMappingList) {
licenseToServerPortMap.get(licenseKey).add(proxyMapping.getServerPort());
licenseToServerPortMap.get(licenseId).add(proxyMapping.getServerPort());
proxyInfoMap.put(proxyMapping.getServerPort(), proxyMapping.getLanInfo());
}
}
/**
* 根据licenseKey获取服务端端口集合
* @param licenseKey 客户端licenseKey
* @param licenseId licenseId
* @return 服务端端口集合
*/
public static Set<Integer> getServerPortsByLicenseKey(String licenseKey) {
return licenseToServerPortMap.get(licenseKey);
public static Set<Integer> getServerPortsByLicenseKey(Integer licenseId) {
return licenseToServerPortMap.get(licenseId);
}
/**
@@ -105,28 +98,25 @@ public class ProxyUtil {
/**
* 添加指令通道相关缓存信息
* @param licenseKey licenseKey
* @param licenseId licenseId
* @param cmdChannel 指令通道
* @param serverPorts 服务端端口集合
*/
public static void addCmdChannel(String licenseKey, Channel cmdChannel, Set<Integer> serverPorts) {
public static void addCmdChannel(Integer licenseId, Channel cmdChannel, Set<Integer> serverPorts) {
if (CollectionUtil.isEmpty(serverPorts)) {
return;
}
// 客户端(proxy-client)相对较少,这里同步的比较重 TODO 后续优化
// 保证服务器对外端口与客户端到服务器的连接关系在临界情况时调用removeChannel(Channel channel)时不出问题
synchronized (serverPortToCmdChannelMap) {
for (int port : serverPorts) {
serverPortToCmdChannelMap.put(port, cmdChannel);
}
for (int port : serverPorts) {
serverPortToCmdChannelMap.put(port, cmdChannel);
}
setAttachInfo(cmdChannel, new CmdChannelAttachInfo()
.setIp(ChannelUtil.getIP(cmdChannel))
.setServerPorts(serverPorts)
.setLicenseKey(licenseKey)
.setLicenseId(licenseId)
.setUserChannelMap(new HashMap<>(16)));
licenseToCmdChannelMap.put(licenseKey, cmdChannel);
licenseToCmdChannelMap.put(licenseId, cmdChannel);
}
/**
@@ -139,9 +129,9 @@ public class ProxyUtil {
}
CmdChannelAttachInfo cmdChannelAttachInfo = getAttachInfo(cmdChannel);
Channel channel0 = licenseToCmdChannelMap.remove(cmdChannelAttachInfo.getLicenseKey());
Channel channel0 = licenseToCmdChannelMap.remove(cmdChannelAttachInfo.getLicenseId());
if (cmdChannel != channel0) {
licenseToCmdChannelMap.put(cmdChannelAttachInfo.getLicenseKey(), cmdChannel);
licenseToCmdChannelMap.put(cmdChannelAttachInfo.getLicenseId(), cmdChannel);
}
for (int port : cmdChannelAttachInfo.getServerPorts()) {
@@ -174,8 +164,8 @@ public class ProxyUtil {
return serverPortToCmdChannelMap.get(serverPort);
}
public static Channel getCmdChannelByLicenseKey(String licenseKey) {
return licenseToCmdChannelMap.get(licenseKey);
public static Channel getCmdChannelByLicenseId(Integer licenseId) {
return licenseToCmdChannelMap.get(licenseId);
}
/**
@@ -190,6 +180,7 @@ public class ProxyUtil {
setAttachInfo(userChannel, new UserChannelAttachInfo()
.setUserId(userId)
.setLanInfo(lanInfo)
.setIp(ChannelUtil.getIP(userChannel))
);
userChannelMapLock.writeLock().lock();
try {
@@ -8,6 +8,7 @@ CREATE TABLE IF NOT EXISTS `user` (
`create_time` INTEGER(20) NOT NULL,
`update_time` INTEGER(20) NOT NULL
);
CREATE UNIQUE INDEX IF NOT EXISTS I_login_name ON `user` (login_name ASC);
#license表
CREATE TABLE IF NOT EXISTS `license` (
@@ -20,6 +21,7 @@ CREATE TABLE IF NOT EXISTS `license` (
`create_time` INTEGER(20) NOT NULL,
`update_time` INTEGER(20) NOT NULL
);
CREATE UNIQUE INDEX IF NOT EXISTS I_key ON `license` (`key` ASC);
#token表
CREATE TABLE IF NOT EXISTS `user_token` (
@@ -49,6 +51,7 @@ CREATE TABLE IF NOT EXISTS `port_pool` (
`update_time` INTEGER(20) NOT NULL,
`create_time` INTEGER(20) NOT NULL
);
CREATE UNIQUE INDEX IF NOT EXISTS I_port ON port_pool (port ASC);
#
CREATE TABLE IF NOT EXISTS `port_mapping` (
@@ -62,6 +65,7 @@ CREATE TABLE IF NOT EXISTS `port_mapping` (
`create_time` INTEGER(20) NOT NULL,
`update_time` INTEGER(20) NOT NULL
);
CREATE UNIQUE INDEX IF NOT EXISTS I_server_port ON port_mapping (server_port ASC);
#
CREATE TABLE IF NOT EXISTS `client_connect_record` (