Compare commits

...
Author SHA1 Message Date
aoshiguchen 85d3ed914f 更新dromara组织项目logo. 2023-09-01 12:41:29 +08:00
aoshiguchen bf5028e056 更新dromara组织项目logo 2023-09-01 12:36:11 +08:00
aoshiguchen 3bd011b58d Merge remote-tracking branch 'origin/dev' 2023-08-31 21:04:01 +08:00
aoshiguchen 3610de97db 客户端优化,收到DISCONNECT消息时断开代理隧道连接 2023-08-31 16:55:34 +08:00
aoshiguchen 40a03c1630 更新文档. 2023-08-31 16:46:45 +08:00
aoshiguchen f1ea585cec 更新赞赏记录 2023-08-31 16:42:00 +08:00
aoshiguchen 9647006ed1 更新TODOLIST 2023-08-31 16:39:29 +08:00
aoshiguchen 8c5a6b2f0d 解决端口映射编辑时,如果端口号没有变动,则不验证。避免出现端口映射正在使用时,无法更新端口映射其他信息的问题 2023-08-31 16:29:16 +08:00
aoshiguchen 3991fcb91c 端口映射页面增加快捷打开网页按钮 2023-08-30 18:13:01 +08:00
傲世孤尘 93e8879bf5 !37 客户端断开连接时,记录日志空指针异常和捕获异常错误
Merge pull request !37 from Metal/dev
2023-08-28 07:32:31 +00:00
MnMainTao 0466710f73 1、修复客户端断开连接时,记录日志空指针异常
2、修复客户端通道异常时,捕获异常抛到父类会造成异常的问题
2023-08-28 15:21:11 +08:00
aoshiguchen ef8cab0a36 更新README.MD 2023-08-10 19:44:23 +08:00
傲世孤尘 7a9e81c27a !36 新增一键访问穿透 url 的按钮
Merge pull request !36 from 孔明/dev
2023-08-10 11:19:47 +00:00
click33 3f42b58471 新增一键访问穿透url的按钮 2023-08-10 19:01:27 +08:00
aoshiguchen 323d86b49d 新增icon 2023-08-10 16:45:50 +08:00
aoshiguchen e2226f7d0b Merge branch 'dev' of https://gitee.com/asgc/neutrino-proxy into dev 2023-08-04 13:55:44 +08:00
傲世孤尘 5094700b66 !35 修复删除license时未做端口映射检查BUG
Merge pull request !35 from tan90/dev
2023-07-29 08:07:10 +00:00
陈浩杰 b737535b0f fix: 修复删除license时未做端口映射检查BUG 2023-07-29 15:52:33 +08:00
傲世孤尘 7a95fbddbc !34 修复日志异常打印msg为空
Merge pull request !34 from Yohanes/dev
2023-07-26 05:46:11 +00:00
Yohanes f00d8d1479 修复日志打印msg为null 2023-07-26 13:43:13 +08:00
aoshiguchen 4550a677db 更新客户端镜像build脚本 2023-07-26 10:11:36 +08:00
Yohanes f604e8b011 Merge remote-tracking branch 'upstream/dev' into dev 2023-07-26 08:48:15 +08:00
aoshiguchen a400fccf77 更新TODOLIST 2023-07-25 17:16:38 +08:00
傲世孤尘 87e4af5ba5 !33 端口映射、license页面下拉框课增加可输入搜索
Merge pull request !33 from Yohanes/dev
2023-07-25 09:09:59 +00:00
aoshiguchen 1d11dd3f85 脚本变量命名修正 2023-07-25 16:11:35 +08:00
Yohanes b3e85b6a65 Merge remote-tracking branch 'upstream/dev' into dev 2023-07-25 14:36:18 +08:00
aoshiguchen c76c4d8257 新增客户端docker镜像build脚本 2023-07-25 14:34:04 +08:00
Yohanes 64fcd43be5 端口映射、license页面下拉框课增加可输入搜索 2023-07-24 17:01:27 +08:00
aoshiguchen a7b077af8c 更新赞赏记录 2023-07-21 20:49:02 +08:00
aoshiguchen a4c2addb33 更新todolist. 2023-07-18 10:19:19 +08:00
傲世孤尘 dd6493cc66 !32 检查端口是否被占用
Merge pull request !32 from Metal/dev
2023-07-18 01:59:00 +00:00
Metal 52ce6d265a 代理配置-端口映射,配置服务端端口时,检查端口是否被占用,无法保存的问题 2023-07-18 09:51:06 +08:00
aoshiguchen eacc98d18f 更新todolist 2023-07-17 21:54:14 +08:00
傲世孤尘 65af658be5 !31 检查端口是否被占用
Merge pull request !31 from Metal/dev
2023-07-17 13:39:33 +00:00
Metal a7b2694204 代理配置-端口映射,配置服务端端口时,检查端口是否被占用 2023-07-17 21:06:51 +08:00
aoshiguchen abab45785b 更新todolist 2023-07-16 11:10:37 +08:00
aoshiguchen 9da00e47bd 更新前端打包脚本. 2023-07-07 12:11:00 +08:00
aoshiguchen 4eea46fa46 官网首页跳转链接增加来源参数 2023-07-07 11:31:44 +08:00
傲世孤尘 b7518bfbeb !30 新增选择器组件支持滚动加载
Merge pull request !30 from Metal/dev
2023-07-06 13:27:54 +00:00
Metal a95b534701 1、添加前端组件:选择器支持滚动加载
2、代理配置-端口映射,新增和修改功能服务端端口字段选择器修改为支持滚动加载
3、代理配置-端口映射,后台接口getAvailablePortList修改参数内容并支持滚动加载模式也即是分页加载
2023-07-06 21:22:42 +08:00
aoshiguchen 04747296c5 Merge remote-tracking branch 'origin/dev' 2023-07-04 21:48:05 +08:00
aoshiguchen 0a5d50b84d 更新README 2023-07-04 21:46:22 +08:00
aoshiguchen 22461066a4 更新官网文档. 2023-07-04 21:38:11 +08:00
aoshiguchen cd4c9f2aae 调整url命名 2023-07-04 21:03:26 +08:00
傲世孤尘 30b115610b !29 端口池管理和端口映射修改
Merge pull request !29 from Metal/dev
2023-07-04 12:41:45 +00:00
aoshiguchen c971bee96c 更新前端打包脚本 2023-07-04 20:39:55 +08:00
Metal 7ea723b578 1、系统管理-端口池管理添加批量删除的功能
2、代理配置-端口映射添加和编辑页面服务端端口字段,支持输入搜索的功能
2023-07-04 20:08:27 +08:00
aoshiguchen 1625187bb1 报文相关日志优化. 2023-07-01 17:02:07 +08:00
aoshiguchen 934ceaadca 报文相关日志优化 2023-07-01 16:09:01 +08:00
aoshiguchen bb7fe668b1 更新官网文档,项目README. 2023-07-01 14:17:16 +08:00
aoshiguchen f78a74cd0b Merge remote-tracking branch 'origin/dev' 2023-07-01 14:05:44 +08:00
aoshiguchen c385030fc4 更新官网文档,项目README 2023-07-01 14:04:53 +08:00
aoshiguchen 767860643d 新增心跳日志开关处理 2023-06-30 18:16:52 +08:00
aoshiguchen c20a6db44a 服务端客户端,cmd通道读写超时处理调整. 2023-06-30 18:06:03 +08:00
aoshiguchen f423056361 更新赞赏记录 2023-06-30 14:05:09 +08:00
aoshiguchen 86a3cf92b5 更新赞赏记录. 2023-06-26 18:04:40 +08:00
aoshiguchen b28d476081 更新赞赏记录 2023-06-26 18:00:25 +08:00
aoshiguchen 48c8df15e7 1、升级solon版本为2.3.6
2、管理后台支持带context-path访问
2023-06-26 10:30:44 +08:00
傲世孤尘 a31b0ebc95 !28 修复端口映射页面分页查询BUG
Merge pull request !28 from tan90/dev
2023-06-22 14:17:23 +00:00
陈浩杰 fe86d786f4 fix: 修复端口映射查询BUG 2023-06-22 15:51:50 +08:00
aoshiguchen c48404e3bb 更新官网赞助记录 2023-06-12 21:19:50 +08:00
aoshiguchen 5daec7195f 更新文档. 2023-06-09 23:22:56 +08:00
aoshiguchen 533675b367 更新文档.新增打赏记录 2023-06-09 21:43:32 +08:00
aoshiguchen e547895a9c 更新文档. 2023-06-09 21:27:23 +08:00
aoshiguchen 42b7163f5b 支持指定重连间隔、是否无限重连 2023-06-09 20:54:15 +08:00
aoshiguchen 2ceacc6916 支持配置文件、启动参数指定日志级别 2023-06-09 20:41:11 +08:00
aoshiguchen 124273e8d7 日志调整. 2023-06-09 13:07:25 +08:00
aoshiguchen 5a36c88875 支持域名带端口访问 2023-06-09 12:55:24 +08:00
aoshiguchen 70e6d2ab45 更新官网文档 2023-06-08 22:13:52 +08:00
aoshiguchen 2dc8965cdb 适配mariadb. 2023-06-08 22:00:11 +08:00
aoshiguchen 0d997bbe92 适配mariadb 2023-06-08 21:58:39 +08:00
aoshiguchen f88bbb53cb 更新TODOLIST 2023-06-07 21:35:02 +08:00
aoshiguchen 2ae3267049 更新logback配置 2023-06-07 20:41:33 +08:00
aoshiguchen 62bbd48b33 更新TODOLIST 2023-06-07 20:37:26 +08:00
aoshiguchen aa131b0705 解决http域名映射的问题 2023-06-06 10:11:12 +08:00
aoshiguchen 1510e16e50 客户端服务端、日志优化 2023-06-05 18:02:03 +08:00
aoshiguchen a3b324c72b http代理日志调整. 2023-06-05 17:48:33 +08:00
aoshiguchen c959ce13a3 解决端口映射选择https,域名输入框没出来的问题 2023-06-05 10:00:59 +08:00
aoshiguchen e715976726 Merge remote-tracking branch 'origin/dev' 2023-05-27 12:09:01 +08:00
aoshiguchen f66791678c . 2023-05-27 12:08:55 +08:00
147 changed files with 1651 additions and 606 deletions
+1
View File
@@ -56,3 +56,4 @@ hs_err_pid*
neutrino-proxy-vuepress/deploy.sh
.NEUTRINO_PROXY_CLIENT_ID
logs
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

+10 -129
View File
@@ -34,144 +34,19 @@
![License管理](assets/run-example/license1.png)
![端口映射管理](assets/run-example/port-mapping1.png)
# 4、项目结构
- neutrino-proxy
- neutrino-proxy-core 与代理相关的公共常量、编解码器
- neutrino-proxy-client 代理客户端项目
- neutrino-proxy-server 代理服务端项目
- neutrino-proxy-admin 代理监控项目(基于vue-element-admin开发)
# 5、运行
## 5.1、使用keytool工具生成ssl证书, 若不需要ssl加密可跳过
```shell
keytool -genkey -alias test1 -keyalg RSA -keysize 1024 -validity 3650 -keypass 123456 -storepass 123456 -keystore "./test.jks"
```
## 5.2、修改服务端配置(app.yml
```yml
application:
name: neutrino-proxy-server
neutrino:
proxy:
protocol:
max-frame-length: 2097152
length-field-offset: 0
length-field-length: 4
initial-bytes-to-strip: 0
length-adjustment: 0
read-idle-time: 60
write-idle-time: 40
all-idle-time-seconds: 0
tunnel:
boss-thread-count: 2
work-thread-count: 10
# 服务端端口,用于保持与客户端的连接,非SSL
port: ${OPEN_PORT:9000}
# 服务端端口,用于保持与客户端的连接,SSL,需要jks证书文件,若不需要ssl支持,可不配置
ssl-port: ${SSL_PORT:9002}
# 证书配置,用于隧道通信SSL加密
key-store-password: ${STORE_PASS:123456}
key-manager-password: ${MGR_PASS:123456}
jks-path: ${JKS_PATH:classpath:/test.jks}
server:
boss-thread-count: 5
work-thread-count: 20
# HTTP代理端口,默认80,也可以用其他端口,走nginx转发
http-proxy-port: ${HTTP_PROXY_PORT:80}
# HTTPS代理端口,默认443,也可以用其他端口,走nginx转发
https-proxy-port: ${HTTPS_PROXY_PORT:443}
# 如果不配置,则不支持域名映射
domain-name: ${DOMAIN_NAME:}
# 证书配置,用于支持HTTPS
key-store-password: ${HTTPS_STORE_PASS:}
jks-path: ${HTTPS_JKS_PATH:}
data:
# 数据库配置(支持mysql
type: sqlite
url: jdbc:sqlite:data.db
driver-class: org.sqlite.JDBC
username:
password:
```
## 5.3、启动服务端
> java -jar neutrino-proxy-server.jar
## 5.4、修改客户端配置
```yml
application:
name: neutrino-proxy-client
proxy:
protocol:
max-frame-length: 2097152
length-field-offset: 0
length-field-length: 4
initial-bytes-to-strip: 0
length-adjustment: 0
read-idle-time: 60
write-idle-time: 30
all-idle-time-seconds: 0
client:
# ssl证书密码
key-store-password: 123456
# ssl证书存放位置
jks-path: classpath:/test.jks
# 服务端ip,若部署到服务器,则配置服务器的ip
server-ip: localhost
# 服务端端口,若使用ssl,则需要配置为服务端的"ssl-port"
server-port: 9000
# 是否启用ssl,启用则必须配置ssl相关参数
ssl-enable: false
```
## 5.5、代理示意图
# 4、代理示意图
![代理流程](assets/design/neutrino-proxy-process.jpg)
## 5.6、启动客户端
### 5.6.1、启动参数直接指定配置
> java -jar neutrino-proxy-client.jar serverIp=localhost serverPort=9000 licenseKey=b0a907332b474b25897c4dcb31fc7eb6
### 5.6.2、启动参数指定外部配置文件
> java -jar neutrino-proxy-client.jar config=app.properties
配置文件格式如下:
```
neutrino.proxy.client.server-ip=localhost
neutrino.proxy.client.server-port=9002
neutrino.proxy.client.ssl-enable=true
neutrino.proxy.client.key-store-password=123456
neutrino.proxy.client.jks-path=classpath:/test.jks
neutrino.proxy.client.license-key=b0a907332b474b25897c4dcb31fc7eb6
```
## 5.7、Docker快速启动
```shell script
# 一键部署前端和后端,客户端按上方部署即可
docker run -it -p 9000-9200:9000-9200/tcp -p 8888:8888 -d --name neutrino registry.cn-hangzhou.aliyuncs.com/asgc/aoshiguchen-docker-images:1.64
# 如没docker环境,可以一键部署docker环境(centos 7.8)系统
curl http://www.wangke666.cn/static/createDocker.sh | bash
```
# 6、演示环境
# 5、演示环境
> 可使用分配好的游客license试用。服务器带宽较低,仅供学习使用!
- 管理后台地址:http://103.163.47.16:9527
- 游客账号:visitor/123456
# 7、未来迭代方向
- 优化代码、增强稳定性
- 服务端增加管理页面,提供报表、授权、限流等功能
- 从项目中分离、孵化出另一个开源项目(neutrino-framework)
# 8、技术文档
- [Aop](./docs/Aop.MD)
- [Channel](./docs/Channel.MD)
# 9、联系我们
# 6、联系我们
- 微信: yuyunshize
- Gitee: https://gitee.com/asgc/neutrino-proxy
# 10、贡献者列表
# 7、贡献者列表
<p>
<a href="https://gitee.com/zcans" target="_blank">
<img src="assets/developer/zcans.png" width="12%">
@@ -209,6 +84,12 @@ neutrino.proxy.client.license-key=b0a907332b474b25897c4dcb31fc7eb6
<a href="https://gitee.com/zoo-plus" target="_blank">
<img src="assets/developer/zoo-plus.png" width="12%">
</a>
<a href="https://gitee.com/MetalXingxing" target="_blank">
<img src="assets/developer/metal.png" width="12%">
</a>
<a href="https://gitee.com/click33" target="_blank">
<img src="assets/developer/click33.png" width="12%">
</a>
</p>
# ❤️ 感谢
Binary file not shown.

After

Width:  |  Height:  |  Size: 350 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

