mirror of
https://gitee.com/wujiawei1207537021/wu-lazy-cloud-network.git
synced 2025-06-07 05:47:57 +08:00
[fix] 修改bean 创建,添加网络榴莲监控
This commit is contained in:
parent
20f3f9307c
commit
1ee7021aa1
@ -2,11 +2,11 @@
|
||||
|
||||
#### 模块说明
|
||||
|
||||
| 模块 | 所属层级 | 描述 | 端口 |
|
||||
|----------------------------------------------------------------------------------------|------|------------------------|----------------------------------------------------------------|
|
||||
| [middleground-cloud-heartbeat-common](middleground-cloud-heartbeat-common) | 基础模块 | 基于Netty数据解码、编码、通道处理器声明 | 无 |
|
||||
| [middleground-on-cloud-heartbeat-server](middleground-on-cloud-heartbeat-server) | 启动模块 | 内网穿透服务端 | http端口:6001、tcp端口:7001 (默认tcp端口=http端口+1000 如:6001+1000=7001) |
|
||||
| [middleground-under-cloud-heartbeat-client](middleground-under-cloud-heartbeat-client) | 启动模块 | 内网穿透客户端 | 6004 |
|
||||
| 模块 | 所属层级 | 描述 | 端口 |
|
||||
|------------------------------------------------------------------|------|------------------------|----------------------------------------------------------------|
|
||||
| [wu-lazy-cloud-heartbeat-common](wu-lazy-cloud-heartbeat-common) | 基础模块 | 基于Netty数据解码、编码、通道处理器声明 | 无 |
|
||||
| [wu-lazy-cloud-heartbeat-server](wu-lazy-cloud-heartbeat-server) | 启动模块 | 内网穿透服务端 | http端口:6001、tcp端口:7001 (默认tcp端口=http端口+1000 如:6001+1000=7001) |
|
||||
| [wu-lazy-cloud-heartbeat-client](wu-lazy-cloud-heartbeat-client) | 启动模块 | 内网穿透客户端 | 6004 |
|
||||
|
||||
#### 功能
|
||||
|
||||
@ -52,13 +52,13 @@ spring:
|
||||
如果云端需要部署云上暂存+内网穿透功能:需要部署 内网穿透服务端、暂存服务、内网穿透客户端、云上离线网关
|
||||
```
|
||||
|
||||
| 模块 | 说明 | 部署内网穿透必须 | 部署内网穿透+云上暂存必须 |
|
||||
|----------------------------------------------------------------------------------------|------------|----------|---------------|
|
||||
| [middleground-on-cloud-heartbeat-server](middleground-on-cloud-heartbeat-server) | 内网穿透+心跳服务端 | ☑️ | ☑️ |
|
||||
| [middleground-under-cloud-heartbeat-client](middleground-under-cloud-heartbeat-client) | 内网穿透+心跳客户端 | ✖️ | ☑️ |
|
||||
| [middleground-cloud-staging-provider](middleground-cloud-staging-provider) | 暂存服务 | ✖️ | ☑️ |
|
||||
| [middleground-on-cloud-central-gateway](middleground-on-cloud-central-gateway) | 云上暂存网关 | ✖️ | ☑️ |
|
||||
| [middleground-under-cloud-central-gateway](middleground-under-cloud-central-gateway) | 云下暂存网关 | ✖️ | ✖️ |
|
||||
| 模块 | 说明 | 部署内网穿透必须 | 部署内网穿透+云上暂存必须 |
|
||||
|------------------------------------------------------------------|------------|----------|---------------|
|
||||
| [wu-lazy-cloud-heartbeat-server](wu-lazy-cloud-heartbeat-server) | 内网穿透+心跳服务端 | ☑️ | ☑️ |
|
||||
| [wu-lazy-cloud-heartbeat-client](wu-lazy-cloud-heartbeat-client) | 内网穿透+心跳客户端 | ✖️ | ☑️ |
|
||||
| [wu-lazy-cloud-staging-provider](wu-lazy-cloud-staging-provider) | 暂存服务 | ✖️ | ☑️ |
|
||||
| [wu-lazy-cloud-central-gateway](wu-lazy-cloud-central-gateway) | 云上暂存网关 | ✖️ | ☑️ |
|
||||
| [wu-lazy-cloud-central-gateway](wu-lazy-cloud-central-gateway) | 云下暂存网关 | ✖️ | ✖️ |
|
||||
|
||||
##### 云网关部署
|
||||
|
||||
@ -66,13 +66,13 @@ spring:
|
||||
云网关部署内网穿透客户端
|
||||
```
|
||||
|
||||
| 模块 | 说明 | 部署内网穿透必须 | 部署内网穿透+云上暂存必须 |
|
||||
|----------------------------------------------------------------------------------------|------------|----------|---------------|
|
||||
| [middleground-on-cloud-heartbeat-server](middleground-on-cloud-heartbeat-server) | 内网穿透+心跳服务端 | ✖️ | ✖️ |
|
||||
| [middleground-under-cloud-heartbeat-client](middleground-under-cloud-heartbeat-client) | 内网穿透+心跳客户端 | ✖️ | ☑️ |
|
||||
| [middleground-cloud-staging-provider](middleground-cloud-staging-provider) | 暂存服务 | ✖️ | ✖️ |
|
||||
| [middleground-on-cloud-central-gateway](middleground-on-cloud-central-gateway) | 云上暂存网关 | ✖️ | ☑️ |
|
||||
| [middleground-under-cloud-central-gateway](middleground-under-cloud-central-gateway) | 云下暂存网关 | ✖️ | ✖️ |
|
||||
| 模块 | 说明 | 部署内网穿透必须 | 部署内网穿透+云上暂存必须 |
|
||||
|------------------------------------------------------------------|------------|----------|---------------|
|
||||
| [wu-lazy-cloud-heartbeat-server](wu-lazy-cloud-heartbeat-server) | 内网穿透+心跳服务端 | ✖️ | ✖️ |
|
||||
| [wu-lazy-cloud-heartbeat-client](wu-lazy-cloud-heartbeat-client) | 内网穿透+心跳客户端 | ✖️ | ☑️ |
|
||||
| [wu-lazy-cloud-staging-provider](wu-lazy-cloud-staging-provider) | 暂存服务 | ✖️ | ✖️ |
|
||||
| [wu-lazy-cloud-central-gateway](wu-lazy-cloud-central-gateway) | 云上暂存网关 | ✖️ | ☑️ |
|
||||
| [wu-lazy-cloud-central-gateway](wu-lazy-cloud-central-gateway) | 云下暂存网关 | ✖️ | ✖️ |
|
||||
|
||||
##### 独立租户部署
|
||||
|
||||
@ -81,12 +81,12 @@ spring:
|
||||
内网穿透+离线暂存能力: 需要部署内网穿透客户端、离线网关、离线暂存服务
|
||||
```
|
||||
|
||||
| 模块 | 说明 | 部署内网穿透必须 | 部署内网穿透+云上暂存必须 |
|
||||
|----------------------------------------------------------------------------------------|------------|----------|---------------|
|
||||
| [middleground-on-cloud-heartbeat-server](middleground-on-cloud-heartbeat-server) | 内网穿透+心跳服务端 | ✖️ | ✖️ |
|
||||
| [middleground-under-cloud-heartbeat-client](middleground-under-cloud-heartbeat-client) | 内网穿透+心跳客户端 | ☑️ | ☑️ |
|
||||
| [middleground-cloud-staging-provider](middleground-cloud-staging-provider) | 暂存服务 | ✖️ | ☑️ |
|
||||
| [middleground-on-cloud-central-gateway](middleground-on-cloud-central-gateway) | 云上暂存网关 | ✖️ | ✖️ |
|
||||
| [middleground-under-cloud-central-gateway](middleground-under-cloud-central-gateway) | 云下暂存网关 | ✖️ | ☑️ |
|
||||
| 模块 | 说明 | 部署内网穿透必须 | 部署内网穿透+云上暂存必须 |
|
||||
|------------------------------------------------------------------|------------|----------|---------------|
|
||||
| [wu-lazy-cloud-heartbeat-server](wu-lazy-cloud-heartbeat-server) | 内网穿透+心跳服务端 | ✖️ | ✖️ |
|
||||
| [wu-lazy-cloud-heartbeat-client](wu-lazy-cloud-heartbeat-client) | 内网穿透+心跳客户端 | ☑️ | ☑️ |
|
||||
| [wu-lazy-cloud-staging-provider](wu-lazy-cloud-staging-provider) | 暂存服务 | ✖️ | ☑️ |
|
||||
| [wu-lazy-cloud-central-gateway](wu-lazy-cloud-central-gateway) | 云上暂存网关 | ✖️ | ✖️ |
|
||||
| [wu-lazy-cloud-central-gateway](wu-lazy-cloud-central-gateway) | 云下暂存网关 | ✖️ | ☑️ |
|
||||
|
||||
|
||||
|
36
k8s-on.yaml
36
k8s-on.yaml
@ -6,8 +6,8 @@ metadata:
|
||||
k8s.kuboard.cn/displayName: 【云上云下】云上心跳服务端(新)
|
||||
labels:
|
||||
k8s.kuboard.cn/layer: monitor
|
||||
k8s.kuboard.cn/name: middleground-on-cloud-heartbeat-server
|
||||
name: middleground-on-cloud-heartbeat-server
|
||||
k8s.kuboard.cn/name: wu-lazy-cloud-heartbeat-server
|
||||
name: wu-lazy-cloud-heartbeat-server
|
||||
namespace: middleground-management
|
||||
spec:
|
||||
progressDeadlineSeconds: 600
|
||||
@ -16,7 +16,7 @@ spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
k8s.kuboard.cn/layer: monitor
|
||||
k8s.kuboard.cn/name: middleground-on-cloud-heartbeat-server
|
||||
k8s.kuboard.cn/name: wu-lazy-cloud-heartbeat-server
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
maxSurge: 25%
|
||||
@ -26,16 +26,16 @@ spec:
|
||||
metadata:
|
||||
labels:
|
||||
k8s.kuboard.cn/layer: monitor
|
||||
k8s.kuboard.cn/name: middleground-on-cloud-heartbeat-server
|
||||
k8s.kuboard.cn/name: wu-lazy-cloud-heartbeat-server
|
||||
spec:
|
||||
containers:
|
||||
- envFrom:
|
||||
- configMapRef:
|
||||
name: common-cnf
|
||||
image: >-
|
||||
docker-registry.laihui.com/middleground/middleground-on-cloud-heartbeat-server:master_latest
|
||||
docker-registry.laihui.com/middleground/wu-lazy-cloud-heartbeat-server:master_latest
|
||||
imagePullPolicy: Always
|
||||
name: middleground-on-cloud-heartbeat-server
|
||||
name: wu-lazy-cloud-heartbeat-server
|
||||
resources:
|
||||
limits:
|
||||
memory: 512Mi
|
||||
@ -57,8 +57,8 @@ metadata:
|
||||
k8s.kuboard.cn/displayName: 【云上云下】云上中心网关(新)
|
||||
labels:
|
||||
k8s.kuboard.cn/layer: gateway
|
||||
k8s.kuboard.cn/name: middleground-on-cloud-central-gateway
|
||||
name: middleground-on-cloud-central-gateway
|
||||
k8s.kuboard.cn/name: wu-lazy-cloud-central-gateway
|
||||
name: wu-lazy-cloud-central-gateway
|
||||
namespace: middleground-management
|
||||
spec:
|
||||
progressDeadlineSeconds: 600
|
||||
@ -67,7 +67,7 @@ spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
k8s.kuboard.cn/layer: gateway
|
||||
k8s.kuboard.cn/name: middleground-on-cloud-central-gateway
|
||||
k8s.kuboard.cn/name: wu-lazy-cloud-central-gateway
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
maxSurge: 25%
|
||||
@ -77,16 +77,16 @@ spec:
|
||||
metadata:
|
||||
labels:
|
||||
k8s.kuboard.cn/layer: gateway
|
||||
k8s.kuboard.cn/name: middleground-on-cloud-central-gateway
|
||||
k8s.kuboard.cn/name: wu-lazy-cloud-central-gateway
|
||||
spec:
|
||||
containers:
|
||||
- envFrom:
|
||||
- configMapRef:
|
||||
name: common-cnf
|
||||
image: >-
|
||||
docker-registry.laihui.com/middleground/middleground-on-cloud-central-gateway:master_latest
|
||||
docker-registry.laihui.com/middleground/wu-lazy-cloud-central-gateway:master_latest
|
||||
imagePullPolicy: Always
|
||||
name: middleground-on-cloud-central-gateway
|
||||
name: wu-lazy-cloud-central-gateway
|
||||
resources:
|
||||
limits:
|
||||
memory: 384Mi
|
||||
@ -108,8 +108,8 @@ metadata:
|
||||
k8s.kuboard.cn/displayName: 【云上云下】暂存服务(新)
|
||||
labels:
|
||||
k8s.kuboard.cn/layer: svc
|
||||
k8s.kuboard.cn/name: middleground-cloud-staging-provider
|
||||
name: middleground-cloud-staging-provider
|
||||
k8s.kuboard.cn/name: wu-lazy-cloud-staging-provider
|
||||
name: wu-lazy-cloud-staging-provider
|
||||
namespace: middleground-management
|
||||
spec:
|
||||
progressDeadlineSeconds: 600
|
||||
@ -118,7 +118,7 @@ spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
k8s.kuboard.cn/layer: svc
|
||||
k8s.kuboard.cn/name: middleground-cloud-staging-provider
|
||||
k8s.kuboard.cn/name: wu-lazy-cloud-staging-provider
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
maxSurge: 25%
|
||||
@ -128,16 +128,16 @@ spec:
|
||||
metadata:
|
||||
labels:
|
||||
k8s.kuboard.cn/layer: svc
|
||||
k8s.kuboard.cn/name: middleground-cloud-staging-provider
|
||||
k8s.kuboard.cn/name: wu-lazy-cloud-staging-provider
|
||||
spec:
|
||||
containers:
|
||||
- envFrom:
|
||||
- configMapRef:
|
||||
name: common-cnf
|
||||
image: >-
|
||||
docker-registry.laihui.com/middleground/middleground-cloud-staging-provider:master_latest
|
||||
docker-registry.laihui.com/middleground/wu-lazy-cloud-staging-provider:master_latest
|
||||
imagePullPolicy: Always
|
||||
name: middleground-cloud-staging-provider
|
||||
name: wu-lazy-cloud-staging-provider
|
||||
resources:
|
||||
limits:
|
||||
memory: 384Mi
|
||||
|
@ -7,8 +7,8 @@ metadata:
|
||||
k8s.kuboard.cn/displayName: 【云上云下】云下心跳客户端(新)
|
||||
labels:
|
||||
k8s.kuboard.cn/layer: monitor
|
||||
k8s.kuboard.cn/name: middleground-under-cloud-heartbeat-client
|
||||
name: middleground-under-cloud-heartbeat-client
|
||||
k8s.kuboard.cn/name: wu-lazy-cloud-heartbeat-client
|
||||
name: wu-lazy-cloud-heartbeat-client
|
||||
namespace: middleground-tenant-share
|
||||
spec:
|
||||
progressDeadlineSeconds: 600
|
||||
@ -17,7 +17,7 @@ spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
k8s.kuboard.cn/layer: monitor
|
||||
k8s.kuboard.cn/name: middleground-under-cloud-heartbeat-client
|
||||
k8s.kuboard.cn/name: wu-lazy-cloud-heartbeat-client
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
maxSurge: 25%
|
||||
@ -27,16 +27,16 @@ spec:
|
||||
metadata:
|
||||
labels:
|
||||
k8s.kuboard.cn/layer: monitor
|
||||
k8s.kuboard.cn/name: middleground-under-cloud-heartbeat-client
|
||||
k8s.kuboard.cn/name: wu-lazy-cloud-heartbeat-client
|
||||
spec:
|
||||
containers:
|
||||
- envFrom:
|
||||
- configMapRef:
|
||||
name: common-cnf
|
||||
image: >-
|
||||
docker-registry.laihui.com/middleground/middleground-under-cloud-heartbeat-client:master_latest
|
||||
docker-registry.laihui.com/middleground/wu-lazy-cloud-heartbeat-client:master_latest
|
||||
imagePullPolicy: Always
|
||||
name: middleground-under-cloud-heartbeat-client
|
||||
name: wu-lazy-cloud-heartbeat-client
|
||||
resources:
|
||||
limits:
|
||||
memory: 384Mi
|
||||
@ -58,8 +58,8 @@ metadata:
|
||||
k8s.kuboard.cn/displayName: 【云上云下】云下中心网关(新)
|
||||
labels:
|
||||
k8s.kuboard.cn/layer: gateway
|
||||
k8s.kuboard.cn/name: middleground-under-cloud-central-gateway
|
||||
name: middleground-under-cloud-central-gateway
|
||||
k8s.kuboard.cn/name: wu-lazy-cloud-central-gateway
|
||||
name: wu-lazy-cloud-central-gateway
|
||||
namespace: middleground-tenant-share
|
||||
spec:
|
||||
progressDeadlineSeconds: 600
|
||||
@ -68,7 +68,7 @@ spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
k8s.kuboard.cn/layer: gateway
|
||||
k8s.kuboard.cn/name: middleground-under-cloud-central-gateway
|
||||
k8s.kuboard.cn/name: wu-lazy-cloud-central-gateway
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
maxSurge: 25%
|
||||
@ -78,16 +78,16 @@ spec:
|
||||
metadata:
|
||||
labels:
|
||||
k8s.kuboard.cn/layer: gateway
|
||||
k8s.kuboard.cn/name: middleground-under-cloud-central-gateway
|
||||
k8s.kuboard.cn/name: wu-lazy-cloud-central-gateway
|
||||
spec:
|
||||
containers:
|
||||
- envFrom:
|
||||
- configMapRef:
|
||||
name: common-cnf
|
||||
image: >-
|
||||
docker-registry.laihui.com/middleground/middleground-under-cloud-central-gateway:master_latest
|
||||
docker-registry.laihui.com/middleground/wu-lazy-cloud-central-gateway:master_latest
|
||||
imagePullPolicy: Always
|
||||
name: middleground-under-cloud-central-gateway
|
||||
name: wu-lazy-cloud-central-gateway
|
||||
resources:
|
||||
limits:
|
||||
memory: 384Mi
|
||||
@ -109,8 +109,8 @@ metadata:
|
||||
k8s.kuboard.cn/displayName: 【云上云下】云下暂存服务(新)
|
||||
labels:
|
||||
k8s.kuboard.cn/layer: svc
|
||||
k8s.kuboard.cn/name: middleground-cloud-staging-provider
|
||||
name: middleground-cloud-staging-provider
|
||||
k8s.kuboard.cn/name: wu-lazy-cloud-staging-provider
|
||||
name: wu-lazy-cloud-staging-provider
|
||||
namespace: middleground-tenant-share
|
||||
spec:
|
||||
progressDeadlineSeconds: 600
|
||||
@ -119,7 +119,7 @@ spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
k8s.kuboard.cn/layer: svc
|
||||
k8s.kuboard.cn/name: middleground-cloud-staging-provider
|
||||
k8s.kuboard.cn/name: wu-lazy-cloud-staging-provider
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
maxSurge: 25%
|
||||
@ -129,16 +129,16 @@ spec:
|
||||
metadata:
|
||||
labels:
|
||||
k8s.kuboard.cn/layer: svc
|
||||
k8s.kuboard.cn/name: middleground-cloud-staging-provider
|
||||
k8s.kuboard.cn/name: wu-lazy-cloud-staging-provider
|
||||
spec:
|
||||
containers:
|
||||
- envFrom:
|
||||
- configMapRef:
|
||||
name: common-cnf
|
||||
image: >-
|
||||
docker-registry.laihui.com/middleground/middleground-cloud-staging-provider:master_latest
|
||||
docker-registry.laihui.com/middleground/wu-lazy-cloud-staging-provider:master_latest
|
||||
imagePullPolicy: Always
|
||||
name: middleground-cloud-staging-provider
|
||||
name: wu-lazy-cloud-staging-provider
|
||||
resources:
|
||||
limits:
|
||||
memory: 384Mi
|
||||
|
@ -1,15 +1,14 @@
|
||||
package wu.framework.lazy.cloud.heartbeat.client.netty.filter;
|
||||
|
||||
import wu.framework.lazy.cloud.heartbeat.client.netty.handler.NettyClientVisitorRealHandler;
|
||||
import wu.framework.lazy.cloud.heartbeat.common.adapter.ChannelTypeAdapter;
|
||||
import wu.framework.lazy.cloud.heartbeat.common.decoder.NettyProxyMsgDecoder;
|
||||
import wu.framework.lazy.cloud.heartbeat.common.encoder.NettMsgEncoder;
|
||||
import wu.framework.lazy.cloud.heartbeat.common.encoder.NettyProxyMsgEncoder;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import wu.framework.lazy.cloud.heartbeat.client.netty.handler.NettyClientVisitorRealHandler;
|
||||
import wu.framework.lazy.cloud.heartbeat.common.adapter.ChannelTypeAdapter;
|
||||
import wu.framework.lazy.cloud.heartbeat.common.decoder.NettyProxyMsgDecoder;
|
||||
import wu.framework.lazy.cloud.heartbeat.common.encoder.NettyProxyMsgEncoder;
|
||||
|
||||
/**
|
||||
* netty 客户端连接真实服服务端访客拦截器
|
||||
@ -34,8 +33,8 @@ public class NettyClientVisitorRealFilter extends ChannelInitializer<SocketChann
|
||||
protected void initChannel(SocketChannel ch) throws Exception {
|
||||
ChannelPipeline pipeline = ch.pipeline();
|
||||
// // 解码、编码
|
||||
pipeline.addLast(new NettyProxyMsgDecoder(Integer.MAX_VALUE, 0, 4, -4, 0));
|
||||
pipeline.addLast(new NettMsgEncoder());
|
||||
// pipeline.addLast(new NettyProxyMsgDecoder(Integer.MAX_VALUE, 0, 4, -4, 0));
|
||||
// pipeline.addLast(new NettMsgEncoder());
|
||||
pipeline.addLast(new NettyProxyMsgDecoder(Integer.MAX_VALUE, 0, 4, -4, 0));
|
||||
pipeline.addLast(new NettyProxyMsgEncoder());
|
||||
pipeline.addLast(new NettyClientVisitorRealHandler(channelTypeAdapter));
|
||||
|
@ -46,8 +46,11 @@ public class NettyClientRealSocket {
|
||||
NettyServerProperties nettyServerProperties,
|
||||
List<HandleChannelTypeAdvanced> handleChannelTypeAdvancedList) {
|
||||
try {
|
||||
String clientId = internalNetworkPenetrationRealClient.getClientId();
|
||||
String clientTargetIp = internalNetworkPenetrationRealClient.getClientTargetIp();
|
||||
Integer clientTargetPort = internalNetworkPenetrationRealClient.getClientTargetPort();
|
||||
Integer visitorPort = internalNetworkPenetrationRealClient.getVisitorPort();
|
||||
String visitorId = internalNetworkPenetrationRealClient.getVisitorId();
|
||||
Bootstrap bootstrap = new Bootstrap();
|
||||
bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class)
|
||||
.handler(new NettyClientRealFilter());
|
||||
@ -56,12 +59,8 @@ public class NettyClientRealSocket {
|
||||
// 客户端链接真实服务成功 设置自动读写false 等待访客连接成功后设置成true
|
||||
Channel realChannel = future.channel();
|
||||
realChannel.config().setOption(ChannelOption.AUTO_READ, false);
|
||||
String clientId = internalNetworkPenetrationRealClient.getClientId();// 客户端ID
|
||||
String clientTargetIp1 = internalNetworkPenetrationRealClient.getClientTargetIp();
|
||||
Integer clientTargetPort1 = internalNetworkPenetrationRealClient.getClientTargetPort();
|
||||
Integer visitorPort = internalNetworkPenetrationRealClient.getVisitorPort();
|
||||
String visitorId = internalNetworkPenetrationRealClient.getVisitorId();
|
||||
log.info("访客通过 客户端:【{}】,绑定本地服务,IP:{},端口:{} 新建通道成功", clientId, clientTargetIp1, clientTargetPort1);
|
||||
|
||||
log.info("访客通过 客户端:【{}】,绑定本地服务,IP:{},端口:{} 新建通道成功", clientId, clientTargetIp, clientTargetPort);
|
||||
// 客户端真实通道
|
||||
NettyRealIdContext.pushReal(realChannel, visitorId);
|
||||
// 绑定访客ID到当前真实通道属性
|
||||
@ -99,6 +98,8 @@ public class NettyClientRealSocket {
|
||||
// future.channel().attr(Constant.VID).set(internalNetworkPenetrationRealClient);
|
||||
// Constant.vrc.put(internalNetworkPenetrationRealClient, future.channel());
|
||||
// ProxySocket.connectProxyServer(internalNetworkPenetrationRealClient);
|
||||
}else {
|
||||
log.error("客户:【{}】,无法连接当前网络内的目标IP:【{}】,目标端口:【{}】",clientId,clientTargetIp,clientTargetPort);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package wu.framework.lazy.cloud.heartbeat.common;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@ -9,6 +10,7 @@ import lombok.experimental.Accessors;
|
||||
* @author Jia wei Wu
|
||||
* @date 2023/12/29 05:21 下午
|
||||
**/
|
||||
@Builder
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class InternalNetworkPenetrationRealClient {
|
||||
|
@ -7,7 +7,8 @@ import wu.framework.lazy.cloud.heartbeat.common.enums.MessageTypeEnums;
|
||||
|
||||
/**
|
||||
* @see MessageTypeEnums
|
||||
* -128~ 127
|
||||
* 数据取值范围 -128~ 127
|
||||
* 当前约束范围 -100~100
|
||||
*/
|
||||
public class MessageType {
|
||||
/**
|
||||
@ -79,7 +80,7 @@ public class MessageType {
|
||||
*/
|
||||
public static final byte REPORT_SINGLE_CLIENT_MESSAGE = 0X09;
|
||||
/**
|
||||
* 服务端通道 is active
|
||||
* 服务端通道 is active
|
||||
*
|
||||
* @see MessageTypeEnums#SERVER_CHANNEL_ACTIVE
|
||||
* @see AbstractHandleServerChannelActiveTypeAdvanced
|
||||
|
@ -1,6 +1,8 @@
|
||||
package wu.framework.lazy.cloud.heartbeat.common;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@ -8,6 +10,7 @@ import java.nio.charset.StandardCharsets;
|
||||
/**
|
||||
* netty 代理请求数据
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Setter
|
||||
@Getter
|
||||
public class NettyProxyMsg {
|
||||
|
@ -0,0 +1,41 @@
|
||||
package wu.framework.lazy.cloud.heartbeat.common.adapter;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import wu.framework.lazy.cloud.heartbeat.common.advanced.flow.ChannelFlow;
|
||||
import wu.framework.lazy.cloud.heartbeat.common.advanced.flow.HandleChannelFlowAdvanced;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 通道流量适配器
|
||||
*
|
||||
* @see HandleChannelFlowAdvanced
|
||||
*/
|
||||
@Slf4j
|
||||
public class ChannelFlowAdapter {
|
||||
|
||||
protected final List<HandleChannelFlowAdvanced> handleChannelFlowAdvancedList;
|
||||
|
||||
public ChannelFlowAdapter(List<HandleChannelFlowAdvanced> handleChannelFlowAdvancedList) {
|
||||
this.handleChannelFlowAdvancedList = handleChannelFlowAdvancedList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理当前数据
|
||||
*
|
||||
* @param channelFlow 通道数据
|
||||
*/
|
||||
public void handler(Channel channel, ChannelFlow channelFlow) {
|
||||
for (HandleChannelFlowAdvanced handleChannelTypeAdvanced : handleChannelFlowAdvancedList) {
|
||||
if (handleChannelTypeAdvanced.support(channelFlow)) {
|
||||
try {
|
||||
handleChannelTypeAdvanced.handler(channel, channelFlow);
|
||||
} catch (Exception e) {
|
||||
log.error("流量统计失败:{}", e.getMessage());
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -27,7 +27,12 @@ public abstract class AbstractHandleChannelTypeAdvanced<MSG> implements HandleCh
|
||||
public void handler(Channel channel, Object msg) {
|
||||
doHandler(channel, (MSG) msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否支持当前类型
|
||||
*
|
||||
* @param msg 通道数据
|
||||
* @return 布尔类型 是、否
|
||||
*/
|
||||
protected abstract boolean doSupport(MSG msg);
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,47 @@
|
||||
package wu.framework.lazy.cloud.heartbeat.common.advanced.flow;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
/**
|
||||
* 处理通道流量适配者 抽象类
|
||||
*
|
||||
* @see HandleChannelFlowAdvanced
|
||||
*/
|
||||
public abstract class AbstractHandleChannelFlowAdvanced implements HandleChannelFlowAdvanced {
|
||||
|
||||
/**
|
||||
* 是否支持当前这种类型
|
||||
*
|
||||
* @param channelFlow 数据
|
||||
* @return boolean
|
||||
*/
|
||||
@Override
|
||||
public boolean support(ChannelFlow channelFlow) {
|
||||
return doSupport(channelFlow);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理是否支持这种类型
|
||||
* @param channelFlow 数据
|
||||
* @return boolean
|
||||
*/
|
||||
abstract boolean doSupport(ChannelFlow channelFlow);
|
||||
|
||||
/**
|
||||
* 处理当前数据
|
||||
*
|
||||
* @param channel 当前通道
|
||||
* @param channelFlow 通道数据
|
||||
*/
|
||||
@Override
|
||||
public void handler(Channel channel, ChannelFlow channelFlow) {
|
||||
doHandler(channel, channelFlow);
|
||||
}
|
||||
/**
|
||||
* 处理当前数据
|
||||
*
|
||||
* @param channel 当前通道
|
||||
* @param channelFlow 通道数据
|
||||
*/
|
||||
abstract void doHandler(Channel channel, ChannelFlow channelFlow);
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package wu.framework.lazy.cloud.heartbeat.common.advanced.flow;
|
||||
|
||||
import wu.framework.lazy.cloud.heartbeat.common.enums.ChannelFlowEnum;
|
||||
|
||||
public interface ChannelFlow {
|
||||
|
||||
/**
|
||||
* 通道客户端ID
|
||||
*
|
||||
* @return 通道客户端ID
|
||||
*/
|
||||
String clientId();
|
||||
|
||||
/**
|
||||
* 通道使用的端口(服务端访客端口、客户端真实端口)
|
||||
*
|
||||
* @return 端口
|
||||
*/
|
||||
Integer port();
|
||||
|
||||
/**
|
||||
* 通道流量类型
|
||||
*
|
||||
* @return ChannelFlowEnum
|
||||
* @see ChannelFlowEnum
|
||||
*/
|
||||
ChannelFlowEnum channelFlowEnum();
|
||||
|
||||
/**
|
||||
* 流量
|
||||
* @return 流量
|
||||
*/
|
||||
Integer flow();
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,25 @@
|
||||
package wu.framework.lazy.cloud.heartbeat.common.advanced.flow;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
/**
|
||||
* 处理通道流量适配者
|
||||
*/
|
||||
public interface HandleChannelFlowAdvanced {
|
||||
|
||||
/**
|
||||
* 是否支持当前这种类型
|
||||
*
|
||||
* @param channelFlow 数据
|
||||
* @return boolean
|
||||
*/
|
||||
boolean support(ChannelFlow channelFlow);
|
||||
|
||||
/**
|
||||
* 处理当前数据
|
||||
*
|
||||
* @param channel 当前通道
|
||||
* @param channelFlow 通道数据
|
||||
*/
|
||||
void handler(Channel channel, ChannelFlow channelFlow);
|
||||
}
|
@ -9,6 +9,7 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
|
||||
* @see NettyMsg
|
||||
* NettyMsg 对象解码
|
||||
*/
|
||||
@Deprecated
|
||||
public class NettyMsgDecoder extends LengthFieldBasedFrameDecoder {
|
||||
|
||||
public NettyMsgDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment,
|
||||
|
@ -10,6 +10,7 @@ import io.netty.handler.codec.MessageToByteEncoder;
|
||||
* @see NettyProxyMsg
|
||||
* NettyProxyMsg 对象编码
|
||||
*/
|
||||
@Deprecated
|
||||
public class NettMsgEncoder extends MessageToByteEncoder<NettyMsg> {
|
||||
|
||||
public NettMsgEncoder() {
|
||||
|
@ -0,0 +1,17 @@
|
||||
package wu.framework.lazy.cloud.heartbeat.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 通道流量类型
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ChannelFlowEnum {
|
||||
|
||||
// 出口流量
|
||||
OUT_FLOW,
|
||||
// 进口流量
|
||||
IN_FLOW
|
||||
}
|
@ -10,6 +10,8 @@ public class ChannelAttributeKeyUtils {
|
||||
|
||||
private static final AttributeKey<String> VISITOR_ID = AttributeKey.newInstance("visitorId");
|
||||
private static final AttributeKey<String> CLIENT_ID = AttributeKey.newInstance("clientId");
|
||||
private static final AttributeKey<Integer> OUT_FLOW = AttributeKey.newInstance("outFlow");
|
||||
private static final AttributeKey<Integer> IN_FLOW = AttributeKey.newInstance("inFlow");
|
||||
|
||||
|
||||
/**
|
||||
@ -34,7 +36,8 @@ public class ChannelAttributeKeyUtils {
|
||||
|
||||
/**
|
||||
* 获取 通道中访客ID
|
||||
* @param channel 通道
|
||||
*
|
||||
* @param channel 通道
|
||||
*/
|
||||
public static String getVisitorId(Channel channel) {
|
||||
return channel.attr(VISITOR_ID).get();
|
||||
@ -44,16 +47,17 @@ public class ChannelAttributeKeyUtils {
|
||||
/**
|
||||
* 为通道绑定 访客属性
|
||||
*
|
||||
* @param channel 通道
|
||||
* @param channel 通道
|
||||
* @param clientId 客户端ID
|
||||
*/
|
||||
public static void buildClientId(Channel channel, byte[] clientId) {
|
||||
channel.attr(CLIENT_ID).set(new String(clientId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 为通道绑定 访客属性
|
||||
*
|
||||
* @param channel 通道
|
||||
* @param channel 通道
|
||||
* @param clientId 客户端ID
|
||||
*/
|
||||
public static void buildClientId(Channel channel, String clientId) {
|
||||
@ -62,9 +66,49 @@ public class ChannelAttributeKeyUtils {
|
||||
|
||||
/**
|
||||
* 获取 通道中访客ID
|
||||
* @param channel 通道
|
||||
*
|
||||
* @param channel 通道
|
||||
*/
|
||||
public static String getClientId(Channel channel) {
|
||||
return channel.attr(CLIENT_ID).get();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 为通道绑定 出口流量
|
||||
*
|
||||
* @param channel 通道
|
||||
* @param outFlow 出口流量
|
||||
*/
|
||||
public static void buildOutFlow(Channel channel, Integer outFlow) {
|
||||
channel.attr(OUT_FLOW).set(outFlow);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 通道中出口流量
|
||||
*
|
||||
* @param channel 通道
|
||||
*/
|
||||
public static Integer getOutFlow(Channel channel) {
|
||||
return channel.attr(OUT_FLOW).get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 为通道绑定 进口流量
|
||||
*
|
||||
* @param channel 通道
|
||||
* @param inFlow 进口流量
|
||||
*/
|
||||
public static void buildInFlow(Channel channel, Integer inFlow) {
|
||||
channel.attr(IN_FLOW).set(inFlow);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 通道中进口流量
|
||||
*
|
||||
* @param channel 通道
|
||||
*/
|
||||
public static Integer getInFlow(Channel channel) {
|
||||
return channel.attr(IN_FLOW).get();
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ MAINTAINER wujiawei <1207537021@qq.com>
|
||||
RUN echo "Asia/Shanghai" > /etc/timezone
|
||||
|
||||
|
||||
COPY target/middleground-under-cloud-heartbeat-client /native-app
|
||||
COPY target/wu-lazy-cloud-heartbeat-client /native-app
|
||||
|
||||
ENTRYPOINT ["/bin/sh" ,"-c", "exec ./native-app"]
|
||||
|
||||
|
@ -9,8 +9,8 @@ mvn native:build -Pnative
|
||||
```
|
||||
### 构建docker镜像
|
||||
```shell
|
||||
docker build -t docker-registry.laihui.com/middleground/middleground-under-cloud-heartbeat-client:middleground-2.4.2-native-SNAPSHOT_latest -f Native-Dockerfile .
|
||||
docker push docker-registry.laihui.com/middleground/middleground-under-cloud-heartbeat-client:middleground-2.4.2-native-SNAPSHOT_latest
|
||||
docker build -t docker-registry.laihui.com/middleground/wu-lazy-cloud-heartbeat-client:middleground-2.4.2-native-SNAPSHOT_latest -f Native-Dockerfile .
|
||||
docker push docker-registry.laihui.com/middleground/wu-lazy-cloud-heartbeat-client:middleground-2.4.2-native-SNAPSHOT_latest
|
||||
```
|
||||
|
||||
|
||||
|
@ -3,10 +3,10 @@ spring:
|
||||
netty:
|
||||
# inet-host: 127.0.0.1
|
||||
# inet-port: 7001
|
||||
# inet-path: middleground-on-cloud-heartbeat-server
|
||||
# inet-path: wu-lazy-cloud-heartbeat-server
|
||||
inet-host: 124.222.48.62 # 服务端地址
|
||||
inet-port: 30676 #服务端端口
|
||||
# inet-path: middleground-on-cloud-heartbeat-server
|
||||
# inet-path: wu-lazy-cloud-heartbeat-server
|
||||
client-id: wujiawei # 客户端ID
|
||||
data:
|
||||
redis:
|
||||
|
@ -2,6 +2,7 @@ package wu.framework.lazy.cloud.heartbeat.server.application.impl;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import wu.framework.lazy.cloud.heartbeat.common.InternalNetworkPenetrationRealClient;
|
||||
import wu.framework.lazy.cloud.heartbeat.common.adapter.ChannelFlowAdapter;
|
||||
import wu.framework.lazy.cloud.heartbeat.server.application.InternalNetworkPenetrationMappingApplication;
|
||||
import wu.framework.lazy.cloud.heartbeat.server.application.assembler.InternalNetworkPenetrationMappingDTOAssembler;
|
||||
import wu.framework.lazy.cloud.heartbeat.server.application.command.internal.network.penetration.mapping.*;
|
||||
@ -34,6 +35,9 @@ public class InternalNetworkPenetrationMappingApplicationImpl implements Interna
|
||||
@Resource
|
||||
InternalNetworkPenetrationMappingRepository internalNetworkPenetrationMappingRepository;
|
||||
|
||||
@Resource
|
||||
ChannelFlowAdapter channelFlowAdapter;
|
||||
|
||||
|
||||
/**
|
||||
* describe 新增内网穿透映射
|
||||
@ -160,20 +164,28 @@ public class InternalNetworkPenetrationMappingApplicationImpl implements Interna
|
||||
String clientTargetIp = networkPenetrationMapping.getClientTargetIp();
|
||||
Integer clientTargetPort = networkPenetrationMapping.getClientTargetPort();
|
||||
|
||||
InternalNetworkPenetrationRealClient internalNetworkPenetrationRealClient = new InternalNetworkPenetrationRealClient();
|
||||
internalNetworkPenetrationRealClient.setClientTargetIp(clientTargetIp);
|
||||
internalNetworkPenetrationRealClient.setClientTargetPort(clientTargetPort);
|
||||
internalNetworkPenetrationRealClient.setClientId(clientId);
|
||||
internalNetworkPenetrationRealClient.setVisitorPort(visitorPort);
|
||||
// InternalNetworkPenetrationRealClient internalNetworkPenetrationRealClient = new InternalNetworkPenetrationRealClient();
|
||||
// internalNetworkPenetrationRealClient.setClientTargetIp(clientTargetIp);
|
||||
// internalNetworkPenetrationRealClient.setClientTargetPort(clientTargetPort);
|
||||
// internalNetworkPenetrationRealClient.setClientId(clientId);
|
||||
// internalNetworkPenetrationRealClient.setVisitorPort(visitorPort);
|
||||
|
||||
// 创建服务端代理连接
|
||||
VisitorFilter visitorFilter = new VisitorFilter(internalNetworkPenetrationRealClient);
|
||||
NettyVisitorSocket nettyVisitorSocket = new NettyVisitorSocket(visitorFilter);
|
||||
// VisitorFilter visitorFilter = new VisitorFilter(internalNetworkPenetrationRealClient);
|
||||
// NettyVisitorSocket nettyVisitorSocket = new NettyVisitorSocket(visitorFilter);
|
||||
NettyVisitorSocket nettyVisitorSocket = NettyVisitorSocket.NettyVisitorSocketBuilder
|
||||
.builder()
|
||||
.builderClientId(clientId)
|
||||
.builderClientTargetIp(clientTargetIp)
|
||||
.builderClientTargetPort(clientTargetPort)
|
||||
.builderVisitorPort(visitorPort)
|
||||
.builderChannelFlowAdapter(channelFlowAdapter)
|
||||
.build();
|
||||
|
||||
try {
|
||||
nettyVisitorSocket.startServer(visitorPort);
|
||||
} catch (Exception e) {
|
||||
log.error("客户端:{},网络端口:{},开放失败",clientId,visitorPort);
|
||||
log.error("客户端:{},网络端口:{},开放失败", clientId, visitorPort);
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,32 @@
|
||||
package wu.framework.lazy.cloud.heartbeat.server.netty.config;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Role;
|
||||
import wu.framework.lazy.cloud.heartbeat.common.adapter.ChannelFlowAdapter;
|
||||
import wu.framework.lazy.cloud.heartbeat.common.advanced.flow.HandleChannelFlowAdvanced;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @see ChannelFlowAdapter
|
||||
* @see HandleChannelFlowAdvanced
|
||||
*/
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public class ServerFlowConfiguration {
|
||||
|
||||
|
||||
/**
|
||||
* 服务端流量适配器
|
||||
* @param handleChannelFlowAdvancedList 服务端流量适配者
|
||||
* @return 服务端流量适配器
|
||||
*/
|
||||
@ConditionalOnMissingBean(ChannelFlowAdapter.class)
|
||||
@Bean
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public ChannelFlowAdapter channelFlowAdapter(List<HandleChannelFlowAdvanced> handleChannelFlowAdvancedList){
|
||||
return new ChannelFlowAdapter(handleChannelFlowAdvancedList);
|
||||
}
|
||||
|
||||
}
|
@ -3,13 +3,16 @@ package wu.framework.lazy.cloud.heartbeat.server.netty.filter;
|
||||
import wu.framework.lazy.cloud.heartbeat.common.InternalNetworkPenetrationRealClient;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import wu.framework.lazy.cloud.heartbeat.common.adapter.ChannelFlowAdapter;
|
||||
import wu.framework.lazy.cloud.heartbeat.server.netty.handler.VisitorHandler;
|
||||
|
||||
public class VisitorFilter extends ChannelInitializer<SocketChannel> {
|
||||
private final InternalNetworkPenetrationRealClient internalNetworkPenetrationRealClient;
|
||||
private final ChannelFlowAdapter channelFlowAdapter;
|
||||
|
||||
public VisitorFilter(InternalNetworkPenetrationRealClient internalNetworkPenetrationRealClient) {
|
||||
public VisitorFilter(InternalNetworkPenetrationRealClient internalNetworkPenetrationRealClient, ChannelFlowAdapter channelFlowAdapter) {
|
||||
this.internalNetworkPenetrationRealClient = internalNetworkPenetrationRealClient;
|
||||
this.channelFlowAdapter = channelFlowAdapter;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -25,7 +28,7 @@ public class VisitorFilter extends ChannelInitializer<SocketChannel> {
|
||||
protected void initChannel(SocketChannel ch) throws Exception {
|
||||
ChannelPipeline pipeline = ch.pipeline();
|
||||
pipeline.addLast(new ChannelDuplexHandler());
|
||||
pipeline.addLast(new VisitorHandler(internalNetworkPenetrationRealClient));
|
||||
pipeline.addLast(new VisitorHandler(internalNetworkPenetrationRealClient,channelFlowAdapter));
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,56 @@
|
||||
package wu.framework.lazy.cloud.heartbeat.server.netty.flow;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import wu.framework.lazy.cloud.heartbeat.common.advanced.flow.ChannelFlow;
|
||||
import wu.framework.lazy.cloud.heartbeat.common.enums.ChannelFlowEnum;
|
||||
|
||||
@Builder
|
||||
@Data
|
||||
public class ServerChannelFlow implements ChannelFlow {
|
||||
private String clientId;
|
||||
private Integer port;
|
||||
private ChannelFlowEnum channelFlowEnum;
|
||||
private Integer flow;
|
||||
|
||||
/**
|
||||
* 通道客户端ID
|
||||
*
|
||||
* @return 通道客户端ID
|
||||
*/
|
||||
@Override
|
||||
public String clientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通道使用的端口(服务端访客端口、客户端真实端口)
|
||||
*
|
||||
* @return 端口
|
||||
*/
|
||||
@Override
|
||||
public Integer port() {
|
||||
return port;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通道流量类型
|
||||
*
|
||||
* @return ChannelFlowEnum
|
||||
* @see ChannelFlowEnum
|
||||
*/
|
||||
@Override
|
||||
public ChannelFlowEnum channelFlowEnum() {
|
||||
return channelFlowEnum;
|
||||
}
|
||||
|
||||
/**
|
||||
* 流量
|
||||
*
|
||||
* @return 流量
|
||||
*/
|
||||
@Override
|
||||
public Integer flow() {
|
||||
return flow;
|
||||
}
|
||||
}
|
@ -2,6 +2,8 @@ package wu.framework.lazy.cloud.heartbeat.server.netty.handler;
|
||||
|
||||
|
||||
import wu.framework.lazy.cloud.heartbeat.common.*;
|
||||
import wu.framework.lazy.cloud.heartbeat.common.adapter.ChannelFlowAdapter;
|
||||
import wu.framework.lazy.cloud.heartbeat.common.enums.ChannelFlowEnum;
|
||||
import wu.framework.lazy.cloud.heartbeat.common.utils.ChannelAttributeKeyUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.Channel;
|
||||
@ -10,15 +12,18 @@ import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import wu.framework.lazy.cloud.heartbeat.server.netty.flow.ServerChannelFlow;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Slf4j
|
||||
public class VisitorHandler extends SimpleChannelInboundHandler<ByteBuf> {
|
||||
private final InternalNetworkPenetrationRealClient internalNetworkPenetrationRealClient;
|
||||
private final ChannelFlowAdapter channelFlowAdapter;// 流量适配器
|
||||
|
||||
public VisitorHandler(InternalNetworkPenetrationRealClient internalNetworkPenetrationRealClient) {
|
||||
public VisitorHandler(InternalNetworkPenetrationRealClient internalNetworkPenetrationRealClient, ChannelFlowAdapter channelFlowAdapter) {
|
||||
this.internalNetworkPenetrationRealClient = internalNetworkPenetrationRealClient;
|
||||
this.channelFlowAdapter = channelFlowAdapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -52,10 +57,10 @@ public class VisitorHandler extends SimpleChannelInboundHandler<ByteBuf> {
|
||||
// 客户端心跳通道
|
||||
ChannelContext.ClientChannel clientChannel = ChannelContext.get(clientId);
|
||||
if (clientChannel != null) {
|
||||
log.info("通过客户端:{},获取通道而后创建连接",clientId);
|
||||
log.info("通过客户端:{},获取通道而后创建连接", clientId);
|
||||
Channel channel = clientChannel.getChannel();
|
||||
channel.writeAndFlush(nettyProxyMsg);
|
||||
}else {
|
||||
} else {
|
||||
log.error("无法通过客户端ID获取客户端通道");
|
||||
}
|
||||
|
||||
@ -70,11 +75,12 @@ public class VisitorHandler extends SimpleChannelInboundHandler<ByteBuf> {
|
||||
@Override
|
||||
public void channelRead0(ChannelHandlerContext ctx, ByteBuf buf) {
|
||||
|
||||
Channel realChannel = ctx.channel();
|
||||
String clientId = internalNetworkPenetrationRealClient.getClientId();
|
||||
String clientTargetIp = internalNetworkPenetrationRealClient.getClientTargetIp();
|
||||
Integer clientTargetPort = internalNetworkPenetrationRealClient.getClientTargetPort();
|
||||
Integer visitorPort = internalNetworkPenetrationRealClient.getVisitorPort();
|
||||
String visitorId = ChannelAttributeKeyUtils.getVisitorId(ctx.channel());
|
||||
String visitorId = ChannelAttributeKeyUtils.getVisitorId(realChannel);
|
||||
if (StringUtil.isNullOrEmpty(clientId)) {
|
||||
return;
|
||||
}
|
||||
@ -82,9 +88,11 @@ public class VisitorHandler extends SimpleChannelInboundHandler<ByteBuf> {
|
||||
buf.readBytes(bytes);
|
||||
// 获取客户端通道,而后进行数据下发
|
||||
log.debug("服务端访客端口成功接收数据:{}", new String(bytes));
|
||||
|
||||
// 使用访客的通信通道
|
||||
Channel visitorCommunicationChannel = NettyCommunicationIdContext.getVisitor(visitorId);
|
||||
|
||||
// 绑定数据流量
|
||||
ChannelAttributeKeyUtils.buildInFlow(visitorCommunicationChannel, bytes.length);
|
||||
NettyProxyMsg nettyProxyMsg = new NettyProxyMsg();
|
||||
nettyProxyMsg.setType(MessageType.DISTRIBUTE_CLIENT_TRANSFER);
|
||||
nettyProxyMsg.setClientId(clientId);
|
||||
@ -94,6 +102,15 @@ public class VisitorHandler extends SimpleChannelInboundHandler<ByteBuf> {
|
||||
nettyProxyMsg.setVisitorId(visitorId);
|
||||
nettyProxyMsg.setData(bytes);
|
||||
visitorCommunicationChannel.writeAndFlush(nettyProxyMsg);
|
||||
// 处理访客流量
|
||||
ServerChannelFlow serverChannelFlow = ServerChannelFlow
|
||||
.builder()
|
||||
.channelFlowEnum(ChannelFlowEnum.IN_FLOW)
|
||||
.port(visitorPort)
|
||||
.clientId(clientId)
|
||||
.flow(bytes.length)
|
||||
.build();
|
||||
channelFlowAdapter.handler(realChannel, serverChannelFlow);
|
||||
log.debug("服务端访客端口成功发送数据了");
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package wu.framework.lazy.cloud.heartbeat.server.netty.socket;
|
||||
|
||||
import wu.framework.lazy.cloud.heartbeat.common.InternalNetworkPenetrationRealClient;
|
||||
import wu.framework.lazy.cloud.heartbeat.common.NettyVisitorPortContext;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
@ -9,6 +10,7 @@ import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import wu.framework.lazy.cloud.heartbeat.common.adapter.ChannelFlowAdapter;
|
||||
import wu.framework.lazy.cloud.heartbeat.server.netty.filter.VisitorFilter;
|
||||
|
||||
/**
|
||||
@ -17,10 +19,11 @@ import wu.framework.lazy.cloud.heartbeat.server.netty.filter.VisitorFilter;
|
||||
@Slf4j
|
||||
public class NettyVisitorSocket {
|
||||
private final VisitorFilter visitorFilter;
|
||||
|
||||
private static final EventLoopGroup bossGroup = new NioEventLoopGroup();
|
||||
private static final EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
|
||||
public NettyVisitorSocket(VisitorFilter visitorFilter) {
|
||||
public NettyVisitorSocket(VisitorFilter visitorFilter ) {
|
||||
this.visitorFilter = visitorFilter;
|
||||
}
|
||||
|
||||
@ -39,7 +42,7 @@ public class NettyVisitorSocket {
|
||||
.childHandler(visitorFilter);
|
||||
ChannelFuture sync = b.bind(visitorPort).sync();
|
||||
sync.addListener((ChannelFutureListener) future -> {
|
||||
if(future.isSuccess()){
|
||||
if (future.isSuccess()) {
|
||||
Channel channel = future.channel();
|
||||
log.info("访客端口:{} 开启", visitorPort);
|
||||
NettyVisitorPortContext.pushVisitor(visitorPort, channel);
|
||||
@ -52,4 +55,133 @@ public class NettyVisitorSocket {
|
||||
|
||||
}
|
||||
|
||||
public static final class NettyVisitorSocketBuilder {
|
||||
|
||||
/**
|
||||
* 客户端ID
|
||||
*/
|
||||
private String clientId;
|
||||
|
||||
/**
|
||||
* 客户端目标地址
|
||||
*/
|
||||
private String clientTargetIp;
|
||||
|
||||
/**
|
||||
* 客户端目标端口
|
||||
*/
|
||||
private Integer clientTargetPort;
|
||||
|
||||
|
||||
/**
|
||||
* 访问端口
|
||||
*/
|
||||
private Integer visitorPort;
|
||||
/**
|
||||
* 访客ID
|
||||
*/
|
||||
private String visitorId;
|
||||
|
||||
/**
|
||||
* 流量适配器
|
||||
*/
|
||||
private ChannelFlowAdapter channelFlowAdapter;
|
||||
|
||||
/**
|
||||
* 填充客户端
|
||||
*
|
||||
* @param clientId 客户端
|
||||
* @return 返回当前对象
|
||||
*/
|
||||
public NettyVisitorSocketBuilder builderClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定客户端目标IP
|
||||
*
|
||||
* @param clientTargetIp 客户端目标IP
|
||||
* @return 当前对象
|
||||
*/
|
||||
public NettyVisitorSocketBuilder builderClientTargetIp(String clientTargetIp) {
|
||||
this.clientTargetIp = clientTargetIp;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定客户端目标端口
|
||||
*
|
||||
* @param clientTargetPort 客户端目标端口
|
||||
* @return 当前对象
|
||||
*/
|
||||
public NettyVisitorSocketBuilder builderClientTargetPort(Integer clientTargetPort) {
|
||||
this.clientTargetPort = clientTargetPort;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定访客端口
|
||||
*
|
||||
* @param visitorPort 访客端口
|
||||
* @return 当前对象
|
||||
*/
|
||||
public NettyVisitorSocketBuilder builderVisitorPort(Integer visitorPort) {
|
||||
this.visitorPort = visitorPort;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定流量适配器
|
||||
* @param channelFlowAdapter 流量适配器
|
||||
* @return 当前对象
|
||||
*/
|
||||
public NettyVisitorSocketBuilder builderChannelFlowAdapter(ChannelFlowAdapter channelFlowAdapter) {
|
||||
this.channelFlowAdapter = channelFlowAdapter;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定访客ID
|
||||
*
|
||||
* @param visitorId 访客ID
|
||||
* @return 当前对象
|
||||
*/
|
||||
public NettyVisitorSocketBuilder builderVisitorId(String visitorId) {
|
||||
this.visitorId = visitorId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public static NettyVisitorSocketBuilder builder() {
|
||||
return new NettyVisitorSocketBuilder();
|
||||
}
|
||||
|
||||
public NettyVisitorSocket build() {
|
||||
if (clientId == null) {
|
||||
throw new IllegalArgumentException("clientId must not null");
|
||||
}
|
||||
if (clientTargetIp == null) {
|
||||
throw new IllegalArgumentException("clientTargetIp must not null");
|
||||
}
|
||||
if (clientTargetPort == null) {
|
||||
throw new IllegalArgumentException("clientTargetPort must not null");
|
||||
}
|
||||
if (visitorPort == null) {
|
||||
throw new IllegalArgumentException("visitorPort must not null");
|
||||
}
|
||||
InternalNetworkPenetrationRealClient internalNetworkPenetrationRealClient = InternalNetworkPenetrationRealClient
|
||||
.builder()
|
||||
.clientId(clientId)
|
||||
.clientTargetIp(clientTargetIp)
|
||||
.clientTargetPort(clientTargetPort)
|
||||
.visitorPort(visitorPort)
|
||||
.visitorId(visitorId).build();
|
||||
|
||||
VisitorFilter visitorFilter = new VisitorFilter(internalNetworkPenetrationRealClient,channelFlowAdapter);
|
||||
return new NettyVisitorSocket(visitorFilter);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -2,4 +2,5 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
wu.framework.lazy.cloud.heartbeat.server.EnableHeartbeatServerAutoConfiguration,\
|
||||
wu.framework.lazy.cloud.heartbeat.server.netty.config.HeartbeatServerConfiguration,\
|
||||
wu.framework.lazy.cloud.heartbeat.server.netty.config.ServerAutoConfiguration
|
||||
wu.framework.lazy.cloud.heartbeat.server.netty.config.ServerAutoConfiguration,\
|
||||
wu.framework.lazy.cloud.heartbeat.server.netty.config.ServerFlowConfiguration
|
||||
|
@ -1,3 +1,4 @@
|
||||
wu.framework.lazy.cloud.heartbeat.server.EnableHeartbeatServerAutoConfiguration
|
||||
wu.framework.lazy.cloud.heartbeat.server.netty.config.HeartbeatServerConfiguration
|
||||
wu.framework.lazy.cloud.heartbeat.server.netty.config.ServerAutoConfiguration
|
||||
wu.framework.lazy.cloud.heartbeat.server.netty.config.ServerFlowConfiguration
|
||||
|
@ -1 +1 @@
|
||||
<!doctype html><html lang="zh-cn"><head><meta charset="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><link rel="icon" href="favicon.ico"/><title>lazy-ui</title><script defer="defer" src="js/chunk-elementPlusIcon.7f775a37.js"></script><script defer="defer" src="js/chunk-elementPlus.51ee9f03.js"></script><script defer="defer" src="js/chunk-mockjs.208b5e15.js"></script><script defer="defer" src="js/chunk-vendors.4fee82e9.js"></script><script defer="defer" src="js/app.ae95a4ac.js"></script><link href="css/chunk-elementPlus.e89c9935.css" rel="stylesheet"><link href="css/app.4ce91422.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but lazy-ui doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
||||
<!doctype html><html lang="zh-cn"><head><meta charset="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><link rel="icon" href="favicon.ico"/><title>lazy-ui</title><script defer="defer" src="js/chunk-elementPlusIcon.7f775a37.js"></script><script defer="defer" src="js/chunk-elementPlus.51ee9f03.js"></script><script defer="defer" src="js/chunk-mockjs.208b5e15.js"></script><script defer="defer" src="js/chunk-vendors.4fee82e9.js"></script><script defer="defer" src="js/app.2f951f67.js"></script><link href="css/chunk-elementPlus.e89c9935.css" rel="stylesheet"><link href="css/app.4ce91422.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but lazy-ui doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
@ -273,8 +273,18 @@ VE_API [ fileName ][ portName ] (params,{Global:false) //没有全局loading
|
||||
```shell
|
||||
npm config set registry http://registry.npm.taobao.org/
|
||||
```
|
||||
|
||||
### 打包
|
||||
|
||||
```shell
|
||||
yarn run build
|
||||
```
|
||||
|
||||
### 拷贝前端
|
||||
```shell
|
||||
echo "开始拷贝前端UI"
|
||||
rm -rf ../wu-lazy-cloud-heartbeat-server/src/resources/static
|
||||
cp -r ../wu-lazy-cloud-network-ui/dist/* ../wu-lazy-cloud-heartbeat-server/src/main/resources/static/
|
||||
|
||||
```
|
||||
|
||||
|
@ -0,0 +1,203 @@
|
||||
<template>
|
||||
<div class="ve_container">
|
||||
<!-- 搜索 -->
|
||||
<el-form ref="queryForm" :inline="true" :model="params">
|
||||
<el-form-item label="客户端ID" prop="clientId">
|
||||
<el-input
|
||||
clearable
|
||||
v-model="clientId"
|
||||
placeholder="客户端ID"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="onSubmit(params, getDataList)"
|
||||
>
|
||||
{{ buttons.search.name }}
|
||||
</el-button>
|
||||
<el-button @click="resetForm(queryForm, params, getDataList)">
|
||||
重置
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 列表 -->
|
||||
<ve-table
|
||||
:table="{
|
||||
data: tableData,
|
||||
}"
|
||||
:pagination="{
|
||||
onSizeChange: (val) =>
|
||||
handleSizeChange(val, params, getDataList),
|
||||
onCurrentChange: (val) =>
|
||||
handleCurrentChange(val, params, getDataList),
|
||||
currentPage: current,
|
||||
pageSize: size,
|
||||
total: total,
|
||||
}"
|
||||
>
|
||||
<template #tool_bar>
|
||||
<el-button
|
||||
title="弹窗式"
|
||||
v-permission="['add']"
|
||||
size="small"
|
||||
type="primary"
|
||||
@click="handleEdit(buttons.add.name)"
|
||||
>
|
||||
{{ buttons.add.name }}
|
||||
</el-button>
|
||||
</template>
|
||||
<el-table-column prop="clientId" label="客户端ID"></el-table-column>
|
||||
<el-table-column prop="onLineState" label="客户端在线状态">
|
||||
</el-table-column>
|
||||
<el-table-column prop="stagingState" label="暂存状态">
|
||||
</el-table-column>
|
||||
<el-table-column fixed="right" label="操作">
|
||||
<template v-slot:default="{ row }">
|
||||
<el-button
|
||||
v-permission="['offLine']"
|
||||
@click.prevent="handleOffLine(row.clientId)"
|
||||
type="danger"
|
||||
size="small"
|
||||
>
|
||||
{{ buttons.offLine.name }}
|
||||
</el-button>
|
||||
<el-button
|
||||
v-permission="['sendMessage']"
|
||||
@click.prevent="handleArouse2SendMessage(row)"
|
||||
type="primary"
|
||||
size="small"
|
||||
>
|
||||
{{ buttons.sendMessage.name }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ve-table>
|
||||
<!--发送消息到客户端-->
|
||||
<cloud-server-send-message2-clinet
|
||||
v-if="showDialog"
|
||||
:rowData="rowData"
|
||||
:showDialog="showDialog"
|
||||
@closeDialog="handelDialog($event)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import cloudNetworkMenu from "@/views/layoutpages/cloud_network/components/CloudNetworkMenu";
|
||||
|
||||
export default {
|
||||
data: () => ({
|
||||
description: "客户端流量管理",
|
||||
buttons: {
|
||||
search: { name: "查询" },
|
||||
add: { name: "添加" },
|
||||
edit: { name: "编辑" },
|
||||
offLine: { name: "下线" },
|
||||
sendMessage: { name: "发送消息" },
|
||||
export: { name: "导出用户" },
|
||||
},
|
||||
// type 0:目录 1:菜单 2:按钮
|
||||
type: "1",
|
||||
icon: "Avatar",
|
||||
name: "客户端流量管理",
|
||||
parentMenu: cloudNetworkMenu,
|
||||
}),
|
||||
};
|
||||
</script>
|
||||
|
||||
<script setup>
|
||||
import { reactive, toRefs, ref, onMounted, getCurrentInstance } from "vue";
|
||||
//?导入公共查询方法
|
||||
import {
|
||||
onSubmit,
|
||||
resetForm,
|
||||
handleSizeChange,
|
||||
handleCurrentChange,
|
||||
} from "@/views/layoutpages/common";
|
||||
import CloudServerSendMessage2Clinet from "@/views/layoutpages/cloud_network/components/CloudServerSendMessage2Clinet.vue";
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const queryForm = ref(null);
|
||||
const tableData = ref([]);
|
||||
|
||||
const rowData = ref(null);
|
||||
const showDialog = ref(false);
|
||||
|
||||
const params = reactive({
|
||||
clientId: "",
|
||||
size: 10,
|
||||
current: 1,
|
||||
total: 0,
|
||||
});
|
||||
const { clientId, size, current, total } = toRefs(params);
|
||||
|
||||
/**
|
||||
* @description: dialog事件
|
||||
* @param {*}
|
||||
* @return {*}
|
||||
*/
|
||||
const handelDialog = (e) => {
|
||||
showDialog.value = e;
|
||||
getDataList();
|
||||
};
|
||||
/**
|
||||
* @description:添加or编辑事件
|
||||
* @param {*}
|
||||
* @return {*}
|
||||
*/
|
||||
const handleArouse2SendMessage = (row = null) => {
|
||||
showDialog.value = true;
|
||||
rowData.value = row;
|
||||
};
|
||||
|
||||
/**删除行数据
|
||||
* @description:
|
||||
* @param {*}
|
||||
* @return {*}
|
||||
*/
|
||||
const handleOffLine = (clientId) => {
|
||||
proxy
|
||||
.$confirm("此操作将永久删除该数据, 是否继续?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "error",
|
||||
})
|
||||
.then(async () => {
|
||||
const { code } = await VE_API.cloudNetwork.cloudClientDelete({
|
||||
clientId,
|
||||
});
|
||||
if (code == "00") {
|
||||
getDataList();
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
proxy.$message({
|
||||
type: "info",
|
||||
message: "已取消删除",
|
||||
});
|
||||
});
|
||||
};
|
||||
/**
|
||||
* @description: 获取列表数据
|
||||
* @param {*}
|
||||
* @return {*}
|
||||
*/
|
||||
const getDataList = async () => {
|
||||
const { code, data } =
|
||||
await VE_API.cloudNetwork.cloudClientFindPage(params);
|
||||
if (code === 0) {
|
||||
const { size, current, total, record } = data;
|
||||
params.size = size;
|
||||
params.current = current;
|
||||
params.total = total;
|
||||
tableData.value = record;
|
||||
}
|
||||
};
|
||||
onMounted(async () => {
|
||||
await getDataList();
|
||||
// maxHeight(pagination, queryForm, toolBar, ve_max_height);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
@ -56,12 +56,12 @@
|
||||
<el-table-column fixed="right" label="操作">
|
||||
<template v-slot:default="{ row }">
|
||||
<el-button
|
||||
v-permission="['off_line']"
|
||||
v-permission="['offLine']"
|
||||
@click.prevent="handleOffLine(row.clientId)"
|
||||
type="danger"
|
||||
size="small"
|
||||
>
|
||||
{{ buttons.del.name }}
|
||||
{{ buttons.offLine.name }}
|
||||
</el-button>
|
||||
<el-button
|
||||
v-permission="['sendMessage']"
|
||||
@ -93,7 +93,7 @@ export default {
|
||||
search: { name: "查询" },
|
||||
add: { name: "添加" },
|
||||
edit: { name: "编辑" },
|
||||
off_line: { name: "下线" },
|
||||
offLine: { name: "下线" },
|
||||
sendMessage: { name: "发送消息" },
|
||||
export: { name: "导出用户" },
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user