From 3ffba1744fab01c4b481c7241662ba0455f96365 Mon Sep 17 00:00:00 2001 From: xiaojie <550345579@qq.com> Date: Fri, 1 Mar 2024 17:34:47 +0800 Subject: [PATCH 01/15] =?UTF-8?q?=E9=83=A8=E5=88=86=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- neutrino-proxy-admin/config/dev.env.js | 2 +- neutrino-proxy-admin/package.json | 4 ++-- neutrino-proxy-client/src/main/resources/app.yml | 2 +- .../dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java | 3 ++- .../server/proxy/enhance/HttpVisitorChannelHandler.java | 2 +- .../neutrinoproxy/server/proxy/enhance/HttpsProxy.java | 3 ++- .../proxy/security/HttpVisitorSecurityChannelHandler.java | 1 + neutrino-proxy-server/src/main/resources/app.yml | 2 +- 8 files changed, 11 insertions(+), 8 deletions(-) diff --git a/neutrino-proxy-admin/config/dev.env.js b/neutrino-proxy-admin/config/dev.env.js index 03fd65b0..799ec796 100644 --- a/neutrino-proxy-admin/config/dev.env.js +++ b/neutrino-proxy-admin/config/dev.env.js @@ -1,7 +1,7 @@ module.exports = { NODE_ENV: '"development"', ENV_CONFIG: '"dev"', - BASE_API: '"https://neutrino-proxy.asgc.fun/neutrino-proxy-server"', + BASE_API: '"https://server.com"', USER_NAME: '"visitor"', USER_PWD: '"123456"' } diff --git a/neutrino-proxy-admin/package.json b/neutrino-proxy-admin/package.json index d2bdb819..3fafb115 100644 --- a/neutrino-proxy-admin/package.json +++ b/neutrino-proxy-admin/package.json @@ -36,7 +36,7 @@ "showdown": "1.8.5", "simplemde": "1.11.2", "sortablejs": "1.7.0", - "vue": "2.5.10", + "vue": "2.5.17", "vue-count-to": "1.0.13", "vue-i18n": "7.3.2", "vue-multiselect": "2.0.8", @@ -88,7 +88,7 @@ "url-loader": "0.6.2", "vue-loader": "13.5.0", "vue-style-loader": "3.0.3", - "vue-template-compiler": "2.5.10", + "vue-template-compiler": "2.5.17", "webpack": "3.10.0", "webpack-bundle-analyzer": "2.9.1", "webpack-dev-server": "2.9.7", diff --git a/neutrino-proxy-client/src/main/resources/app.yml b/neutrino-proxy-client/src/main/resources/app.yml index a122416c..8099182a 100644 --- a/neutrino-proxy-client/src/main/resources/app.yml +++ b/neutrino-proxy-client/src/main/resources/app.yml @@ -44,7 +44,7 @@ neutrino: # 是否启用SSL(注意:该配置必须和server-port对应上) ssl-enable: ${SSL_ENABLE:true} # 客户端连接唯一凭证 - license-key: ${LICENSE_KEY:} + license-key: ${LICENSE_KEY:ce554b47de80495b9d1996cd62084973} # 客户端唯一身份标识(可忽略,若不设置首次启动会自动生成) client-id: ${CLIENT_ID:} # 是否开启隧道传输报文日志(日志级别为debug时开启才有效) diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java index ce1197db..1782d004 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java @@ -19,7 +19,8 @@ import org.noear.solon.core.event.AppLoadEndEvent; import org.noear.solon.core.event.EventListener; /** - * HTTP代理 + * 应用加载完成事件(即启动完成)- 判断是否配置域名-配置了域名则启动HTTP代理 + * 默认端口 80 * @author: aoshiguchen * @date: 2023/4/2 */ diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpVisitorChannelHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpVisitorChannelHandler.java index 40a18a0f..3ec2f8d0 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpVisitorChannelHandler.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpVisitorChannelHandler.java @@ -19,6 +19,7 @@ import org.noear.solon.Solon; import java.net.InetSocketAddress; /** + * HTTP 访客处理器 * @author: aoshiguchen * @date: 2023/5/27 */ @@ -54,7 +55,6 @@ public class HttpVisitorChannelHandler extends SimpleChannelInboundHandler Date: Sun, 3 Mar 2024 22:36:04 +0800 Subject: [PATCH 02/15] =?UTF-8?q?=E5=9F=9F=E5=90=8D=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- neutrino-proxy-admin/package.json | 2 +- neutrino-proxy-admin/src/api/domain.js | 2 +- neutrino-proxy-admin/src/lang/zh.js | 1 + neutrino-proxy-admin/src/router/index.js | 3 +- .../src/views/proxy/domainMapping.vue | 638 ++++++++++++++++++ .../server/base/db/DBInitialize.java | 1 - .../controller/DomainNameController.java | 2 +- .../main/resources/sql/h2/init-structure.sql | 18 + 8 files changed, 662 insertions(+), 5 deletions(-) create mode 100644 neutrino-proxy-admin/src/views/proxy/domainMapping.vue diff --git a/neutrino-proxy-admin/package.json b/neutrino-proxy-admin/package.json index 3fafb115..b64788bb 100644 --- a/neutrino-proxy-admin/package.json +++ b/neutrino-proxy-admin/package.json @@ -70,7 +70,7 @@ "friendly-errors-webpack-plugin": "1.6.1", "html-webpack-plugin": "2.30.1", "node-notifier": "5.1.2", - "node-sass": "^9.0.0", + "node-sass": "4.13.1", "optimize-css-assets-webpack-plugin": "3.2.0", "ora": "1.3.0", "portfinder": "1.0.13", diff --git a/neutrino-proxy-admin/src/api/domain.js b/neutrino-proxy-admin/src/api/domain.js index d3a9f7fd..21c16e34 100644 --- a/neutrino-proxy-admin/src/api/domain.js +++ b/neutrino-proxy-admin/src/api/domain.js @@ -2,7 +2,7 @@ import request from '@/utils/request' export function domainNameBindInfo(query) { return request({ - url: '/domain-name/bind-info', + url: '/domain/bind-info', method: 'get', params: query }) diff --git a/neutrino-proxy-admin/src/lang/zh.js b/neutrino-proxy-admin/src/lang/zh.js index 998795df..e613c8d9 100644 --- a/neutrino-proxy-admin/src/lang/zh.js +++ b/neutrino-proxy-admin/src/lang/zh.js @@ -55,6 +55,7 @@ export default { proxy: '代理配置', license: 'License管理', portMapping: '端口映射', + domainMapping: '域名解析', jobManager: '调度管理', jobLog: '调度日志', log: '日志管理', diff --git a/neutrino-proxy-admin/src/router/index.js b/neutrino-proxy-admin/src/router/index.js index 47a870f2..331573a8 100644 --- a/neutrino-proxy-admin/src/router/index.js +++ b/neutrino-proxy-admin/src/router/index.js @@ -61,7 +61,8 @@ export const asyncRouterMap = [ }, children: [ { path: 'license', component: _import('proxy/license'), name: 'license', meta: { title: 'license' }}, - { path: 'portMapping', component: _import('proxy/portMapping'), name: 'portMapping', meta: { title: 'portMapping' }} + { path: 'portMapping', component: _import('proxy/portMapping'), name: 'portMapping', meta: { title: 'portMapping' }}, + { path: 'domainMapping', component: _import('proxy/domainMapping'), name: 'domainMapping', meta: { title: 'domainMapping' }} ] }, { diff --git a/neutrino-proxy-admin/src/views/proxy/domainMapping.vue b/neutrino-proxy-admin/src/views/proxy/domainMapping.vue new file mode 100644 index 00000000..5e71a596 --- /dev/null +++ b/neutrino-proxy-admin/src/views/proxy/domainMapping.vue @@ -0,0 +1,638 @@ + + + diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/db/DBInitialize.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/db/DBInitialize.java index a387e1ce..51ad71b2 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/db/DBInitialize.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/db/DBInitialize.java @@ -109,7 +109,6 @@ public class DBInitialize implements EventListener { } for (String tableName : initDataTableNameList) { // 表里没有数据的时候,才进行初始化操作 - Object result = dbContext.exe(String.format("select count(1) from `%s`", tableName)); if (result != null && ((Number) result).intValue() > 0) { continue; diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/DomainNameController.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/DomainNameController.java index 3f64d661..319a4e5b 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/DomainNameController.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/DomainNameController.java @@ -12,7 +12,7 @@ import org.noear.solon.annotation.Mapping; * @date: 2023/4/2 */ @Slf4j -@Mapping("/domain-name") +@Mapping("/domain") @Controller public class DomainNameController { @Inject diff --git a/neutrino-proxy-server/src/main/resources/sql/h2/init-structure.sql b/neutrino-proxy-server/src/main/resources/sql/h2/init-structure.sql index bfeaeda7..ba58704d 100644 --- a/neutrino-proxy-server/src/main/resources/sql/h2/init-structure.sql +++ b/neutrino-proxy-server/src/main/resources/sql/h2/init-structure.sql @@ -229,3 +229,21 @@ CREATE INDEX IF NOT EXISTS I_flow_report_month_create_time ON flow_report_month( CREATE INDEX IF NOT EXISTS I_flow_report_month_date ON flow_report_month(`date`); CREATE INDEX IF NOT EXISTS I_flow_report_month_user_id ON flow_report_month(`user_id`); CREATE INDEX IF NOT EXISTS I_flow_report_month_license_id ON flow_report_month(`license_id`); + +# 域名 映射表 +CREATE TABLE IF NOT EXISTS `domain_mapping` ( + `id` INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, + `license_id` INTEGER(20) NOT NULL, + `protocal` VARCHAR(10) NOT NULL DEFAULT 'HTTP', + `domain` VARCHAR(50) DEFAULT NULL, + `target_path` VARCHAR(50) NOT NULL, + `up_limit_rate` VARCHAR(20) DEFAULT NULL, + `down_limit_rate` VARCHAR(20) DEFAULT NULL, + `description` VARCHAR(100) DEFAULT NULL, + `request_header` INTEGER(20) NOT NULL DEFAULT 0, + `enable` INTEGER(2) NOT NULL, + `security_group_id` INTEGER(20) NOT NULL DEFAULT 0, + `create_time` TIMESTAMP NOT NULL, + `update_time` TIMESTAMP NOT NULL +); +CREATE UNIQUE INDEX IF NOT EXISTS I_domain_mapping_domain ON domain_mapping (`domain` ASC); \ No newline at end of file From 6d26c58843e81efd726116564404bcbbd3ad1e70 Mon Sep 17 00:00:00 2001 From: xiaojie <550345579@qq.com> Date: Mon, 4 Mar 2024 17:38:52 +0800 Subject: [PATCH 03/15] =?UTF-8?q?=E9=83=A8=E5=88=86=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/views/proxy/domainMapping.vue | 7 +- .../server/controller/DomainController.java | 128 +++++ .../controller/DomainNameController.java | 27 -- .../res/proxy/DomainMappingDto.java | 31 ++ .../server/dal/DomainMappingMapper.java | 112 +++++ .../server/dal/entity/DomainMappingDO.java | 110 +++++ .../server/service/DomainMappingService.java | 441 ++++++++++++++++++ .../resources/mapper/DomainMappingMapper.xml | 34 ++ .../resources/mapper/PortMappingMapper.xml | 2 +- 9 files changed, 861 insertions(+), 31 deletions(-) create mode 100644 neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/DomainController.java delete mode 100644 neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/DomainNameController.java create mode 100644 neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/res/proxy/DomainMappingDto.java create mode 100644 neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/DomainMappingMapper.java create mode 100644 neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/entity/DomainMappingDO.java create mode 100644 neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/DomainMappingService.java create mode 100644 neutrino-proxy-server/src/main/resources/mapper/DomainMappingMapper.xml diff --git a/neutrino-proxy-admin/src/views/proxy/domainMapping.vue b/neutrino-proxy-admin/src/views/proxy/domainMapping.vue index 5e71a596..bd8a6c7c 100644 --- a/neutrino-proxy-admin/src/views/proxy/domainMapping.vue +++ b/neutrino-proxy-admin/src/views/proxy/domainMapping.vue @@ -7,10 +7,10 @@ - + + @@ -277,6 +277,7 @@ export default { listQuery: { current: 1, size: 10, + domain: null, importance: undefined, title: undefined, type: undefined, diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/DomainController.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/DomainController.java new file mode 100644 index 00000000..4e94c5ea --- /dev/null +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/DomainController.java @@ -0,0 +1,128 @@ +package org.dromara.neutrinoproxy.server.controller; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.dromara.neutrinoproxy.server.base.page.PageInfo; +import org.dromara.neutrinoproxy.server.base.page.PageQuery; +import org.dromara.neutrinoproxy.server.base.proxy.ProxyConfig; +import org.dromara.neutrinoproxy.server.constant.ExceptionConstant; +import org.dromara.neutrinoproxy.server.constant.NetworkProtocolEnum; +import org.dromara.neutrinoproxy.server.controller.req.proxy.*; +import org.dromara.neutrinoproxy.server.controller.res.proxy.*; +import org.dromara.neutrinoproxy.server.service.DomainMappingService; +import org.dromara.neutrinoproxy.server.service.PortMappingService; +import org.dromara.neutrinoproxy.server.util.ParamCheckUtil; +import org.noear.solon.annotation.*; + +/** + * @author: aoshiguchen + * @date: 2023/4/2 + */ +@Slf4j +@Mapping("/domain") +@Controller +public class DomainController { + @Inject + private ProxyConfig proxyConfig; + + @Inject + private DomainMappingService domainMappingService; + + @Get + @Mapping("/bind-info") + public String bindInfo () { + return proxyConfig.getServer().getTcp().getDomainName(); + } + + + @Get + @Mapping("/page") + public PageInfo page(PageQuery pageQuery, PortMappingListReq req) { + ParamCheckUtil.checkNotNull(pageQuery, "pageQuery"); + return domainMappingService.page(pageQuery, req); + } + + @Post + @Mapping("/modify") + public PortMappingCreateRes create(PortMappingCreateReq req) { + ParamCheckUtil.checkNotNull(req, "req"); + ParamCheckUtil.checkNotNull(req.getLicenseId(), "licenseId"); + ParamCheckUtil.checkNotNull(req.getServerPort(), "serverPort"); + ParamCheckUtil.checkNotNull(req.getClientPort(), "clientPort"); + ParamCheckUtil.checkNotEmpty(req.getProtocal(), "protocal"); + ParamCheckUtil.checkMaxLength(req.getDescription(), 50, "描述", "50"); + ParamCheckUtil.checkBytesDesc(req.getUpLimitRate(), "upLimitRate"); + ParamCheckUtil.checkBytesDesc(req.getDownLimitRate(), "downLimitRate"); + if (StringUtils.isBlank(req.getClientIp())) { + // 没传客户端ip,默认为127.0.0.1 + req.setClientIp("127.0.0.1"); + } + NetworkProtocolEnum networkProtocolEnum = NetworkProtocolEnum.of(req.getProtocal()); + ParamCheckUtil.checkNotNull(networkProtocolEnum, ExceptionConstant.AN_UNSUPPORTED_PROTOCOL, req.getProtocal()); + if (networkProtocolEnum != NetworkProtocolEnum.HTTP) { + // 目前仅HTTP支持绑定域名 + req.setSubdomain(null); + } + req.setProtocal(networkProtocolEnum.getDesc()); + if (null == req.getProxyResponses()) { + req.setProxyResponses(0); + } + if (null == req.getProxyTimeoutMs()) { + req.setProxyTimeoutMs(0L); + } + if (null == req.getSecurityGroupId()) { + req.setSecurityGroupId(0); + } + + return domainMappingService.create(req); + } + + @Get + @Mapping("/one/{id}") + public DomainMappingDto one(Integer id) { + return domainMappingService.one(id); + } + + @Post + @Mapping("/update/enable-status") + public PortMappingUpdateEnableStatusRes updateEnableStatus(PortMappingUpdateEnableStatusReq req) { + ParamCheckUtil.checkNotNull(req, "req"); + ParamCheckUtil.checkNotNull(req.getId(), "id"); + ParamCheckUtil.checkNotNull(req.getEnable(), "enable"); + + return domainMappingService.updateEnableStatus(req); + } + + @Post + @Mapping("/delete") + public void delete(PortMappingDeleteReq req) { + ParamCheckUtil.checkNotNull(req, "req"); + ParamCheckUtil.checkNotNull(req.getId(), "id"); + + domainMappingService.delete(req.getId()); + } + + /** + * 绑定安全组 + * @param req portMappingId和securityGroupId + */ + @Post + @Mapping("/bind/security-group") + public void bindSecurityGroup(PortMappingBindSecurityGroupReq req) { + domainMappingService.portBindSecurityGroup(req.getId(), req.getSecurityGroupId()); + } + + /** + * 安全组解绑 + * @param id 端口映射Id + */ + @Post + @Mapping("/unbind/security-group") + public void unbindSecurityGroup(Integer id) { + domainMappingService.portUnbindSecurityGroup(id); + } + + + + +} diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/DomainNameController.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/DomainNameController.java deleted file mode 100644 index 319a4e5b..00000000 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/DomainNameController.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.dromara.neutrinoproxy.server.controller; - -import lombok.extern.slf4j.Slf4j; -import org.dromara.neutrinoproxy.server.base.proxy.ProxyConfig; -import org.noear.solon.annotation.Controller; -import org.noear.solon.annotation.Get; -import org.noear.solon.annotation.Inject; -import org.noear.solon.annotation.Mapping; - -/** - * @author: aoshiguchen - * @date: 2023/4/2 - */ -@Slf4j -@Mapping("/domain") -@Controller -public class DomainNameController { - @Inject - private ProxyConfig proxyConfig; - - @Get - @Mapping("/bind-info") - public String bindInfo () { - return proxyConfig.getServer().getTcp().getDomainName(); - } - -} diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/res/proxy/DomainMappingDto.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/res/proxy/DomainMappingDto.java new file mode 100644 index 00000000..ad05d7fe --- /dev/null +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/res/proxy/DomainMappingDto.java @@ -0,0 +1,31 @@ +package org.dromara.neutrinoproxy.server.controller.res.proxy; + + +import lombok.Data; +import lombok.experimental.Accessors; +import org.dromara.neutrinoproxy.server.dal.entity.DomainMappingDO; + +/** + * + * @author xiaojie + * @date + */ +@Accessors(chain = true) +@Data +public class DomainMappingDto extends DomainMappingDO { + + /** + * licenseId + */ + private String licenseName; + + /** + * 用户ID + */ + private Integer userId; + + /** + * 用户名称 + */ + private String userName; +} diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/DomainMappingMapper.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/DomainMappingMapper.java new file mode 100644 index 00000000..bf2c44a3 --- /dev/null +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/DomainMappingMapper.java @@ -0,0 +1,112 @@ +package org.dromara.neutrinoproxy.server.dal; + +import cn.hutool.core.collection.CollectionUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.dromara.neutrinoproxy.server.constant.EnableStatusEnum; +import org.dromara.neutrinoproxy.server.controller.req.proxy.PortMappingListReq; +import org.dromara.neutrinoproxy.server.dal.entity.DomainMappingDO; +import org.dromara.neutrinoproxy.server.dal.entity.DomainMappingDO; + +import java.util.Date; +import java.util.List; +import java.util.Set; + +/** + * + * @author: aoshiguchen + * @date: 2022/8/8 + */ +@Mapper +public interface DomainMappingMapper extends BaseMapper { + + default DomainMappingDO findById(Integer id) { + return this.selectById(id); + } + + default void updateEnableStatus(Integer id, Integer enable, Date updateTime) { + this.update(null, new LambdaUpdateWrapper() + .eq(DomainMappingDO::getId, id) + .set(DomainMappingDO::getEnable, enable) + .set(DomainMappingDO::getUpdateTime, updateTime) + ); + } + + default DomainMappingDO findByDomain(String domain, Set excludeIds) { + return this.selectOne(new LambdaQueryWrapper() + .eq(DomainMappingDO::getDomain, domain) + .notIn(!CollectionUtil.isEmpty(excludeIds), DomainMappingDO::getId, excludeIds) + .last("limit 1") + ); + } + + /** + * 校验域名是否重复 + * @param subdomain + * @return + */ + default Boolean checkRepeatByDomain(String subdomain, Set excludeIds) { + return StringUtils.isEmpty(subdomain)? Boolean.FALSE : this.selectCount(new LambdaQueryWrapper() + .eq(DomainMappingDO::getDomain, subdomain) + .notIn(!CollectionUtil.isEmpty(excludeIds), DomainMappingDO::getId, excludeIds) + ).intValue() > 0; + } + + default List findEnableListByLicenseId(Integer licenseId) { + return this.selectList(new LambdaQueryWrapper() + .eq(DomainMappingDO::getLicenseId, licenseId) + .eq(DomainMappingDO::getEnable, EnableStatusEnum.ENABLE.getStatus()) + ); + } + + default List findListByServerPort(Integer serverPort) { + return this.selectList(new LambdaQueryWrapper() + .eq(DomainMappingDO::getServerPort, serverPort) + ); + } + + default List findListByLicenseId(Integer licenseId) { + return this.selectList(new LambdaQueryWrapper() + .eq(DomainMappingDO::getLicenseId, licenseId) + ); + } + + default DomainMappingDO findByLicenseIdAndServerPort(Integer licenseId, Integer serverPort) { + return this.selectOne(new LambdaQueryWrapper() + .eq(DomainMappingDO::getLicenseId, licenseId) + .eq(DomainMappingDO::getServerPort, serverPort) + .last("limit 1") + ); + } + + default void updateOnlineStatus(Integer licenseId,Integer serverPort, Integer isOnline, Date updateTime) { + this.update(null, new LambdaUpdateWrapper() + .eq(DomainMappingDO::getLicenseId, licenseId) + .eq(DomainMappingDO::getServerPort, serverPort) + .set(DomainMappingDO::getIsOnline, isOnline) + .set(DomainMappingDO::getUpdateTime, updateTime) + ); + } + + default void updateOnlineStatus(Integer licenseId, Integer isOnline, Date updateTime) { + this.update(null, new LambdaUpdateWrapper() + .eq(DomainMappingDO::getLicenseId, licenseId) + .set(DomainMappingDO::getIsOnline, isOnline) + .set(DomainMappingDO::getUpdateTime, updateTime) + ); + } + + default void updateOnlineStatus(Integer isOnline, Date updateTime) { + this.update(null, new LambdaUpdateWrapper() + .set(DomainMappingDO::getIsOnline, isOnline) + .set(DomainMappingDO::getUpdateTime, updateTime) + ); + } + + List selectDomainMappingByCondition(IPage page, @Param("req") PortMappingListReq req); +} diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/entity/DomainMappingDO.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/entity/DomainMappingDO.java new file mode 100644 index 00000000..c87ceb1a --- /dev/null +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/entity/DomainMappingDO.java @@ -0,0 +1,110 @@ +/** + * 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 org.dromara.neutrinoproxy.server.dal.entity; + +import cn.hutool.core.bean.BeanUtil; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.ToString; +import lombok.experimental.Accessors; +import org.dromara.neutrinoproxy.server.constant.EnableStatusEnum; +import org.dromara.neutrinoproxy.server.constant.OnlineStatusEnum; +import org.dromara.neutrinoproxy.server.controller.res.proxy.DomainMappingDto; +import org.dromara.neutrinoproxy.server.controller.res.proxy.PortMappingListRes; + +import java.util.Date; + +/** + * 端口映射 + * @author: aoshiguchen + * @date: 2022/8/8 + */ +@ToString +@Accessors(chain = true) +@Data +@TableName("domain_mapping") +public class DomainMappingDO { + @TableId(type = IdType.AUTO) + private Integer id; + /** + * licenseId + */ + private Integer licenseId; + /** + * 协议 + */ + private String protocal; + /** + * 域名 + */ + private String domain; + /** + * 描述 + */ + private String description; + /** + * 目标地址(licenseId客户端,ip:port) + */ + private String targetPath; + /** + * 上传限速 + */ + private String upLimitRate; + /** + * 下载限速 + */ + private String downLimitRate; + + /** + * 是否在线 + * {@link OnlineStatusEnum} + */ + @TableField(exist=false) + private Integer isOnline; + + /** + * 启用状态 + * {@link EnableStatusEnum} + */ + private Integer enable; + + /** + * 安全组Id + */ + private Integer securityGroupId = 0; // 设置为null不生效,不知道为啥 + + /** + * 创建时间 + */ + private Date createTime; + /** + * 更新时间 + */ + private Date updateTime; + + public DomainMappingDto toRes() { + return (DomainMappingDto) this; + } +} diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/DomainMappingService.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/DomainMappingService.java new file mode 100644 index 00000000..9d92a1cb --- /dev/null +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/DomainMappingService.java @@ -0,0 +1,441 @@ +package org.dromara.neutrinoproxy.server.service; + +import cn.hutool.cache.Cache; +import cn.hutool.cache.CacheUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.solon.plugins.pagination.Page; +import com.google.common.collect.Sets; +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; +import org.dromara.neutrinoproxy.server.base.proxy.ProxyConfig; +import org.dromara.neutrinoproxy.server.base.rest.SystemContextHolder; +import org.dromara.neutrinoproxy.server.constant.EnableStatusEnum; +import org.dromara.neutrinoproxy.server.constant.ExceptionConstant; +import org.dromara.neutrinoproxy.server.constant.NetworkProtocolEnum; +import org.dromara.neutrinoproxy.server.constant.OnlineStatusEnum; +import org.dromara.neutrinoproxy.server.controller.req.proxy.PortMappingCreateReq; +import org.dromara.neutrinoproxy.server.controller.req.proxy.PortMappingListReq; +import org.dromara.neutrinoproxy.server.controller.req.proxy.PortMappingUpdateEnableStatusReq; +import org.dromara.neutrinoproxy.server.controller.req.proxy.PortMappingUpdateReq; +import org.dromara.neutrinoproxy.server.controller.res.proxy.*; +import org.dromara.neutrinoproxy.server.dal.DomainMappingMapper; +import org.dromara.neutrinoproxy.server.dal.LicenseMapper; +import org.dromara.neutrinoproxy.server.dal.PortPoolMapper; +import org.dromara.neutrinoproxy.server.dal.UserMapper; +import org.dromara.neutrinoproxy.server.dal.entity.*; +import org.dromara.neutrinoproxy.server.service.bo.FlowLimitBO; +import org.dromara.neutrinoproxy.server.util.ParamCheckUtil; +import org.dromara.neutrinoproxy.server.util.ProxyUtil; +import org.dromara.neutrinoproxy.server.util.StringUtil; +import org.noear.solon.annotation.Component; +import org.noear.solon.annotation.Init; +import org.noear.solon.annotation.Inject; +import org.noear.solon.core.bean.LifecycleBean; +import org.noear.solon.core.runtime.NativeDetector; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * + * 域名解析 service + * author xiaojie + */ +@Component +public class DomainMappingService implements LifecycleBean { + @Db + private DomainMappingMapper domainMappingMapper; + @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 LicenseService licenseService; + + /** 端口到安全组Id的映射 */ + private final Map mappingDomainToSecurityGroupMap = new ConcurrentHashMap<>(); + /** + * 域名 到 域名解析id的映射 + */ + private final Cache domainToDomainMappingIdCache = CacheUtil.newLRUCache(500, 1000 * 60 * 10); + // 域名解析id到licenseId + private final Cache idToLicenseIdCache = CacheUtil.newLRUCache(500, 1000 * 60 * 10); + // 流量限制缓存 + private final Cache flowLimitCache = CacheUtil.newLRUCache(500, 1000 * 60 * 5); + + public PageInfo page(PageQuery pageQuery, PortMappingListReq req) { + if (StringUtils.isNotEmpty(req.getDescription())) { + //描述字段为模糊查询,在应用层处理,否则sqlite不支持 + req.setDescription("%" + req.getDescription() + "%"); + } + + // 协议名称转换 + if (StringUtils.isNotBlank(req.getProtocal())) { + NetworkProtocolEnum networkProtocolEnum = NetworkProtocolEnum.of(req.getProtocal()); + req.setProtocal(networkProtocolEnum.getDesc()); + } + + Page page = new Page<>(pageQuery.getCurrent(), pageQuery.getSize()); + List list = domainMappingMapper.selectDomainMappingByCondition(page, req); + List respList = list.stream().map(DomainMappingDO::toRes).collect(Collectors.toList()); + if (CollectionUtils.isEmpty(list)) { + return PageInfo.of(respList, page.getTotal(), pageQuery.getCurrent(), pageQuery.getSize()); + } + + Set licenseIds = respList.stream().map(DomainMappingDto::getLicenseId).collect(Collectors.toSet()); + List licenseList = licenseMapper.findByIds(licenseIds); + if (CollectionUtil.isEmpty(licenseList)) { + return PageInfo.of(respList, page.getTotal(), pageQuery.getCurrent(), pageQuery.getSize()); + } + Set userIds = licenseList.stream().map(LicenseDO::getUserId).collect(Collectors.toSet()); + List userList = userMapper.findByIds(userIds); + Map licenseMap = licenseList.stream().collect(Collectors.toMap(LicenseDO::getId, Function.identity())); + Map userMap = userList.stream().collect(Collectors.toMap(UserDO::getId, Function.identity())); + + respList.forEach(item -> { + LicenseDO license = licenseMap.get(item.getLicenseId()); + if (null == license) { + return; + } + item.setLicenseName(license.getName()); + item.setUserId(license.getUserId()); + UserDO user = userMap.get(license.getUserId()); + if (null == user) { + return; + } + item.setUserName(user.getName()); +// if (StrUtil.isNotBlank(proxyConfig.getServer().getTcp().getDomainName()) && StrUtil.isNotBlank(item.getDomain())) { +// item.setDomain(item.getDomain() + "." + proxyConfig.getServer().getTcp().getDomainName()); +// } + if (NetworkProtocolEnum.HTTP.getDesc().equals(item.getProtocal())) { + item.setProtocal("HTTP(S)"); + } + }); + //sorted [userId asc] [licenseId asc] [createTime asc] + respList = respList.stream() + .filter(e -> null != e.getUserId()) + .sorted(Comparator.comparing(DomainMappingDto::getUserId).thenComparing(DomainMappingDto::getLicenseId).thenComparing(DomainMappingDto::getCreateTime)).collect(Collectors.toList()); + return PageInfo.of(respList, page.getTotal(), pageQuery.getCurrent(), pageQuery.getSize()); + } + + public PortMappingCreateRes modify(DomainMappingDto req) { + LicenseDO licenseDO = licenseMapper.findById(req.getLicenseId()); + ParamCheckUtil.checkNotNull(licenseDO, ExceptionConstant.LICENSE_NOT_EXIST); + if (!SystemContextHolder.isAdmin()) { + // 临时处理,如果当前用户不是管理员,则操作userId不能为1 + ParamCheckUtil.checkExpression(!licenseDO.getUserId().equals(1), ExceptionConstant.NO_PERMISSION_VISIT); + } + PortPoolDO portPoolDO = portPoolMapper.findByPort(req.getDomain()); + ParamCheckUtil.checkNotNull(portPoolDO, ExceptionConstant.PORT_NOT_EXIST); + ParamCheckUtil.checkExpression(null == domainMappingMapper.findByDomain(req.getDomain(), null), ExceptionConstant.PORT_CANNOT_REPEAT_MAPPING, req.getDomain()); + ParamCheckUtil.checkExpression(!domainMappingMapper.checkRepeatByDomain(req.getDomain(), null), ExceptionConstant.PORT_MAPPING_SUBDONAME_CONNOT_REPEAT); + + Date now = new Date(); + PortMappingDO portMappingDO = ; + portMappingDO.setLicenseId(req.getLicenseId()); + portMappingDO.setProtocal(req.getProtocal()); + portMappingDO.setSubdomain(req.getSubdomain()); + portMappingDO.setServerPort(req.getServerPort()); + portMappingDO.setClientIp(req.getClientIp()); + portMappingDO.setClientPort(req.getClientPort()); + portMappingDO.setUpLimitRate(req.getUpLimitRate()); + portMappingDO.setDownLimitRate(req.getDownLimitRate()); + portMappingDO.setProxyResponses(req.getProxyResponses()); + portMappingDO.setProxyTimeoutMs(req.getProxyTimeoutMs()); + portMappingDO.setDescription(req.getDescription()); + portMappingDO.setIsOnline(OnlineStatusEnum.OFFLINE.getStatus()); + portMappingDO.setEnable(EnableStatusEnum.ENABLE.getStatus()); + portMappingDO.setCreateTime(now); + portMappingDO.setUpdateTime(now); + domainMappingMapper.insert(portMappingDO); + // 更新VisitorChannel + visitorChannelService.addVisitorChannelByPortMapping(portMappingDO); + // 更新域名映射 + if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) && StrUtil.isNotBlank(proxyConfig.getServer().getTcp().getDomainName()) && StrUtil.isNotBlank(portMappingDO.getSubdomain())) { + ProxyUtil.setSubdomainToServerPort(portMappingDO.getSubdomain(), portMappingDO.getServerPort()); + } + + updateMappingDomainToSecurityGroupMap(portMappingDO.getServerPort(), req.getSecurityGroupId()); + + // 更新端口到映射的缓存 + domainToDomainMappingIdCache.put(req.getServerPort(), portMappingDO.getId()); + // 更新端口映射到licenseId的缓存 + idToLicenseIdCache.put(portMappingDO.getId(), portMappingDO.getLicenseId()); + // 刷新流量限制缓存 + refreshFlowLimitCache(portMappingDO.getId(), portMappingDO.getUpLimitRate(), portMappingDO.getDownLimitRate()); + + return new PortMappingCreateRes(); + } + + + + public PortMappingUpdateEnableStatusRes updateEnableStatus(PortMappingUpdateEnableStatusReq req) { + PortMappingDO portMappingDO = domainMappingMapper.findById(req.getId()); + ParamCheckUtil.checkNotNull(portMappingDO, ExceptionConstant.PORT_MAPPING_NOT_EXIST); + + LicenseDO licenseDO = licenseMapper.findById(portMappingDO.getLicenseId()); + ParamCheckUtil.checkNotNull(licenseDO, ExceptionConstant.LICENSE_NOT_EXIST); + if (!SystemContextHolder.isAdmin()) { + ParamCheckUtil.checkExpression(!licenseDO.getUserId().equals(1), ExceptionConstant.NO_PERMISSION_VISIT); + } + + domainMappingMapper.updateEnableStatus(req.getId(), req.getEnable(), new Date()); + + // 更新VisitorChannel + portMappingDO.setEnable(req.getEnable()); + if (EnableStatusEnum.ENABLE == EnableStatusEnum.of(req.getEnable())) { + visitorChannelService.addVisitorChannelByPortMapping(portMappingDO); + } else { + visitorChannelService.removeVisitorChannelByPortMapping(portMappingDO); + } + + return new PortMappingUpdateEnableStatusRes(); + } + + public void delete(Integer id) { + PortMappingDO portMappingDO = domainMappingMapper.findById(id); + ParamCheckUtil.checkNotNull(portMappingDO, ExceptionConstant.PORT_MAPPING_NOT_EXIST); + + LicenseDO licenseDO = licenseMapper.findById(portMappingDO.getLicenseId()); + if (null != licenseDO && !SystemContextHolder.isAdmin()) { + // 临时处理,如果当前用户不是管理员,则操作userId不能为1 + ParamCheckUtil.checkExpression(!licenseDO.getUserId().equals(1), ExceptionConstant.NO_PERMISSION_VISIT); + } + + domainMappingMapper.deleteById(id); + + // 更新VisitorChannel + visitorChannelService.removeVisitorChannelByPortMapping(portMappingDO); + // 更新域名映射 + if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) && StrUtil.isNotBlank(portMappingDO.getSubdomain())) { + ProxyUtil.removeSubdomainToServerPort(portMappingDO.getSubdomain()); + } + + updateMappingDomainToSecurityGroupMap(portMappingDO.getServerPort(), null); + + // 删除id到licenseId的映射 + idToLicenseIdCache.remove(id); + // 删除流量限制缓存 + flowLimitCache.remove(id); + } + + public void portBindSecurityGroup(Integer portMappingId, Integer groupId) { + PortMappingDO mappingDO = domainMappingMapper.findById(portMappingId); + if (mappingDO == null) { + throw new RuntimeException("指定的端口映射不存在"); + } + mappingDO.setSecurityGroupId(groupId); + mappingDO.setUpdateTime(new Date()); + domainMappingMapper.updateById(mappingDO); + updateMappingDomainToSecurityGroupMap(mappingDO.getServerPort(), groupId); + } + + public void portUnbindSecurityGroup(Integer portMappingId) { + PortMappingDO mappingDO = domainMappingMapper.findById(portMappingId); + if (mappingDO == null) { + throw new RuntimeException("指定的端口映射不存在"); + } + mappingDO.setSecurityGroupId(0); + mappingDO.setUpdateTime(new Date()); + domainMappingMapper.updateById(mappingDO); + updateMappingDomainToSecurityGroupMap(mappingDO.getServerPort(), null); + } + + /** + * 根据license查询可用的端口映射列表 + * + * @param licenseId + * @return + */ + public List findEnableListByLicenseId(Integer licenseId) { + return domainMappingMapper.findEnableListByLicenseId(licenseId); + } + + public Integer getSecurityGroupIdByMappingPort(Integer port) { + return mappingDomainToSecurityGroupMap.get(port); + } + + + /** + * 服务端项目停止、启动时,更新在线状态为离线 + */ + @Init + public void init() { + // aot 阶段,不初始化 + if (NativeDetector.isAotRuntime()) { + return; + } + // 服务刚启动,所以默认所有license都是离线状态。解决服务突然关闭,在线状态来不及更新的问题 + domainMappingMapper.updateOnlineStatus(OnlineStatusEnum.OFFLINE.getStatus(), new Date()); + + List allMappingDOList = domainMappingMapper.selectList(Wrappers.lambdaQuery(DomainMappingDO.class)); + allMappingDOList.forEach(item -> { + Integer securityGroupId = item.getSecurityGroupId(); + if (securityGroupId != null && securityGroupId > 0) { + updateMappingDomainToSecurityGroupMap(item.getDomain(), item.getSecurityGroupId()); + } + // 更新端口到映射的缓存 + domainToDomainMappingIdCache.put(item.getDomain(), item.getId()); + // 更新端口映射到licenseId的缓存 + idToLicenseIdCache.put(item.getId(), item.getLicenseId()); + // 刷新流量限制缓存 + refreshFlowLimitCache(item.getId(), item.getUpLimitRate(), item.getDownLimitRate()); + }); + + // 未配置域名,则不需要处理域名映射逻辑 + if (StrUtil.isBlank(proxyConfig.getServer().getTcp().getDomainName())) { + return; + } + List portMappingDOList = allMappingDOList.stream() + .filter(item -> NetworkProtocolEnum.HTTP.getDesc().equals(item.getProtocal()) && item.getDomain() != null) + .collect(Collectors.toList()); + if (CollectionUtil.isEmpty(portMappingDOList)) { + return; + } + portMappingDOList.forEach(item -> { + if (StrUtil.isBlank(item.getSubdomain())) { + return; + } + ProxyUtil.setSubdomainToServerPort(item.getSubdomain(), item.getServerPort()); + + }); + } + + /** + * 刷新流量限制缓存 + * @param id + * @param upLimitRate + * @param downLimitRate + */ + private void refreshFlowLimitCache(Integer id, String upLimitRate, String downLimitRate) { + if (null == id) { + return; + } + flowLimitCache.put(id, new FlowLimitBO() + .setUpLimitRate(StringUtil.parseBytes(upLimitRate)) + .setDownLimitRate(StringUtil.parseBytes(downLimitRate)) + ); + } + + /** + * 获取license的流量限制 + * @param id + * @return + */ + public FlowLimitBO getFlowLimit(Integer id) { + FlowLimitBO res = flowLimitCache.get(id); + if (null == res) { + DomainMappingDO domainMappingDO = domainMappingMapper.findById(id); + if (null != domainMappingDO) { + refreshFlowLimitCache(id, domainMappingDO.getUpLimitRate(), domainMappingDO.getDownLimitRate()); + res = flowLimitCache.get(id); + } + } + return res; + } + + public Integer getDomainMappingIdByServerPort(Integer serverPort) { + if (null == serverPort) { + return null; + } + Integer id = domainToDomainMappingIdCache.get(serverPort); + if (null != id) { + return id; + } + List domainMappingDOList = domainMappingMapper.findListByServerPort(serverPort); + // 不存在 或者 有多条记录,都不处理 + if (CollectionUtils.isEmpty(domainMappingDOList) || domainMappingDOList.size() > 1) { + return null; + } + id = domainMappingDOList.get(0).getId(); + domainToDomainMappingIdCache.put(serverPort, id); + return id; + } + + public Integer getLicenseIdById(Integer id) { + Integer licenseId = idToLicenseIdCache.get(id); + if (null == licenseId) { + DomainMappingDO domainMappingDO = domainMappingMapper.findById(id); + if (null != domainMappingDO) { + licenseId = domainMappingDO.getLicenseId(); + idToLicenseIdCache.put(id, licenseId); + } + } + return licenseId; + } + + public FlowLimitBO getFlowLimitByServerPort(Integer serverPort) { + Integer id = getPortMappingIdByServerPort(serverPort); + if (null == id) { + return null; + } + FlowLimitBO res = getFlowLimit(id); + if (null == res || (null == res.getUpLimitRate() && null == res.getDownLimitRate())) { + Integer licenseId = getLicenseIdById(id); + if (null != licenseId) { + res = licenseService.getFlowLimit(licenseId); + } + } + return res; + } + + private void updateMappingDomainToSecurityGroupMap(Integer serverPort, Integer securityGroupId) { + if (securityGroupId == null || securityGroupId == 0) { + mappingDomainToSecurityGroupMap.remove(serverPort); + return; + } + mappingDomainToSecurityGroupMap.put(serverPort, securityGroupId); + } + + @Override + public void start() throws Throwable { + + } + + /** + * 服务端项目停止、启动时,更新在线状态为离线 + */ + @Override + public void stop() throws Throwable { + domainMappingMapper.updateOnlineStatus(OnlineStatusEnum.OFFLINE.getStatus(), new Date()); + } + + public DomainMappingDto one(Integer id) { + DomainMappingDO domainMappingDO = domainMappingMapper.findById(id); + if (null == domainMappingDO) { + return null; + } + DomainMappingDto res = (DomainMappingDto)domainMappingDO; + + LicenseDO license = licenseMapper.findById(domainMappingDO.getLicenseId()); + if (null != license) { + res.setLicenseName(license.getName()); + res.setUserId(license.getUserId()); + UserDO user = userMapper.findById(license.getUserId()); + if (null != user) { + res.setUserName(user.getName()); + } + } + return res; + } +} diff --git a/neutrino-proxy-server/src/main/resources/mapper/DomainMappingMapper.xml b/neutrino-proxy-server/src/main/resources/mapper/DomainMappingMapper.xml new file mode 100644 index 00000000..8d169bdd --- /dev/null +++ b/neutrino-proxy-server/src/main/resources/mapper/DomainMappingMapper.xml @@ -0,0 +1,34 @@ + + + + + + \ No newline at end of file diff --git a/neutrino-proxy-server/src/main/resources/mapper/PortMappingMapper.xml b/neutrino-proxy-server/src/main/resources/mapper/PortMappingMapper.xml index 22348ef9..72b473d0 100644 --- a/neutrino-proxy-server/src/main/resources/mapper/PortMappingMapper.xml +++ b/neutrino-proxy-server/src/main/resources/mapper/PortMappingMapper.xml @@ -2,7 +2,7 @@ - SELECT pm.* from port_mapping pm left join license on pm.license_id = license.`id` From aca5fb847bb8648df2e90ebcf727e11d9e31936b Mon Sep 17 00:00:00 2001 From: xj <550345579@qq.com> Date: Mon, 4 Mar 2024 21:35:03 +0800 Subject: [PATCH 04/15] =?UTF-8?q?=E5=9F=9F=E5=90=8D=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/views/proxy/domainMapping.vue | 265 +++--------------- .../src/views/proxy/portMapping.vue | 63 +---- .../server/controller/DomainController.java | 51 +--- .../PortMappingUpdateEnableStatusReq.java | 3 + .../server/dal/DomainMappingMapper.java | 34 +-- .../server/service/DomainMappingService.java | 119 ++++---- .../resources/mapper/DomainMappingMapper.xml | 8 +- .../resources/mapper/PortMappingMapper.xml | 2 +- 8 files changed, 121 insertions(+), 424 deletions(-) diff --git a/neutrino-proxy-admin/src/views/proxy/domainMapping.vue b/neutrino-proxy-admin/src/views/proxy/domainMapping.vue index bd8a6c7c..8d49f298 100644 --- a/neutrino-proxy-admin/src/views/proxy/domainMapping.vue +++ b/neutrino-proxy-admin/src/views/proxy/domainMapping.vue @@ -10,12 +10,12 @@ - + - + - + {{ @@ -54,7 +54,6 @@ - @@ -92,19 +91,19 @@ @@ -113,8 +112,7 @@ {{ $t('table.edit') }} {{ $t('table.disable') }} {{ $t('table.enable') }} - - + @@ -128,58 +126,21 @@ - - - - - - - - - - - - - + + + + - - - - - + + - - - - - - - - - - - - - - - @@ -223,38 +184,20 @@ import { fetchList, createUserPortMapping, updateUserPortMapping, updateEnableSt import { fetchGroupList } from '@/api/securityGroup' import { availablePortList, portAvailable } from '@/api/portPool' import { licenseList, licenseAuthList } from '@/api/license' -import { protocalList } from '@/api/protocal' import { userList } from '@/api/user' import { domainNameBindInfo } from '@/api/domain' import waves from '@/directive/waves' // 水波纹指令 import { parseTime } from '@/utils' import ButtonPopover from '../../components/Button/buttonPopover' import DropdownTable from '../../components/Dropdown/DropdownTable' -// 下拉选择加载组件 -import loadSelect from "@/components/Select/SelectLoadMore"; - -const calendarTypeOptions = [ - { key: 'CN', display_name: 'China' }, - { key: 'US', display_name: 'USA' }, - { key: 'JP', display_name: 'Japan' }, - { key: 'EU', display_name: 'Eurozone' } -] - -// arr to obj ,such as { CN : "China", US : "USA" } -const calendarTypeKeyValue = calendarTypeOptions.reduce((acc, cur) => { - acc[cur.key] = cur.display_name - return acc -}, {}) - export default { - name: 'complexTable', + name: 'DmainMaping', directives: { waves }, components: { DropdownTable, - ButtonPopover, - loadSelect + ButtonPopover }, data() { const isPortAvailable = (rule, value, callback) => { @@ -278,7 +221,6 @@ export default { current: 1, size: 10, domain: null, - importance: undefined, title: undefined, type: undefined, userId: undefined, @@ -287,33 +229,32 @@ export default { isOnline: undefined, enable: undefined, description: undefined - }, - importanceOptions: [1, 2, 3], - calendarTypeOptions, - sortOptions: [{ label: 'ID Ascending', key: '+id' }, { label: 'ID Descending', key: '-id' }], - statusOptions: ['published', 'draft', 'deleted'], userList: [], licenseList: [], - protocalList: [], licenseAuthList: [], - serverPortList: [], domainName: '', showReviewer: false, temp: { id: undefined, licenseId: undefined, licenseName: undefined, - serverPort: undefined, clientIp: undefined, clientPort: undefined, - protocal: undefined, proxyResponses: undefined, proxyTimeoutMs: undefined }, - selectObj: { - statusOptions: [{ label: '启用', value: 1 }, { label: '禁用', value: 2 }], - onlineOptions: [{ label: '在线', value: 1 }, { label: '离线', value: 2 }] + statusOptions: { + 1: '启用', + 2: '禁用', + }, + onlineOptions: { + 1: '在线', + 2: '离线' + }, + colorOption: { + 1: 'success', + 2: 'danger' }, dialogFormVisible: false, dialogStatus: '', @@ -330,54 +271,18 @@ export default { ], clientIp: [{ required: true, message: '请输入客户端IP', trigger: 'blur' }], clientPort: [{ required: true, message: '请输入客户端端口', trigger: 'blur' }], - protocal: [{ required: true, message: '请选择协议', trigger: 'blur' }] - }, - downloadLoading: false, - countryColumns: [ - { prop: 'userName', label: '用户名', align: 'center' }, - { prop: 'name', label: 'License', align: 'center' } - ], - loadServerPortQuery: { //下拉框加载数据请求参数 - page: 1, - size: 50, - licenseId: null, }, more: true, securityGroupList: [] } }, - filters: { - statusName(status) { - const statusMap = { - 1: '启用', - 2: '禁用' - } - return statusMap[status] - }, - isOnlineName(isOnline) { - const isOnlineMap = { - 1: '在线', - 2: '离线' - } - return isOnlineMap[isOnline] - }, - statusFilter(status) { - const statusMap = { - 1: 'success', - 2: 'danger' - } - return statusMap[status] - }, - typeFilter(type) { - return calendarTypeKeyValue[type] - } - }, + // filters: { + // }, created() { this.getDomainNameBindInfo() this.getDataList() this.getLicenseList() this.getLicenseAuthList() - this.getProtocalList() this.fetchSecurityGroupList() }, methods: { @@ -412,10 +317,6 @@ export default { this.domainName = response.data.data }) }, - getAvailablePortList(licenseId) { - this.loadServerPortQuery.licenseId = licenseId; - this.serverPortList = []; //清掉数据 - }, getAllUserList() { userList().then(response => { this.userList = response.data.data @@ -426,11 +327,6 @@ export default { this.licenseList = response.data.data }) }, - getProtocalList() { - protocalList().then(response => { - this.protocalList = response.data.data - }) - }, getLicenseAuthList() { licenseAuthList().then(response => { this.licenseAuthList = response.data.data @@ -465,15 +361,12 @@ export default { id: undefined, licenseId: undefined, licenseName: undefined, - serverPort: undefined, clientIp: '127.0.0.1', clientPort: undefined, userId: undefined, proxyResponses: undefined, proxyTimeoutMs: undefined } - this.serverPortList = [] - this.loadServerPortQuery.licenseId = null; this.more = true; }, handleCreate() { @@ -502,36 +395,12 @@ export default { } }) }, - handleOpenWebPage(row) { - let url = location.protocol + '//' + location.hostname + ':' + row.serverPort - if (row.domain) { - url = location.protocol + '//' + row.domain - } - open(url) - }, - handleUpdate(row) { - this.temp = Object.assign({}, row) // copy obj - if (row.securityGroupId === 0) { - this.temp.securityGroupId = null - } - this.temp.timestamp = new Date(this.temp.timestamp) - this.dialogStatus = 'update' - this.dialogFormVisible = true - this.$nextTick(() => { - this.$refs['dataForm'].clearValidate() - }) - this.getAvailablePortList(row.licenseId) - }, updateData() { this.$refs['dataForm'].validate((valid) => { if (valid) { const tempData = Object.assign({}, this.temp) updateUserPortMapping(tempData).then(response => { if (response.data.code === 0) { - // this.$message({ - // message: '操作成功', - // type: 'success' - // }) this.$notify({ title: '成功', message: '更新成功', @@ -545,11 +414,25 @@ export default { } }) }, + handleOpenWebPage(row) { + open(location.protocol + '//' + row.domain) + }, + handleUpdate(row) { + this.temp = Object.assign({}, row) // copy obj + if (row.securityGroupId === 0) { + this.temp.securityGroupId = null + } + this.temp.timestamp = new Date(this.temp.timestamp) + this.dialogStatus = 'update' + this.dialogFormVisible = true + this.$nextTick(() => { + this.$refs['dataForm'].clearValidate() + }) + }, selectedFeeItem(row, list) { if (this.temp.licenseId !== row.id) { this.temp.licenseId = row.id this.temp.licenseName = row.name - this.getAvailablePortList(row.id) this.temp.serverPort = null } }, @@ -572,68 +455,6 @@ export default { }) }).catch(() => { }) }, - handleDelete2(row) { - deletePortMapping(row.id).then(response => { - if (response.data.code === 0) { - this.$notify({ - title: '成功', - message: '删除成功', - type: 'success', - duration: 2000 - }) - this.getList() - } - }) - }, - handleDownload() { - this.downloadLoading = true - import('@/vendor/Export2Excel').then(excel => { - const tHeader = ['timestamp', 'title', 'type', 'importance', 'status'] - const filterVal = ['timestamp', 'title', 'type', 'importance', 'status'] - const data = this.formatJson(filterVal, this.list) - excel.export_json_to_excel(tHeader, data, 'table-list') - this.downloadLoading = false - }) - }, - formatJson(filterVal, jsonData) { - return jsonData.map(v => filterVal.map(j => { - if (j === 'timestamp') { - return parseTime(v[j]) - } else { - return v[j] - } - })) - }, - // 传入给load-select组件的函数 - loadServerPort({ page = 1, more = false, keyword = "" } = {}) { - if (this.loadServerPortQuery.licenseId == null || this.loadServerPortQuery.licenseId == '') { - this.more = false; - this.$message({ - message: '请先选择License', - type: 'warning' - }) - return; - } - return new Promise(resolve => { - this.loadServerPortQuery.page = page; - this.loadServerPortQuery.keyword = keyword; - // 访问后端接口API - availablePortList(this.loadServerPortQuery).then(res => { - let result = res.data; - if (more) { - this.serverPortList = [...this.serverPortList, ...result.data.records]; - } else { - this.serverPortList = result.data.records; - } - - // this.loadServerPortQuery.page = result.data.current; - let { total, current, size } = result.data; - this.more = page * size < total; - this.loadServerPortQuery.page = current; - resolve(); - }); - }); - } } } diff --git a/neutrino-proxy-admin/src/views/proxy/portMapping.vue b/neutrino-proxy-admin/src/views/proxy/portMapping.vue index 597edaf6..29864686 100644 --- a/neutrino-proxy-admin/src/views/proxy/portMapping.vue +++ b/neutrino-proxy-admin/src/views/proxy/portMapping.vue @@ -105,9 +105,7 @@ {{ $t('table.edit') }} {{$t('table.disable')}} {{ $t('table.enable') }} - - - + @@ -122,26 +120,9 @@ - - - - - - - - @@ -232,20 +213,6 @@ import ButtonPopover from '../../components/Button/buttonPopover' import DropdownTable from '../../components/Dropdown/DropdownTable' // 下拉选择加载组件 import loadSelect from "@/components/Select/SelectLoadMore"; - -const calendarTypeOptions = [ - { key: 'CN', display_name: 'China' }, - { key: 'US', display_name: 'USA' }, - { key: 'JP', display_name: 'Japan' }, - { key: 'EU', display_name: 'Eurozone' } -] - -// arr to obj ,such as { CN : "China", US : "USA" } -const calendarTypeKeyValue = calendarTypeOptions.reduce((acc, cur) => { - acc[cur.key] = cur.display_name - return acc -}, {}) - export default { name: 'complexTable', directives: { @@ -277,7 +244,6 @@ export default { listQuery: { current: 1, size: 10, - importance: undefined, title: undefined, type: undefined, userId: undefined, @@ -288,7 +254,6 @@ export default { description: undefined }, - importanceOptions: [1, 2, 3], calendarTypeOptions, sortOptions: [{ label: 'ID Ascending', key: '+id' }, { label: 'ID Descending', key: '-id' }], statusOptions: ['published', 'draft', 'deleted'], @@ -367,9 +332,6 @@ export default { } return statusMap[status] }, - typeFilter(type) { - return calendarTypeKeyValue[type] - } }, created() { this.getDomainNameBindInfo() @@ -571,29 +533,6 @@ export default { }) }).catch(() => { }) }, - handleDelete2(row) { - deletePortMapping(row.id).then(response => { - if (response.data.code === 0) { - this.$notify({ - title: '成功', - message: '删除成功', - type: 'success', - duration: 2000 - }) - this.getList() - } - }) - }, - handleDownload() { - this.downloadLoading = true - import('@/vendor/Export2Excel').then(excel => { - const tHeader = ['timestamp', 'title', 'type', 'importance', 'status'] - const filterVal = ['timestamp', 'title', 'type', 'importance', 'status'] - const data = this.formatJson(filterVal, this.list) - excel.export_json_to_excel(tHeader, data, 'table-list') - this.downloadLoading = false - }) - }, formatJson(filterVal, jsonData) { return jsonData.map(v => filterVal.map(j => { if (j === 'timestamp') { diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/DomainController.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/DomainController.java index 4e94c5ea..abf62019 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/DomainController.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/DomainController.java @@ -37,44 +37,22 @@ public class DomainController { @Get @Mapping("/page") - public PageInfo page(PageQuery pageQuery, PortMappingListReq req) { + public PageInfo page(PageQuery pageQuery, DomainMappingDto req) { ParamCheckUtil.checkNotNull(pageQuery, "pageQuery"); return domainMappingService.page(pageQuery, req); } @Post @Mapping("/modify") - public PortMappingCreateRes create(PortMappingCreateReq req) { - ParamCheckUtil.checkNotNull(req, "req"); - ParamCheckUtil.checkNotNull(req.getLicenseId(), "licenseId"); - ParamCheckUtil.checkNotNull(req.getServerPort(), "serverPort"); - ParamCheckUtil.checkNotNull(req.getClientPort(), "clientPort"); - ParamCheckUtil.checkNotEmpty(req.getProtocal(), "protocal"); - ParamCheckUtil.checkMaxLength(req.getDescription(), 50, "描述", "50"); - ParamCheckUtil.checkBytesDesc(req.getUpLimitRate(), "upLimitRate"); - ParamCheckUtil.checkBytesDesc(req.getDownLimitRate(), "downLimitRate"); - if (StringUtils.isBlank(req.getClientIp())) { - // 没传客户端ip,默认为127.0.0.1 - req.setClientIp("127.0.0.1"); - } - NetworkProtocolEnum networkProtocolEnum = NetworkProtocolEnum.of(req.getProtocal()); - ParamCheckUtil.checkNotNull(networkProtocolEnum, ExceptionConstant.AN_UNSUPPORTED_PROTOCOL, req.getProtocal()); - if (networkProtocolEnum != NetworkProtocolEnum.HTTP) { - // 目前仅HTTP支持绑定域名 - req.setSubdomain(null); - } - req.setProtocal(networkProtocolEnum.getDesc()); - if (null == req.getProxyResponses()) { - req.setProxyResponses(0); - } - if (null == req.getProxyTimeoutMs()) { - req.setProxyTimeoutMs(0L); + public PortMappingCreateRes modify(DomainMappingDto req) { + if (StringUtils.isBlank(req.getTargetPath())) {// targetPath,默认为127.0.0.1 + req.setTargetPath("127.0.0.1"); } + req.setProtocal(NetworkProtocolEnum.HTTP.getDesc()); if (null == req.getSecurityGroupId()) { req.setSecurityGroupId(0); } - - return domainMappingService.create(req); + return domainMappingService.modify(req); } @Get @@ -86,20 +64,13 @@ public class DomainController { @Post @Mapping("/update/enable-status") public PortMappingUpdateEnableStatusRes updateEnableStatus(PortMappingUpdateEnableStatusReq req) { - ParamCheckUtil.checkNotNull(req, "req"); - ParamCheckUtil.checkNotNull(req.getId(), "id"); - ParamCheckUtil.checkNotNull(req.getEnable(), "enable"); - return domainMappingService.updateEnableStatus(req); } @Post - @Mapping("/delete") - public void delete(PortMappingDeleteReq req) { - ParamCheckUtil.checkNotNull(req, "req"); - ParamCheckUtil.checkNotNull(req.getId(), "id"); - - domainMappingService.delete(req.getId()); + @Mapping("/delete/{id}") + public void delete(Integer id) { + domainMappingService.delete(id); } /** @@ -109,7 +80,7 @@ public class DomainController { @Post @Mapping("/bind/security-group") public void bindSecurityGroup(PortMappingBindSecurityGroupReq req) { - domainMappingService.portBindSecurityGroup(req.getId(), req.getSecurityGroupId()); + domainMappingService.domainBindSecurityGroup(req.getId(), req.getSecurityGroupId()); } /** @@ -119,7 +90,7 @@ public class DomainController { @Post @Mapping("/unbind/security-group") public void unbindSecurityGroup(Integer id) { - domainMappingService.portUnbindSecurityGroup(id); + domainMappingService.domainUnbindSecurityGroup(id); } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/req/proxy/PortMappingUpdateEnableStatusReq.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/req/proxy/PortMappingUpdateEnableStatusReq.java index 0c832fb1..d89b3986 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/req/proxy/PortMappingUpdateEnableStatusReq.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/req/proxy/PortMappingUpdateEnableStatusReq.java @@ -22,6 +22,7 @@ package org.dromara.neutrinoproxy.server.controller.req.proxy; import lombok.Data; +import lombok.NonNull; /** * 端口映射更新启用状态请求 @@ -34,10 +35,12 @@ public class PortMappingUpdateEnableStatusReq { /** * id */ + @NonNull private Integer id; /** * 启用状态 */ + @NonNull private Integer enable; } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/DomainMappingMapper.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/DomainMappingMapper.java index bf2c44a3..fff1a211 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/DomainMappingMapper.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/DomainMappingMapper.java @@ -10,6 +10,7 @@ import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.dromara.neutrinoproxy.server.constant.EnableStatusEnum; import org.dromara.neutrinoproxy.server.controller.req.proxy.PortMappingListReq; +import org.dromara.neutrinoproxy.server.controller.res.proxy.DomainMappingDto; import org.dromara.neutrinoproxy.server.dal.entity.DomainMappingDO; import org.dromara.neutrinoproxy.server.dal.entity.DomainMappingDO; @@ -64,9 +65,9 @@ public interface DomainMappingMapper extends BaseMapper { ); } - default List findListByServerPort(Integer serverPort) { + default List findListByServerPort(String domain) { return this.selectList(new LambdaQueryWrapper() - .eq(DomainMappingDO::getServerPort, serverPort) + .eq(DomainMappingDO::getDomain, domain) ); } @@ -76,37 +77,14 @@ public interface DomainMappingMapper extends BaseMapper { ); } - default DomainMappingDO findByLicenseIdAndServerPort(Integer licenseId, Integer serverPort) { + default DomainMappingDO findByLicenseIdAndServerPort(Integer licenseId, String domain) { return this.selectOne(new LambdaQueryWrapper() .eq(DomainMappingDO::getLicenseId, licenseId) - .eq(DomainMappingDO::getServerPort, serverPort) + .eq(DomainMappingDO::getDomain, domain) .last("limit 1") ); } - default void updateOnlineStatus(Integer licenseId,Integer serverPort, Integer isOnline, Date updateTime) { - this.update(null, new LambdaUpdateWrapper() - .eq(DomainMappingDO::getLicenseId, licenseId) - .eq(DomainMappingDO::getServerPort, serverPort) - .set(DomainMappingDO::getIsOnline, isOnline) - .set(DomainMappingDO::getUpdateTime, updateTime) - ); - } - default void updateOnlineStatus(Integer licenseId, Integer isOnline, Date updateTime) { - this.update(null, new LambdaUpdateWrapper() - .eq(DomainMappingDO::getLicenseId, licenseId) - .set(DomainMappingDO::getIsOnline, isOnline) - .set(DomainMappingDO::getUpdateTime, updateTime) - ); - } - - default void updateOnlineStatus(Integer isOnline, Date updateTime) { - this.update(null, new LambdaUpdateWrapper() - .set(DomainMappingDO::getIsOnline, isOnline) - .set(DomainMappingDO::getUpdateTime, updateTime) - ); - } - - List selectDomainMappingByCondition(IPage page, @Param("req") PortMappingListReq req); + List selectDomainMappingByCondition(IPage page, @Param("req") DomainMappingDto req); } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/DomainMappingService.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/DomainMappingService.java index 9d92a1cb..a791e278 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/DomainMappingService.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/DomainMappingService.java @@ -77,13 +77,13 @@ public class DomainMappingService implements LifecycleBean { /** * 域名 到 域名解析id的映射 */ - private final Cache domainToDomainMappingIdCache = CacheUtil.newLRUCache(500, 1000 * 60 * 10); + private final Cache domainToDomainMappingIdCache = CacheUtil.newLRUCache(500, 1000 * 60 * 10); // 域名解析id到licenseId private final Cache idToLicenseIdCache = CacheUtil.newLRUCache(500, 1000 * 60 * 10); // 流量限制缓存 private final Cache flowLimitCache = CacheUtil.newLRUCache(500, 1000 * 60 * 5); - public PageInfo page(PageQuery pageQuery, PortMappingListReq req) { + public PageInfo page(PageQuery pageQuery, DomainMappingDto req) { if (StringUtils.isNotEmpty(req.getDescription())) { //描述字段为模糊查询,在应用层处理,否则sqlite不支持 req.setDescription("%" + req.getDescription() + "%"); @@ -145,55 +145,42 @@ public class DomainMappingService implements LifecycleBean { // 临时处理,如果当前用户不是管理员,则操作userId不能为1 ParamCheckUtil.checkExpression(!licenseDO.getUserId().equals(1), ExceptionConstant.NO_PERMISSION_VISIT); } - PortPoolDO portPoolDO = portPoolMapper.findByPort(req.getDomain()); - ParamCheckUtil.checkNotNull(portPoolDO, ExceptionConstant.PORT_NOT_EXIST); +// PortPoolDO portPoolDO = portPoolMapper.findByPort(req.getDomain()); +// ParamCheckUtil.checkNotNull(portPoolDO, ExceptionConstant.PORT_NOT_EXIST); ParamCheckUtil.checkExpression(null == domainMappingMapper.findByDomain(req.getDomain(), null), ExceptionConstant.PORT_CANNOT_REPEAT_MAPPING, req.getDomain()); ParamCheckUtil.checkExpression(!domainMappingMapper.checkRepeatByDomain(req.getDomain(), null), ExceptionConstant.PORT_MAPPING_SUBDONAME_CONNOT_REPEAT); Date now = new Date(); - PortMappingDO portMappingDO = ; - portMappingDO.setLicenseId(req.getLicenseId()); - portMappingDO.setProtocal(req.getProtocal()); - portMappingDO.setSubdomain(req.getSubdomain()); - portMappingDO.setServerPort(req.getServerPort()); - portMappingDO.setClientIp(req.getClientIp()); - portMappingDO.setClientPort(req.getClientPort()); - portMappingDO.setUpLimitRate(req.getUpLimitRate()); - portMappingDO.setDownLimitRate(req.getDownLimitRate()); - portMappingDO.setProxyResponses(req.getProxyResponses()); - portMappingDO.setProxyTimeoutMs(req.getProxyTimeoutMs()); - portMappingDO.setDescription(req.getDescription()); - portMappingDO.setIsOnline(OnlineStatusEnum.OFFLINE.getStatus()); - portMappingDO.setEnable(EnableStatusEnum.ENABLE.getStatus()); - portMappingDO.setCreateTime(now); - portMappingDO.setUpdateTime(now); - domainMappingMapper.insert(portMappingDO); + DomainMappingDO domainMappingDO = (DomainMappingDO) req; + domainMappingDO.setIsOnline(OnlineStatusEnum.OFFLINE.getStatus()); + domainMappingDO.setEnable(EnableStatusEnum.ENABLE.getStatus()); + domainMappingDO.setCreateTime(now); + domainMappingDO.setUpdateTime(now); + domainMappingMapper.insert(domainMappingDO); // 更新VisitorChannel - visitorChannelService.addVisitorChannelByPortMapping(portMappingDO); +// visitorChannelService.addVisitorChannelByPortMapping(domainMappingDO); // 更新域名映射 - if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) && StrUtil.isNotBlank(proxyConfig.getServer().getTcp().getDomainName()) && StrUtil.isNotBlank(portMappingDO.getSubdomain())) { - ProxyUtil.setSubdomainToServerPort(portMappingDO.getSubdomain(), portMappingDO.getServerPort()); + if (NetworkProtocolEnum.isHttp(domainMappingDO.getProtocal()) && StrUtil.isNotBlank(proxyConfig.getServer().getTcp().getDomainName()) && StrUtil.isNotBlank(domainMappingDO.getDomain())) { +// ProxyUtil.setSubdomainToServerPort(domainMappingDO.getDomain(), domainMappingDO.getServerPort()); } - updateMappingDomainToSecurityGroupMap(portMappingDO.getServerPort(), req.getSecurityGroupId()); + updateMappingDomainToSecurityGroupMap(domainMappingDO.getDomain(), req.getSecurityGroupId()); // 更新端口到映射的缓存 - domainToDomainMappingIdCache.put(req.getServerPort(), portMappingDO.getId()); + domainToDomainMappingIdCache.put(req.getDomain(), domainMappingDO.getId()); // 更新端口映射到licenseId的缓存 - idToLicenseIdCache.put(portMappingDO.getId(), portMappingDO.getLicenseId()); + idToLicenseIdCache.put(domainMappingDO.getId(), domainMappingDO.getLicenseId()); // 刷新流量限制缓存 - refreshFlowLimitCache(portMappingDO.getId(), portMappingDO.getUpLimitRate(), portMappingDO.getDownLimitRate()); + refreshFlowLimitCache(domainMappingDO.getId(), domainMappingDO.getUpLimitRate(), domainMappingDO.getDownLimitRate()); return new PortMappingCreateRes(); } - - public PortMappingUpdateEnableStatusRes updateEnableStatus(PortMappingUpdateEnableStatusReq req) { - PortMappingDO portMappingDO = domainMappingMapper.findById(req.getId()); - ParamCheckUtil.checkNotNull(portMappingDO, ExceptionConstant.PORT_MAPPING_NOT_EXIST); + DomainMappingDO domainMappingDO = domainMappingMapper.findById(req.getId()); + ParamCheckUtil.checkNotNull(domainMappingDO, ExceptionConstant.PORT_MAPPING_NOT_EXIST); - LicenseDO licenseDO = licenseMapper.findById(portMappingDO.getLicenseId()); + LicenseDO licenseDO = licenseMapper.findById(domainMappingDO.getLicenseId()); ParamCheckUtil.checkNotNull(licenseDO, ExceptionConstant.LICENSE_NOT_EXIST); if (!SystemContextHolder.isAdmin()) { ParamCheckUtil.checkExpression(!licenseDO.getUserId().equals(1), ExceptionConstant.NO_PERMISSION_VISIT); @@ -202,21 +189,21 @@ public class DomainMappingService implements LifecycleBean { domainMappingMapper.updateEnableStatus(req.getId(), req.getEnable(), new Date()); // 更新VisitorChannel - portMappingDO.setEnable(req.getEnable()); + domainMappingDO.setEnable(req.getEnable()); if (EnableStatusEnum.ENABLE == EnableStatusEnum.of(req.getEnable())) { - visitorChannelService.addVisitorChannelByPortMapping(portMappingDO); +// visitorChannelService.addVisitorChannelByPortMapping(domainMappingDO); } else { - visitorChannelService.removeVisitorChannelByPortMapping(portMappingDO); +// visitorChannelService.removeVisitorChannelByPortMapping(domainMappingDO); } return new PortMappingUpdateEnableStatusRes(); } public void delete(Integer id) { - PortMappingDO portMappingDO = domainMappingMapper.findById(id); - ParamCheckUtil.checkNotNull(portMappingDO, ExceptionConstant.PORT_MAPPING_NOT_EXIST); + DomainMappingDO domainMappingDO = domainMappingMapper.findById(id); + ParamCheckUtil.checkNotNull(domainMappingDO, ExceptionConstant.PORT_MAPPING_NOT_EXIST); - LicenseDO licenseDO = licenseMapper.findById(portMappingDO.getLicenseId()); + LicenseDO licenseDO = licenseMapper.findById(domainMappingDO.getLicenseId()); if (null != licenseDO && !SystemContextHolder.isAdmin()) { // 临时处理,如果当前用户不是管理员,则操作userId不能为1 ParamCheckUtil.checkExpression(!licenseDO.getUserId().equals(1), ExceptionConstant.NO_PERMISSION_VISIT); @@ -225,13 +212,14 @@ public class DomainMappingService implements LifecycleBean { domainMappingMapper.deleteById(id); // 更新VisitorChannel - visitorChannelService.removeVisitorChannelByPortMapping(portMappingDO); +// visitorChannelService.removeVisitorChannelByPortMapping(domainMappingDO); + // 更新域名映射 - if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) && StrUtil.isNotBlank(portMappingDO.getSubdomain())) { - ProxyUtil.removeSubdomainToServerPort(portMappingDO.getSubdomain()); + if (NetworkProtocolEnum.isHttp(domainMappingDO.getProtocal()) && StrUtil.isNotBlank(domainMappingDO.getDomain())) { + ProxyUtil.removeSubdomainToServerPort(domainMappingDO.getDomain()); } - updateMappingDomainToSecurityGroupMap(portMappingDO.getServerPort(), null); + updateMappingDomainToSecurityGroupMap(domainMappingDO.getDomain(), null); // 删除id到licenseId的映射 idToLicenseIdCache.remove(id); @@ -239,26 +227,26 @@ public class DomainMappingService implements LifecycleBean { flowLimitCache.remove(id); } - public void portBindSecurityGroup(Integer portMappingId, Integer groupId) { - PortMappingDO mappingDO = domainMappingMapper.findById(portMappingId); + public void domainBindSecurityGroup(Integer portMappingId, Integer groupId) { + DomainMappingDO mappingDO = domainMappingMapper.findById(portMappingId); if (mappingDO == null) { throw new RuntimeException("指定的端口映射不存在"); } mappingDO.setSecurityGroupId(groupId); mappingDO.setUpdateTime(new Date()); domainMappingMapper.updateById(mappingDO); - updateMappingDomainToSecurityGroupMap(mappingDO.getServerPort(), groupId); + updateMappingDomainToSecurityGroupMap(mappingDO.getDomain(), groupId); } - public void portUnbindSecurityGroup(Integer portMappingId) { - PortMappingDO mappingDO = domainMappingMapper.findById(portMappingId); + public void domainUnbindSecurityGroup(Integer portMappingId) { + DomainMappingDO mappingDO = domainMappingMapper.findById(portMappingId); if (mappingDO == null) { throw new RuntimeException("指定的端口映射不存在"); } mappingDO.setSecurityGroupId(0); mappingDO.setUpdateTime(new Date()); domainMappingMapper.updateById(mappingDO); - updateMappingDomainToSecurityGroupMap(mappingDO.getServerPort(), null); + updateMappingDomainToSecurityGroupMap(mappingDO.getDomain(), null); } /** @@ -267,7 +255,7 @@ public class DomainMappingService implements LifecycleBean { * @param licenseId * @return */ - public List findEnableListByLicenseId(Integer licenseId) { + public List findEnableListByLicenseId(Integer licenseId) { return domainMappingMapper.findEnableListByLicenseId(licenseId); } @@ -286,7 +274,7 @@ public class DomainMappingService implements LifecycleBean { return; } // 服务刚启动,所以默认所有license都是离线状态。解决服务突然关闭,在线状态来不及更新的问题 - domainMappingMapper.updateOnlineStatus(OnlineStatusEnum.OFFLINE.getStatus(), new Date()); +// domainMappingMapper.updateOnlineStatus(OnlineStatusEnum.OFFLINE.getStatus(), new Date()); List allMappingDOList = domainMappingMapper.selectList(Wrappers.lambdaQuery(DomainMappingDO.class)); allMappingDOList.forEach(item -> { @@ -306,17 +294,17 @@ public class DomainMappingService implements LifecycleBean { if (StrUtil.isBlank(proxyConfig.getServer().getTcp().getDomainName())) { return; } - List portMappingDOList = allMappingDOList.stream() + List portMappingDOList = allMappingDOList.stream() .filter(item -> NetworkProtocolEnum.HTTP.getDesc().equals(item.getProtocal()) && item.getDomain() != null) .collect(Collectors.toList()); if (CollectionUtil.isEmpty(portMappingDOList)) { return; } portMappingDOList.forEach(item -> { - if (StrUtil.isBlank(item.getSubdomain())) { + if (StrUtil.isBlank(item.getDomain())) { return; } - ProxyUtil.setSubdomainToServerPort(item.getSubdomain(), item.getServerPort()); +// ProxyUtil.setSubdomainToServerPort(item.getDomain(), item.getServerPort()); }); } @@ -354,21 +342,18 @@ public class DomainMappingService implements LifecycleBean { return res; } - public Integer getDomainMappingIdByServerPort(Integer serverPort) { - if (null == serverPort) { - return null; - } - Integer id = domainToDomainMappingIdCache.get(serverPort); + public Integer getDomainMappingIdByDomain(String domain) { + Integer id = domainToDomainMappingIdCache.get(domain); if (null != id) { return id; } - List domainMappingDOList = domainMappingMapper.findListByServerPort(serverPort); + List domainMappingDOList = domainMappingMapper.findListByServerPort(domain); // 不存在 或者 有多条记录,都不处理 if (CollectionUtils.isEmpty(domainMappingDOList) || domainMappingDOList.size() > 1) { return null; } id = domainMappingDOList.get(0).getId(); - domainToDomainMappingIdCache.put(serverPort, id); + domainToDomainMappingIdCache.put(domain, id); return id; } @@ -384,8 +369,8 @@ public class DomainMappingService implements LifecycleBean { return licenseId; } - public FlowLimitBO getFlowLimitByServerPort(Integer serverPort) { - Integer id = getPortMappingIdByServerPort(serverPort); + public FlowLimitBO getFlowLimitByServerPort(String domain) { + Integer id = getDomainMappingIdByDomain(domain); if (null == id) { return null; } @@ -399,12 +384,12 @@ public class DomainMappingService implements LifecycleBean { return res; } - private void updateMappingDomainToSecurityGroupMap(Integer serverPort, Integer securityGroupId) { + private void updateMappingDomainToSecurityGroupMap(String domain, Integer securityGroupId) { if (securityGroupId == null || securityGroupId == 0) { - mappingDomainToSecurityGroupMap.remove(serverPort); + mappingDomainToSecurityGroupMap.remove(domain); return; } - mappingDomainToSecurityGroupMap.put(serverPort, securityGroupId); + mappingDomainToSecurityGroupMap.put(domain, securityGroupId); } @Override @@ -417,7 +402,7 @@ public class DomainMappingService implements LifecycleBean { */ @Override public void stop() throws Throwable { - domainMappingMapper.updateOnlineStatus(OnlineStatusEnum.OFFLINE.getStatus(), new Date()); +// domainMappingMapper.updateOnlineStatus(OnlineStatusEnum.OFFLINE.getStatus(), new Date()); } public DomainMappingDto one(Integer id) { diff --git a/neutrino-proxy-server/src/main/resources/mapper/DomainMappingMapper.xml b/neutrino-proxy-server/src/main/resources/mapper/DomainMappingMapper.xml index 8d169bdd..912fb5cb 100644 --- a/neutrino-proxy-server/src/main/resources/mapper/DomainMappingMapper.xml +++ b/neutrino-proxy-server/src/main/resources/mapper/DomainMappingMapper.xml @@ -1,10 +1,10 @@ - + - + SELECT pm.*,l.is_online as isOnline + FROM domain_mapping pm LEFT JOIN license l ON pm.license_id = l.`id` diff --git a/neutrino-proxy-server/src/main/resources/mapper/PortMappingMapper.xml b/neutrino-proxy-server/src/main/resources/mapper/PortMappingMapper.xml index 72b473d0..22348ef9 100644 --- a/neutrino-proxy-server/src/main/resources/mapper/PortMappingMapper.xml +++ b/neutrino-proxy-server/src/main/resources/mapper/PortMappingMapper.xml @@ -2,7 +2,7 @@ - SELECT pm.* from port_mapping pm left join license on pm.license_id = license.`id` From be4e3b4baef2083160b086b011fb001374a867b9 Mon Sep 17 00:00:00 2001 From: xj <550345579@qq.com> Date: Mon, 4 Mar 2024 23:20:41 +0800 Subject: [PATCH 05/15] =?UTF-8?q?=E5=9F=9F=E5=90=8D=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- neutrino-proxy-admin/src/api/domain.js | 56 +++++++++++++++++++ .../src/views/proxy/domainMapping.vue | 21 ++----- 2 files changed, 62 insertions(+), 15 deletions(-) diff --git a/neutrino-proxy-admin/src/api/domain.js b/neutrino-proxy-admin/src/api/domain.js index 21c16e34..5c12b337 100644 --- a/neutrino-proxy-admin/src/api/domain.js +++ b/neutrino-proxy-admin/src/api/domain.js @@ -7,3 +7,59 @@ export function domainNameBindInfo(query) { params: query }) } +export function fetchList(query) { + return request({ + url: '/domain/page', + method: 'get', + params: query + }) +} + + +export function mappingModify(data) { + return request({ + url: '/port-mapping/update', + method: 'post', + data + }) +} + +export function deleteMapping(id) { + return request({ + url: '/port-mapping/delete', + method: 'post', + params: { + id: id + } + }) +} + +export function updateEnableStatus(id, enable) { + return request({ + url: '/port-mapping/update/enable-status', + method: 'post', + data: { + id: id, + enable: enable + } + }) +} + +export function portMappingBindSecurityGroup(id, securityGroupId) { + return request({ + url: '/port-mapping/bind/security-group', + method: 'post', + data: { + id: id, + securityGroupId: securityGroupId + } + }) +} + +export function portMappingUnbindSecurityGroup(id) { + return request({ + url: `/port-mapping/unbind/security-group?id=${id}`, + method: 'post' + }) +} + diff --git a/neutrino-proxy-admin/src/views/proxy/domainMapping.vue b/neutrino-proxy-admin/src/views/proxy/domainMapping.vue index 8d49f298..da61b0b5 100644 --- a/neutrino-proxy-admin/src/views/proxy/domainMapping.vue +++ b/neutrino-proxy-admin/src/views/proxy/domainMapping.vue @@ -132,11 +132,11 @@ - + - + @@ -180,7 +180,7 @@