+1 -1
View File
@@ -1,5 +1,5 @@
module.exports = {
NODE_ENV: '"development"',
ENV_CONFIG: '"docker"',
BASE_API: '"/"'
BASE_API: '"/neutrino-proxy-server"'
}
+20 -4
View File
@@ -14,13 +14,11 @@ export function portPoolList() {
method: 'get'
})
}
export function availablePortList(licenseId) {
export function availablePortList(query) {
return request({
url: '/port-pool/get-available-port-list',
method: 'get',
params: {
licenseId: licenseId
}
params: query
})
}
@@ -60,3 +58,21 @@ export function deletePortPool(id) {
}
})
}
export function deleteBatchPortPool(ids) {
return request({
url: '/port-pool/delete-batch',
method: 'post',
data: {
ids: ids
}
})
}
export function portAvailable(query) {
return request({
url: '/port-pool/port-available',
method: 'get',
params: query
})
}
@@ -8,60 +8,68 @@
<el-button size="mini" @click="handleCancelClick">{{cancelText}}</el-button>
<el-button type="primary" size="mini" @click="handleCommitClick">{{okText}}</el-button>
</div>
<el-button slot="reference" :type="type" :size="size">{{buttonText}}</el-button>
<el-button slot="reference" :type="type" :size="size" :icon="icon" :disabled="disabled">{{buttonText}}</el-button>
</el-popover>
</template>
<script>
export default {
name: 'deleteButton',
props: {
width: {
type: Number,
default: 160
export default {
name: 'deleteButton',
props: {
width: {
type: Number,
default: 160
},
buttonText: {
type: String,
default: '删除'
},
type: {
type: String,
default: 'danger'
},
size: {
type: String,
default: 'mini'
},
icon: {
type: String,
default: ''
},
disabled: {
type: Boolean,
default: false
},
title: {
type: String,
default: '确定删除吗?'
},
okText: {
type: String,
default: '确定'
},
cancelText: {
type: String,
default: '取消'
}
},
buttonText: {
type: String,
default: '删除'
data() {
return {
visible: false
}
},
type: {
type: String,
default: 'danger'
},
size: {
type: String,
default: 'mini'
},
title: {
type: String,
default: '确定删除吗?'
},
okText: {
type: String,
default: '确定'
},
cancelText: {
type: String,
default: '取消'
}
},
data() {
return {
visible: false
}
},
methods: {
handleCancelClick() {
this.visible = false
this.$emit('handleCancelClick')
},
handleCommitClick() {
this.visible = false
this.$emit('handleCommitClick')
methods: {
handleCancelClick() {
this.visible = false
this.$emit('handleCancelClick')
},
handleCommitClick() {
this.visible = false
this.$emit('handleCommitClick')
}
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
@@ -0,0 +1,168 @@
<!--
采用github上面的开源组件https://github.com/johnhom1024/vue-load-select
不过有个bug就是没办法展示下拉的箭头目前修复的方式等dom加载完毕后补充箭头的class
参考https://blog.csdn.net/weixin_42381896/article/details/122258563
-->
<template>
<el-select
ref="selectLoadMore"
:value="value"
v-loadmore="loadMore"
@focus="focus"
@clear="clear"
filterable
remote
:filter-method="handleSearch"
:loading="loading"
clearable
v-bind="$attrs"
v-on="$listeners"
>
<el-option
v-for="option in data"
:label="option[dictLabel]"
:value="option[dictValue]"
:key="option.value"
></el-option>
<!-- 此处加载中的value可以随便设置只要不与其他数据重复即可 -->
<el-option
v-if="hasMore"
disabled
label="加载中..."
value="-1" />
<!--补充页面无数据时显示无数据的效果-->
<el-option
v-if="!hasMore && data.length==0"
disabled
label="暂无数据"
value="-2" />
</el-select>
</template>
<script>
export default {
name: "SelectLoadMore",
props: {
value: {
default: null
},
// 列表数据
data: {
type: Array,
default: () => []
},
dictLabel: {
type: String,
default: "label"
},
dictValue: {
type: String,
default: "value"
},
// 调用页数的接口
request: {
type: Function,
default: () => {
}
},
// 传入的页码
page: {
type: [Number, String],
default: 1
},
// 是否还有更多数据
hasMore: {
type: Boolean,
default: true
}
},
directives: {
// 这里实现一个组件内部的自定义指令
loadmore: {
// 指令的定义
bind(el, binding) {
const SELECTWRAP = el.querySelector(
".el-select-dropdown .el-select-dropdown__wrap"
);
if (!SELECTWRAP) {
throw new Error('获取不到"el-select-dropdown__wrap"节点');
}
SELECTWRAP.addEventListener("scroll", () => {
// scrollTop 这里可能因为浏览器缩放存在小数点的情况,导致了滚动到底部时
// scrollHeight 减去滚动到底部时的scrollTop ,依然大于clientHeight 导致无法请求更多数据
// 这里将scrollTop向上取整 保证滚到底部时,触发调用
const CONDITION =
SELECTWRAP.scrollHeight -
Math.ceil(SELECTWRAP.scrollTop) <=
SELECTWRAP.clientHeight;
// el.scrollTop !== 0 当输入时,如果搜索结果很少,以至于没看到滚动条,那么此时的CONDITION计算结果是true,会执行bind.value(),此时不应该执行,否则搜索结果不匹配
if (CONDITION && SELECTWRAP.scrollTop !== 0) {
binding.value();
}
});
}
}
},
data() {
return {
keyword: "", // 存储关键字用
loading: false
};
},
methods: {
// 请求下一页的数据
loadMore() {
// 如果没有更多数据,则不请求
if (!this.hasMore) {
return;
}
// 如果intercept属性为true则不请求数据,
if (this.loadMore.intercept) {
return;
}
this.loadMore.intercept = true;
this.request({
page: this.page + 1,
more: true,
keyword: this.keyword
}).then(() => {
this.loadMore.intercept = false;
});
},
// 选中下拉框没有数据时,自动请求第一页的数据
focus() {
if (!this.data.length) {
this.request({page: 1});
}
},
handleSearch(keyword) {
this.keyword = keyword;
this.loading = true;
console.log(keyword);
this.request({page: 1, keyword: keyword}).then(() => {
this.loading = false;
});
},
// 删除选中时,如果请求了关键字,则清除关键字再请求第一页的数据
clear() {
if (this.keyword) {
this.keyword = "";
this.request({page: 1});
}
}
},
mounted() {
this.$nextTick(function () {
// github代码有个bug,下拉的箭头无法加载的问题,需要等dom页面加载完毕后,添加箭头的class
let rulesDom = this.$refs["selectLoadMore"].$el.querySelector(
".el-input .el-input__suffix .el-input__suffix-inner .el-input__icon"
);// 找到dom
rulesDom.classList.add("el-icon-arrow-up");// 对dom新增class
})
}
}
</script>
<style scoped>
</style>
+2
View File
@@ -97,10 +97,12 @@ export default {
readings: 'Readings',
status: 'Status',
actions: 'Actions',
access: 'Access',
edit: 'Edit',
publish: 'Publish',
draft: 'Draft',
delete: 'Delete',
deleteBatch: 'DeleteBatch',
cancel: 'Cancel',
confirm: 'Confirm',
portOrRange: 'example: 3306 or 1000-2000'
+3
View File
@@ -117,10 +117,13 @@ export default {
readings: '阅读数',
status: '状态',
actions: '操作',
access: '访问',
openWebPage: '打开网页',
edit: '编辑',
publish: '发布',
draft: '草稿',
delete: '删除',
deleteBatch: '批量删除',
cancel: '取 消',
confirm: '确 定',
userId: '用户ID',
@@ -1,7 +1,7 @@
<template>
<div class="app-container calendar-list-container">
<div class="filter-container">
<el-select v-model="listQuery.userId" placeholder="请选择用户" clearable>
<el-select v-model="listQuery.userId" placeholder="请选择用户" filterable clearable>
<el-option v-for="item in userList" :key="item.id" :label="item.name" :value="item.id"/>
</el-select>
<el-select v-model="listQuery.isOnline" placeholder="请选择在线状态" clearable>
@@ -1,10 +1,10 @@
<template>
<div class="app-container calendar-list-container">
<div class="filter-container" style="display:flex">
<el-select v-model="listQuery.userId" placeholder="请选择用户" clearable style="margin-right:10px;width: 120px;">
<el-select v-model="listQuery.userId" placeholder="请选择用户" filterable clearable style="margin-right:10px;width: 120px;">
<el-option v-for="item in userList" :key="item.loginName" :label="item.name" :value="item.id" />
</el-select>
<el-select v-model="listQuery.licenseId" placeholder="请选择license" clearable style="margin-right:10px;width: 135px;">
<el-select v-model="listQuery.licenseId" placeholder="请选择license" filterable clearable style="margin-right:10px;width: 135px;">
<el-option v-for="item in licenseList" :key="item.key" :label="item.name" :value="item.id" />
</el-select>
<el-select v-model="listQuery.protocal" placeholder="请选择协议" clearable style="margin-right:10px;width: 120px;">
@@ -90,11 +90,15 @@
<el-tag :type="scope.row.isOnline | statusFilter">{{ scope.row.isOnline | isOnlineName }}</el-tag>
</template>
</el-table-column>
<el-table-column align="center" :label="$t('table.actions')" width="230" class-name="small-padding fixed-width">
<el-table-column class-name="status-col" :label="$t('table.access')" width="120">
<template slot-scope="scope">
<el-button size="mini" v-if="(scope.row.protocal === 'HTTP' || scope.row.protocal === 'HTTP(S)')" @click="handleOpenWebPage(scope.row)">{{$t('table.openWebPage')}}</el-button>
</template>
</el-table-column>
<el-table-column align="center" :label="$t('table.actions')" width="320" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button type="primary" size="mini" @click="handleUpdate(scope.row)">{{ $t('table.edit') }}</el-button>
<el-button v-if="scope.row.enable == '1'" size="mini" type="danger" @click="handleModifyStatus(scope.row, 2)">{{
$t('table.disable') }}</el-button>
<el-button v-if="scope.row.enable == '1'" size="mini" type="danger" @click="handleModifyStatus(scope.row, 2)">{{$t('table.disable')}}</el-button>
<el-button v-if="scope.row.enable == '2'" size="mini" type="success"
@click="handleModifyStatus(scope.row, 1)">{{ $t('table.enable') }}</el-button>
<!-- <el-button size="mini" type="danger" @click="handleDelete(scope.row,'deleted')">{{$t('table.delete')}}</el-button>-->
@@ -142,11 +146,16 @@
</el-option>
</el-select>
</el-form-item>
<el-form-item :label="$t('服务端端口')" prop="serverPort">
<el-select style="width: 280px;" class="filter-item" v-model="temp.serverPort" placeholder="请选择">
<el-option v-for="item in serverPortList" :key="item.port" :label="item.port" :value="item.port">
</el-option>
</el-select>
<el-form-item :label="$t('服务端端口')" prop="serverPort" >
<load-select style="width: 280px;" class="filter-item"
v-model="temp.serverPort"
:data="serverPortList"
:page="loadServerPortQuery.page"
:hasMore="more"
:clearable="false"
:dictLabel="'port'"
:dictValue="'port'"
:request="loadServerPort"/>
</el-form-item>
<el-form-item :label="$t('客户端IP')" prop="clientIp">
<el-input v-model="temp.clientIp"></el-input>
@@ -154,7 +163,7 @@
<el-form-item :label="$t('客户端端口')" prop="clientPort">
<el-input v-model="temp.clientPort"></el-input>
</el-form-item>
<el-form-item :label="$t('域名')" prop="subdomain" v-if="temp.protocal === 'HTTP' && domainName && domainName != ''">
<el-form-item :label="$t('域名')" prop="subdomain" v-if="(temp.protocal === 'HTTP' || temp.protocal === 'HTTP(S)') && domainName && domainName != ''">
<el-input v-model="temp.subdomain">
<template slot="append">.{{ domainName }}</template>
</el-input>
@@ -187,7 +196,7 @@
<script>
import { fetchList, createUserPortMapping, updateUserPortMapping, updateEnableStatus, deletePortMapping } from '@/api/portMapping'
import { portPoolList, availablePortList } from '@/api/portPool'
import { portPoolList, availablePortList, portAvailable } from '@/api/portPool'
import { licenseList, licenseAuthList } from '@/api/license'
import { protocalList } from '@/api/protocal'
import { userList } from '@/api/user'
@@ -196,6 +205,8 @@ 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' },
@@ -217,9 +228,22 @@ export default {
},
components: {
DropdownTable,
ButtonPopover
ButtonPopover,
loadSelect
},
data() {
const isPortAvailable = (rule, value, callback) => {
if (value != null) {
const param = { port: value, portMappingId: this.temp.id }
portAvailable(param).then(res => {
if (!res.data.data) {
return callback(new Error('该端口被占用'))
} else {
callback()
}
})
}
}
return {
tableKey: 0,
list: null,
@@ -273,7 +297,8 @@ export default {
pvData: [],
rules: {
licenseId: [{ required: true, message: '请选择License', trigger: 'blur,change' }],
serverPort: [{ required: true, message: '请输入服务端端口', trigger: 'blur' }],
serverPort: [{ required: true, message: '请输入服务端端口', trigger: 'blur' },
{ validator: isPortAvailable, trigger: 'change' }],
clientIp: [{ required: true, message: '请输入客户端IP', trigger: 'blur' }],
clientPort: [{ required: true, message: '请输入客户端端口', trigger: 'blur' }],
protocal: [{ required: true, message: '请选择协议', trigger: 'blur' }]
@@ -282,7 +307,13 @@ export default {
countryColumns: [
{ prop: 'userName', label: '用户名', align: 'center' },
{ prop: 'name', label: 'License', align: 'center' }
]
],
loadServerPortQuery:{ //下拉框加载数据请求参数
page:1,
size:50,
licenseId:null,
},
more: true,
}
},
filters: {
@@ -343,15 +374,9 @@ export default {
this.domainName = response.data.data
})
},
getPortPoolList() {
portPoolList().then(response => {
this.serverPortList = response.data.data
})
},
getAvailablePortList(licenseId) {
availablePortList(licenseId).then(response => {
this.serverPortList = response.data.data
})
this.loadServerPortQuery.licenseId = licenseId;
this.serverPortList = []; //清掉数据
},
getAllUserList() {
userList().then(response => {
@@ -408,6 +433,8 @@ export default {
userId: undefined
}
this.serverPortList = []
this.loadServerPortQuery.licenseId = null;
this.more = true;
},
handleCreate() {
this.resetTemp()
@@ -435,6 +462,10 @@ export default {
}
})
},
handleOpenWebPage(row) {
const url = location.protocol + '//' + location.hostname + ':' + row.serverPort
open(url)
},
handleUpdate(row) {
this.temp = Object.assign({}, row) // copy obj
this.temp.timestamp = new Date(this.temp.timestamp)
@@ -526,6 +557,36 @@ export default {
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();
});
});
}
}
}
@@ -6,10 +6,13 @@
</el-select>
<el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">{{$t('table.search')}}</el-button>
<el-button class="filter-item" style="margin-left: 10px;" @click="handleCreate" type="primary" icon="el-icon-edit">{{$t('table.add')}}</el-button>
<button-popover class="filter-item" style="margin-left: 10px;" size="medium" icon="el-icon-delete"
:buttonText="$t('table.deleteBatch')" :disabled="checkBoxData.length==0" @handleCommitClick="handleDeleteBatch" />
</div>
<el-table :key='tableKey' :data="list" v-loading="listLoading" element-loading-text="给我一点时间" border fit highlight-current-row
style="width: 100%">
style="width: 100%" @selection-change="onTableRowChange">
<el-table-column align="center" width="40" type="selection" />
<el-table-column align="center" :label="$t('table.id')" width="120">
<template slot-scope="scope">
<span>{{scope.row.id}}</span>
@@ -92,7 +95,7 @@
</template>
<script>
import { createPortPool, deletePortPool, fetchList, updateEnableStatus, updatePortPool } from '@/api/portPool'
import { createPortPool, deletePortPool, deleteBatchPortPool, fetchList, updateEnableStatus, updatePortPool } from '@/api/portPool'
import { portGroupList } from '@/api/portGroup'
import waves from '@/directive/waves' // 水波纹指令
import { parseTime } from '@/utils'
@@ -157,7 +160,8 @@ const calendarTypeOptions = [
rules: {
port: [{ required: true, message: '端口必填', trigger: 'blur' }]
},
downloadLoading: false
downloadLoading: false,
checkBoxData:[], //表单勾选的行
}
},
filters: {
@@ -320,6 +324,24 @@ const calendarTypeOptions = [
return v[j]
}
}))
},
onTableRowChange(val){ //表单勾选后赋值
this.checkBoxData = val
},
handleDeleteBatch(){ //批量删除操作
let ids = []
this.checkBoxData.forEach(item => {ids.push(item.id)})
deleteBatchPortPool(ids).then(response => {
if (response.data.code === 0) {
this.$notify({
title: '成功',
message: '删除成功',
type: 'success',
duration: 2000
})
this.getList()
}
})
}
}
}
+1 -1
View File
@@ -33,7 +33,7 @@
<filtering>false</filtering>
<excludes>
<exclude>app-*.yml</exclude>
<exclude>app-dev.yml</exclude>
</excludes>
</resource>
</resources>
@@ -1,14 +1,22 @@
package org.dromara.neutrinoproxy.client;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.noear.solon.Solon;
import org.noear.solon.SolonApp;
import org.noear.solon.annotation.SolonMain;
import org.slf4j.LoggerFactory;
/**
*
* @author: aoshiguchen
* @date: 2022/6/16
*/
@Slf4j
@SolonMain
public class ProxyClient {
@@ -20,6 +28,8 @@ public class ProxyClient {
setAlias("neutrino.proxy.client.jksPath", "jksPath");
setAlias("neutrino.proxy.client.keyStorePassword", "keyStorePassword");
setAlias("neutrino.proxy.client.licenseKey", "licenseKey");
// 设置日志级别
setLogLevel(app);
});
}
@@ -34,4 +44,21 @@ public class ProxyClient {
Solon.cfg().put(key, val);
}
}
private static void setLogLevel(SolonApp app) {
String loggerLevel = app.cfg().get("neutrino.proxy.logger.level");
if (StringUtils.isBlank(loggerLevel)) {
return;
}
try {
Level level = Level.toLevel(loggerLevel);
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
for (Logger logger : loggerContext.getLoggerList()) {
logger.setLevel(level);
}
} catch (Exception e) {
log.error("日志级别设置失败", e);
}
}
}
@@ -40,5 +40,14 @@ public class ProxyConfig {
private String licenseKey;
private Integer threadCount;
private String clientId;
private Boolean transferLogEnable;
private Boolean heartbeatLogEnable;
private Reconnection reconnection;
}
@Data
public static class Reconnection {
private Integer intervalSeconds;
private Boolean unlimited;
}
}
@@ -1,5 +1,6 @@
package org.dromara.neutrinoproxy.client.core;
import org.dromara.neutrinoproxy.client.config.ProxyConfig;
import org.dromara.neutrinoproxy.client.util.ProxyUtil;
import org.dromara.neutrinoproxy.core.Constants;
import org.dromara.neutrinoproxy.core.ProxyMessage;
@@ -19,12 +20,19 @@ import org.noear.solon.Solon;
*/
@Slf4j
public class CmdChannelHandler extends SimpleChannelInboundHandler<ProxyMessage> {
private static volatile Boolean transferLogEnable = Boolean.FALSE;
public CmdChannelHandler() {
ProxyConfig proxyConfig = Solon.context().getBean(ProxyConfig.class);
if (null != proxyConfig.getClient() && null != proxyConfig.getClient().getHeartbeatLogEnable()) {
transferLogEnable = proxyConfig.getClient().getHeartbeatLogEnable();
}
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, ProxyMessage proxyMessage) throws Exception {
if (ProxyMessage.TYPE_HEARTBEAT != proxyMessage.getType()) {
log.info("Client CmdChannel recieved proxy message, type is {}", proxyMessage.getType());
if (ProxyMessage.TYPE_HEARTBEAT != proxyMessage.getType() || transferLogEnable) {
log.debug("Client CmdChannel recieved proxy message, type is {}", proxyMessage.getType());
}
Solon.context().getBean(Dispatcher.class).dispatch(ctx, proxyMessage);
}
@@ -61,14 +69,14 @@ public class CmdChannelHandler extends SimpleChannelInboundHandler<ProxyMessage>
switch (event.state()) {
case READER_IDLE:
// 读超时,断开连接
// log.info("读超时");
// ctx.channel().close();
log.error("Client CmdChannel 读超时,断开连接");
ctx.channel().close();
break;
case WRITER_IDLE:
ctx.channel().writeAndFlush(ProxyMessage.buildHeartbeatMessage());
break;
case ALL_IDLE:
log.info("Client CmdChannel 读写超时");
log.error("Client CmdChannel 读写超时,断开连接");
ctx.close();
break;
}
@@ -24,7 +24,7 @@ public class ProxyChannelHandler extends SimpleChannelInboundHandler<ProxyMessag
@Override
protected void channelRead0(ChannelHandlerContext ctx, ProxyMessage proxyMessage) throws Exception {
if (ProxyMessage.TYPE_HEARTBEAT != proxyMessage.getType()) {
log.info("Client ProxyChannel recieved proxy message, type is {}", proxyMessage.getType());
log.debug("Client ProxyChannel recieved proxy message, type is {}", proxyMessage.getType());
}
Solon.context().getBean(Dispatcher.class).dispatch(ctx, proxyMessage);
}
@@ -71,7 +71,7 @@ public class ProxyChannelHandler extends SimpleChannelInboundHandler<ProxyMessag
ctx.channel().writeAndFlush(ProxyMessage.buildHeartbeatMessage());
break;
case ALL_IDLE:
log.info("读写超时");
log.debug("读写超时");
ctx.close();
break;
}
@@ -1,6 +1,7 @@
package org.dromara.neutrinoproxy.client.core;
import cn.hutool.core.util.StrUtil;
import io.netty.handler.logging.LoggingHandler;
import org.dromara.neutrinoproxy.client.config.ProxyConfig;
import org.dromara.neutrinoproxy.client.util.ProxyUtil;
import org.dromara.neutrinoproxy.core.ProxyMessage;
@@ -48,10 +49,10 @@ public class ProxyClientService {
@Inject("realServerBootstrap")
private Bootstrap realServerBootstrap;
private volatile Channel channel;
/**
* 重连间隔(秒)
*/
private static final long RECONNECT_INTERVAL_SECONDS = 5;
// /**
// * 重连间隔(秒)
// */
// private static final long RECONNECT_INTERVAL_SECONDS = 5;
/**
* 重连次数
*/
@@ -68,7 +69,7 @@ public class ProxyClientService {
@Init
public void init() {
this.reconnectExecutor.scheduleWithFixedDelay(this::reconnect, 10, RECONNECT_INTERVAL_SECONDS, TimeUnit.SECONDS);
this.reconnectExecutor.scheduleWithFixedDelay(this::reconnect, 10, proxyConfig.getClient().getReconnection().getIntervalSeconds(), TimeUnit.SECONDS);
this.workerGroup = new NioEventLoopGroup(proxyConfig.getClient().getThreadCount());
realServerBootstrap.group(workerGroup);
@@ -77,6 +78,9 @@ public class ProxyClientService {
@Override
public void initChannel(SocketChannel ch) throws Exception {
if (null != proxyConfig.getClient().getTransferLogEnable() && proxyConfig.getClient().getTransferLogEnable()) {
ch.pipeline().addFirst(new LoggingHandler(RealServerChannelHandler.class));
}
ch.pipeline().addLast(new RealServerChannelHandler());
}
});
@@ -91,7 +95,9 @@ public class ProxyClientService {
if (proxyConfig.getClient().getSslEnable()) {
ch.pipeline().addLast(createSslHandler());
}
// ch.pipeline().addFirst(new LoggingHandler(ProxyClientService.class));
if (null != proxyConfig.getClient().getTransferLogEnable() && proxyConfig.getClient().getTransferLogEnable()) {
ch.pipeline().addFirst(new LoggingHandler(ProxyChannelHandler.class));
}
ch.pipeline().addLast(new ProxyMessageDecoder(proxyConfig.getProtocol().getMaxFrameLength(),
proxyConfig.getProtocol().getLengthFieldOffset(), proxyConfig.getProtocol().getLengthFieldLength(),
proxyConfig.getProtocol().getLengthAdjustment(), proxyConfig.getProtocol().getInitialBytesToStrip()));
@@ -119,7 +125,9 @@ public class ProxyClientService {
if (proxyConfig.getClient().getSslEnable()) {
ch.pipeline().addLast(createSslHandler());
}
// ch.pipeline().addFirst(new LoggingHandler(ProxyClientService.class));
if (null != proxyConfig.getClient().getTransferLogEnable() && proxyConfig.getClient().getTransferLogEnable()) {
ch.pipeline().addFirst(new LoggingHandler(CmdChannelHandler.class));
}
ch.pipeline().addLast(new ProxyMessageDecoder(proxyConfig.getProtocol().getMaxFrameLength(),
proxyConfig.getProtocol().getLengthFieldOffset(), proxyConfig.getProtocol().getLengthFieldLength(),
proxyConfig.getProtocol().getLengthAdjustment(), proxyConfig.getProtocol().getInitialBytesToStrip()));
@@ -1,6 +1,7 @@
package org.dromara.neutrinoproxy.client.handler;
import com.alibaba.fastjson.JSONObject;
import org.dromara.neutrinoproxy.client.config.ProxyConfig;
import org.dromara.neutrinoproxy.core.Constants;
import org.dromara.neutrinoproxy.core.ExceptionEnum;
import org.dromara.neutrinoproxy.core.ProxyMessage;
@@ -10,6 +11,7 @@ import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.Solon;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
/**
* 认证信息处理器
@@ -20,6 +22,8 @@ import org.noear.solon.annotation.Component;
@Match(type = Constants.ProxyDataTypeName.AUTH)
@Component
public class ProxyMessageAuthHandler implements ProxyMessageHandler {
@Inject
private ProxyConfig proxyConfig;
@Override
public void handle(ChannelHandlerContext context, ProxyMessage proxyMessage) {
String info = proxyMessage.getInfo();
@@ -30,7 +34,9 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler {
// 客户端认证失败,直接停止服务
log.info("client auth failed , client stop.");
context.channel().close();
Solon.stop();
if (!proxyConfig.getClient().getReconnection().getUnlimited()) {
Solon.stop();
}
} else if (ExceptionEnum.CONNECT_FAILED.getCode().equals(code) ||
ExceptionEnum.LICENSE_CANNOT_REPEAT_CONNECT.getCode().equals(code)
){
@@ -29,6 +29,7 @@ public class ProxyMessageDisconnectHandler implements ProxyMessageHandler {
ProxyUtil.returnProxyChanel(ctx.channel());
realServerChannel.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
}
ctx.close();
}
@Override
@@ -12,13 +12,32 @@ neutrino:
read-idle-time: 8
write-idle-time: 3
all-idle-time-seconds: 8
logger:
# 日志级别
level: ${LOG_LEVEL:info}
client:
# 线程池相关配置,用于技术调优,可忽略
thread-count: 50
# 隧道SSL证书配置
key-store-password: ${STORE_PASS:123456}
jks-path: ${JKS_PATH:classpath:/test.jks}
# 服务端IP
server-ip: ${SERVER_IP:localhost}
# 服务端端口(对应服务端app.yml中的tunnel.port、tunnel.ssl-port)
server-port: ${SERVER_PORT:9002}
# 是否启用SSL(注意:该配置必须和server-port对应上)
ssl-enable: ${SSL_ENABLE:true}
obtain-license-interval: 5
# 客户端连接唯一凭证
license-key: ${LICENSE_KEY:}
# 客户端唯一身份标识(可忽略,若不设置首次启动会自动生成)
client-id: ${CLIENT_ID:}
# 是否开启隧道传输报文日志(日志级别为debug时开启才有效)
transfer-log-enable: ${CLIENT_LOG:false}
# 是否开启心跳日志
heartbeat-log-enable: ${HEARTBEAT_LOG:false}
# 重连设置
reconnection:
# 重连间隔(秒)
interval-seconds: 10
# 是否开启无限重连(未开启时,客户端license不合法会自动停止应用,开启了则不会,请谨慎开启)
unlimited: false
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="LOG_FILE" value="./neutrino-proxy-client.log"/>
<property name="LOG_FILE" value="./logs/neutrino-proxy-client.log"/>
<property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{50} - %msg%n"/>
<!-- <property name="ENCODE" value="utf8" />-->
+5 -1
View File
@@ -51,6 +51,10 @@
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
@@ -66,7 +70,7 @@
<filtering>false</filtering>
<excludes>
<exclude>app-*.yml</exclude>
<exclude>app-dev.yml</exclude>
</excludes>
</resource>
</resources>
@@ -1,15 +1,25 @@
package org.dromara.neutrinoproxy.server;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.dromara.solonplugins.job.annotation.EnableJob;
import org.noear.solon.Solon;
import org.noear.solon.SolonApp;
import org.noear.solon.annotation.SolonMain;
import org.noear.solon.web.cors.CrossFilter;
import org.slf4j.LoggerFactory;
import java.util.List;
/**
*
* @author: aoshiguchen
* @date: 2022/6/16
*/
@Slf4j
@EnableJob
@SolonMain
public class ProxyServer {
@@ -18,6 +28,25 @@ public class ProxyServer {
Solon.start(ProxyServer.class, args, app -> {
// 跨域支持。加-1 优先级更高
app.filter(-1, new CrossFilter().allowedOrigins("*"));
// 设置日志级别
setLogLevel(app);
});
}
private static void setLogLevel(SolonApp app) {
String loggerLevel = app.cfg().get("neutrino.proxy.logger.level");
if (StringUtils.isBlank(loggerLevel)) {
return;
}
try {
Level level = Level.toLevel(loggerLevel);
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
for (Logger logger : loggerContext.getLoggerList()) {
logger.setLevel(level);
}
} catch (Exception e) {
log.error("日志级别设置失败", e);
}
}
}
@@ -31,7 +31,6 @@ public class DbConfiguration {
dataSource.setJournalMode(SQLiteConfig.JournalMode.WAL.getValue());
return dataSource;
} else if (DbTypeEnum.MYSQL == dbTypeEnum) {
HikariDataSource dataSource = new HikariDataSource();
String driver = "com.mysql.cj.jdbc.Driver";
try {
Class.forName(driver);
@@ -39,24 +38,26 @@ public class DbConfiguration {
// 对类名的判断,异常则说明不存在:
driver = "com.mysql.jdbc.Driver";
}
dataSource.setDriverClassName(driver);
dataSource.setJdbcUrl(dbConfig.getUrl());
dataSource.setMinimumIdle(5);
dataSource.setMaximumPoolSize(20);
dataSource.setMaxLifetime(60000);
// dataSource.setInitialSize(5);
// dataSource.setMinIdle(5);
// dataSource.setMaxActive(20);
// dataSource.setMaxWait(60000);
// dataSource.setPoolPreparedStatements(true);
dataSource.setUsername(dbConfig.getUsername());
dataSource.setPassword(dbConfig.getPassword());
return dataSource;
return newHikariDataSource(dbConfig, driver);
} else if (DbTypeEnum.MARIADB == dbTypeEnum) {
return newHikariDataSource(dbConfig, "org.mariadb.jdbc.Driver");
}
return null;
}
private HikariDataSource newHikariDataSource(DbConfig dbConfig, String driverClass) {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setDriverClassName(driverClass);
dataSource.setJdbcUrl(dbConfig.getUrl());
dataSource.setMinimumIdle(5);
dataSource.setMaximumPoolSize(20);
dataSource.setMaxLifetime(60000);
dataSource.setUsername(dbConfig.getUsername());
dataSource.setPassword(dbConfig.getPassword());
return dataSource;
}
@Bean
public void db1_ext(@Db("db") GlobalConfig globalConfig) {
MetaObjectHandler metaObjectHandler = new MetaObjectHandlerImpl();
@@ -49,6 +49,7 @@ public class ProxyConfig {
private Integer httpsProxyPort;
private String keyStorePassword;
private String jksPath;
private Boolean transferLogEnable;
}
@Data
@@ -60,6 +61,8 @@ public class ProxyConfig {
private String keyStorePassword;
private String keyManagerPassword;
private String jksPath;
private Boolean transferLogEnable;
private Boolean heartbeatLogEnable;
}
}
@@ -4,6 +4,7 @@ import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LoggingHandler;
import org.dromara.neutrinoproxy.core.ProxyDataTypeEnum;
import org.dromara.neutrinoproxy.core.ProxyMessage;
import org.dromara.neutrinoproxy.core.ProxyMessageHandler;
@@ -12,6 +13,7 @@ import org.dromara.neutrinoproxy.core.dispatcher.Dispatcher;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.nio.NioEventLoopGroup;
import org.dromara.neutrinoproxy.server.proxy.core.BytesMetricsHandler;
import org.dromara.neutrinoproxy.server.proxy.core.ProxyTunnelServer;
import org.dromara.neutrinoproxy.server.proxy.core.TcpVisitorChannelHandler;
import org.noear.solon.Solon;
import org.noear.solon.annotation.Bean;
@@ -51,13 +53,18 @@ public class ProxyConfiguration implements LifecycleBean {
@Bean("tcpServerBootstrap")
public ServerBootstrap tcpServerBootstrap(@Inject("serverBossGroup") NioEventLoopGroup serverBossGroup,
@Inject("serverWorkerGroup") NioEventLoopGroup serverWorkerGroup) {
@Inject("serverWorkerGroup") NioEventLoopGroup serverWorkerGroup,
@Inject ProxyConfig proxyConfig
) {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(serverBossGroup, serverWorkerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
if (null != proxyConfig.getServer().getTransferLogEnable() && proxyConfig.getServer().getTransferLogEnable()) {
ch.pipeline().addFirst(new LoggingHandler(TcpVisitorChannelHandler.class));
}
ch.pipeline().addFirst(new BytesMetricsHandler());
ch.pipeline().addLast(new TcpVisitorChannelHandler());
}
@@ -42,6 +42,7 @@ public class ServiceException extends RuntimeException {
private String msg;
public ServiceException(int code, String msg) {
super(msg);
this.code = code;
this.msg = msg;
}
@@ -31,7 +31,7 @@ public class VisitLogInterceptor implements RouterInterceptor {
} finally {
Date now = new Date();
long elapsedTime = now.getTime() - startTime.getTime();
log.info("\n-----------------------------------------------------------------接口请求日志:\n{} url:{} 执行耗时:{}\n请求体参数:{}\n响应结果:{}\n客户端IP:{}\n",
log.debug("\n-----------------------------------------------------------------接口请求日志:\n{} url:{} 执行耗时:{}\n请求体参数:{}\n响应结果:{}\n客户端IP:{}\n",
ctx.method(), ctx.path(), getElapsedTimeStr(elapsedTime),
JSONObject.toJSONString(ctx.paramMap()),
JSONObject.toJSONString(JSONObject.toJSONString(ctx.result)),
@@ -38,7 +38,9 @@ import java.util.stream.Stream;
@AllArgsConstructor
public enum DbTypeEnum {
SQLITE("sqlite"),
MYSQL("mysql");
MYSQL("mysql"),
MARIADB("mariadb"),
;
private String type;
@@ -50,6 +50,7 @@ public enum ExceptionConstant {
ORIGIN_PASSWORD_CHECK_FAIL(12002, "原密码验证失败"),
LOGIN_PASSWORD_LENGTH_CHECK_FAIL(12003, "登录密码不能小于6位数"),
LOGIN_PASSWORD_NO_CHANGE_MODIFY_FAIL(12004, "密码没有变化,修改失败"),
LICENSE_CANNOT_BE_DELETED(12005, "license下存在[{}]个端口映射!"),
// 端口池管理(13000)
PORT_CANNOT_REPEAT(13000,"端口不能重复"),
PORT_NOT_EXIST(13001, "该端口在端口池中不存在"),
@@ -33,4 +33,9 @@ public enum NetworkProtocolEnum {
}
return map.get(desc);
}
public static Boolean isHttp(String desc) {
NetworkProtocolEnum networkProtocolEnum = of(desc);
return NetworkProtocolEnum.HTTP == networkProtocolEnum;
}
}
@@ -51,6 +51,7 @@ public class PortMappingController {
// 目前仅HTTP支持绑定域名
req.setSubdomain(null);
}
req.setProtocal(networkProtocolEnum.getDesc());
return portMappingService.create(req);
}
@@ -74,6 +75,7 @@ public class PortMappingController {
// 目前仅HTTP支持绑定域名
req.setSubdomain(null);
}
req.setProtocal(networkProtocolEnum.getDesc());
return portMappingService.update(req);
}
@@ -102,7 +102,7 @@ public class PortPoolController {
@Get
@Mapping("/get-available-port-list")
public List<PortPoolListRes> getAvailablePortList(AvailablePortListReq req) {
public PageInfo<PortPoolListRes> getAvailablePortList(AvailablePortListReq req) {
ParamCheckUtil.checkNotNull(req, "req");
ParamCheckUtil.checkNotNull(req.getLicenseId(), "licenseId");
return portPoolService.getAvailablePortList(req);
@@ -123,4 +123,22 @@ public class PortPoolController {
ParamCheckUtil.checkNotEmpty(req.getPortIdList(), "portIdList");
return portPoolService.updateGroup(req);
}
@Post
@Mapping("/delete-batch")
@Authorization(onlyAdmin = true)
public void deleteBatch(PortPoolDeleteBatchReq req) {
ParamCheckUtil.checkNotNull(req, "req");
ParamCheckUtil.checkNotNull(req.getIds(), "ids");
portPoolService.deleteBatch(req.getIds());
}
@Get
@Mapping("/port-available")
public boolean portAvailable(Integer port, Integer portMappingId) {
ParamCheckUtil.checkNotNull(port, "port");
return portPoolService.portAvailable(port, portMappingId);
}
}
@@ -30,8 +30,16 @@ import lombok.Data;
*/
@Data
public class LicenseListReq {
/**
* 用户ID
*/
private Integer userId;
/**
* 是否在线
*/
private Integer isOnline;
/**
* 启动状态 1启用 2禁用
*/
private Integer enable;
}
@@ -12,4 +12,18 @@ public class AvailablePortListReq {
* licenseId
*/
private Integer licenseId;
/**
* 当前页
*/
private int page = 1;
/**
* 分页大小
*/
private int size = 10;
/**
* 搜索关键字
*/
private String keyword;
}
@@ -0,0 +1,14 @@
package org.dromara.neutrinoproxy.server.controller.req.system;
import lombok.Data;
import java.util.List;
/**
* @author: Metal
* @date: 2023/7/3
*/
@Data
public class PortPoolDeleteBatchReq {
private List<Integer> ids;
}
@@ -67,5 +67,5 @@ public interface PortPoolMapper extends BaseMapper<PortPoolDO> {
List<PortPoolListRes> selectResList(@Param("req") PortPoolListReq req);
List<PortPoolListRes> getAvailablePortList(@Param("licenseId") Integer licenseId,@Param("userId") Integer userId);
List<PortPoolListRes> getAvailablePortList(@Param("licenseId") Integer licenseId,@Param("userId") Integer userId, @Param("keyword") String keyword);
}
@@ -17,6 +17,6 @@ public class DemoJob implements IJobHandler {
@Override
public void execute(String param) throws Exception {
System.out.println("DemoJob execute param:" + param);
log.debug("DemoJob execute param: {}", param);
}
}
@@ -25,6 +25,7 @@ package org.dromara.neutrinoproxy.server.proxy.core;
import org.dromara.neutrinoproxy.core.Constants;
import org.dromara.neutrinoproxy.core.ProxyMessage;
import org.dromara.neutrinoproxy.core.dispatcher.Dispatcher;
import org.dromara.neutrinoproxy.server.base.proxy.ProxyConfig;
import org.dromara.neutrinoproxy.server.constant.ClientConnectTypeEnum;
import org.dromara.neutrinoproxy.server.constant.SuccessCodeEnum;
import org.dromara.neutrinoproxy.server.dal.entity.ClientConnectRecordDO;
@@ -49,13 +50,21 @@ import java.util.Date;
@Slf4j
public class ProxyTunnelChannelHandler extends SimpleChannelInboundHandler<ProxyMessage> {
private static volatile Dispatcher<ChannelHandlerContext, ProxyMessage> dispatcher;
private static volatile Boolean transferLogEnable = Boolean.FALSE;
public ProxyTunnelChannelHandler() {
dispatcher = Solon.context().getBean(Dispatcher.class);
ProxyConfig proxyConfig = Solon.context().getBean(ProxyConfig.class);
if (null != proxyConfig.getTunnel() && null != proxyConfig.getTunnel().getHeartbeatLogEnable()) {
transferLogEnable = proxyConfig.getTunnel().getHeartbeatLogEnable();
}
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, ProxyMessage proxyMessage) throws Exception {
if (ProxyMessage.TYPE_HEARTBEAT != proxyMessage.getType() || transferLogEnable) {
log.debug("Server CmdChannel recieved proxy message, type is {}", proxyMessage.getType());
}
dispatcher.dispatch(ctx, proxyMessage);
}
@@ -97,16 +106,16 @@ public class ProxyTunnelChannelHandler extends SimpleChannelInboundHandler<Proxy
// 防止下次换一个客户端,无法连接的情况
ProxyUtil.removeClientIdByLicenseId(cmdChannelAttachInfo.getLicenseId());
}
// 即便是因为上述原因断开,断开的日志依然要记录,方便排查问题
Solon.context().getBean(ClientConnectRecordService.class).add(new ClientConnectRecordDO()
.setIp(((InetSocketAddress)ctx.channel().remoteAddress()).getAddress().getHostAddress())
.setLicenseId(cmdChannelAttachInfo.getLicenseId())
.setType(ClientConnectTypeEnum.DISCONNECT.getType())
.setMsg("")
.setCode(SuccessCodeEnum.SUCCESS.getCode())
.setCreateTime(new Date())
);
}
// 即便是因为上述原因断开,断开的日志依然要记录,方便排查问题
Solon.context().getBean(ClientConnectRecordService.class).add(new ClientConnectRecordDO()
.setIp(((InetSocketAddress)ctx.channel().remoteAddress()).getAddress().getHostAddress())
.setLicenseId(cmdChannelAttachInfo.getLicenseId())
.setType(ClientConnectTypeEnum.DISCONNECT.getType())
.setMsg("")
.setCode(SuccessCodeEnum.SUCCESS.getCode())
.setCreateTime(new Date())
);
}
super.channelInactive(ctx);
@@ -114,7 +123,7 @@ public class ProxyTunnelChannelHandler extends SimpleChannelInboundHandler<Proxy
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
// super.exceptionCaught(ctx, cause);
if (ctx.channel().isActive()) {
ctx.channel().close();
}
@@ -127,10 +136,11 @@ public class ProxyTunnelChannelHandler extends SimpleChannelInboundHandler<Proxy
switch (event.state()) {
case READER_IDLE:
// 读超时,断开连接
log.info("读超时");
log.debug("读超时");
ctx.channel().close();
break;
case WRITER_IDLE:
ctx.channel().writeAndFlush(ProxyMessage.buildHeartbeatMessage());
break;
case ALL_IDLE:
break;
@@ -1,5 +1,6 @@
package org.dromara.neutrinoproxy.server.proxy.core;
import io.netty.handler.logging.LoggingHandler;
import org.dromara.neutrinoproxy.core.ProxyMessageDecoder;
import org.dromara.neutrinoproxy.core.ProxyMessageEncoder;
import org.dromara.neutrinoproxy.core.util.FileUtil;
@@ -111,7 +112,9 @@ public class ProxyTunnelServer implements EventListener<AppLoadEndEvent> {
}
private void proxyServerCommonInitHandler(SocketChannel ch) {
// ch.pipeline().addFirst(new LoggingHandler(ProxyServerRunner.class));
if (null != proxyConfig.getTunnel().getTransferLogEnable() && proxyConfig.getTunnel().getTransferLogEnable()) {
ch.pipeline().addFirst(new LoggingHandler(ProxyTunnelServer.class));
}
ch.pipeline().addLast(new ProxyMessageDecoder(proxyConfig.getProtocol().getMaxFrameLength(),
proxyConfig.getProtocol().getLengthFieldOffset(), proxyConfig.getProtocol().getLengthFieldLength(),
proxyConfig.getProtocol().getLengthAdjustment(), proxyConfig.getProtocol().getInitialBytesToStrip()));
@@ -6,9 +6,11 @@ import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;
import org.dromara.neutrinoproxy.server.base.proxy.ProxyConfig;
import org.dromara.neutrinoproxy.server.proxy.core.BytesMetricsHandler;
import org.dromara.neutrinoproxy.server.proxy.core.ProxyTunnelServer;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.event.AppLoadEndEvent;
@@ -40,12 +42,15 @@ public class HttpProxy implements EventListener<AppLoadEndEvent> {
.channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
if (null != proxyConfig.getServer().getTransferLogEnable() && proxyConfig.getServer().getTransferLogEnable()) {
ch.pipeline().addFirst(new LoggingHandler(HttpProxy.class));
}
ch.pipeline().addFirst(new BytesMetricsHandler());
ch.pipeline().addLast(new HttpVisitorChannelHandler(proxyConfig.getServer().getDomainName()));
}
});
bootstrap.bind("0.0.0.0", proxyConfig.getServer().getHttpProxyPort()).sync();
log.info("Http代理服务启动成功!");
log.info("Http代理服务启动成功!port:{}", proxyConfig.getServer().getHttpProxyPort());
} catch (Exception e) {
log.error("http proxy start err!", e);
}
@@ -68,11 +68,11 @@ public class HttpVisitorChannelHandler extends SimpleChannelInboundHandler<ByteB
ctx.channel().config().setOption(ChannelOption.AUTO_READ, false);
String host = getHost(bytes);
log.debug("HttpProxy host: {}", host);
if (StringUtils.isBlank(host)) {
ctx.channel().close();
return;
}
log.debug("HttpProxy host: {}", host);
if (!host.endsWith(domainName)) {
ctx.channel().close();
return;
@@ -163,7 +163,8 @@ public class HttpVisitorChannelHandler extends SimpleChannelInboundHandler<ByteB
}
// 域名
String domain = line.substring(6);
return domain;
// 去掉域名后面的端口号
return domain.replaceAll(":.*", "");
}
return null;
}
@@ -6,12 +6,14 @@ import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.dromara.neutrinoproxy.core.util.FileUtil;
import org.dromara.neutrinoproxy.server.base.proxy.ProxyConfig;
import org.dromara.neutrinoproxy.server.proxy.core.BytesMetricsHandler;
import org.dromara.neutrinoproxy.server.proxy.core.ProxyTunnelServer;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.event.AppLoadEndEvent;
@@ -48,13 +50,16 @@ public class HttpsProxy implements EventListener<AppLoadEndEvent> {
.channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
if (null != proxyConfig.getServer().getTransferLogEnable() && proxyConfig.getServer().getTransferLogEnable()) {
ch.pipeline().addFirst(new LoggingHandler(HttpsProxy.class));
}
ch.pipeline().addLast(createSslHandler());
ch.pipeline().addFirst(new BytesMetricsHandler());
ch.pipeline().addLast(new HttpVisitorChannelHandler(proxyConfig.getServer().getDomainName()));
}
});
bootstrap.bind("0.0.0.0", proxyConfig.getServer().getHttpsProxyPort()).sync();
log.info("Https代理服务启动成功!");
log.info("Https代理服务启动成功!port:{}", proxyConfig.getServer().getHttpsProxyPort());
} catch (Exception e) {
log.error("https proxy start err!", e);
}
@@ -61,7 +61,7 @@ public class JobLogService implements IJobCallback {
String msg = "";
if (null == throwable) {
msg = "执行成功";
log.info("job[id={},name={}]执行完毕", jobInfo.getId(), jobInfo.getName());
log.debug("job[id={},name={}]执行完毕", jobInfo.getId(), jobInfo.getName());
} else {
log.error("job[id={},name={}]执行异常", jobInfo.getId(), jobInfo.getName(), throwable);
msg = "执行异常:\r\n" + ExceptionUtils.getStackTrace(throwable);
@@ -6,9 +6,12 @@ import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Sets;
import ma.glasnost.orika.MapperFacade;
import org.apache.ibatis.solon.annotation.Db;
import org.dromara.neutrinoproxy.server.base.db.DBInitialize;
import org.dromara.neutrinoproxy.server.base.page.PageInfo;
import org.dromara.neutrinoproxy.server.base.page.PageQuery;
import org.dromara.neutrinoproxy.server.base.rest.ServiceException;
import org.dromara.neutrinoproxy.server.base.rest.SystemContextHolder;
import org.dromara.neutrinoproxy.server.constant.EnableStatusEnum;
import org.dromara.neutrinoproxy.server.constant.ExceptionConstant;
@@ -19,18 +22,15 @@ import org.dromara.neutrinoproxy.server.controller.req.proxy.LicenseUpdateEnable
import org.dromara.neutrinoproxy.server.controller.req.proxy.LicenseUpdateReq;
import org.dromara.neutrinoproxy.server.controller.res.proxy.*;
import org.dromara.neutrinoproxy.server.dal.LicenseMapper;
import org.dromara.neutrinoproxy.server.dal.PortMappingMapper;
import org.dromara.neutrinoproxy.server.dal.UserMapper;
import org.dromara.neutrinoproxy.server.dal.entity.LicenseDO;
import org.dromara.neutrinoproxy.server.dal.entity.PortMappingDO;
import org.dromara.neutrinoproxy.server.dal.entity.UserDO;
import org.dromara.neutrinoproxy.server.util.ParamCheckUtil;
import ma.glasnost.orika.MapperFacade;
import org.apache.ibatis.solon.annotation.Db;
import org.dromara.neutrinoproxy.server.controller.res.proxy.*;
import org.jetbrains.annotations.Nullable;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Init;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.Lifecycle;
import org.noear.solon.core.bean.LifecycleBean;
import java.util.*;
@@ -39,220 +39,231 @@ import java.util.stream.Collectors;
/**
* license服务
*
* @author: aoshiguchen
* @date: 2022/8/6
*/
@Component
public class LicenseService implements LifecycleBean {
@Inject
private MapperFacade mapperFacade;
@Db
private LicenseMapper licenseMapper;
@Db
private UserMapper userMapper;
@Inject
private VisitorChannelService visitorChannelService;
@Inject
private DBInitialize dbInitialize;
@Inject
private MapperFacade mapperFacade;
@Db
private LicenseMapper licenseMapper;
@Db
private PortMappingMapper portMappingMapper;
@Db
private UserMapper userMapper;
@Inject
private VisitorChannelService visitorChannelService;
@Inject
private DBInitialize dbInitialize;
public PageInfo<LicenseListRes> page(PageQuery pageQuery, LicenseListReq req) {
Page<LicenseListRes> result = PageHelper.startPage(pageQuery.getCurrent(), pageQuery.getSize());
List<LicenseDO> list = licenseMapper.selectList(new LambdaQueryWrapper<LicenseDO>()
.eq(req.getUserId() != null, LicenseDO::getUserId, req.getUserId())
.eq(req.getIsOnline() != null, LicenseDO::getIsOnline, req.getIsOnline())
.eq(req.getEnable() != null, LicenseDO::getEnable, req.getEnable())
.orderByAsc(Arrays.asList(LicenseDO::getUserId, LicenseDO::getId))
);
List<LicenseListRes> respList = mapperFacade.mapAsList(list, LicenseListRes.class);
if (CollectionUtils.isEmpty(list)) {
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
}
if (!CollectionUtil.isEmpty(respList)) {
Set<Integer> userIds = respList.stream().map(LicenseListRes::getUserId).collect(Collectors.toSet());
List<UserDO> userList = userMapper.findByIds(userIds);
Map<Integer, UserDO> userMap = userList.stream().collect(Collectors.toMap(UserDO::getId, Function.identity()));
for (LicenseListRes item : respList) {
UserDO userDO = userMap.get(item.getUserId());
if (null != userDO) {
item.setUserName(userDO.getName());
}
item.setKey(desensitization(item.getUserId(), item.getKey()));
}
}
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
}
public PageInfo<LicenseListRes> page(PageQuery pageQuery, LicenseListReq req) {
Page<LicenseListRes> result = PageHelper.startPage(pageQuery.getCurrent(), pageQuery.getSize());
List<LicenseDO> list = licenseMapper.selectList(new LambdaQueryWrapper<LicenseDO>()
.eq(req.getUserId() != null, LicenseDO::getUserId, req.getUserId())
.eq(req.getIsOnline() != null, LicenseDO::getIsOnline, req.getIsOnline())
.eq(req.getEnable() != null, LicenseDO::getEnable, req.getEnable())
.orderByAsc(Arrays.asList(LicenseDO::getUserId, LicenseDO::getId))
);
List<LicenseListRes> respList = mapperFacade.mapAsList(list, LicenseListRes.class);
if (CollectionUtils.isEmpty(list)) {
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
}
if (!CollectionUtil.isEmpty(respList)) {
Set<Integer> userIds = respList.stream().map(LicenseListRes::getUserId).collect(Collectors.toSet());
List<UserDO> userList = userMapper.findByIds(userIds);
Map<Integer, UserDO> userMap = userList.stream().collect(Collectors.toMap(UserDO::getId, Function.identity()));
for (LicenseListRes item : respList) {
UserDO userDO = userMap.get(item.getUserId());
if (null != userDO) {
item.setUserName(userDO.getName());
}
item.setKey(desensitization(item.getUserId(), item.getKey()));
}
}
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
}
public List<LicenseListRes> list(LicenseListReq req) {
List<LicenseDO> list = licenseMapper.selectList(new LambdaQueryWrapper<LicenseDO>()
.eq(null != req.getEnable(), LicenseDO::getEnable, req.getEnable())
);
List<LicenseListRes> licenseList = assembleConvertLicenses(list);
return licenseList;
}
public List<LicenseListRes> list(LicenseListReq req) {
List<LicenseDO> list = licenseMapper.selectList(new LambdaQueryWrapper<LicenseDO>()
.eq(null != req.getEnable(), LicenseDO::getEnable, req.getEnable())
);
List<LicenseListRes> licenseList = assembleConvertLicenses(list);
return licenseList;
}
@Nullable
private List<LicenseListRes> assembleConvertLicenses(List<LicenseDO> list) {
List<LicenseListRes> licenseList = mapperFacade.mapAsList(list, LicenseListRes.class);
if (!CollectionUtil.isEmpty(licenseList)) {
Set<Integer> userIds = licenseList.stream().map(LicenseListRes::getUserId).collect(Collectors.toSet());
List<UserDO> userList = userMapper.findByIds(userIds);
Map<Integer, UserDO> userMap = userList.stream().collect(Collectors.toMap(UserDO::getId, Function.identity()));
for (LicenseListRes item : licenseList) {
UserDO userDO = userMap.get(item.getUserId());
if (null != userDO) {
item.setUserName(userDO.getName());
}
item.setKey(desensitization(item.getUserId(), item.getKey()));
}
}
return licenseList;
}
private List<LicenseListRes> assembleConvertLicenses(List<LicenseDO> list) {
List<LicenseListRes> licenseList = mapperFacade.mapAsList(list, LicenseListRes.class);
if (!CollectionUtil.isEmpty(licenseList)) {
Set<Integer> userIds = licenseList.stream().map(LicenseListRes::getUserId).collect(Collectors.toSet());
List<UserDO> userList = userMapper.findByIds(userIds);
Map<Integer, UserDO> userMap = userList.stream().collect(Collectors.toMap(UserDO::getId, Function.identity()));
for (LicenseListRes item : licenseList) {
UserDO userDO = userMap.get(item.getUserId());
if (null != userDO) {
item.setUserName(userDO.getName());
}
item.setKey(desensitization(item.getUserId(), item.getKey()));
}
}
return licenseList;
}
/**
* 创建license
* @param req
* @return
*/
public LicenseCreateRes create(LicenseCreateReq req) {
LicenseDO licenseDO = licenseMapper.checkRepeat(req.getUserId(), req.getName());
ParamCheckUtil.checkExpression(null == licenseDO, ExceptionConstant.LICENSE_NAME_CANNOT_REPEAT);
/**
* 创建license
*
* @param req
* @return
*/
public LicenseCreateRes create(LicenseCreateReq req) {
LicenseDO licenseDO = licenseMapper.checkRepeat(req.getUserId(), req.getName());
ParamCheckUtil.checkExpression(null == licenseDO, ExceptionConstant.LICENSE_NAME_CANNOT_REPEAT);
String key = UUID.randomUUID().toString().replaceAll("-", "");
Date now = new Date();
String key = UUID.randomUUID().toString().replaceAll("-", "");
Date now = new Date();
licenseMapper.insert(new LicenseDO()
.setName(req.getName())
.setKey(key)
.setUserId(req.getUserId())
.setIsOnline(OnlineStatusEnum.OFFLINE.getStatus())
.setEnable(EnableStatusEnum.ENABLE.getStatus())
.setCreateTime(now)
.setUpdateTime(now)
);
return new LicenseCreateRes();
}
licenseMapper.insert(new LicenseDO()
.setName(req.getName())
.setKey(key)
.setUserId(req.getUserId())
.setIsOnline(OnlineStatusEnum.OFFLINE.getStatus())
.setEnable(EnableStatusEnum.ENABLE.getStatus())
.setCreateTime(now)
.setUpdateTime(now)
);
return new LicenseCreateRes();
}
public LicenseUpdateRes update(LicenseUpdateReq req) {
LicenseDO oldLicenseDO = licenseMapper.findById(req.getId());
ParamCheckUtil.checkNotNull(oldLicenseDO, ExceptionConstant.LICENSE_NOT_EXIST);
public LicenseUpdateRes update(LicenseUpdateReq req) {
LicenseDO oldLicenseDO = licenseMapper.findById(req.getId());
ParamCheckUtil.checkNotNull(oldLicenseDO, ExceptionConstant.LICENSE_NOT_EXIST);
LicenseDO licenseCheck = licenseMapper.checkRepeat(oldLicenseDO.getUserId(), req.getName(), Sets.newHashSet(oldLicenseDO.getId()));
ParamCheckUtil.checkMustNull(licenseCheck, ExceptionConstant.LICENSE_NAME_CANNOT_REPEAT);
LicenseDO licenseCheck = licenseMapper.checkRepeat(oldLicenseDO.getUserId(), req.getName(), Sets.newHashSet(oldLicenseDO.getId()));
ParamCheckUtil.checkMustNull(licenseCheck, ExceptionConstant.LICENSE_NAME_CANNOT_REPEAT);
licenseMapper.update(req.getId(), req.getName(), new Date());
return new LicenseUpdateRes();
}
licenseMapper.update(req.getId(), req.getName(), new Date());
return new LicenseUpdateRes();
}
public LicenseDetailRes detail(Integer id) {
LicenseDO licenseDO = licenseMapper.findById(id);
if (null == licenseDO) {
return null;
}
UserDO userDO = userMapper.findById(licenseDO.getUserId());
String userName = "";
if (null != userDO) {
userName = userDO.getName();
}
return new LicenseDetailRes()
.setId(licenseDO.getId())
.setName(licenseDO.getName())
.setKey(desensitization(licenseDO.getUserId(), licenseDO.getKey()))
.setUserId(licenseDO.getUserId())
.setUserName(userName)
.setIsOnline(licenseDO.getIsOnline())
.setEnable(licenseDO.getEnable())
.setCreateTime(licenseDO.getCreateTime())
.setUpdateTime(licenseDO.getUpdateTime())
;
}
public LicenseDetailRes detail(Integer id) {
LicenseDO licenseDO = licenseMapper.findById(id);
if (null == licenseDO) {
return null;
}
UserDO userDO = userMapper.findById(licenseDO.getUserId());
String userName = "";
if (null != userDO) {
userName = userDO.getName();
}
return new LicenseDetailRes()
.setId(licenseDO.getId())
.setName(licenseDO.getName())
.setKey(desensitization(licenseDO.getUserId(), licenseDO.getKey()))
.setUserId(licenseDO.getUserId())
.setUserName(userName)
.setIsOnline(licenseDO.getIsOnline())
.setEnable(licenseDO.getEnable())
.setCreateTime(licenseDO.getCreateTime())
.setUpdateTime(licenseDO.getUpdateTime())
;
}
/**
* 更新license启用状态
* @param req
* @return
*/
public LicenseUpdateEnableStatusRes updateEnableStatus(LicenseUpdateEnableStatusReq req) {
licenseMapper.updateEnableStatus(req.getId(), req.getEnable(), new Date());
// 更新VisitorChannel
visitorChannelService.updateVisitorChannelByLicenseId(req.getId(), req.getEnable());
return new LicenseUpdateEnableStatusRes();
}
/**
* 更新license启用状态
*
* @param req
* @return
*/
public LicenseUpdateEnableStatusRes updateEnableStatus(LicenseUpdateEnableStatusReq req) {
licenseMapper.updateEnableStatus(req.getId(), req.getEnable(), new Date());
// 更新VisitorChannel
visitorChannelService.updateVisitorChannelByLicenseId(req.getId(), req.getEnable());
return new LicenseUpdateEnableStatusRes();
}
/**
* 删除license
* @param id
*/
public void delete(Integer id) {
licenseMapper.deleteById(id);
// 更新VisitorChannel
visitorChannelService.updateVisitorChannelByLicenseId(id, EnableStatusEnum.DISABLE.getStatus());
}
/**
* 删除license
*
* @param id
*/
public void delete(Integer id) {
List<PortMappingDO> portMappingDOList = portMappingMapper.findListByLicenseId(id);
if (CollectionUtil.isNotEmpty(portMappingDOList)) {
throw ServiceException.create(ExceptionConstant.LICENSE_CANNOT_BE_DELETED, portMappingDOList.size());
}
licenseMapper.deleteById(id);
// 更新VisitorChannel
visitorChannelService.updateVisitorChannelByLicenseId(id, EnableStatusEnum.DISABLE.getStatus());
}
/**
* 重置license
* @param id
*/
public void reset(Integer id) {
String key = UUID.randomUUID().toString().replaceAll("-", "");
Date now = new Date();
/**
* 重置license
*
* @param id
*/
public void reset(Integer id) {
String key = UUID.randomUUID().toString().replaceAll("-", "");
Date now = new Date();
licenseMapper.reset(id, key, now);
}
licenseMapper.reset(id, key, now);
}
public LicenseDO findByKey(String license) {
return licenseMapper.findByKey(license);
}
public LicenseDO findByKey(String license) {
return licenseMapper.findByKey(license);
}
/**
* 脱敏处理
* 非当前登录人的license,一律脱敏
* @param userId
* @param licenseKey
* @return
*/
private String desensitization(Integer userId, String licenseKey) {
Integer currentUserId = SystemContextHolder.getUser().getId();
if (currentUserId.equals(userId)) {
return licenseKey;
}
return licenseKey.substring(0, 10) + "****" + licenseKey.substring(licenseKey.length() - 10);
}
/**
* 脱敏处理
* 非当前登录人的license,一律脱敏
*
* @param userId
* @param licenseKey
* @return
*/
private String desensitization(Integer userId, String licenseKey) {
Integer currentUserId = SystemContextHolder.getUser().getId();
if (currentUserId.equals(userId)) {
return licenseKey;
}
return licenseKey.substring(0, 10) + "****" + licenseKey.substring(licenseKey.length() - 10);
}
/**
* 服务端项目停止、启动时,更新在线状态为离线
*/
@Init
public void init() {
licenseMapper.updateOnlineStatus(OnlineStatusEnum.OFFLINE.getStatus(), new Date());
}
/**
* 服务端项目停止、启动时,更新在线状态为离线
*/
@Init
public void init() {
licenseMapper.updateOnlineStatus(OnlineStatusEnum.OFFLINE.getStatus(), new Date());
}
@Override
public void start() throws Throwable {
@Override
public void start() throws Throwable {
}
}
/**
* 服务端项目停止、启动时,更新在线状态为离线
*/
@Override
public void stop() throws Throwable {
licenseMapper.updateOnlineStatus(OnlineStatusEnum.OFFLINE.getStatus(), new Date());
}
/**
* 服务端项目停止、启动时,更新在线状态为离线
*/
@Override
public void stop() throws Throwable {
licenseMapper.updateOnlineStatus(OnlineStatusEnum.OFFLINE.getStatus(), new Date());
}
/**
* 查询当前角色下的license,若为管理员 则返回全部license
*/
public List<LicenseListRes> queryCurUserLicense(LicenseListReq req) {
if(SystemContextHolder.isAdmin()){
return this.list(req);
}
/**
* 查询当前角色下的license,若为管理员 则返回全部license
*/
public List<LicenseListRes> queryCurUserLicense(LicenseListReq req) {
if (SystemContextHolder.isAdmin()) {
return this.list(req);
}
List<LicenseDO> list = licenseMapper.selectList(new LambdaQueryWrapper<LicenseDO>()
.eq(LicenseDO::getEnable, EnableStatusEnum.ENABLE.getStatus())
.eq(LicenseDO::getUserId,SystemContextHolder.getUserId())
);
List<LicenseListRes> licenseList = assembleConvertLicenses(list);
return licenseList;
}
List<LicenseDO> list = licenseMapper.selectList(new LambdaQueryWrapper<LicenseDO>()
.eq(LicenseDO::getEnable, EnableStatusEnum.ENABLE.getStatus())
.eq(LicenseDO::getUserId, SystemContextHolder.getUserId())
);
List<LicenseListRes> licenseList = assembleConvertLicenses(list);
return licenseList;
}
}
@@ -8,6 +8,8 @@ import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Sets;
import ma.glasnost.orika.MapperFacade;
import org.apache.ibatis.solon.annotation.Db;
import org.dromara.neutrinoproxy.server.base.db.DBInitialize;
import org.dromara.neutrinoproxy.server.base.page.PageInfo;
import org.dromara.neutrinoproxy.server.base.page.PageQuery;
@@ -31,14 +33,10 @@ import org.dromara.neutrinoproxy.server.dal.entity.PortMappingDO;
import org.dromara.neutrinoproxy.server.dal.entity.PortPoolDO;
import org.dromara.neutrinoproxy.server.dal.entity.UserDO;
import org.dromara.neutrinoproxy.server.util.ParamCheckUtil;
import ma.glasnost.orika.MapperFacade;
import org.apache.ibatis.solon.annotation.Db;
import org.dromara.neutrinoproxy.server.controller.res.proxy.*;
import org.dromara.neutrinoproxy.server.util.ProxyUtil;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Init;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.Lifecycle;
import org.noear.solon.core.bean.LifecycleBean;
import java.util.*;
@@ -51,25 +49,25 @@ import java.util.stream.Collectors;
*/
@Component
public class PortMappingService implements LifecycleBean {
@Inject
private MapperFacade mapperFacade;
@Db
private PortMappingMapper portMappingMapper;
@Db
private LicenseMapper licenseMapper;
@Db
private UserMapper userMapper;
@Db
private PortPoolMapper portPoolMapper;
@Inject
private VisitorChannelService visitorChannelService;
@Inject
private MapperFacade mapperFacade;
@Db
private PortMappingMapper portMappingMapper;
@Db
private LicenseMapper licenseMapper;
@Db
private UserMapper userMapper;
@Db
private PortPoolMapper portPoolMapper;
@Inject
private VisitorChannelService visitorChannelService;
@Inject
private PortPoolService portPoolService;
@Inject
private ProxyConfig proxyConfig;
@Inject
private DBInitialize dbInitialize;
@Inject
private PortPoolService portPoolService;
@Inject
private ProxyConfig proxyConfig;
@Inject
private DBInitialize dbInitialize;
public PageInfo<PortMappingListRes> page(PageQuery pageQuery, PortMappingListReq req) {
Page<PortMappingListRes> result = PageHelper.startPage(pageQuery.getCurrent(), pageQuery.getSize());
@@ -77,6 +75,13 @@ public class PortMappingService implements LifecycleBean {
//描述字段为模糊查询,在应用层处理,否则sqlite不支持
req.setDescription("%" + req.getDescription() + "%");
}
// 协议名称转换
if (StringUtils.isNotBlank(req.getProtocal())) {
NetworkProtocolEnum networkProtocolEnum = NetworkProtocolEnum.of(req.getProtocal());
req.setProtocal(networkProtocolEnum.getDesc());
}
List<PortMappingDO> list = portMappingMapper.selectPortMappingByCondition(req);
List<PortMappingListRes> respList = mapperFacade.mapAsList(list, PortMappingListRes.class);
if (CollectionUtils.isEmpty(list)) {
@@ -113,10 +118,7 @@ public class PortMappingService implements LifecycleBean {
}
});
//sorted [userId asc] [licenseId asc] [createTime asc]
respList = respList.stream().sorted(Comparator.comparing(PortMappingListRes::getUserId)
.thenComparing(PortMappingListRes::getLicenseId)
.thenComparing(PortMappingListRes::getCreateTime))
.collect(Collectors.toList());
respList = respList.stream().sorted(Comparator.comparing(PortMappingListRes::getUserId).thenComparing(PortMappingListRes::getLicenseId).thenComparing(PortMappingListRes::getCreateTime)).collect(Collectors.toList());
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
}
@@ -149,9 +151,7 @@ public class PortMappingService implements LifecycleBean {
// 更新VisitorChannel
visitorChannelService.addVisitorChannelByPortMapping(portMappingDO);
// 更新域名映射
if (NetworkProtocolEnum.HTTP.getDesc().equals(portMappingDO.getProtocal()) &&
StrUtil.isNotBlank(proxyConfig.getServer().getDomainName()) &&
StrUtil.isNotBlank(portMappingDO.getSubdomain())) {
if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) && StrUtil.isNotBlank(proxyConfig.getServer().getDomainName()) && StrUtil.isNotBlank(portMappingDO.getSubdomain())) {
ProxyUtil.setSubdomainToServerPort(portMappingDO.getSubdomain(), portMappingDO.getServerPort());
}
return new PortMappingCreateRes();
@@ -188,14 +188,11 @@ public class PortMappingService implements LifecycleBean {
// 更新VisitorChannel
visitorChannelService.updateVisitorChannelByPortMapping(oldPortMappingDO, portMappingDO);
// 删除老的域名映射
if (NetworkProtocolEnum.HTTP.getDesc().equals(oldPortMappingDO.getProtocal()) &&
StrUtil.isNotBlank(oldPortMappingDO.getSubdomain())) {
if (NetworkProtocolEnum.isHttp(oldPortMappingDO.getProtocal()) && StrUtil.isNotBlank(oldPortMappingDO.getSubdomain())) {
ProxyUtil.removeSubdomainToServerPort(oldPortMappingDO.getSubdomain());
}
// 更新域名映射
if (NetworkProtocolEnum.HTTP.getDesc().equals(portMappingDO.getProtocal()) &&
StrUtil.isNotBlank(proxyConfig.getServer().getDomainName()) &&
StrUtil.isNotBlank(portMappingDO.getSubdomain())) {
if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) && StrUtil.isNotBlank(proxyConfig.getServer().getDomainName()) && StrUtil.isNotBlank(portMappingDO.getSubdomain())) {
ProxyUtil.setSubdomainToServerPort(portMappingDO.getSubdomain(), portMappingDO.getServerPort());
}
return new PortMappingUpdateRes();
@@ -206,16 +203,7 @@ public class PortMappingService implements LifecycleBean {
if (null == portMappingDO) {
return null;
}
PortMappingDetailRes res = new PortMappingDetailRes()
.setId(portMappingDO.getId())
.setLicenseId(portMappingDO.getLicenseId())
.setServerPort(portMappingDO.getServerPort())
.setClientIp(portMappingDO.getClientIp())
.setClientPort(portMappingDO.getClientPort())
.setIsOnline(portMappingDO.getIsOnline())
.setEnable(portMappingDO.getEnable())
.setCreateTime(portMappingDO.getCreateTime())
.setUpdateTime(portMappingDO.getUpdateTime());
PortMappingDetailRes res = new PortMappingDetailRes().setId(portMappingDO.getId()).setLicenseId(portMappingDO.getLicenseId()).setServerPort(portMappingDO.getServerPort()).setClientIp(portMappingDO.getClientIp()).setClientPort(portMappingDO.getClientPort()).setIsOnline(portMappingDO.getIsOnline()).setEnable(portMappingDO.getEnable()).setCreateTime(portMappingDO.getCreateTime()).setUpdateTime(portMappingDO.getUpdateTime());
LicenseDO license = licenseMapper.findById(portMappingDO.getLicenseId());
if (null != license) {
@@ -268,8 +256,7 @@ public class PortMappingService implements LifecycleBean {
// 更新VisitorChannel
visitorChannelService.removeVisitorChannelByPortMapping(portMappingDO);
// 更新域名映射
if (NetworkProtocolEnum.HTTP.getDesc().equals(portMappingDO.getProtocal()) &&
StrUtil.isNotBlank(portMappingDO.getSubdomain())) {
if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) && StrUtil.isNotBlank(portMappingDO.getSubdomain())) {
ProxyUtil.removeSubdomainToServerPort(portMappingDO.getSubdomain());
}
}
@@ -295,10 +282,7 @@ public class PortMappingService implements LifecycleBean {
if (StrUtil.isBlank(proxyConfig.getServer().getDomainName())) {
return;
}
List<PortMappingDO> portMappingDOList = portMappingMapper.selectList(new LambdaQueryWrapper<PortMappingDO>()
.eq(PortMappingDO::getProtocal, NetworkProtocolEnum.HTTP.getDesc())
.isNotNull(PortMappingDO::getSubdomain)
);
List<PortMappingDO> portMappingDOList = portMappingMapper.selectList(new LambdaQueryWrapper<PortMappingDO>().eq(PortMappingDO::getProtocal, NetworkProtocolEnum.HTTP.getDesc()).isNotNull(PortMappingDO::getSubdomain));
if (CollectionUtil.isEmpty(portMappingDOList)) {
return;
}
@@ -28,6 +28,7 @@ import org.apache.ibatis.solon.annotation.Db;
import org.dromara.neutrinoproxy.server.controller.req.system.*;
import org.dromara.neutrinoproxy.server.controller.res.system.*;
import org.dromara.neutrinoproxy.server.dal.entity.PortGroupDO;
import org.dromara.neutrinoproxy.server.util.PortAvailableUtil;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
@@ -175,8 +176,44 @@ public class PortPoolService {
* 游客:全局端口 + 当前选择用户独占端口 + 当前选择license独占端口
* 非管理员身份时:下拉选择license,只能选当前用户下的LICENSE
*/
public List<PortPoolListRes> getAvailablePortList(AvailablePortListReq req) {
public PageInfo<PortPoolListRes> getAvailablePortList(AvailablePortListReq req) {
LicenseDO licenseDO = licenseMapper.queryById(req.getLicenseId());
return portPoolMapper.getAvailablePortList(req.getLicenseId(), licenseDO.getUserId());
if(StringUtils.isNotEmpty(req.getKeyword())){
req.setKeyword(req.getKeyword()+"%");
}
Page<PortPoolListRes> result = PageHelper.startPage(req.getPage(), req.getSize());
List<PortPoolListRes> portList = portPoolMapper.getAvailablePortList(req.getLicenseId(), licenseDO.getUserId(), req.getKeyword());
return PageInfo.of(portList, result.getTotal(), req.getPage(), req.getSize());
}
public void deleteBatch(List<Integer> ids) {
List<PortPoolDO> portPoolDOList = portPoolMapper.selectBatchIds(ids);
ParamCheckUtil.checkNotNull(portPoolDOList, ExceptionConstant.PORT_NOT_EXIST);
portPoolMapper.deleteBatchIds(ids);
// 更新visitorChannel
portPoolDOList.stream().forEach(portPoolDO -> {
visitorChannelService.updateVisitorChannelByPortPool(portPoolDO.getPort(), EnableStatusEnum.DISABLE.getStatus());
});
}
/**
* 检查端口是否被占用
* 端口映射编辑时,如果端口号没有变动,则不验证。避免出现端口映射正在使用时,无法更新端口映射其他信息的问题
* @param port
* @param portMappingId
* @return
*/
public boolean portAvailable(Integer port, Integer portMappingId) {
if (null != portMappingId) {
PortMappingDO portMappingDO = portMappingMapper.findById(portMappingId);
if (null != portMappingDO && portMappingDO.getServerPort().equals(port)) {
return Boolean.TRUE;
}
}
return PortAvailableUtil.isPortAvailable(port);
}
}
@@ -0,0 +1,39 @@
package org.dromara.neutrinoproxy.server.util;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
/**
* 检查端口是否被占用
* 文章参考:https://blog.csdn.net/xingluxiaoseng/article/details/40148527
*/
public class PortAvailableUtil {
private static void bindPort(String host, int port) throws IOException {
Socket s = new Socket();
s.bind(new InetSocketAddress(host, port));
s.close();
}
/**
* 端口占用判断,若是端口被占用,则会抛出IOException异常,表示端口被占用
* @param port
* @return
*/
public static boolean isPortAvailable(int port) {
try {
bindPort("0.0.0.0", port);
bindPort(InetAddress.getLocalHost().getHostAddress(), port);
return true;
} catch (Exception e) {
return false;
}
}
public static void main(String[] args) {
System.out.println("端口被占用:"+isPortAvailable(9527));
}
}
@@ -1,5 +1,7 @@
server:
# 服务端web端口,用于支持HTTP接口,管理后台页面访问
port: ${WEB_PORT:8888}
context-path: /neutrino-proxy-server
neutrino:
proxy:
@@ -12,28 +14,50 @@ neutrino:
read-idle-time: 30
write-idle-time: 5
all-idle-time-seconds: 0
logger:
# 日志级别
level: ${LOG_LEVEL:info}
# 隧道相关配置-用于维持服务端与客户端的通信
tunnel:
# 线程池相关配置,用于技术调优,可忽略
boss-thread-count: 2
work-thread-count: 10
# 隧道非SSL端口
port: ${OPEN_PORT:9000}
# 隧道SSL端口
ssl-port: ${SSL_PORT:9002}
# 隧道SSL证书配置
key-store-password: ${STORE_PASS:123456}
key-manager-password: ${MGR_PASS:123456}
jks-path: ${JKS_PATH:classpath:/test.jks}
# 是否开启隧道传输报文日志(日志级别为debug时开启才有效)
transfer-log-enable: ${TUNNEL_LOG:false}
# 是否开启心跳日志
heartbeat-log-enable: ${HEARTBEAT_LOG:false}
server:
# 线程池相关配置,用于技术调优,可忽略
boss-thread-count: 5
work-thread-count: 20
# http代理端口,默认80
http-proxy-port: ${HTTP_PROXY_PORT:80}
# https代理端口,默认443 (需要配置域名、证书)
https-proxy-port: ${HTTPS_PROXY_PORT:443}
# 如果不配置,则不支持域名映射
domain-name: ${DOMAIN_NAME:}
# https证书配置
key-store-password: ${HTTPS_STORE_PASS:}
jks-path: ${HTTPS_JKS_PATH:}
# 是否开启代理服务报文日志(日志级别为debug时开启才有效)
transfer-log-enable: ${SERVER_LOG:false}
data:
db:
# 数据库类型,目前支持sqlite、mysql、mariadb
type: ${DB_TYPE:sqlite}
# 数据库连接URL
url: ${DB_URL:jdbc:sqlite:data.db}
# 数据库用户名
username: ${DB_USER:}
# 数据库密码
password: ${DB_PASSWORD:}
#添加MIME印射(如果有需要?)
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="LOG_FILE" value="./neutrino-proxy-server.log"/>
<property name="LOG_FILE" value="./logs/neutrino-proxy-server.log"/>
<property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{50} - %msg%n"/>
<!-- <property name="ENCODE" value="utf8" />-->
@@ -32,6 +32,9 @@
possessor_type = 0
OR ( possessor_type = 1 AND possessor_id = #{userId,jdbcType=INTEGER} )
OR ( possessor_type = 2 AND possessor_id = #{licenseId,jdbcType=INTEGER} )
)
)
<if test="keyword!=null and keyword!=''">
AND `port` LIKE #{keyword}
</if>
</select>
</mapper>
@@ -0,0 +1,207 @@
##########################################################
#
CREATE TABLE IF NOT EXISTS `user` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`name` varchar(50) NOT NULL COMMENT '用户名',
`login_name` varchar(50) NOT NULL COMMENT '登录名',
`login_password` varchar(255) NOT NULL COMMENT '登录密码',
`enable` int NOT NULL COMMENT '是否启用(1、启用 2、禁用)',
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
`update_time` datetime(3) NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `I_user_login_name` (`login_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
#token表
CREATE TABLE IF NOT EXISTS `user_token` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`token` varchar(50) NOT NULL COMMENT 'token',
`user_id` int NOT NULL COMMENT '用户ID',
`expiration_time` datetime(3) NOT NULL COMMENT '过期时间',
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
`update_time` datetime(3) NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `I_user_token_user_id` (`user_id`),
KEY `I_user_token_token` (`token`),
KEY `I_user_token_expiration_time` (`expiration_time`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
#
CREATE TABLE IF NOT EXISTS `port_pool` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`group_id` int NOT NULL DEFAULT 1 COMMENT '分组ID',
`port` int NOT NULL COMMENT '端口',
`enable` int NOT NULL COMMENT '是否启用(1、启用 2、禁用)',
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
`update_time` datetime(3) NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `I_port_pool_port` (`port`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
#
CREATE TABLE IF NOT EXISTS `port_group` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`name` varchar(255) NOT NULL COMMENT '分组名称',
`possessor_type` int NOT NULL DEFAULT '0' COMMENT '所有者类型 (0、全局共享 1、用户所有 2License所有) ',
`possessor_id` int NOT NULL DEFAULT '-1' COMMENT '所有者id(当type为0时 固定为-1、当type为1时为用户id 、当type为2时为licenseid)',
`enable` int NOT NULL COMMENT '是否启用(1、启用 2、禁用)',
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
`update_time` datetime(3) NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;
##########################################################
#license表
CREATE TABLE IF NOT EXISTS `license` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`name` varchar(50) NOT NULL COMMENT 'license名称',
`key` varchar(100) NOT NULL COMMENT 'license key',
`user_id` int NOT NULL COMMENT '用户ID',
`is_online` int NOT NULL COMMENT '是否在线(1、在线 2、离线)',
`enable` int NOT NULL COMMENT '是否启用(1、启用 2、禁用)',
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
`update_time` datetime(3) NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
KEY `I_license_key` (`key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
#
CREATE TABLE IF NOT EXISTS `port_mapping` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`license_id` int NOT NULL COMMENT 'licenseID',
`protocal` varchar(10) NOT NULL DEFAULT 'TCP' COMMENT '协议',
`subdomain` varchar(50) DEFAULT NULL COMMENT '子域名(仅HTTP时有效)',
`server_port` int NOT NULL COMMENT '服务端端口',
`client_ip` varchar(20) NOT NULL COMMENT '客户端IP',
`client_port` int NOT NULL COMMENT '客户端端口',
`is_online` int NOT NULL COMMENT '是否在线(1、在线 2、离线)',
`description` varchar(100) DEFAULT NULL COMMENT '描述',
`enable` int NOT NULL COMMENT '是否启用(1、启用 2、禁用)',
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
`update_time` datetime(3) NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `I_port_mapping_server_port` (`server_port`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
##########################################################
#
CREATE TABLE IF NOT EXISTS `user_login_record` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`user_id` int NOT NULL COMMENT '用户ID',
`ip` varchar(50) NOT NULL COMMENT 'IP',
`token` varchar(100) NOT NULL COMMENT 'token',
`type` int NOT NULL COMMENT '类型(1、登录 2、登出)',
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
#
CREATE TABLE IF NOT EXISTS `client_connect_record` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`ip` varchar(50) NOT NULL COMMENT 'IP',
`license_id` int NOT NULL COMMENT 'licenseId',
`type` int NOT NULL COMMENT '类型(1、连接 2、断开连接)',
`msg` varchar(512) DEFAULT NULL COMMENT '消息',
`code` int NOT NULL COMMENT '结果 1、成功 2、失败)',
`err` text DEFAULT NULL COMMENT '异常信息',
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
##########################################################
#
CREATE TABLE IF NOT EXISTS `job_info` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`desc` varchar(255) NOT NULL COMMENT '描述',
`handler` varchar(255) NOT NULL COMMENT '处理器',
`cron` varchar(128) NOT NULL COMMENT 'cron',
`param` varchar(512) DEFAULT NULL COMMENT '参数',
`alarm_email` varchar(255) DEFAULT NULL COMMENT '报警邮箱',
`alarm_ding` varchar(255) DEFAULT NULL COMMENT '报警钉钉配置',
`enable` int NOT NULL COMMENT '是否启用(1、启用 2、禁用)',
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
`update_time` datetime(3) NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `I_job_info_handler` (`handler`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
#
CREATE TABLE IF NOT EXISTS `job_log` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`job_id` int NOT NULL COMMENT 'JobId',
`handler` varchar(255) NOT NULL COMMENT '处理器',
`param` varchar(512) DEFAULT NULL COMMENT '参数',
`code` int NOT NULL COMMENT '结果(1、成功 2、失败)',
`msg` text COMMENT '消息',
`alarm_status` int NOT NULL COMMENT '报警状态(1、未报警 2、已报警)',
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
KEY `I_job_log_create_time` (`create_time`) USING BTREE,
KEY `I_job_log_code` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
##########################################################
#-(24)
CREATE TABLE IF NOT EXISTS `flow_report_minute` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`user_id` int NOT NULL COMMENT '用户ID',
`license_id` int NOT NULL COMMENT 'licenseId',
`write_bytes` int NOT NULL COMMENT '写入流量',
`read_bytes` int NOT NULL COMMENT '读取流量',
`date` datetime(3) NOT NULL COMMENT '时间',
`date_str` varchar(20) NOT NULL COMMENT '时间 yyyy-MM-dd HH:mm',
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `I_flow_report_minute_create_time` (`create_time`) USING BTREE,
KEY `I_flow_report_minute_date` (`date`) USING BTREE,
KEY `I_flow_report_minute_user_id` (`user_id`),
KEY `I_flow_report_minute_license_id` (`license_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
#-(60)
CREATE TABLE IF NOT EXISTS `flow_report_hour` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`user_id` int NOT NULL COMMENT '用户ID',
`license_id` int NOT NULL COMMENT 'licenseId',
`write_bytes` int NOT NULL COMMENT '写入流量',
`read_bytes` int NOT NULL COMMENT '读取流量',
`date` datetime(3) NOT NULL COMMENT '时间',
`date_str` varchar(20) NOT NULL COMMENT '时间 yyyy-MM-dd HH',
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `I_flow_report_hour_create_time` (`create_time`) USING BTREE,
KEY `I_flow_report_hour_date` (`date`) USING BTREE,
KEY `I_flow_report_hour_user_id` (`user_id`),
KEY `I_flow_report_hour_license_id` (`license_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
#-(1)
CREATE TABLE IF NOT EXISTS `flow_report_day` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`user_id` int NOT NULL COMMENT '用户ID',
`license_id` int NOT NULL COMMENT 'licenseId',
`write_bytes` int NOT NULL COMMENT '写入流量',
`read_bytes` int NOT NULL COMMENT '读取流量',
`date` datetime(3) NOT NULL COMMENT '时间',
`date_str` varchar(20) NOT NULL COMMENT '时间 yyyy-MM-dd',
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `I_flow_report_day_create_time` (`create_time`) USING BTREE,
KEY `I_flow_report_day_date` (`date`) USING BTREE,
KEY `I_flow_report_day_user_id` (`user_id`),
KEY `I_flow_report_day_license_id` (`license_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
#-()
CREATE TABLE IF NOT EXISTS `flow_report_month` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`user_id` int NOT NULL COMMENT '用户ID',
`license_id` int NOT NULL COMMENT 'licenseId',
`write_bytes` int NOT NULL COMMENT '写入流量',
`read_bytes` int NOT NULL COMMENT '读取流量',
`date` datetime(3) NOT NULL COMMENT '时间',
`date_str` varchar(20) NOT NULL COMMENT '时间 yyyy-MM',
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `I_flow_report_month_create_time` (`create_time`) USING BTREE,
KEY `I_flow_report_month_date` (`date`) USING BTREE,
KEY `I_flow_report_month_user_id` (`user_id`),
KEY `I_flow_report_month_license_id` (`license_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
@@ -0,0 +1,13 @@
#job_qrtz_trigger_info
INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES
(1, '示例Job', 'DemoJob', '0/10 * * * * ?', '{"a":101}', 1, now(), now());
INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES
(2, '数据清理任务', 'DataCleanJob', '0 0 1 * * ?', '', 1, now(), now());
INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES
(3, '流量统计报表-分钟', 'FlowReportForMinuteJob', '0 */1 * * * ?', '', 1, now(), now());
INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES
(4, '流量统计报表-小时', 'FlowReportForHourJob', '0 0 */1 * * ?', '', 1, now(), now());
INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES
(5, '流量统计报表-天', 'FlowReportForDayJob', '0 0 1 * * ?', '', 1, now(), now());
INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES
(6, '流量统计报表-月', 'FlowReportForMonthJob', '0 30 1 1 * ?', '', 1, now(), now());
@@ -0,0 +1,3 @@
#license
INSERT INTO license(`id`, `name`, `key`, `user_id`, `is_online`, `enable`, `create_time`, `update_time`) VALUES
(1, '我的mac', 'b0a907332b474b25897c4dcb31fc7eb6', 1, 2, 1, now(), now());
@@ -0,0 +1,3 @@
#port_group
INSERT INTO `port_group`(`id`,`name`,`possessor_type`,`possessor_id`,`enable`,`create_time`,`update_time`) VALUES
(1, '全局(默认)', 0, -1, 1, now(), now());
@@ -0,0 +1,7 @@
#port_mapping
INSERT INTO port_mapping(`id`, `license_id`, `server_port`, `protocal`, `subdomain`, `client_ip`, `client_port`, `is_online`, `enable`, `create_time`, `update_time`) VALUES
(1, 1, 9101, 'HTTP', 'test1', '127.0.0.1', 8080, 2, 1, now(), now());
INSERT INTO port_mapping(`id`, `license_id`, `server_port`, `protocal`, `subdomain`, `client_ip`, `client_port`, `is_online`, `enable`, `create_time`, `update_time`) VALUES
(2, 1, 9102, 'TCP', '', '127.0.0.1', 3306, 2, 1, now(), now());
INSERT INTO port_mapping(`id`, `license_id`, `server_port`, `protocal`, `subdomain`, `client_ip`, `client_port`, `is_online`, `enable`, `create_time`, `update_time`) VALUES
(3, 1, 9103, 'HTTP', 'test2', '127.0.0.1', 8081, 2, 1, now(), now());
@@ -0,0 +1,41 @@
#
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
(1, 1, 9101, 1, now(), now());
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
(2, 1, 9102, 1, now(), now());
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
(3, 1, 9103, 1, now(), now());
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
(4, 1, 9104, 1, now(), now());
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
(5, 1, 9105, 1, now(), now());
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
(6, 1, 9106, 1, now(), now());
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
(7, 1, 9107, 1, now(), now());
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
(8, 1, 9108, 1, now(), now());
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
(9, 1, 9109, 1, now(), now());
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
(10, 1, 9110, 1, now(), now());
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
(11, 1, 9111, 1, now(), now());
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
(12, 1, 9112, 1, now(), now());
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
(13, 1, 9113, 1, now(), now());
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
(14, 1, 9114, 1, now(), now());
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
(15, 1, 9115, 1, now(), now());
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
(16, 1, 9116, 1, now(), now());
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
(17, 1, 9117, 1, now(), now());
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
(18, 1, 9118, 1, now(), now());
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
(19, 1, 9119, 1, now(), now());
INSERT INTO port_pool(`id`, `group_id`, `port`, `enable`, `create_time`, `update_time`) VALUES
(20, 1, 9120, 1, now(), now());
@@ -0,0 +1,5 @@
# 6613b92b77056faeb72068f184ed4c4f
INSERT INTO `user`(`id`, `name`,`login_name`,`login_password`,`enable`,`create_time`, `update_time`) VALUES
(1, '管理员', 'admin', 'e10adc3949ba59abbe56e057f20f883e', 1, now(), now());
INSERT INTO `user`(`id`, `name`,`login_name`,`login_password`,`enable`,`create_time`, `update_time`) VALUES
(2, '游客', 'visitor', 'e10adc3949ba59abbe56e057f20f883e', 1, now(), now());
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

@@ -0,0 +1,11 @@
<svg width="206" height="53" viewBox="0 0 206 53" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_501_120)">
<path d="M59.0087 36H54.5243V13.5938H59.0087V22.5625H67.9618V13.5938H72.4462V36H67.9618V27.0469H59.0087V36ZM82.5712 31.9062C82.7378 31.9583 82.9045 31.9948 83.0712 32.0156C83.2378 32.026 83.4045 32.0312 83.5712 32.0312C83.9878 32.0312 84.3889 31.974 84.7743 31.8594C85.1597 31.7448 85.5191 31.5833 85.8524 31.375C86.1962 31.1562 86.4983 30.8958 86.7587 30.5938C87.0295 30.2812 87.2483 29.9375 87.4149 29.5625L90.5399 32.7031C90.1441 33.2656 89.6858 33.7708 89.1649 34.2188C88.6545 34.6667 88.0972 35.0469 87.493 35.3594C86.8993 35.6719 86.2691 35.9062 85.6024 36.0625C84.9462 36.2292 84.2691 36.3125 83.5712 36.3125C82.3941 36.3125 81.2847 36.0938 80.243 35.6562C79.2118 35.2188 78.3055 34.6094 77.5243 33.8281C76.7535 33.0469 76.1441 32.1198 75.6962 31.0469C75.2483 29.9635 75.0243 28.776 75.0243 27.4844C75.0243 26.1615 75.2483 24.9531 75.6962 23.8594C76.1441 22.7656 76.7535 21.8333 77.5243 21.0625C78.3055 20.2917 79.2118 19.6927 80.243 19.2656C81.2847 18.8385 82.3941 18.625 83.5712 18.625C84.2691 18.625 84.9514 18.7083 85.618 18.875C86.2847 19.0417 86.9149 19.2812 87.5087 19.5938C88.1128 19.9062 88.6753 20.2917 89.1962 20.75C89.717 21.1979 90.1753 21.7031 90.5712 22.2656L82.5712 31.9062ZM84.7587 23.1094C84.5608 23.0365 84.3628 22.9896 84.1649 22.9688C83.9774 22.9479 83.7795 22.9375 83.5712 22.9375C82.9878 22.9375 82.4358 23.0469 81.9149 23.2656C81.4045 23.474 80.9566 23.776 80.5712 24.1719C80.1962 24.5677 79.8993 25.0469 79.6805 25.6094C79.4618 26.1615 79.3524 26.7865 79.3524 27.4844C79.3524 27.6406 79.3576 27.8177 79.368 28.0156C79.3889 28.2135 79.4149 28.4167 79.4462 28.625C79.4878 28.8229 79.5347 29.0156 79.5868 29.2031C79.6389 29.3906 79.7066 29.5573 79.7899 29.7031L84.7587 23.1094ZM96.993 36H92.7274V19.2656H93.7587L95.1649 21.25C95.8524 20.625 96.6337 20.1458 97.5087 19.8125C98.3837 19.4688 99.2899 19.2969 100.227 19.2969H103.993V23.5469H100.227C99.7795 23.5469 99.3576 23.6302 98.9618 23.7969C98.566 23.9635 98.2222 24.1927 97.9305 24.4844C97.6389 24.776 97.4097 25.1198 97.243 25.5156C97.0764 25.9115 96.993 26.3333 96.993 26.7812V36ZM114.368 36C113.337 36 112.368 35.8073 111.462 35.4219C110.556 35.026 109.759 34.4896 109.071 33.8125C108.394 33.125 107.858 32.3281 107.462 31.4219C107.076 30.5156 106.884 29.5469 106.884 28.5156V23.5469H104.806V19.2969H106.884V12.6094H111.134V19.2969H117.602V23.5469H111.134V28.5156C111.134 28.9635 111.217 29.3854 111.384 29.7812C111.55 30.1667 111.78 30.5052 112.071 30.7969C112.363 31.0885 112.707 31.3229 113.102 31.5C113.498 31.6667 113.92 31.75 114.368 31.75H117.602V36H114.368ZM133.071 36H119.118L126.165 23.5469H119.118V19.2969H133.071L126.024 31.75H133.071V36ZM153.821 29.2812C153.821 30.2083 153.644 31.0781 153.29 31.8906C152.936 32.7031 152.451 33.4167 151.837 34.0312C151.233 34.6354 150.524 35.1146 149.712 35.4688C148.899 35.8229 148.03 36 147.102 36H135.899V13.5938H147.102C148.03 13.5938 148.899 13.7708 149.712 14.125C150.524 14.4792 151.233 14.9635 151.837 15.5781C152.451 16.1823 152.936 16.8906 153.29 17.7031C153.644 18.5156 153.821 19.3854 153.821 20.3125C153.821 20.7292 153.764 21.1562 153.649 21.5938C153.535 22.0312 153.373 22.4531 153.165 22.8594C152.957 23.2656 152.707 23.6354 152.415 23.9688C152.123 24.3021 151.8 24.5781 151.446 24.7969C151.811 24.9948 152.139 25.2656 152.431 25.6094C152.722 25.9427 152.972 26.3125 153.181 26.7188C153.389 27.125 153.545 27.5521 153.649 28C153.764 28.4375 153.821 28.8646 153.821 29.2812ZM140.384 31.5156H147.102C147.415 31.5156 147.707 31.4583 147.977 31.3438C148.248 31.2292 148.483 31.0729 148.681 30.875C148.889 30.6667 149.05 30.4271 149.165 30.1562C149.28 29.8854 149.337 29.5938 149.337 29.2812C149.337 28.9688 149.28 28.6771 149.165 28.4062C149.05 28.1354 148.889 27.901 148.681 27.7031C148.483 27.4948 148.248 27.3333 147.977 27.2188C147.707 27.1042 147.415 27.0469 147.102 27.0469H140.384V31.5156ZM140.384 22.5625H147.102C147.415 22.5625 147.707 22.5052 147.977 22.3906C148.248 22.276 148.483 22.1198 148.681 21.9219C148.889 21.7135 149.05 21.474 149.165 21.2031C149.28 20.9219 149.337 20.625 149.337 20.3125C149.337 20 149.28 19.7083 149.165 19.4375C149.05 19.1667 148.889 18.9323 148.681 18.7344C148.483 18.526 148.248 18.3646 147.977 18.25C147.707 18.1354 147.415 18.0781 147.102 18.0781H140.384V22.5625ZM163.415 31.9062C163.582 31.9583 163.748 31.9948 163.915 32.0156C164.082 32.026 164.248 32.0312 164.415 32.0312C164.832 32.0312 165.233 31.974 165.618 31.8594C166.003 31.7448 166.363 31.5833 166.696 31.375C167.04 31.1562 167.342 30.8958 167.602 30.5938C167.873 30.2812 168.092 29.9375 168.259 29.5625L171.384 32.7031C170.988 33.2656 170.53 33.7708 170.009 34.2188C169.498 34.6667 168.941 35.0469 168.337 35.3594C167.743 35.6719 167.113 35.9062 166.446 36.0625C165.79 36.2292 165.113 36.3125 164.415 36.3125C163.238 36.3125 162.128 36.0938 161.087 35.6562C160.056 35.2188 159.149 34.6094 158.368 33.8281C157.597 33.0469 156.988 32.1198 156.54 31.0469C156.092 29.9635 155.868 28.776 155.868 27.4844C155.868 26.1615 156.092 24.9531 156.54 23.8594C156.988 22.7656 157.597 21.8333 158.368 21.0625C159.149 20.2917 160.056 19.6927 161.087 19.2656C162.128 18.8385 163.238 18.625 164.415 18.625C165.113 18.625 165.795 18.7083 166.462 18.875C167.128 19.0417 167.759 19.2812 168.352 19.5938C168.957 19.9062 169.519 20.2917 170.04 20.75C170.561 21.1979 171.019 21.7031 171.415 22.2656L163.415 31.9062ZM165.602 23.1094C165.405 23.0365 165.207 22.9896 165.009 22.9688C164.821 22.9479 164.623 22.9375 164.415 22.9375C163.832 22.9375 163.28 23.0469 162.759 23.2656C162.248 23.474 161.8 23.776 161.415 24.1719C161.04 24.5677 160.743 25.0469 160.524 25.6094C160.306 26.1615 160.196 26.7865 160.196 27.4844C160.196 27.6406 160.201 27.8177 160.212 28.0156C160.233 28.2135 160.259 28.4167 160.29 28.625C160.332 28.8229 160.378 29.0156 160.431 29.2031C160.483 29.3906 160.55 29.5573 160.634 29.7031L165.602 23.1094ZM189.649 36H188.618L186.962 33.7031C186.556 34.0677 186.123 34.4115 185.665 34.7344C185.217 35.0469 184.743 35.3229 184.243 35.5625C183.743 35.7917 183.227 35.974 182.696 36.1094C182.175 36.2448 181.644 36.3125 181.102 36.3125C179.925 36.3125 178.816 36.1146 177.774 35.7188C176.743 35.3229 175.837 34.75 175.056 34C174.285 33.2396 173.675 32.3125 173.227 31.2188C172.78 30.125 172.556 28.8802 172.556 27.4844C172.556 26.1823 172.78 24.9896 173.227 23.9062C173.675 22.8125 174.285 21.875 175.056 21.0938C175.837 20.3125 176.743 19.7083 177.774 19.2812C178.816 18.8438 179.925 18.625 181.102 18.625C181.644 18.625 182.181 18.6927 182.712 18.8281C183.243 18.9635 183.759 19.151 184.259 19.3906C184.759 19.6302 185.233 19.9115 185.681 20.2344C186.139 20.5573 186.566 20.9062 186.962 21.2812L188.618 19.2969H189.649V36ZM185.352 27.4844C185.352 26.901 185.238 26.3385 185.009 25.7969C184.79 25.2448 184.488 24.7604 184.102 24.3438C183.717 23.9167 183.264 23.5781 182.743 23.3281C182.233 23.0677 181.686 22.9375 181.102 22.9375C180.519 22.9375 179.967 23.0365 179.446 23.2344C178.936 23.4323 178.488 23.724 178.102 24.1094C177.727 24.4948 177.431 24.974 177.212 25.5469C176.993 26.1094 176.884 26.7552 176.884 27.4844C176.884 28.2135 176.993 28.8646 177.212 29.4375C177.431 30 177.727 30.474 178.102 30.8594C178.488 31.2448 178.936 31.5365 179.446 31.7344C179.967 31.9323 180.519 32.0312 181.102 32.0312C181.686 32.0312 182.233 31.9062 182.743 31.6562C183.264 31.3958 183.717 31.0573 184.102 30.6406C184.488 30.2135 184.79 29.7292 185.009 29.1875C185.238 28.6354 185.352 28.0677 185.352 27.4844ZM201.306 36C200.274 36 199.306 35.8073 198.399 35.4219C197.493 35.026 196.696 34.4896 196.009 33.8125C195.332 33.125 194.795 32.3281 194.399 31.4219C194.014 30.5156 193.821 29.5469 193.821 28.5156V23.5469H191.743V19.2969H193.821V12.6094H198.071V19.2969H204.54V23.5469H198.071V28.5156C198.071 28.9635 198.155 29.3854 198.321 29.7812C198.488 30.1667 198.717 30.5052 199.009 30.7969C199.3 31.0885 199.644 31.3229 200.04 31.5C200.436 31.6667 200.858 31.75 201.306 31.75H204.54V36H201.306Z" fill="#B421CC"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M24.8453 0C11.1261 0 0 10.745 0 24.001C0 33.826 6.11788 42.271 14.8744 45.982C14.804 44.308 14.862 42.293 15.304 40.47C15.7823 38.522 17.7077 27.5 17.7077 27.5C17.7077 27.5 17.7077 25.861 17.7077 23.595C17.7077 20.039 20.1176 21.819 22.7739 21.819L26.397 23C33.1256 23 43.995 23 43.995 23C43.995 23 34.1018 15.5 27.4322 15.5C19.8971 15.5 19.1508 15.5 19.1508 15.5C19.1508 17.594 13.9749 18 13.9749 18L11.9045 15.5L9.31658 14.5C9.31658 7.684 13.9956 8.069 25.7987 8.069C35.285 8.069 49.6884 14.5 43.995 23C43.995 23 34.3875 23 26.397 23C23.718 23 29.3327 31.09 28.4673 29.5C28.4673 29.5 28.9849 33 22.7739 37C22.248 38.85 18.7481 45.575 17.805 47.015C20.04 47.653 22.4012 48 24.8453 48C38.5655 48 49.6884 37.255 49.6884 24.001C49.6884 10.745 38.5655 0 24.8453 0Z" fill="#B421CC"/>
</g>
<defs>
<clipPath id="clip0_501_120">
<rect width="206" height="53" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="380px" height="120px" viewBox="0 0 380 120" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>jpom-logo</title>
<defs>
<linearGradient x1="0.0077378419%" y1="0%" x2="99.9922622%" y2="100%" id="linearGradient-1">
<stop stop-color="#5988FF" offset="0%"></stop>
<stop stop-color="#0D58FF" offset="100%"></stop>
</linearGradient>
<path d="M97.0595063,0 C98.6792225,0 99.9922619,1.31303939 99.9922619,2.93275555 L99.9922619,83.9820475 C98.0456091,82.5565127 95.6960926,81.7868903 93.2832934,81.7844154 L92.9319967,81.7897766 C90.0097544,81.8790045 87.225876,83.0788415 85.1523588,85.1523588 C82.9959008,87.3088167 81.7844154,90.2336013 81.7844154,93.2832934 C81.7887374,95.7018607 82.5669783,98.0555651 84.0052619,100 L2.93275555,100 C1.31303939,100 0,98.6869606 0,97.0672444 L0,23.3072816 C0,21.6875654 1.31303939,20.374526 2.93275555,20.374526 L40.9038149,20.374526 C41.6822604,20.3724639 42.429417,20.6807875 42.979863,21.2312335 C43.530309,21.7816795 43.8386326,22.5288361 43.8365705,23.3072816 L43.8365705,78.9367794 L30.5114911,78.9367794 C29.733676,78.9367794 28.9877182,78.6277935 28.4377198,78.0777952 C27.8877214,77.5277968 27.5787356,76.781839 27.5787356,76.0040238 L27.5787356,34.4192525 C27.5787412,32.7982798 26.2669471,31.4830245 24.64598,31.4787588 L19.113209,31.4787588 C18.3340513,31.4787561 17.5869184,31.7888039 17.036697,32.3404771 C16.4864757,32.8921502 16.1783976,33.6400975 16.1804535,34.4192525 L16.1804535,73.9456782 C16.1783993,77.9092655 17.7520185,81.7111045 20.5546982,84.5137843 C23.357378,87.3164641 27.1592171,88.8900833 31.1228043,88.8880291 L68.8849338,88.8880291 C72.8478917,88.8880291 76.6485371,87.3137502 79.4507714,84.5115159 C82.2530058,81.7092815 83.8272847,77.9086361 83.8272847,73.9456782 L83.8272847,26.0543218 C83.8230153,17.8036584 77.1355972,11.1162403 68.8849338,11.1119709 L2.93275555,11.1119709 C1.31303939,11.1119709 0,9.79893152 0,8.17921535 L0,2.93275555 C0,1.31303939 1.31303939,0 2.93275555,0 Z M69.5271996,20.4054786 C71.1481666,20.4097443 72.4599551,21.7249996 72.4599551,23.3459723 L72.4599551,76.0427145 C72.4599551,76.8205297 72.1509693,77.5664875 71.6009709,78.1164859 C71.0509726,78.6664842 70.3050147,78.9754701 69.5271996,78.9754701 L59.1967809,78.9754701 C57.5758082,78.9754701 56.260553,77.6636816 56.2562872,76.0427145 L56.2562872,34.3573474 C56.2583431,33.5781924 55.950265,32.830245 55.4000437,32.2785719 C54.8498223,31.7268988 54.1026894,31.416851 53.3235317,31.4168537 L49.2842219,31.4168537 C47.6645058,31.4168537 46.3514664,30.1038143 46.3514664,28.4840981 L46.3514664,23.3459723 C46.3514664,21.7249996 47.6632549,20.4097443 49.2842219,20.4054786 Z" id="path-2"></path>
<filter x="-6.5%" y="-5.5%" width="113.0%" height="113.0%" filterUnits="objectBoundingBox" id="filter-3">
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="2" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0.239215686 0 0 0 0 0.466666667 0 0 0 0 1 0 0 0 0.4 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
</filter>
<linearGradient x1="0%" y1="41.21675%" x2="100%" y2="58.78325%" id="linearGradient-4">
<stop stop-color="#5988FF" offset="0%"></stop>
<stop stop-color="#0D58FF" offset="100%"></stop>
</linearGradient>
<path d="M321.177106,22 C326.648252,22 330.951915,23.8568225 334.001288,27.5645829 C337.018271,31.2329589 338.5054,36.5562047 338.5054,43.5075594 L338.5054,72.2764579 C338.5054,73.5037494 337.841444,74.4996824 336.640847,75.1857377 C335.575623,75.7944374 334.335668,76.0950324 332.937365,76.0950324 C331.544467,76.0950324 330.325067,75.8136323 329.292975,75.240248 C328.109924,74.5829978 327.466523,73.558321 327.466523,72.2764579 L327.466523,45.8401728 C327.466523,40.8955189 326.694202,37.2501639 325.194838,34.9111564 C323.764436,32.6797287 321.623311,31.5809935 318.650108,31.5809935 C316.79872,31.5809935 314.959692,32.2377892 313.114393,33.5771188 C311.238478,34.9386702 309.704728,36.7913184 308.510889,39.1483861 C307.319542,41.5005314 306.723542,44.0831986 306.723542,46.9092873 L306.723542,72.2764579 C306.723542,73.558321 306.08014,74.5829978 304.89709,75.240248 C303.864998,75.8136323 302.645598,76.0950324 301.2527,76.0950324 C299.859802,76.0950324 298.640401,75.8136323 297.60831,75.240248 C296.425259,74.5829978 295.781857,73.558321 295.781857,72.2764579 L295.781857,45.8401728 C295.781857,40.8955189 295.009536,37.2501639 293.510173,34.9111564 C292.080954,32.6815753 289.908011,31.5809935 286.868251,31.5809935 C285.088109,31.5809935 283.283388,32.2504868 281.43818,33.6195127 C279.556179,35.0158357 278.019002,36.8726239 276.823821,39.2016947 C275.633386,41.5215173 275.038877,44.0215023 275.038877,46.7149028 L275.038877,72.2764579 C275.038877,73.5037494 274.374922,74.4996824 273.174325,75.1857377 C272.111504,75.793064 270.90363,76.0950324 269.568035,76.0950324 C268.169731,76.0950324 266.929777,75.7944374 265.864552,75.1857377 C264.663955,74.4996824 264,73.5037494 264,72.2764579 L264,26.4989201 C264,25.2077738 264.668286,24.181477 265.88847,23.5278073 C266.948186,22.9601019 268.179114,22.6803456 269.568035,22.6803456 C270.71541,22.6803456 271.794876,22.969488 272.789139,23.5431017 C273.934643,24.2039694 274.552916,25.2264969 274.552916,26.4989201 L274.552,30.281 L274.790224,29.9647489 C276.112461,28.2407943 277.63116,26.7395118 279.345238,25.4631222 L279.777828,25.1487113 C282.731605,23.0535904 285.978736,22 289.492441,22 C293.59303,22 297.017667,23.0550649 299.730507,25.1766448 C301.838091,26.8248839 303.45357,29.0787041 304.580218,31.9217647 L304.664,32.141 L304.894304,31.758482 C306.256617,29.541499 308.04526,27.5894747 310.255056,25.9061867 L310.674327,25.5937203 C313.951412,23.204179 317.460734,22 321.177106,22 Z M231.214173,22.2721382 C235.842656,22.2721382 240.114809,23.2813081 244.017009,25.2996873 C247.949275,27.3336181 251.102191,30.4187296 253.463829,34.534728 C255.824475,38.648996 256.99819,43.6792053 256.99819,49.6112311 C256.99819,55.477913 255.824553,60.4910223 253.465574,64.636085 C251.105109,68.7837598 247.953791,71.9011925 244.023018,73.968237 C240.119404,76.0209992 235.845055,77.0475162 231.214173,77.0475162 C226.582371,77.0475162 222.323058,76.0205671 218.450763,73.9665673 C215.78895,72.5546487 213.481953,70.6522464 211.530874,68.2601777 C209.80805,70.6713158 207.747453,72.5853025 205.353205,73.9936837 C201.893057,76.0290653 198.056892,77.0475162 193.863464,77.0475162 C189.54284,77.0475162 185.913019,76.1613627 182.990636,74.373552 C181.090035,73.2108313 179.432511,71.7008619 178.019516,69.8490491 L177.854,69.627 L177.854825,92.1814255 C177.854825,93.3365234 177.266684,94.2866808 176.196546,94.966436 L175.990272,95.0907053 C174.927451,95.6980316 173.719578,96 172.383982,96 C170.985679,96 169.745724,95.699405 168.6805,95.0907053 C167.479903,94.40465 166.815948,93.408717 166.815948,92.1814255 L166.815948,26.7710583 C166.815948,25.479912 167.484234,24.4536152 168.704417,23.7999455 C169.764134,23.2322402 170.995062,22.9524838 172.383982,22.9524838 C173.531358,22.9524838 174.610823,23.2416263 175.605087,23.8152399 C176.750591,24.4761076 177.368863,25.4986352 177.368863,26.7710583 L177.368,30.16 L177.461941,30.0361727 C178.783959,28.309545 180.389965,26.8166359 182.276634,25.5604571 L182.685215,25.2949004 C185.864442,23.2779717 189.597959,22.2721382 193.863464,22.2721382 C198.128773,22.2721382 202.004283,23.3430028 205.46887,25.4828953 C207.771196,26.9049197 209.757739,28.7668286 211.429887,31.0693813 C213.399057,28.641774 215.743808,26.7167895 218.456791,25.3013201 C222.327675,23.2817281 226.584779,22.2721382 231.214173,22.2721382 Z M191.530851,31.6587473 C187.243462,31.6587473 183.896417,33.3099564 181.39759,36.6517607 C178.844201,40.0665344 177.563248,44.3106557 177.563248,49.4168467 C177.563248,55.109921 178.816344,59.5808448 181.296842,62.8575524 C183.727136,66.0679395 187.106609,67.6609071 191.530851,67.6609071 C195.643176,67.6609071 198.975743,66.1216499 201.603835,63.0102305 C203.930389,60.255805 205.247205,56.4902582 205.534777,51.6932527 L205.559596,51.2685058 L205.545125,50.8489568 C205.533272,50.4407123 205.527348,50.0281371 205.527348,49.6112311 C205.527348,49.189798 205.533269,48.7729418 205.545271,48.355724 L205.556796,48.0938945 L205.551214,47.9513662 C205.38458,44.9043393 204.749828,42.2339124 203.652128,39.9339693 C202.366962,37.2412414 200.654503,35.195383 198.511261,33.7766173 C196.374155,32.3619136 194.055203,31.6587473 191.530851,31.6587473 Z M231.214173,31.6587473 C226.836455,31.6587473 223.357717,33.2031872 220.700173,36.3137216 C218.430591,38.9701643 217.111936,42.5417911 216.759905,47.0508924 L216.700355,47.9290956 L216.714085,48.3122437 C216.725839,48.7404962 216.731714,49.1734918 216.731714,49.6112311 C216.731714,50.0470061 216.726182,50.47794 216.71489,50.911505 L216.700355,51.2251958 L216.724381,51.660711 C217.015654,56.4203676 218.347416,60.1767886 220.703261,62.9609692 C223.36111,66.1020631 226.838531,67.6609071 231.214173,67.6609071 C235.591349,67.6609071 239.086753,66.1007268 241.777295,62.9567219 C244.491519,59.7850452 245.862121,55.3498364 245.862121,49.6112311 C245.862121,43.8739162 244.492208,39.456332 241.78041,36.317958 C239.090148,33.2045095 235.593424,31.6587473 231.214173,31.6587473 Z M150.712743,4 C149.259053,4 147.963783,4.29606168 146.840427,4.89518486 C145.554497,5.58101431 144.853132,6.6564405 144.853132,8.01295896 L144.853132,50.3887689 C144.853132,54.9604969 144.458747,58.4784132 143.684829,60.9239931 C142.944236,63.264268 141.87171,64.8087043 140.491802,65.6090509 C139.040305,66.4509193 137.071912,66.8833693 134.578834,66.8833693 C133.004999,66.8833693 131.710962,66.6900075 130.699158,66.3141946 C129.625877,65.9155473 128.398225,65.3094909 127.020608,64.495445 C126.731999,64.3493116 126.45579,64.2036746 126.173893,64.0486339 L125.744519,63.8077828 C125.260149,63.5309997 124.711978,63.2569143 124.099443,62.9846766 C123.527077,62.7889863 123.145105,62.7041037 122.818575,62.7041037 C121.483129,62.7041037 120.469249,63.6183631 119.75338,65.2384268 L119.527332,65.7673253 C119.172059,66.6629279 119,67.5887714 119,68.5637149 C119,70.7152148 119.984373,72.4418969 121.873536,73.6494261 L122.114388,73.7976565 C125.574241,75.9689259 130.225662,77.0475162 136.036717,77.0475162 C140.933982,77.0475162 144.881961,76.1664222 147.872655,74.3788806 C150.905083,72.5663953 153.107534,69.6529168 154.47669,65.6823622 C155.813792,61.8047679 156.475162,56.6460815 156.475162,50.1943844 L156.475162,8.01295896 C156.475162,6.66509921 155.798106,5.59114857 154.548952,4.90196011 C153.45357,4.29761162 152.17012,4 150.712743,4 Z" id="path-5"></path>
<filter x="-3.0%" y="-6.0%" width="105.9%" height="114.1%" filterUnits="objectBoundingBox" id="filter-6">
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="2" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0.239215686 0 0 0 0 0.466666667 0 0 0 0 1 0 0 0 0.4 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
</filter>
</defs>
<g id="jpom-logo" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="1" transform="translate(12.000000, 10.000000)" fill-rule="nonzero">
<g id="2">
<use fill="black" fill-opacity="1" filter="url(#filter-3)" xlink:href="#path-2"></use>
<use fill="url(#linearGradient-1)" xlink:href="#path-2"></use>
</g>
<rect id="4" fill="#F74C00" x="345" y="64" width="12" height="12" rx="6"></rect>
<g id="5">
<use fill="black" fill-opacity="1" filter="url(#filter-6)" xlink:href="#path-5"></use>
<use fill="url(#linearGradient-4)" xlink:href="#path-5"></use>
</g>
<rect id="3" fill="#F74C00" x="88" y="88" width="12" height="12" rx="6"></rect>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="_图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 240">
<defs>
<style>
.cls-1 {
fill: #ff9045;
}
.cls-2 {
fill: #333;
}
.cls-3 {
fill: #0079dd;
}
.cls-4 {
fill: #595959;
}
</style>
</defs>
<g>
<g>
<circle class="cls-1" cx="145.28" cy="62.13" r="13.63"/>
<path class="cls-1" d="M154.29,83.78h-18.09c-4.56,0-8.26,3.7-8.26,8.26v92.19c0,4.02,3.26,7.28,7.28,7.28h.07c4.02,0,7.28-3.26,7.28-7.28v-54.05c2.96,0,5.36,2.4,5.36,5.36v16.41c0,4.02,3.26,7.28,7.28,7.28h.07c4.02,0,7.28-3.26,7.28-7.28v-21.16s0-38.75,0-38.75c0-4.56-3.7-8.26-8.26-8.26Z"/>
</g>
<path class="cls-3" d="M117.19,125.56h-1.98c-3.07,0-5.56-2.49-5.56-5.56s2.49-5.56,5.56-5.56h1.98s.04,0,.06,0v-25.71c0-4.77-2.32-9.24-6.21-11.98L50.81,34.3c-4.86-3.42-11.55,.05-11.55,5.99V199.71c0,5.94,6.7,9.41,11.55,5.99l60.23-42.45c3.9-2.75,6.21-7.22,6.21-11.98v-25.71s-.04,0-.06,0Z"/>
<path class="cls-3" d="M239.76,34.3l-60.23,42.45c-3.9,2.75-6.21,7.22-6.21,11.98v25.71s.04,0,.06,0h1.98c3.07,0,5.56,2.49,5.56,5.56s-2.49,5.56-5.56,5.56h-1.98s-.04,0-.06,0v25.71c0,4.77,2.32,9.24,6.21,11.98l60.23,42.45c4.86,3.42,11.55-.05,11.55-5.99V40.29c0-5.94-6.7-9.41-11.55-5.99Z"/>
</g>
<g>
<g>
<path class="cls-2" d="M344.63,60.54v-7.61h8.13v7.61h20.8c4.41,0,7.8,.88,10.16,2.64,3.06,2.31,4.58,5.45,4.58,9.43l-.04,32.47c0,3.86-.78,6.82-2.34,8.87-2.42,3.2-6.01,4.8-10.77,4.8h-22.4l.04,7.52-8.17-.04v-7.48h-20.54c-4.15,0-7.24-.59-9.25-1.77-3.66-2.13-5.49-6.18-5.49-12.15v-30.57c0-4.44,1.12-7.77,3.37-9.99,2.51-2.48,5.89-3.72,10.16-3.72h21.75Zm0,50.07v-41.94h-22.01c-2.05,0-3.47,.55-4.28,1.64-.58,.81-.87,2.08-.87,3.8v30.05c0,1.96,.07,3.13,.22,3.5,.72,1.99,2.31,2.98,4.76,2.98l22.18-.04Zm8.13,0l20.93,.04c4.32,.03,6.49-1.79,6.49-5.45v-30.48c0-2.48-.49-4.11-1.47-4.89-.92-.72-2.48-1.1-4.67-1.12l-21.27-.09v41.99Z"/>
<path class="cls-2" d="M401.72,75.41v-8.78c2.13-1.73,3.62-3.34,4.45-4.84,1.12-1.93,2-4.94,2.64-9.04h8.13c-.46,2.19-.79,3.84-.99,4.93-.81,4.12-2.12,7.46-3.93,10.03-1.87,2.62-4.08,4.64-6.62,6.05-.81,.43-2.03,.98-3.67,1.64Zm0,20.67v-8.86c2.36-1.9,3.91-3.56,4.63-4.97,.89-1.67,1.7-4.63,2.42-8.86h8.17l-.91,4.15v48.86h-8.09v-33.77c-1.93,1.44-4.01,2.59-6.23,3.46Zm17.25,30.31v-8.47c1.35-.78,2.03-1.9,2.03-3.37v-10.59c0-2.6,.88-4.79,2.64-6.57,1.59-1.58,4.53-2.38,8.82-2.38h6.87c6.72,0,10.08,3.19,10.08,9.56v8.86c0,1.73,.23,2.87,.69,3.42,.26,.32,.72,.68,1.38,1.08v8.47c-2.88-.43-5.16-1.3-6.83-2.59-.87-.66-1.59-1.56-2.16-2.68-.81-1.53-1.21-3.07-1.21-4.63v-9.95c0-2.39-1.47-3.59-4.41-3.59h-3.5c-1.47,0-2.51,.32-3.11,.95-.81,.81-1.21,2.05-1.21,3.72v8.87c0,2.79-.88,5.07-2.64,6.83-1.39,1.41-3.86,2.44-7.44,3.07Zm.91-73.68h7.22v15.52c0,1.21,.23,2.02,.69,2.42,.52,.43,1.41,.65,2.68,.65h1.08v-18.59h7.74v18.59h1.12c1.07,0,1.84-.29,2.34-.86s.74-1.17,.74-1.77v-15.96h7.05v17.99c0,3.08-1.11,5.35-3.33,6.79-1.21,.78-3.37,1.17-6.49,1.17h-11.68c-3.2,0-5.59-.81-7.18-2.42-.69-.72-1.14-1.37-1.34-1.95-.43-1.21-.65-3.01-.65-5.4v-16.17Zm0,38.18v-7.22h30.66v7.22h-30.66Zm33.12,35.11v-7.74c2.36-.92,4.08-1.72,5.15-2.38,1.1-.69,2.62-1.92,4.58-3.67-2.02-3.83-3.39-7.16-4.11-9.99-.89-3.34-1.34-6.76-1.34-10.25v-14.87c-1.12,.75-2.45,1.37-3.98,1.86v-8.39c1.38-1.53,2.35-3.56,2.9-6.1,.63-3.08,1.08-7,1.34-11.76h7.26v4.89h17.08v8h-4.2v27.46c0,6.05-1.83,12.44-5.49,19.16,1.44,1.38,2.61,2.41,3.5,3.07,1.27,.89,3.33,1.89,6.18,2.98v7.74c-3.98-1.1-6.99-2.28-9.04-3.55-1.5-.89-3.27-2.29-5.32-4.19-3.08,2.54-5.49,4.24-7.22,5.1-1.53,.81-3.96,1.69-7.31,2.64Zm4.67-49.12h6.66l-.13,12.8c-.03,4.56,1.05,9.7,3.24,15.44,2.02-4.44,3.03-8.62,3.03-12.54v-26.98h-6.74c-1.15,4.24-2.38,7.18-3.68,8.82-.52,.69-1.31,1.51-2.38,2.47Z"/>
<path class="cls-2" d="M494.58,91.89v-8h41.21l21.32-17.81c1.21-1.01,1.82-1.9,1.82-2.68,0-.46-.16-.89-.47-1.3-.66-.83-1.75-1.25-3.24-1.25h-56.56v-8h58.98c3.6,0,6.36,.68,8.26,2.03,2.36,1.67,3.55,3.99,3.55,6.96,0,2.56-1.04,4.97-3.11,7.22-1.21,1.3-2.8,2.75-4.76,4.37l-12.93,10.46h26.12v8h-29.45l.04,21.53c0,3.92-1.21,7.1-3.63,9.56-2.25,2.31-5.61,3.46-10.07,3.46h-16.73v-8.04h15.52c2.45,.03,4.12-.47,5.01-1.51,.81-.95,1.21-2.39,1.21-4.33v-20.71l-42.07,.04Z"/>
<path class="cls-2" d="M587.86,86.78v-10.29c3-2.13,5.17-4.28,6.53-6.44,2.88-4.58,4.96-10.29,6.23-17.12h9.08c-1.24,6.26-2.96,11.93-5.15,17.04v56.38h-8.3v-44.88c-2.02,1.62-3.34,2.61-3.98,2.98-.61,.4-2.08,1.18-4.41,2.34Zm21.02-8.78v-8.13h19.46l-5.06-17.08h8.69l4.8,17.08h30.61v8.13h-28.32l5.1,18.81c1.01,3.72,2.31,7.28,3.89,10.68,1.47,3.14,3.66,5.69,6.57,7.65,3.29,2.22,6.69,3.33,10.2,3.33,.46,0,1.17-.04,2.12-.13v8.09c-4.7-.09-8.53-.68-11.5-1.77-5.51-2.07-9.71-5.65-12.63-10.72-1.87-3.23-3.72-7.91-5.53-14.05l-6.53-21.88h-21.88Zm40.99-16.78v-8h17.51v8h-17.51Z"/>
<path class="cls-2" d="M680.84,124.06v-8h7.05v-24.95l-7.09,.04,.04-7.87h7.05v-20.41h-7.05v-8h22.4v8h-7.35v20.41h7.35v7.83h-7.35v24.95h7.35v8h-22.4Zm26.59,2.2v-8h22.92v-9.25h-20.76v-8h20.76v-7.05l-14.01-.04c-2.48,0-4.44-.88-5.88-2.64-.89-1.12-1.41-2.31-1.56-3.55-.09-.72-.13-1.7-.13-2.94v-23.44c0-2.91,.74-5.1,2.2-6.57,1.38-1.38,3.24-2.08,5.58-2.08h33.25c3.52,0,6.04,.72,7.57,2.16,1.33,1.27,1.99,3.17,1.99,5.71v25.47c0,2.42-.71,4.35-2.12,5.79-1.35,1.38-3.06,2.07-5.1,2.07l-13.79,.04v7.05h20.8v8h-20.8v9.25h22.4v8h-53.31Zm9.34-56.99h13.58v-8.56h-10.25c-1.21,0-2.11,.29-2.68,.86-.43,.43-.65,1.25-.65,2.47v5.23Zm13.58,16.56v-8.6h-13.58v4.71c0,1.56,.23,2.6,.69,3.11,.43,.52,1.24,.78,2.42,.78h10.46Zm8-16.56h13.19v-5.23c.03-2.28-1.41-3.42-4.32-3.42l-8.86,.09v8.56Zm0,16.56h9.64c1.41,0,2.35-.26,2.81-.78,.52-.58,.76-1.54,.74-2.9v-4.93h-13.19v8.6Z"/>
</g>
<g>
<path class="cls-4" d="M315.77,154.13l16.1,23.16h.12v-23.16h3.27v28.46h-3.35l-16.18-23.4h-.12v23.4h-3.27v-28.46h3.43Z"/>
<path class="cls-4" d="M370.12,164.77c1.51,1.99,2.31,4.82,2.39,8.41h-16.26c.16,2.31,.76,4.11,1.87,5.38,1.12,1.28,2.67,1.91,4.63,1.91,1.67,0,3.07-.44,4.1-1.28,.88-.72,1.56-1.79,2.07-3.23h3.19c-.48,1.99-1.39,3.59-2.79,4.86-1.71,1.52-3.91,2.31-6.58,2.31-2.95,0-5.34-1-7.1-2.91-1.83-1.99-2.71-4.62-2.71-7.97,0-3.03,.84-5.58,2.59-7.61,1.75-2.15,4.11-3.23,7.1-3.23,3.31,0,5.82,1.12,7.49,3.35Zm-11.84,1.12c-1.12,1.2-1.76,2.79-1.95,4.82h12.88c-.4-4.42-2.59-6.62-6.5-6.62-1.83,0-3.31,.6-4.42,1.79Z"/>
<path class="cls-4" d="M392.99,161.98v12.6c0,1.95,.4,3.43,1.24,4.38,.84,.96,2.19,1.48,4.07,1.48,1.35,0,2.59-.56,3.67-1.59,1.12-1.12,1.79-2.55,2.03-4.3v-12.56h3.19v20.61h-3.19v-3.19c-1.68,2.47-3.91,3.75-6.7,3.75-5.02,0-7.5-2.83-7.5-8.41v-12.76h3.19Z"/>
<path class="cls-4" d="M431.17,161.98h5.1v2.67h-5.1v13.11c0,.76,.12,1.31,.44,1.63,.28,.32,.8,.52,1.51,.52h2.63v2.67h-3.11c-1.67,0-2.91-.44-3.63-1.31-.68-.8-1-1.95-1-3.51v-13.11h-4.15v-2.67h4.15v-5.34l3.15-1.31v6.66Z"/>
<path class="cls-4" d="M465.24,161.9v3.19c-1.04-.32-2.07-.44-3.07-.44-1.59,0-2.95,.68-4.03,2.11-1.12,1.35-1.64,2.99-1.64,4.9v10.92h-3.15v-20.61h3.15v3.59c.56-1.19,1.28-2.15,2.15-2.83,1.08-.88,2.31-1.32,3.75-1.32,1.12,0,2.07,.16,2.83,.48Z"/>
<path class="cls-4" d="M485.8,154.88c.48,.4,.72,.96,.72,1.68,0,.68-.24,1.24-.72,1.71-.48,.44-1.04,.68-1.71,.68s-1.24-.24-1.71-.68c-.48-.48-.68-1.04-.68-1.71,0-.72,.2-1.28,.68-1.68,.48-.48,1.04-.68,1.71-.68s1.24,.2,1.71,.68Zm-.12,7.1v20.61h-3.19v-20.61h3.19Z"/>
<path class="cls-4" d="M522.54,169.91v12.67h-3.19v-12.44c0-4.03-1.83-6.02-5.42-6.02-1.43,0-2.67,.52-3.71,1.56-1.12,1.12-1.71,2.59-1.83,4.46v12.44h-3.19v-20.61h3.19v3.03c.72-1.16,1.64-2.03,2.75-2.63,1.12-.64,2.35-.96,3.71-.96,5.1,0,7.69,2.83,7.69,8.49Z"/>
<path class="cls-4" d="M557.61,164.61c1.75,2.03,2.63,4.58,2.63,7.69s-.88,5.62-2.59,7.61c-1.87,2.15-4.35,3.23-7.41,3.23s-5.54-1.08-7.37-3.23c-1.75-1.99-2.63-4.54-2.63-7.61s.88-5.66,2.63-7.69c1.83-2.15,4.27-3.19,7.37-3.19s5.54,1.04,7.38,3.19Zm-12.48,1.99c-1.12,1.51-1.63,3.39-1.63,5.7s.52,4.15,1.63,5.66c1.2,1.68,2.91,2.51,5.1,2.51s3.87-.84,5.14-2.51c1.07-1.51,1.63-3.43,1.63-5.66s-.56-4.19-1.63-5.7c-1.28-1.68-2.99-2.51-5.14-2.51s-3.91,.84-5.1,2.51Z"/>
<path class="cls-4" d="M616.79,154.13c6.54,0,9.8,2.79,9.8,8.37s-3.31,8.45-9.84,8.45h-8.33v11.64h-3.27v-28.46h11.64Zm-8.37,13.99h8.17c2.31,0,3.99-.48,5.1-1.39,1.07-.92,1.63-2.31,1.63-4.23s-.56-3.31-1.67-4.15c-1.12-.96-2.79-1.4-5.06-1.4h-8.17v11.16Z"/>
<path class="cls-4" d="M655.76,161.9v3.19c-1.04-.32-2.07-.44-3.07-.44-1.59,0-2.95,.68-4.03,2.11-1.11,1.35-1.63,2.99-1.63,4.9v10.92h-3.15v-20.61h3.15v3.59c.56-1.19,1.28-2.15,2.15-2.83,1.07-.88,2.31-1.32,3.75-1.32,1.12,0,2.07,.16,2.83,.48Z"/>
<path class="cls-4" d="M688.55,164.61c1.76,2.03,2.63,4.58,2.63,7.69s-.88,5.62-2.59,7.61c-1.87,2.15-4.34,3.23-7.41,3.23s-5.54-1.08-7.37-3.23c-1.75-1.99-2.63-4.54-2.63-7.61s.88-5.66,2.63-7.69c1.83-2.15,4.27-3.19,7.37-3.19s5.54,1.04,7.37,3.19Zm-12.48,1.99c-1.12,1.51-1.63,3.39-1.63,5.7s.52,4.15,1.63,5.66c1.2,1.68,2.91,2.51,5.1,2.51s3.87-.84,5.14-2.51c1.08-1.51,1.64-3.43,1.64-5.66s-.56-4.19-1.64-5.7c-1.28-1.68-2.99-2.51-5.14-2.51s-3.91,.84-5.1,2.51Z"/>
<path class="cls-4" d="M711.23,161.98l5.34,7.33,5.3-7.33h3.75l-7.29,9.69,8.17,10.92h-3.79l-6.14-8.57-6.18,8.57h-3.79l8.17-10.92-7.29-9.69h3.75Z"/>
<path class="cls-4" d="M743.9,161.98l6.3,16.26,6.1-16.26h3.51l-11.28,28.5h-3.47l3.55-8.37-8.17-20.13h3.47Z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 213.97 125.78"><defs><style>.cls-1{fill:#231815;}</style></defs><title>资源 6</title><g id="图层_2" data-name="图层 2"><g id="图层_1-2" data-name="图层 1"><path class="cls-1" d="M103.07,10C104.83,4.87,101.58-.51,95.14,0A11.77,11.77,0,0,0,90,1.83C58.43,21,59.5,62.37,90.42,82.43A10.38,10.38,0,0,0,95,84.08c7.4.71,12-6.51,7.31-12a10.5,10.5,0,0,0-2.89-2.23c-23.85-13.2-24.7-41.33-.38-55.2A8.85,8.85,0,0,0,103.07,10Z"/><path class="cls-1" d="M124.06,14.2l10.52,6.9a8.84,8.84,0,0,0,1,.56c7.18,3.31,13.75-3.74,9.77-9.95A8.46,8.46,0,0,0,143,9.36L131.66,1.8A8.44,8.44,0,0,0,125.37.4c-4.29.82-6.12,4.75-4.94,9A8.54,8.54,0,0,0,124.06,14.2Z"/><path class="cls-1" d="M132,51.62V62.88a4.06,4.06,0,0,1-2,3.5l-5.34,3.14a7.59,7.59,0,0,0-4.13,8.69c.77,2.74,3.12,5,7.16,5.25a7.37,7.37,0,0,0,2.75-.43,35.87,35.87,0,0,0,13.38-8.55,9.57,9.57,0,0,0,2.76-6.75V42.06h0a6.78,6.78,0,0,0-6.78-6.78H132"/><path class="cls-1" d="M124.17,37.57V48.93a2.3,2.3,0,0,1-2.29,2.29h-7.11a8.48,8.48,0,0,1-7.79-5,7.39,7.39,0,0,1-.33-5.41,8.39,8.39,0,0,1,8-5.57h7.18A2.3,2.3,0,0,1,124.17,37.57Z"/><path class="cls-1" d="M11.91,100.28A2.38,2.38,0,0,0,9.31,97a3.89,3.89,0,0,0-1.68.59c-10.37,6.28-10,19.87.13,26.45a3.4,3.4,0,0,0,1.5.54c2.43.24,3.94-2.14,2.4-3.93a3.26,3.26,0,0,0-.95-.73c-7.82-4.33-8.1-13.57-.12-18.12A2.87,2.87,0,0,0,11.91,100.28Z"/><path class="cls-1" d="M18.8,101.68l3.46,2.26a3.37,3.37,0,0,0,.32.19c2.36,1.08,4.51-1.23,3.21-3.27a2.86,2.86,0,0,0-.78-.77L21.3,97.61a2.78,2.78,0,0,0-2.07-.46,2.18,2.18,0,0,0-1.62,2.95A2.81,2.81,0,0,0,18.8,101.68Z"/><path class="cls-1" d="M39.24,98.82V123a2.3,2.3,0,0,0,0,.37c.37,2.57,3.48,3.12,4.48.91a2.44,2.44,0,0,0,.22-1.07L44,98.69a2.78,2.78,0,0,0-.74-2,2.19,2.19,0,0,0-3.36.25A2.86,2.86,0,0,0,39.24,98.82Z"/><path class="cls-1" d="M71.05,108.91,71,123c0,.12,0,.25,0,.37.38,2.57,3.49,3.12,4.49.91a2.6,2.6,0,0,0,.22-1.07l.06-14.47a2.81,2.81,0,0,0-.73-2,2.2,2.2,0,0,0-3.37.25A2.85,2.85,0,0,0,71.05,108.91Z"/><path class="cls-1" d="M126.44,95.88l-10.13,0a2.42,2.42,0,0,0-.38,0c-2.57.37-3.12,3.49-.91,4.49a2.86,2.86,0,0,0,1.08.22l10.46.06a2.76,2.76,0,0,0,2-.74,2.18,2.18,0,0,0-.25-3.36A2.75,2.75,0,0,0,126.44,95.88Z"/><path class="cls-1" d="M126.44,121l-10.13,0-.38,0c-2.57.38-3.12,3.49-.91,4.49a2.86,2.86,0,0,0,1.08.22l10.46.06a2.8,2.8,0,0,0,2-.73,2.19,2.19,0,0,0-.25-3.37A2.81,2.81,0,0,0,126.44,121Z"/><path class="cls-1" d="M172.85,98.18a2.86,2.86,0,0,1-.91,1.92l-12.34,12v10.86a2.81,2.81,0,0,1-.68,1.86,2.19,2.19,0,0,1-3.36.25,2.85,2.85,0,0,1-.74-2l0-6.36,0-6.61,4.76-4.62,8.91-8.68a2.82,2.82,0,0,1,1.8-.81A2.19,2.19,0,0,1,172.85,98.18Z"/><path class="cls-1" d="M121.44,108.44h-5.13a2.42,2.42,0,0,0-.38,0c-2.57.37-3.12,3.48-.91,4.48a2.68,2.68,0,0,0,1.08.22l5.46.07a2.76,2.76,0,0,0,2-.74,2.18,2.18,0,0,0-.25-3.36A2.81,2.81,0,0,0,121.44,108.44Z"/><path class="cls-1" d="M211.18,95.79H201.05a2.3,2.3,0,0,0-.37,0c-2.57.37-3.12,3.48-.92,4.48a2.68,2.68,0,0,0,1.08.22l10.46.07a2.85,2.85,0,0,0,2-.74,2.19,2.19,0,0,0-.25-3.36A2.86,2.86,0,0,0,211.18,95.79Z"/><path class="cls-1" d="M211.18,120.93l-10.13,0a2.3,2.3,0,0,0-.37,0c-2.57.37-3.12,3.49-.92,4.49a2.86,2.86,0,0,0,1.08.22l10.46.06a2.8,2.8,0,0,0,2-.74,2.19,2.19,0,0,0-.25-3.36A2.8,2.8,0,0,0,211.18,120.93Z"/><path class="cls-1" d="M206.18,108.36l-5.13,0-.37,0c-2.57.38-3.12,3.49-.92,4.49a2.86,2.86,0,0,0,1.08.22l5.46.06a2.84,2.84,0,0,0,2-.73A2.2,2.2,0,0,0,208,109,2.85,2.85,0,0,0,206.18,108.36Z"/><path class="cls-1" d="M151.22,100.83l-3.88-3.36a2.37,2.37,0,0,0-.3-.23c-2.19-1.39-4.63.62-3.61,2.81a2.48,2.48,0,0,0,.67.87l4.1,3.61a2.83,2.83,0,0,0,2,.73,2.18,2.18,0,0,0,2-2.71A2.8,2.8,0,0,0,151.22,100.83Z"/><path class="cls-1" d="M61.45,100.75l24.13-.24.38,0c2.56-.4,3.07-3.52.86-4.49a2.67,2.67,0,0,0-1.08-.21L61.28,96a2.82,2.82,0,0,0-2,.76,2.19,2.19,0,0,0,.29,3.36A2.78,2.78,0,0,0,61.45,100.75Z"/><path class="cls-1" d="M102.73,98.84,103,123a2.42,2.42,0,0,0,0,.38c.4,2.56,3.52,3.08,4.5.86a2.67,2.67,0,0,0,.21-1.08l-.21-24.46a2.76,2.76,0,0,0-.76-2,2.18,2.18,0,0,0-3.35.28A2.81,2.81,0,0,0,102.73,98.84Z"/><path class="cls-1" d="M187.27,98.84l.24,24.13a2.43,2.43,0,0,0,0,.38c.4,2.56,3.52,3.08,4.49.86a2.67,2.67,0,0,0,.21-1.08L192,98.67a2.8,2.8,0,0,0-.76-2,2.19,2.19,0,0,0-3.36.28A2.8,2.8,0,0,0,187.27,98.84Z"/><path class="cls-1" d="M26.18,110.82v8.42a3.13,3.13,0,0,1-.91,2.22,11.64,11.64,0,0,1-4.39,2.8,2.3,2.3,0,0,1-.9.15,2.4,2.4,0,0,1-2.35-1.73A2.49,2.49,0,0,1,19,119.83l1.75-1a1.33,1.33,0,0,0,.65-1.15V114a.23.23,0,0,0,0-.14h-5.6a.86.86,0,0,1-.23,0,2.76,2.76,0,0,1-2.33-1.6,2.43,2.43,0,0,1-.1-1.78,2.74,2.74,0,0,1,2.43-1.82h8.6a2.18,2.18,0,0,1,1.41.64A2.26,2.26,0,0,1,26.18,110.82Z"/><path class="cls-1" d="M15.73,108.59h0Z"/><path class="cls-1" d="M15.52,113.8a.86.86,0,0,0,.23,0h-.23Z"/><path class="cls-1" d="M24.12,108.59h0Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

@@ -0,0 +1,15 @@
<svg width="1053" height="170" viewBox="0 0 1053 170" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M73.9973 35.0579C54.1616 69.8286 42.9756 83.2381 35.8964 77.1848C30.9901 72.9896 47.7987 41.7206 58.7276 21.3898C62.1781 14.9707 65.0426 9.64207 66.4524 6.60013C66.7845 5.88338 66.1105 5.51842 65.5618 6.11847C40.0106 34.0615 -21.3347 135.895 7.5775 162.983C8.93141 164.252 11.0512 163.631 11.7989 161.933L33.1473 113.459C34.035 111.443 36.5449 110.432 38.7533 111.201L48.8546 114.714C51.063 115.483 52.1337 117.739 51.246 119.755L31.2362 165.189C30.3407 167.223 31.8971 169.466 34.0878 169.095C74.8305 162.188 98.0507 93.0493 117.5 36.5C124 14.5 124 14.5 128 0C119.318 15.677 82.7367 82.7294 70.4985 81.4891C61.0082 80.5273 63.8387 71.85 70.8524 50.3486C72.2789 45.9755 73.8785 41.072 75.5826 35.595C75.865 34.6874 74.4765 34.218 73.9973 35.0579Z" fill="#FF5C00"/>
<path d="M200.782 129.157H178.611L171.579 108.423H138.084L131.052 129.157H109L144.163 32.6779H165.5L200.782 129.157ZM154.533 60.2434L144.759 88.7678H164.904L155.249 60.2434H154.533Z" fill="black"/>
<path d="M208.662 159V57.6067H228.806V66.1161H229.522C231.667 62.9201 234.409 60.4432 237.746 58.6854C241.084 56.8477 244.62 55.9288 248.355 55.9288C253.997 55.9288 258.924 57.4469 263.135 60.4832C267.426 63.4395 270.724 67.6742 273.029 73.1873C275.333 78.7004 276.485 85.1723 276.485 92.603C276.485 100.353 275.333 107.105 273.029 112.858C270.724 118.61 267.426 123.045 263.135 126.161C258.844 129.277 253.838 130.835 248.116 130.835C244.302 130.835 240.766 129.916 237.508 128.079C234.329 126.321 231.667 123.844 229.522 120.648H228.806V159H208.662ZM228.33 93.4419C228.33 99.035 229.561 103.509 232.025 106.865C234.488 110.141 237.746 111.779 241.799 111.779C246.09 111.779 249.507 110.141 252.05 106.865C254.593 103.509 255.864 99.035 255.864 93.4419C255.864 87.769 254.633 83.2946 252.169 80.0187C249.706 76.6629 246.408 74.985 242.276 74.985C238.064 74.985 234.687 76.6629 232.144 80.0187C229.601 83.2946 228.33 87.769 228.33 93.4419Z" fill="black"/>
<path d="M306.184 130.835C299.907 130.835 294.702 129.037 290.569 125.442C286.517 121.767 284.49 116.733 284.49 110.341C284.49 105.387 285.881 101.032 288.662 97.2772C291.443 93.5218 295.377 90.6454 300.463 88.6479C305.628 86.5705 311.628 85.5318 318.462 85.5318H324.898V83.7341C324.898 80.2185 323.905 77.5418 321.918 75.7041C320.011 73.7865 317.309 72.8277 313.813 72.8277C308.807 72.8277 304.277 75.3046 300.224 80.2584L287.113 70.191C294.821 60.6829 304.595 55.9288 316.435 55.9288C322.077 55.9288 327.084 57.0874 331.454 59.4045C335.825 61.6417 339.202 64.7978 341.586 68.8727C343.97 72.9476 345.162 77.6617 345.162 83.015V129.157H324.898V121.007H324.183C322.753 124.203 320.448 126.64 317.27 128.318C314.091 129.996 310.396 130.835 306.184 130.835ZM312.502 114.176C316.078 114.176 319.018 113.377 321.322 111.779C323.706 110.101 324.898 107.824 324.898 104.948V102.071H320.488C315.323 102.071 311.469 102.591 308.926 103.629C306.383 104.668 305.111 106.426 305.111 108.903C305.111 110.421 305.747 111.699 307.019 112.738C308.37 113.697 310.197 114.176 312.502 114.176Z" fill="black"/>
<path d="M391.139 130.835C383.829 130.835 377.471 129.317 372.068 126.281C366.744 123.245 362.611 118.93 359.671 113.337C356.811 107.664 355.38 101.032 355.38 93.4419C355.38 85.8514 356.811 79.2197 359.671 73.5468C362.611 67.8739 366.744 63.5194 372.068 60.4832C377.471 57.4469 383.829 55.9288 391.139 55.9288C397.656 55.9288 403.576 57.8464 408.9 61.6816C414.224 65.5169 418.118 70.7104 420.581 77.2622L401.867 84.3333C400.834 81.377 399.205 79.0999 396.98 77.5019C394.835 75.9039 392.451 75.1049 389.828 75.1049C385.617 75.1049 382.239 76.7828 379.696 80.1386C377.233 83.4145 376.001 87.8489 376.001 93.4419C376.001 99.035 377.233 103.469 379.696 106.745C382.239 110.021 385.617 111.659 389.828 111.659C392.451 111.659 394.835 110.86 396.98 109.262C399.205 107.584 400.834 105.307 401.867 102.431L420.581 109.502C418.118 116.054 414.224 121.247 408.9 125.082C403.576 128.918 397.656 130.835 391.139 130.835Z" fill="black"/>
<path d="M430.993 129.157V32.6779H451.138V66.9551H451.734C453.8 63.5194 456.502 60.8427 459.839 58.9251C463.256 56.9276 467.15 55.9288 471.52 55.9288C478.593 55.9288 484.076 58.2459 487.97 62.8801C491.943 67.4345 493.93 73.9463 493.93 82.4157V129.157H473.785V87.0899C473.785 83.4145 472.871 80.5381 471.044 78.4607C469.216 76.3034 466.713 75.2247 463.534 75.2247C459.799 75.2247 456.78 76.4232 454.475 78.8202C452.25 81.1373 451.138 84.3333 451.138 88.4082V129.157H430.993Z" fill="black"/>
<path d="M571.491 88.2884C571.491 93.3221 570.974 97.6367 569.941 101.232H525.361C526.871 109.861 531.719 114.176 539.903 114.176C542.764 114.176 545.347 113.337 547.651 111.659C549.956 109.981 551.783 107.664 553.134 104.708L569.703 111.899C567.319 117.891 563.505 122.566 558.26 125.921C553.095 129.197 546.936 130.835 539.784 130.835C532.632 130.835 526.355 129.357 520.951 126.401C515.547 123.365 511.376 119.09 508.435 113.577C505.575 107.984 504.144 101.472 504.144 94.0412C504.144 86.2909 505.575 79.5793 508.435 73.9064C511.296 68.1536 515.309 63.7191 520.474 60.603C525.719 57.4869 531.838 55.9288 538.831 55.9288C545.347 55.9288 551.068 57.2472 555.995 59.8839C560.922 62.5206 564.736 66.2759 567.438 71.1498C570.14 76.0237 571.491 81.7366 571.491 88.2884ZM550.989 84.573C550.989 80.9775 549.876 78.0612 547.651 75.824C545.506 73.5868 542.565 72.4682 538.831 72.4682C531.997 72.4682 527.626 76.5031 525.719 84.573H550.989Z" fill="black"/>
<path d="M658.286 130.835C649.545 130.835 641.916 128.678 635.4 124.363C628.884 119.969 623.997 114.176 620.739 106.985L638.857 98.4757C640.526 102.79 643.069 106.066 646.486 108.303C649.903 110.541 653.876 111.659 658.405 111.659C663.094 111.659 666.829 110.78 669.61 109.022C672.391 107.265 673.782 104.988 673.782 102.191C673.782 100.194 673.265 98.5556 672.232 97.2772C671.199 95.9189 669.411 94.6804 666.868 93.5618C664.325 92.4432 660.63 91.2047 655.783 89.8464C649.426 88.0087 644.141 86.171 639.93 84.3333C635.718 82.4956 631.983 79.6592 628.725 75.824C625.546 71.9089 623.957 66.7553 623.957 60.3633C623.957 54.7703 625.507 49.7366 628.606 45.2622C631.784 40.7878 636.076 37.3121 641.479 34.8352C646.962 32.2784 653.002 31 659.597 31C676.205 31 688.165 38.5905 695.476 53.7715L677.596 62.5206C675.53 58.206 672.987 55.0899 669.967 53.1723C667.027 51.1748 663.491 50.176 659.359 50.176C655.386 50.176 652.048 51.0549 649.346 52.8127C646.644 54.5705 645.294 56.7278 645.294 59.2846C645.294 61.4419 645.85 63.1997 646.962 64.5581C648.075 65.8365 649.863 67.035 652.326 68.1536C654.869 69.1923 658.604 70.3908 663.531 71.7491C669.808 73.5069 675.053 75.3046 679.265 77.1423C683.476 78.9001 687.172 81.7366 690.35 85.6517C693.529 89.4869 695.118 94.6005 695.118 100.993C695.118 106.985 693.529 112.258 690.35 116.813C687.251 121.287 682.92 124.723 677.358 127.12C671.795 129.597 665.438 130.835 658.286 130.835Z" fill="black"/>
<path d="M706.521 129.157V32.6779H726.665V66.9551H727.261C729.327 63.5194 732.029 60.8427 735.367 58.9251C738.784 56.9276 742.678 55.9288 747.048 55.9288C754.12 55.9288 759.604 58.2459 763.497 62.8801C767.471 67.4345 769.457 73.9463 769.457 82.4157V129.157H749.313V87.0899C749.313 83.4145 748.399 80.5381 746.571 78.4607C744.744 76.3034 742.24 75.2247 739.062 75.2247C735.327 75.2247 732.307 76.4232 730.003 78.8202C727.778 81.1373 726.665 84.3333 726.665 88.4082V129.157H706.521Z" fill="black"/>
<path d="M847.018 88.2884C847.018 93.3221 846.502 97.6367 845.469 101.232H800.889C802.399 109.861 807.246 114.176 815.431 114.176C818.292 114.176 820.874 113.337 823.179 111.659C825.483 109.981 827.311 107.664 828.662 104.708L845.231 111.899C842.847 117.891 839.032 122.566 833.788 125.921C828.622 129.197 822.464 130.835 815.312 130.835C808.16 130.835 801.882 129.357 796.479 126.401C791.075 123.365 786.903 119.09 783.963 113.577C781.102 107.984 779.672 101.472 779.672 94.0412C779.672 86.2909 781.102 79.5793 783.963 73.9064C786.824 68.1536 790.837 63.7191 796.002 60.603C801.247 57.4869 807.365 55.9288 814.358 55.9288C820.874 55.9288 826.596 57.2472 831.523 59.8839C836.45 62.5206 840.264 66.2759 842.966 71.1498C845.668 76.0237 847.018 81.7366 847.018 88.2884ZM826.516 84.573C826.516 80.9775 825.404 78.0612 823.179 75.824C821.033 73.5868 818.093 72.4682 814.358 72.4682C807.524 72.4682 803.154 76.5031 801.247 84.573H826.516Z" fill="black"/>
<path d="M857.962 129.157V57.6067H878.107V66.9551H878.703C880.769 63.5194 883.471 60.8427 886.808 58.9251C890.225 56.9276 894.119 55.9288 898.489 55.9288C905.562 55.9288 911.045 58.2459 914.939 62.8801C918.912 67.4345 920.899 73.9463 920.899 82.4157V129.157H900.754V87.0899C900.754 83.4145 899.84 80.5381 898.013 78.4607C896.185 76.3034 893.682 75.2247 890.503 75.2247C886.768 75.2247 883.749 76.4232 881.444 78.8202C879.219 81.1373 878.107 84.3333 878.107 88.4082V129.157H857.962Z" fill="black"/>
<path d="M944.073 91.4045L909.625 32.6779H934.776L954.205 73.1873H954.92L974.349 32.6779H999.619L965.052 91.4045V129.157H944.073V91.4045Z" fill="black"/>
<path d="M1053 57.6067V129.157H1032.86V120.049H1032.14C1030.15 123.484 1027.49 126.121 1024.15 127.959C1020.9 129.876 1017.08 130.835 1012.71 130.835C1005.64 130.835 1000.08 128.558 996.024 124.004C992.05 119.37 990.064 112.938 990.064 104.708V57.6067H1010.21V100.034C1010.21 103.629 1011.16 106.506 1013.07 108.663C1014.98 110.82 1017.48 111.899 1020.58 111.899C1024.31 111.899 1027.29 110.74 1029.52 108.423C1031.74 106.026 1032.86 102.83 1032.86 98.8352V57.6067H1053Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

@@ -7,7 +7,7 @@ article: false
## 1、 部署服务端
### 1.1、 Docker一键部署
> 当前最新版本为1.8.2,下面的脚本中,可以使用:`registry.cn-hangzhou.aliyuncs.com/asgc/neutrino-proxy:1.8.2` 指定版本安装,推荐使用`latest`直接安装最新版。
> 当前最新版本为1.8.5,下面的脚本中,可以使用:`registry.cn-hangzhou.aliyuncs.com/asgc/neutrino-proxy:1.8.5` 指定版本安装,推荐使用`latest`直接安装最新版。
#### 使用默认sqlite数据库
```shell
@@ -87,6 +87,11 @@ neutrino:
访问成功,至此首次完整的内网穿透体验完成。开源不易,请速至[Gitee仓库](https://gitee.com/dromara/neutrino-proxy)一键三连🤝
## 5、客户端Docker部署
> 因为一些原因,官方不推荐客户端使用Docker方式部署,但有不少朋友希望采用这种方式,因此从1.8.5版本开始维护了客户端镜像,版本号同服务端,也可使用`latest`直接安装最新版。
- 客户端镜像地址:registry.cn-hangzhou.aliyuncs.com/asgc/neutrino-proxy-client:latest
- 注意:客户端采用docker部署时,服务端端口映射客户端ip请不要配置127.0.0.1应该配置为容器访问宿主机的ip或者hostname,具体请自行百度
<!--
## 4.开发&调试
@@ -19,6 +19,9 @@ server:
neutrino:
proxy:
logger:
# 日志级别
level: ${LOG_LEVEL:info}
# 隧道相关配置-用于维持服务端与客户端的通信
tunnel:
# 线程池相关配置,用于技术调优,可忽略
@@ -32,7 +35,8 @@ neutrino:
key-store-password: ${STORE_PASS:123456}
key-manager-password: ${MGR_PASS:123456}
jks-path: ${JKS_PATH:classpath:/test.jks}
# 代理服务相关配置
# 是否开启隧道传输报文日志(日志级别为debug时开启才有效)
transfer-log-enable: ${TUNNEL_LOG:false}
server:
# 线程池相关配置,用于技术调优,可忽略
boss-thread-count: 5
@@ -46,9 +50,11 @@ neutrino:
# https证书配置
key-store-password: ${HTTPS_STORE_PASS:}
jks-path: ${HTTPS_JKS_PATH:}
# 是否开启代理服务报文日志(日志级别为debug时开启才有效)
transfer-log-enable: ${SERVER_LOG:false}
data:
db:
# 数据库类型,目前支持sqlite、mysql两种
# 数据库类型,目前支持sqlite、mysql、mariadb
type: ${DB_TYPE:sqlite}
# 数据库连接URL
url: ${DB_URL:jdbc:sqlite:data.db}
@@ -0,0 +1,38 @@
---
title: 客户端配置
date: 2023-06-09 21:15:35
permalink: /pages/50ce10/
---
# 以下是最新的客户端配置格式(app.yml)
```yml
neutrino:
proxy:
logger:
# 日志级别
level: ${LOG_LEVEL:info}
client:
# 线程池相关配置,用于技术调优,可忽略
thread-count: 50
# 隧道SSL证书配置
key-store-password: ${STORE_PASS:123456}
jks-path: ${JKS_PATH:classpath:/test.jks}
# 服务端IP
server-ip: ${SERVER_IP:localhost}
# 服务端端口(对应服务端app.yml中的tunnel.port、tunnel.ssl-port)
server-port: ${SERVER_PORT:9002}
# 是否启用SSL(注意:该配置必须和server-port对应上)
ssl-enable: ${SSL_ENABLE:true}
# 客户端连接唯一凭证
license-key: ${LICENSE_KEY:}
# 客户端唯一身份标识(可忽略,若不设置首次启动会自动生成)
client-id: ${CLIENT_ID:}
# 是否开启隧道传输报文日志(日志级别为debug时开启才有效)
transfer-log-enable: ${CLIENT_LOG:false}
# 重连设置
reconnection:
# 重连间隔(秒)
interval-seconds: 10
# 是否开启无限重连(未开启时,客户端license不合法会自动停止应用,开启了则不会,请谨慎开启)
unlimited: false
```
@@ -0,0 +1,31 @@
---
title: 常见问题汇总
date: 2023-07-01 13:35:00
permalink: /pages/a00001/
---
## 1、客户端启动后连不上服务端,一直在重连
### 1.1、启动日志包含`not found license-key config`相关字样
出现这种情况,说明客户端没获取到配置的license,可按如下检查:
- 客户端是否有配置app.yml,app.yml中是否有配置`license-key`
- 客户端启动参数是否指定app.yml配置,若未指定客户端不会加载任何jar外部的配置文件
- 客户端启动参数指定的配置文件路径是否正确?如:`java -jar neutrino-proxy-client.jar config=app.yml`,代表`app.yml`文件与jar在同级别目录下,如果不在同级别目录,请使用绝对/相对路径指定
- 除此之外license还可以用以下方法直接在启动参数中指定:
- `java -jar -DLICENSE_KEY=xxxx -DSERVER_IP=x.x.x.x -DSERVER_PORT=9000 -DSSL_ENABLE=false neutrino-proxy-client.jar`
- `java -jar neutrino-proxy-client.jar serverIp=x.x.x.x serverPort=9000 sslEnable=false licenseKey=xxxx`
### 1.2、配置文件确定都已经配置,且启动参数正确指定了,但是没有出现`认证成功日志`
- 确认客户端配置的`server-ip`,必须是服务端所在机器的ip,且保证客户端所在机器能正常ping通
- 确认客户端配置的`server-port``ssl-enable`,默认情况应配置为9000、false或9002、true,除非服务端app.yml有改动隧道对外端口
- 确认服务端对外的9000、9002端口是否已经放开
- 服务端如果采用docker部署,需要确保容器的9000、9002端口映射到宿主机
## 2、关于中微子代理涉及的2类SSL证书
### 2.1、HTTPS证书
该证书用于服务端支持HTTPS,若需要在服务端`app.yml`中配置即可
### 2.2、隧道SSL证书
该证书用于对客户端-服务端之间的数据通信进行加密,因此客户端/服务端均需要配置该证书。可参考如下命令生成:
```
keytool -genkey -alias test1 -keyalg RSA -keysize 1024 -validity 3650 -keypass 123456 -storepass 123456 -keystore "./test.jks"
```
@@ -6,8 +6,10 @@ article: false
---
### 演示环境
> 由于部分用户使用演示环境代理非法网站导致演示环境服务器被封禁,因此不再提供演示服务。
可使用分配好的游客license试用。服务器带宽较低,仅供学习使用!
管理后台地址:<a href="http://103.163.47.16:9527" target="_blank">http://103.163.47.16:9527</a>
游客账号:visitor/123456
游客账号:visitor/123456
@@ -0,0 +1,29 @@
---
title: 2023年
date: 2023-06-09 21:33:17
permalink: /pages/cded59/
---
| 日期 | 渠道 | 金额 |昵称| 备注 |
|:-----------|:---|:-----|:-|:-----------------|
| 2023-07-31 |Gitee捐助| 50 |失败女神| 感谢您的开源项目! |
| 2023-07-28 |微信转账| 50 |AdrianPteLtd.com-咨询| |
| 2023-07-12 |微信红包| 100 |MaxKeyTop| 请大佬抽包烟 |
| 2023-07-04 |微信红包| 50 |姫野永遠| |
| 2023-06-29 |微信红包| 16.8 |迟迟🌱| 加油 |
| 2023-06-27 |微信红包| 30 |Arno| |
| 2023-06-25 |Gitee捐助| 10 |zhujue888| 感谢您的开源项目! |
| 2023-06-16 |微信红包| 50 |小跟班| |
| 2023-06-10 |Gitee捐助| 10 |失败女神| 感谢您的开源项目! |
| 2023-06-09 |Gitee捐助| 50 |Admin| 感谢您的开源项目! |
| 2023-06-09 |微信红包| 50 |李阳| 开源无限好 |
| 2023-06-09 |Gitee捐助| 50 |罗宾| 感谢您的开源项目! |
| 2023-06-07 |Gitee捐助| 50 |罗宾| 感谢您的开源项目! |
| 2023-06-03 |Gitee捐助| 50 |Admin| 感谢您的开源项目! |
| 2023-05-29 |微信红包| 20 |TYY| |
| 2023-05-29 |Gitee捐助| 10 |笑看| 感谢您的开源项目! |
| 2023-05-26 |微信红包| 50 |至少还有满天星光照耀你| |
| 2023-02-23 |Gitee捐助| 10 |Yohanes| 感谢您的开源项目! |
| 2023-02-23 |Gitee捐助| 20 |jam_lee| 感谢您的开源项目!希望能支持域名映射|
| 2023-02-10 |Gitee捐助| 5 |实习两年半| 感谢您的开源项目! |
| 2023-02-02 |Gitee捐助| 10 |阳光很暖| 感谢您的开源项目! |
+85 -85
View File
@@ -166,137 +166,137 @@ postList: none
-->
<h2 id="🤝-dromara-组织项目"><a href="#🤝-dromara-组织项目" class="header-anchor">#</a> 🤝 dromara 组织项目</h2>
<p align="center"><b><a href="https://dromara.org/zh/projects/" target="_blank">为往圣继绝学,一个人或许能走的更快,但一群人会走的更远。</a></b></p>
<p align="center"><b><a href="https://dromara.org/zh/projects/?from=neutrino-proxy" target="_blank">为往圣继绝学,一个人或许能走的更快,但一群人会走的更远。</a></b></p>
<p>
<a href="https://gitee.com/dromara/TLog" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/tlog.png" msg="一个轻量级的分布式日志标记追踪神器,10分钟即可接入,自动对日志打标签完成微服务的链路追踪">
<a href="https://gitee.com/dromara/TLog?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/tlog.png" msg="一个轻量级的分布式日志标记追踪神器,10分钟即可接入,自动对日志打标签完成微服务的链路追踪">
</a>
<a href="https://gitee.com/dromara/liteFlow" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/liteflow.png" msg="轻量,快速,稳定,可编排的组件式流程引擎">
<a href="https://gitee.com/dromara/liteFlow?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/liteflow.png" msg="轻量,快速,稳定,可编排的组件式流程引擎">
</a>
<a href="https://hutool.cn/" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/hutool.jpg" msg="🍬小而全的Java工具类库,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。">
<a href="https://hutool.cn/?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/hutool.jpg" msg="🍬小而全的Java工具类库,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。">
</a>
<a href="https://sa-token.cc/" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/sa-token.png" msg="一个轻量级 java 权限认证框架,让鉴权变得简单、优雅!">
<a href="https://sa-token.cc/?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/sa-token.png" msg="一个轻量级 java 权限认证框架,让鉴权变得简单、优雅!">
</a>
<a href="https://gitee.com/dromara/hmily" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/hmily.png" msg="高性能一站式分布式事务解决方案。">
<a href="https://gitee.com/dromara/hmily?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/hmily.png" msg="高性能一站式分布式事务解决方案。">
</a>
<a href="https://gitee.com/dromara/Raincat" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/raincat.png" msg="强一致性分布式事务解决方案。">
<a href="https://gitee.com/dromara/Raincat?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/raincat.png" msg="强一致性分布式事务解决方案。">
</a>
<a href="https://gitee.com/dromara/myth" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/myth.png" msg="可靠消息分布式事务解决方案。">
<a href="https://gitee.com/dromara/myth?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/myth.png" msg="可靠消息分布式事务解决方案。">
</a>
<a href="https://cubic.jiagoujishu.com/" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/cubic.png" msg="一站式问题定位平台,以agent的方式无侵入接入应用,完整集成arthas功能模块,致力于应用级监控,帮助开发人员快速定位问题">
<a href="https://cubic.jiagoujishu.com/?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/cubic.png" msg="一站式问题定位平台,以agent的方式无侵入接入应用,完整集成arthas功能模块,致力于应用级监控,帮助开发人员快速定位问题">
</a>
<a href="https://maxkey.top/" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/maxkey.png" msg="业界领先的身份管理和认证产品">
<a href="https://maxkey.top/?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/maxkey.png" msg="业界领先的身份管理和认证产品">
</a>
<a href="http://forest.dtflyx.com/" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/forest-logo.png" msg="Forest能够帮助您使用更简单的方式编写Java的HTTP客户端" nf="">
<a href="http://forest.dtflyx.com/?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/forest-logo.png" msg="Forest能够帮助您使用更简单的方式编写Java的HTTP客户端" nf="">
</a>
<a href="https://jpom.top/" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/jpom.png" msg="一款简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件">
<a href="https://jpom.top/?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/jpom.svg" msg="一款简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件">
</a>
<a href="https://su.usthe.com/" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/sureness.png" msg="面向 REST API 的高性能认证鉴权框架">
<a href="https://su.usthe.com/?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/sureness.png" msg="面向 REST API 的高性能认证鉴权框架">
</a>
<a href="https://easy-es.cn/" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/easy-es2.png" msg="🚀傻瓜级ElasticSearch搜索引擎ORM框架">
<a href="https://easy-es.cn/?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/easy-es2.png" msg="🚀傻瓜级ElasticSearch搜索引擎ORM框架">
</a>
<a href="https://gitee.com/dromara/northstar" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/northstar_logo.png" msg="Northstar盈富量化交易平台">
<a href="https://gitee.com/dromara/northstar?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/northstar_logo.png" msg="Northstar盈富量化交易平台">
</a>
<a href="https://hertzbeat.com/" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/hertzbeat-brand.svg" msg="易用友好的云监控系统">
<a href="https://hertzbeat.com/?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/hertzbeat-brand.svg" msg="易用友好的云监控系统">
</a>
<a href="https://dromara.gitee.io/fast-request/" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/fast-request.gif" msg="Idea 版 Postman,为简化调试API而生">
<a href="https://dromara.gitee.io/fast-request/?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/fast-request.gif" msg="Idea 版 Postman,为简化调试API而生">
</a>
<a href="https://www.jeesuite.com/" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/mendmix.png" msg="开源分布式云原生架构一站式解决方案">
<a href="https://www.jeesuite.com/?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/mendmix.png" msg="开源分布式云原生架构一站式解决方案">
</a>
<a href="https://gitee.com/dromara/koalas-rpc" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/koalas-rpc2.png" msg="企业生产级百亿日PV高可用可拓展的RPC框架。">
<a href="https://gitee.com/dromara/koalas-rpc?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/koalas-rpc2.png" msg="企业生产级百亿日PV高可用可拓展的RPC框架。">
</a>
<a href="https://async.sizegang.cn/" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/gobrs-async.png" msg="🔥 配置极简功能强大的异步任务动态编排框架">
<a href="https://async.sizegang.cn/?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/gobrs-async.png" msg="🔥 配置极简功能强大的异步任务动态编排框架">
</a>
<a href="https://dynamictp.cn/" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/dynamic-tp.png" msg="🔥🔥🔥 基于配置中心的轻量级动态可监控线程池">
<a href="https://dynamictp.cn/?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/dynamic-tp.png" msg="🔥🔥🔥 基于配置中心的轻量级动态可监控线程池">
</a>
<a href="https://www.x-easypdf.cn" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/x-easypdf.png" msg="一个用搭积木的方式构建pdf的框架(基于pdfbox">
<a href="https://www.x-easypdf.cn?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/x-easypdf.png" msg="一个用搭积木的方式构建pdf的框架(基于pdfbox">
</a>
<a href="http://dromara.gitee.io/image-combiner" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/image-combiner.png" msg="一个专门用于图片合成的工具,没有很复杂的功能,简单实用,却不失强大">
<a href="http://dromara.gitee.io/image-combiner?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/image-combiner.png" msg="一个专门用于图片合成的工具,没有很复杂的功能,简单实用,却不失强大">
</a>
<a href="https://www.herodotus.cn/" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/dante-cloud2.png" msg="Dante-Cloud 是一款企业级微服务架构和服务能力开发平台。">
<a href="https://www.herodotus.cn/?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/dante-cloud.jpg" msg="Dante-Cloud 是一款企业级微服务架构和服务能力开发平台。">
</a>
<a href="http://www.mtruning.club" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/go-view.png" msg="低代码数据可视化开发平台">
<a href="http://www.mtruning.club?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/go-view.png" msg="低代码数据可视化开发平台">
</a>
<a href="https://tangyh.top/" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/lamp-cloud.png" msg="微服务中后台快速开发平台,支持租户(SaaS)模式、非租户模式">
<a href="https://tangyh.top/?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/lamp-cloud.png" msg="微服务中后台快速开发平台,支持租户(SaaS)模式、非租户模式">
</a>
<a href="https://www.redisfront.com/" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/redis-front.png" msg="RedisFront 是一款开源免费的跨平台 Redis 桌面客户端工具, 支持单机模式, 集群模式, 哨兵模式以及 SSH 隧道连接, 可轻松管理Redis缓存数据.">
<a href="https://www.redisfront.com/?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/redis-front.png" msg="RedisFront 是一款开源免费的跨平台 Redis 桌面客户端工具, 支持单机模式, 集群模式, 哨兵模式以及 SSH 隧道连接, 可轻松管理Redis缓存数据.">
</a>
<a href="https://www.yuque.com/u34495/mivcfg" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/electron-egg.png" msg="一个入门简单、跨平台、企业级桌面软件开发框架">
<a href="https://www.yuque.com/u34495/mivcfg?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/electron-egg.png" msg="一个入门简单、跨平台、企业级桌面软件开发框架">
</a>
<a href="https://gitee.com/dromara/open-capacity-platform" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/open-capacity-platform.jpg" msg="简称ocp是基于Spring Cloud的企业级微服务框架(用户权限管理,配置中心管理,应用管理,....)">
<a href="https://gitee.com/dromara/open-capacity-platform?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/open-capacity-platform.jpg" msg="简称ocp是基于Spring Cloud的企业级微服务框架(用户权限管理,配置中心管理,应用管理,....)">
</a>
<a href="http://easy-trans.fhs-opensource.top/" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/easy_trans.png" msg="Easy-Trans 一个注解搞定数据翻译,减少30%SQL代码量">
<a href="http://easy-trans.fhs-opensource.top/?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/easy_trans.png" msg="Easy-Trans 一个注解搞定数据翻译,减少30%SQL代码量">
</a>
<a href="https://gitee.com/dromara/neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/neutrino-proxy.svg" msg="一款基于 Netty 的、开源的内网穿透神器。">
<a href="https://gitee.com/dromara/neutrino-proxy?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/neutrino-proxy.svg" msg="一款基于 Netty 的、开源的内网穿透神器。">
</a>
<a href="https://chatgpt.cn.obiscr.com/" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/chatgpt.png" msg="一个支持在 JetBrains 系列 IDE 上运行的 ChatGPT 的插件。">
<a href="https://chatgpt.cn.obiscr.com/?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/chatgpt.png" msg="一个支持在 JetBrains 系列 IDE 上运行的 ChatGPT 的插件。">
</a>
<a href="https://gitee.com/dromara/zyplayer-doc" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/zyplayer-doc.png" msg="zyplayer-doc是一款适合团队和个人使用的WIKI文档管理工具,同时还包含数据库文档、Api接口文档。">
<a href="https://gitee.com/dromara/zyplayer-doc?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/zyplayer-doc.png" msg="zyplayer-doc是一款适合团队和个人使用的WIKI文档管理工具,同时还包含数据库文档、Api接口文档。">
</a>
<a href="https://gitee.com/dromara/payment-spring-boot" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/payment-spring-boot.png" msg="最全最好用的微信支付V3 Spring Boot 组件。">
<a href="https://gitee.com/dromara/payment-spring-boot?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/payment-spring-boot.png" msg="最全最好用的微信支付V3 Spring Boot 组件。">
</a>
<a href="https://www.j2eefast.com/" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/j2eefast.png" msg="J2eeFAST 是一个致力于中小企业 Java EE 企业级快速开发平台,我们永久开源!">
<a href="https://www.j2eefast.com/?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/j2eefast.png" msg="J2eeFAST 是一个致力于中小企业 Java EE 企业级快速开发平台,我们永久开源!">
</a>
<a href="https://gitee.com/dromara/data-compare" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/dataCompare.png" msg="数据库比对工具:hive 表数据比对,mysql、Doris 数据比对,实现自动化配置进行数据比对,避免频繁写sql 进行处理,低代码(Low-Code) 平台">
<a href="https://gitee.com/dromara/data-compare?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/dataCompare.png" msg="数据库比对工具:hive 表数据比对,mysql、Doris 数据比对,实现自动化配置进行数据比对,避免频繁写sql 进行处理,低代码(Low-Code) 平台">
</a>
<a href="https://gitee.com/dromara/open-giteye-api" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/open-giteye-api.svg" msg="giteye.net 是专为开源作者设计的数据图表服务工具类站点,提供了包括 Star 趋势图、贡献者列表、Gitee指数等数据图表服务。">
<a href="https://gitee.com/dromara/open-giteye-api?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/open-giteye-api.svg" msg="giteye.net 是专为开源作者设计的数据图表服务工具类站点,提供了包括 Star 趋势图、贡献者列表、Gitee指数等数据图表服务。">
</a>
<a href="https://gitee.com/dromara/RuoYi-Vue-Plus" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/RuoYi-Vue-Plus.png" msg="后台管理系统 重写 RuoYi-Vue 所有功能 集成 Sa-Token + Mybatis-Plus + Jackson + Xxl-Job + SpringDoc + Hutool + OSS 定期同步">
<a href="https://gitee.com/dromara/RuoYi-Vue-Plus?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/RuoYi-Vue-Plus.png" msg="后台管理系统 重写 RuoYi-Vue 所有功能 集成 Sa-Token + Mybatis-Plus + Jackson + Xxl-Job + SpringDoc + Hutool + OSS 定期同步">
</a>
<a href="https://gitee.com/dromara/RuoYi-Cloud-Plus" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/RuoYi-Cloud-Plus.png" msg="微服务管理系统 重写RuoYi-Cloud所有功能 整合 SpringCloudAlibaba Dubbo3.0 Sa-Token Mybatis-Plus MQ OSS ES Xxl-Job Docker 全方位升级 定期同步">
<a href="https://gitee.com/dromara/RuoYi-Cloud-Plus?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/RuoYi-Cloud-Plus.png" msg="微服务管理系统 重写RuoYi-Cloud所有功能 整合 SpringCloudAlibaba Dubbo3.0 Sa-Token Mybatis-Plus MQ OSS ES Xxl-Job Docker 全方位升级 定期同步">
</a>
<a href="https://gitee.com/dromara/stream-query" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/stream-query.png" msg="允许完全摆脱 Mapper 的 mybatis-plus 体验!封装 stream 和 lambda 操作进行数据返回处理。">
<a href="https://gitee.com/dromara/stream-query?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/stream-query.png" msg="允许完全摆脱 Mapper 的 mybatis-plus 体验!封装 stream 和 lambda 操作进行数据返回处理。">
</a>
<a href="https://dromara.org/zh/projects/" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/dromara.png" msg="让每一位开源爱好者,体会到开源的快乐。">
<a href="https://dromara.org/zh/projects/?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" src="img/logo/dromara.png" msg="让每一位开源爱好者,体会到开源的快乐。">
</a>
</p>
<h2>🤝 友情开源项目</h2>
<p>
<a href="https://gitee.com/noear/solon" target="_blank" class="friends-item" >
<img class="no-zoom friends-item-img hover-alt" :src="$withBase('/img/logo/solon_logo_500_150.png')" msg="一个高效的应用开发框架:更快、更小、更简单。" />
<a href="https://gitee.com/noear/solon?from=neutrino-proxy" target="_blank" class="friends-item" >
<img class="no-zoom friends-item-img hover-alt" :src="$withBase('img/logo/solon_logo_500_150.png')" msg="一个高效的应用开发框架:更快、更小、更简单。" />
</a>
<a href="https://gitee.com/xiaonuobase/snowy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" :src="$withBase('/img/logo/xiaonuo.png')" msg="国内首个国密前后端分离快速开发平台" />
<a href="https://gitee.com/xiaonuobase/snowy?from=neutrino-proxy" target="_blank" class="friends-item">
<img class="no-zoom friends-item-img hover-alt" :src="$withBase('img/logo/xiaonuo.png')" msg="国内首个国密前后端分离快速开发平台" />
</a>
</p>
+6 -1
View File
@@ -7,7 +7,7 @@
<parent>
<groupId>org.noear</groupId>
<artifactId>solon-parent</artifactId>
<version>2.2.8</version>
<version>2.3.6</version>
<relativePath />
</parent>
@@ -97,6 +97,11 @@
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<version>2.7.4</version>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
+3 -1
View File
@@ -41,4 +41,6 @@ npm run build:$env
#拷贝
cd ..
cp -rf ./neutrino-proxy-admin/dist $adminDeployDir/
cp -rf ./neutrino-proxy-admin/dist/ $giteePagesDir
cp -rf ./neutrino-proxy-admin/dist/ $giteePagesDir
cd $serverDeployDir
zip -r neutrino-proxy-admin.zip "neutrino-proxy-admin/"
+3 -1
View File
@@ -41,4 +41,6 @@ npm run build:$env
#拷贝
cd ..
cp -rf ./neutrino-proxy-admin/dist $adminDeployDir/
cp -rf ./neutrino-proxy-admin/dist/ $giteePagesDir
cp -rf ./neutrino-proxy-admin/dist/ $giteePagesDir
cd $serverDeployDir
zip -r neutrino-proxy-admin.zip "neutrino-proxy-admin/"
+2 -2
View File
@@ -2,8 +2,8 @@
# 中微子代理客户端编译打包脚本,基础参数请自行修改
export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home
export MAVANE_HOME=/Users/yangwen/my/service/maven/apache-maven-3.8.1
export PATH=:$PATH:$JAVA_HOME/bin:$MAVANE_HOME/bin
export MAVEN_HOME=/Users/yangwen/my/service/maven/apache-maven-3.8.1
export PATH=:$PATH:$JAVA_HOME/bin:$MAVEN_HOME/bin
deployDir="deploy"
clientDeployDir=$deployDir"/client"
+29
View File
@@ -0,0 +1,29 @@
#!/bin/sh
# 镜像版本,每次更新版本时需要调整
ImageVer=1.8.5
ImageName=neutrino-proxy-client
DockerFilePath=$PWD/../../neutrino-proxy-client/Dockerfile
deployDir=$PWD/../../"deploy"
clientDeployDir=$deployDir"/client"
#切到项目根目录
#初始化文件夹
if [ ! -d "$deployDir" ];then
mkdir $deployDir
fi
if [ ! -d "$clientDeployDir" ];then
mkdir $clientDeployDir
fi
rm -rf $clientDeployDir/$ImageName.tar
#echo '打包jar...'
sh ./client_build.sh
# 删除老的本地镜像
docker rmi -f $(docker images | grep $ImageName | awk '{print $3}')
# 构建镜像
docker build -t $ImageName:$ImageVer -t $ImageName:latest -f $DockerFilePath $PWD/../..
# 保存镜像到本地
docker save -o $clientDeployDir/$ImageName.tar $ImageName:$ImageVer
+2 -2
View File
@@ -2,8 +2,8 @@
# 中微子代理客户端编译打包脚本,基础参数请自行修改
export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home
export MAVANE_HOME=/Users/yangwen/my/service/maven/apache-maven-3.8.1
export PATH=:$PATH:$JAVA_HOME/bin:$MAVANE_HOME/bin
export MAVEN_HOME=/Users/yangwen/my/service/maven/apache-maven-3.8.1
export PATH=:$PATH:$JAVA_HOME/bin:$MAVEN_HOME/bin
deployDir="deploy"
serverDeployDir=$deployDir"/server"
+25
View File
@@ -1,3 +1,26 @@
# 1.x规划
- Bug
- 优化
- 添加端口映射时,验证端口是否被其他服务占用
- 拉下搜索license,支持模糊搜索
- license下拉用户搜索,支持模糊搜索
- UDP支持
- 官网文档完善
- HTTPS配置说明
- 协议重构
- 代码重构
# 1.8.6
- [x] 端口映射选择端口支持分页
- [x] 新增/更新端口映射,增加端口占用检测
- [ ] 增加服务端/客户端jar式一键部署脚本
- [x] 拉下搜索license,支持模糊搜索
- [x] license下拉用户搜索,支持模糊搜索
- [x] 端口映射编辑时,如果端口号没有变动,则不验证。避免出现端口映射正在使用时,无法更新端口映射其他信息的问题
- [x] 端口映射HTTP(S)新增打开网页按钮
- [x] 客户端断开连接时,记录日志空指针异常问题修复
- [ ] 排查解决问题:https://gitee.com/dromara/neutrino-proxy/issues/I7LGLB
# Bug
- 指令通达被close的问题,org.dromara.neutrinoproxy.server.proxy.core.ProxyTunnelChannelHandler.channelInactive
- windows环境下直接运行发布版的jar包,日志输出乱码
@@ -17,6 +40,8 @@
- [ ] 支持调整服务端端口、证书
- [ ] 服务端版本、协议版本、客户端版本管理
- [ ] 服务端日志
- [ ] 支持持管理后台动态调整日志级别。
- [ ] 动态调整转发、报文、心跳输出
- client+计划启动
- [ ] 安卓客户端
- [ ] 基于electron-egg的多平台客户端