This commit is contained in:
wujiawei 2024-01-08 18:28:23 +08:00
parent 553f06dbed
commit 0a6f980474
176 changed files with 10256 additions and 1174 deletions

View File

@ -0,0 +1,92 @@
### 内网穿透使用
#### 模块说明
| 模块 | 所属层级 | 描述 | 端口 |
|----------------------------------------------------------------------------------------|------|------------------------|----------------------------------------------------------------|
| [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 |
#### 功能
1.将局域网IP映射到公网IP
2. 支持tcp、http映射
#### 使用
```text
客户端配置信息
```
```yaml
spring:
middleground:
netty:
inet-host: 127.0.0.1 # 服务端地址
inet-port: 7001 #服务端端口
client-id: local # 客户端ID
```
```text
服务端配置客户端映射地址
数据库表【internal_network_penetration_mapping】 添加数据
```
| 客户端ID | 客户端真实地址 | 客户端真实端口 | 创建时间 | id | 是否删除 | 更新时间 | 访客端口 | 描述 |
|--------------|----------------|---------|------|----|------|------|-------|------------------------------------------------------------|
| local | 127.0.0.1 | 18080 | null | 1 | 0 | null | 19080 | 访客通过 --> 19080 --> 访问 --> 客户端 local本地的 18080 |
| local | 127.0.0.1 | 28080 | null | 2 | 0 | null | 29080 | 访客通过 --> 29080 --> 访问 --> 客户端 local本地的 28080 |
| local | 127.0.0.1 | 3306 | null | 3 | 0 | null | 4306 | 访客通过 --> 4306 --> 访问 --> 客户端 local本地的 3306 |
| local | 192.168.17.185 | 80 | null | 4 | 0 | null | 30080 | 访客通过 --> 30080 --> 访问 --> 客户端 local局域网内192.168.17.185的 80 |
| middleground | web-nginx | 80 | null | 5 | 0 | null | 31570 | 访客通过 --> 31570 --> 访问 --> 客户端 local局域网内web-nginx的 80 |
#### 部署
##### 云端部署
```text
云端部署:内网穿透服务端
如果云端需要部署云上暂存+内网穿透功能:需要部署 内网穿透服务端、暂存服务、内网穿透客户端、云上离线网关
```
| 模块 | 说明 | 部署内网穿透必须 | 部署内网穿透+云上暂存必须 |
|----------------------------------------------------------------------------------------|------------|----------|---------------|
| [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) | 云下暂存网关 | ✖️ | ✖️ |
##### 云网关部署
```text
云网关部署内网穿透客户端
```
| 模块 | 说明 | 部署内网穿透必须 | 部署内网穿透+云上暂存必须 |
|----------------------------------------------------------------------------------------|------------|----------|---------------|
| [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) | 云下暂存网关 | ✖️ | ✖️ |
##### 独立租户部署
```text
拥有内网穿透能力:需要部署内网穿透客户端
内网穿透+离线暂存能力: 需要部署内网穿透客户端、离线网关、离线暂存服务
```
| 模块 | 说明 | 部署内网穿透必须 | 部署内网穿透+云上暂存必须 |
|----------------------------------------------------------------------------------------|------------|----------|---------------|
| [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) | 云下暂存网关 | ✖️ | ☑️ |

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@ -0,0 +1,77 @@
@startuml
title 内网穿透
actor 访客
package "客户端"{
node "Netty客户端" {
component [客户端当前通道]{
[客户端心跳通道]
component [客户端代理通信通道]{
[客户端通信通道读数据]
[客户端通信通道返回数据]
}
}
' [客户端当前通道] <...right... [客户端真实代理通道]: 返回真实服务请求结果
' [客户端当前通道] ...right..> [客户端真实代理通道]: 转发二进制请求到真实服务通道
}
node “客户端真实服务”{
component [客户端需要代理的真实服务A]{
[客户端真实通道读数据]
[客户端真实通道返回数据]
}
}
' [客户端真实代理通道] ...right...> [客户端真实服务]: 发送真实二进制请求到真实服务
}
package "服务端"{
node "Netty服务端" {
component [Netty服务端通道] {
component [服务端心跳通道]{
}
component [服务端代理通信通道]{
[服务端通信通道读数据]
[服务端通信通道返回数据]
}
}
component [Netty服务端绑定访客端口] {
component [服务端访客真实通道]{
[服务端访客真实通道读数据]
[服务端访客真实通道返回数据]
}
}
}
}
[服务端心跳通道] <----> [客户端心跳通道]:长连接channel
[访客] ..> [服务端访客真实通道读数据]: 访客访问数据
[服务端访客真实通道读数据] ...> [服务端通信通道读数据]: 服务端访客数据转发到通信通道
[服务端通信通道读数据] ..down..> [客户端通信通道读数据]: 服务端通信将数据转发到客户端通信通道
[客户端通信通道读数据] ..down..> [客户端真实通道读数据]: 客户端通信通道将数据转发道客户端端真实代理通道
[客户端真实通道读数据] ..left..> [客户端真实通道返回数据]: 处理数据。。。
[客户端真实通道返回数据] ..up..> [客户端通信通道返回数据]: 客户端真实服务返回数据
[客户端通信通道返回数据] ..up..> [服务端通信通道返回数据]: 将客户端返回的数据发送给访客真实通道
[服务端通信通道返回数据] ..up..> [服务端访客真实通道返回数据]: 返回数据
@enduml

152
k8s-on.yaml Normal file
View File

@ -0,0 +1,152 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
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
namespace: middleground-management
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
k8s.kuboard.cn/layer: monitor
k8s.kuboard.cn/name: middleground-on-cloud-heartbeat-server
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
labels:
k8s.kuboard.cn/layer: monitor
k8s.kuboard.cn/name: middleground-on-cloud-heartbeat-server
spec:
containers:
- envFrom:
- configMapRef:
name: common-cnf
image: >-
docker-registry.laihui.com/middleground/middleground-on-cloud-heartbeat-server:master_latest
imagePullPolicy: Always
name: middleground-on-cloud-heartbeat-server
resources:
limits:
memory: 512Mi
requests:
memory: 512Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
---
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
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
namespace: middleground-management
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
k8s.kuboard.cn/layer: gateway
k8s.kuboard.cn/name: middleground-on-cloud-central-gateway
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
labels:
k8s.kuboard.cn/layer: gateway
k8s.kuboard.cn/name: middleground-on-cloud-central-gateway
spec:
containers:
- envFrom:
- configMapRef:
name: common-cnf
image: >-
docker-registry.laihui.com/middleground/middleground-on-cloud-central-gateway:master_latest
imagePullPolicy: Always
name: middleground-on-cloud-central-gateway
resources:
limits:
memory: 384Mi
requests:
memory: 384Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
---
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
k8s.kuboard.cn/displayName: 【云上云下】暂存服务(新)
labels:
k8s.kuboard.cn/layer: svc
k8s.kuboard.cn/name: middleground-cloud-staging-provider
name: middleground-cloud-staging-provider
namespace: middleground-management
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
k8s.kuboard.cn/layer: svc
k8s.kuboard.cn/name: middleground-cloud-staging-provider
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
labels:
k8s.kuboard.cn/layer: svc
k8s.kuboard.cn/name: middleground-cloud-staging-provider
spec:
containers:
- envFrom:
- configMapRef:
name: common-cnf
image: >-
docker-registry.laihui.com/middleground/middleground-cloud-staging-provider:master_latest
imagePullPolicy: Always
name: middleground-cloud-staging-provider
resources:
limits:
memory: 384Mi
requests:
memory: 384Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30

154
k8s-under.yaml Normal file
View File

@ -0,0 +1,154 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
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
namespace: middleground-tenant-share
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
k8s.kuboard.cn/layer: monitor
k8s.kuboard.cn/name: middleground-under-cloud-heartbeat-client
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
labels:
k8s.kuboard.cn/layer: monitor
k8s.kuboard.cn/name: middleground-under-cloud-heartbeat-client
spec:
containers:
- envFrom:
- configMapRef:
name: common-cnf
image: >-
docker-registry.laihui.com/middleground/middleground-under-cloud-heartbeat-client:master_latest
imagePullPolicy: Always
name: middleground-under-cloud-heartbeat-client
resources:
limits:
memory: 384Mi
requests:
memory: 384Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
---
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
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
namespace: middleground-tenant-share
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
k8s.kuboard.cn/layer: gateway
k8s.kuboard.cn/name: middleground-under-cloud-central-gateway
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
labels:
k8s.kuboard.cn/layer: gateway
k8s.kuboard.cn/name: middleground-under-cloud-central-gateway
spec:
containers:
- envFrom:
- configMapRef:
name: common-cnf
image: >-
docker-registry.laihui.com/middleground/middleground-under-cloud-central-gateway:master_latest
imagePullPolicy: Always
name: middleground-under-cloud-central-gateway
resources:
limits:
memory: 384Mi
requests:
memory: 384Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
---
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
k8s.kuboard.cn/displayName: 【云上云下】云下暂存服务(新)
labels:
k8s.kuboard.cn/layer: svc
k8s.kuboard.cn/name: middleground-cloud-staging-provider
name: middleground-cloud-staging-provider
namespace: middleground-tenant-share
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
k8s.kuboard.cn/layer: svc
k8s.kuboard.cn/name: middleground-cloud-staging-provider
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
labels:
k8s.kuboard.cn/layer: svc
k8s.kuboard.cn/name: middleground-cloud-staging-provider
spec:
containers:
- envFrom:
- configMapRef:
name: common-cnf
image: >-
docker-registry.laihui.com/middleground/middleground-cloud-staging-provider:master_latest
imagePullPolicy: Always
name: middleground-cloud-staging-provider
resources:
limits:
memory: 384Mi
requests:
memory: 384Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30

View File

@ -0,0 +1,16 @@
FROM alpine
MAINTAINER wujiawei <1207537021@qq.com>
RUN echo "Asia/Shanghai" > /etc/timezone
COPY target/middleground-under-cloud-heartbeat-client /native-app
ENTRYPOINT ["/bin/sh" ,"-c", "exec ./native-app"]

View File

@ -0,0 +1,14 @@
#### 构建native 镜像
```shell
mvn clean compile
mvn spring-boot:process-aot -Pnative
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
```

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>top.wu2020</groupId>
<artifactId>lazy-cloud-network</artifactId>
<version>1.2.1-JDK17-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>lazy-cloud-heartbeat-client</artifactId>
<description>云下心跳客户端</description>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<!-- 通用心跳包 -->
<dependency>
<groupId>top.wu2020</groupId>
<artifactId>lazy-cloud-heartbeat-common</artifactId>
<version>1.2.1-JDK17-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.33</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>top.wu2020</groupId>
<artifactId>wu-database-lazy-plus-starter</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,15 @@
package wu.framework.middleground.under.cloud.heartbeat.client;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 云上云下-云下心跳服务器
*/
@SpringBootApplication
public class MiddlegroundUnderCloudHeartbeatClient {
public static void main(String[] args) {
SpringApplication.run(MiddlegroundUnderCloudHeartbeatClient.class,args);
}
}

View File

@ -0,0 +1,32 @@
package wu.framework.middleground.under.cloud.heartbeat.client.application;
/**
* 云下心跳客户端操作nacos 配置
*/
public interface ClientNettyConfigApplication {
/**
* 推送客户端在线
*/
void clientOnLine(String clientId);
/**
* 推送客户端离线
*/
void clientOffLine(String clientId);
/**
* 暂存开启
* @param clientId 租户ID
*/
void stagingOpen(String clientId);
/**
* 暂存关闭
* @param clientId 客户端ID 对应的租户
*/
void stagingClose(String clientId);
}

View File

@ -0,0 +1,82 @@
package wu.framework.middleground.under.cloud.heartbeat.client.application.impl;
import wu.framework.middleground.under.cloud.heartbeat.client.application.ClientNettyConfigApplication;
import com.wu.framework.database.lazy.web.plus.stereotype.LazyApplication;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@LazyApplication
public class ClientNettyConfigApplicationImpl implements ClientNettyConfigApplication {
// private final StringRedisTemplate stringRedisTemplate;
// private final RedisProviderTemplate redisProviderTemplate;
//
// public ClientNettyConfigApplicationImpl(StringRedisTemplate stringRedisTemplate, RedisProviderTemplate redisProviderTemplate) {
// this.stringRedisTemplate = stringRedisTemplate;
// this.redisProviderTemplate = redisProviderTemplate;
// }
/**
* 推送客户端在线
*/
@Override
public void clientOnLine(String clientId) {
// // 获取当前客户端ID
// if (ObjectUtils.isEmpty(clientId)) {
// clientId = stringRedisTemplate.opsForValue().get(ClientConfigKeyUtils.CLIENT_ID_KEY);
// }
// String clientStatusKey = ClientConfigKeyUtils.getClientStatusKey(clientId);
// // 如果可以已经在线状态不推送
// stringRedisTemplate.opsForValue().set(clientStatusKey, NettyClientStatus.ON_LINE.name());
// ClientOnLineState clientOnLineState = new ClientOnLineState();
// clientOnLineState.setClientId(clientId);
// clientOnLineState.setOnLineState(NettyClientStatus.ON_LINE.name());
// // 暂存扫描触发
// redisProviderTemplate.send(RedisChannelConstant.REDIS_CLIENT_ONLINE_OR_OFFLINE_CHANNEL,clientOnLineState);
}
/**
* 推送客户端离线
*/
@Override
public void clientOffLine(String clientId) {
// if (ObjectUtils.isEmpty(clientId)) {
// clientId = stringRedisTemplate.opsForValue().get(ClientConfigKeyUtils.CLIENT_ID_KEY);
// }
// String clientStatusKey = ClientConfigKeyUtils.getClientStatusKey(clientId);
// // 离线状态
// stringRedisTemplate.opsForValue().set(clientStatusKey, NettyClientStatus.OFF_LINE.name());
// // 暂存状态
// stagingOpen(clientId);
// // 暂存扫描触发
// ClientOnLineState clientOnLineState = new ClientOnLineState();
// clientOnLineState.setClientId(clientId);
// clientOnLineState.setOnLineState(NettyClientStatus.OFF_LINE.name());
// redisProviderTemplate.send(RedisChannelConstant.REDIS_CLIENT_ONLINE_OR_OFFLINE_CHANNEL,clientOnLineState);
}
@Override
public void stagingOpen(String clientId) {
// String stagingStatusKey = StagingConfigKeyConstant.getStagingStatusKey(clientId);
// stringRedisTemplate.opsForValue().set(stagingStatusKey, StagingStatus.OPENED.name());
}
/**
* 暂存关闭
*
* @param clientId 租户ID
*/
@Override
public void stagingClose(String clientId) {
// if (clientId == null) {
// clientId = stringRedisTemplate.opsForValue().get(ClientConfigKeyUtils.CLIENT_ID_KEY);
// }
// String stagingStatusKey = StagingConfigKeyConstant.getStagingStatusKey(clientId);
// stringRedisTemplate.opsForValue().set(stagingStatusKey, StagingStatus.CLOSED.name());
}
}

View File

@ -0,0 +1,31 @@
package wu.framework.middleground.under.cloud.heartbeat.client.netty.advanced;
import wu.framework.middleground.cloud.heartbeat.common.MessageType;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.advanced.AbstractChannelHeartbeatTypeAdvanced;
import io.netty.channel.Channel;
import org.springframework.stereotype.Component;
/**
* 服务端 处理客户端心跳
* TYPE_HEARTBEAT
*/
@Component
public class ClientChannelHeartbeatTypeAdvanced extends AbstractChannelHeartbeatTypeAdvanced<NettyProxyMsg> {
/**
* 处理当前数据
*
* @param channel 当前通道
* @param msg 通道数据
*/
@Override
public void doHandler(Channel channel, NettyProxyMsg msg) {
NettyProxyMsg hb = new NettyProxyMsg();
hb.setType(MessageType.TYPE_HEARTBEAT);
// channel.writeAndFlush(hb);
}
}

View File

@ -0,0 +1,31 @@
package wu.framework.middleground.under.cloud.heartbeat.client.netty.advanced;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.NettyRealIdContext;
import wu.framework.middleground.cloud.heartbeat.common.advanced.client.AbstractDistributeSingleClientRealAutoReadConnectTypeAdvanced;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class ClientDistributeSingleClientRealAutoReadConnectTypeAdvanced extends AbstractDistributeSingleClientRealAutoReadConnectTypeAdvanced<NettyProxyMsg> {
/**
* 处理当前数据
*
* @param channel 当前通道
* @param nettyProxyMsg 通道数据
*/
@Override
protected void doHandler(Channel channel, NettyProxyMsg nettyProxyMsg) {
// 获取访客ID
byte[] visitorId = nettyProxyMsg.getVisitorId();
// 获取访客对应的真实代理通道
Channel realChannel = NettyRealIdContext.getVisitor(visitorId);
if (realChannel != null) {
realChannel.config().setOption(ChannelOption.AUTO_READ, true);
}
}
}

View File

@ -0,0 +1,28 @@
package wu.framework.middleground.under.cloud.heartbeat.client.netty.advanced;
import wu.framework.middleground.cloud.heartbeat.common.NettyCommunicationIdContext;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.NettyRealIdContext;
import wu.framework.middleground.cloud.heartbeat.common.advanced.client.AbstractDistributeSingleClientRealCloseVisitorTypeAdvanced;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class ClientDistributeSingleClientRealCloseVisitorTypeAdvanced extends AbstractDistributeSingleClientRealCloseVisitorTypeAdvanced<NettyProxyMsg> {
/**
* 处理当前数据
*
* @param channel 当前通道
* @param nettyProxyMsg 通道数据
*/
@Override
protected void doHandler(Channel channel, NettyProxyMsg nettyProxyMsg) {
// 关闭代理的真实通道
byte[] visitorId = nettyProxyMsg.getVisitorId();
NettyRealIdContext.clear(visitorId);
NettyCommunicationIdContext.clear(visitorId);
}
}

View File

@ -0,0 +1,56 @@
package wu.framework.middleground.under.cloud.heartbeat.client.netty.advanced;
import wu.framework.middleground.cloud.heartbeat.common.InternalNetworkPenetrationRealClient;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.advanced.ChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.advanced.client.AbstractDistributeSingleClientRealConnectTypeAdvanced;
import wu.framework.middleground.under.cloud.heartbeat.client.netty.config.NettyServerProperties;
import wu.framework.middleground.under.cloud.heartbeat.client.netty.socket.NettyClientRealSocket;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 客户端创建真实代理同奥
*/
@Slf4j
@Component
public class ClientDistributeSingleClientRealConnectTypeAdvanced extends AbstractDistributeSingleClientRealConnectTypeAdvanced<NettyProxyMsg> {
private final NettyServerProperties nettyServerProperties;// 服务端地址信息
private final List<ChannelTypeAdvanced> channelTypeAdvancedList;
public ClientDistributeSingleClientRealConnectTypeAdvanced(NettyServerProperties nettyServerProperties, List<ChannelTypeAdvanced> channelTypeAdvancedList) {
this.nettyServerProperties = nettyServerProperties;
this.channelTypeAdvancedList = channelTypeAdvancedList;
}
/**
* 处理当前数据
*
* @param channel 当前通道
* @param msg 通道数据
*/
@Override
protected void doHandler(Channel channel, NettyProxyMsg msg) {
// 创建真实端口监听
byte[] clientIdBytes = msg.getClientId();
byte[] visitorPort = msg.getVisitorPort();
byte[] clientTargetIp = msg.getClientTargetIp();
byte[] clientTargetPort = msg.getClientTargetPort();
byte[] visitorIdBytes = msg.getVisitorId();
InternalNetworkPenetrationRealClient internalNetworkPenetrationRealClient = new InternalNetworkPenetrationRealClient();
internalNetworkPenetrationRealClient.setClientId(new String(clientIdBytes));
internalNetworkPenetrationRealClient.setVisitorPort(Integer.valueOf(new String(visitorPort)));
internalNetworkPenetrationRealClient.setClientTargetIp(new String( clientTargetIp));
internalNetworkPenetrationRealClient.setClientTargetPort(Integer.valueOf(new String( clientTargetPort)));
String visitorId=new String(visitorIdBytes);// 访客ID
internalNetworkPenetrationRealClient.setVisitorId(visitorId);
// 绑定真实服务端口
NettyClientRealSocket.buildRealServer(internalNetworkPenetrationRealClient,nettyServerProperties,channelTypeAdvancedList );
}
}

View File

@ -0,0 +1,59 @@
package wu.framework.middleground.under.cloud.heartbeat.client.netty.advanced;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.NettyRealIdContext;
import wu.framework.middleground.cloud.heartbeat.common.advanced.client.AbstractDistributeChannelTransferTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.enums.MessageTypeEnums;
import wu.framework.middleground.under.cloud.heartbeat.client.netty.config.NettyServerProperties;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* 服务端处理客户端数据传输
* @see MessageTypeEnums#DISTRIBUTE_CLIENT_TRANSFER
*/
@Slf4j
@Component
public class ClientReportChannelTransferTypeAdvanced extends AbstractDistributeChannelTransferTypeAdvanced<NettyProxyMsg> {
private final NettyServerProperties nettyServerProperties;
public ClientReportChannelTransferTypeAdvanced(NettyServerProperties nettyServerProperties) {
this.nettyServerProperties = nettyServerProperties;
}
/**
* 处理当前数据
*
* @param channel 当前通道
* @param nettyProxyMsg 通道数据
*/
@Override
public void doHandler(Channel channel, NettyProxyMsg nettyProxyMsg) {
log.debug("接收到服务端需要内网穿透的数据" + nettyProxyMsg);
String clientId = nettyServerProperties.getClientId();
byte[] visitorPort = nettyProxyMsg.getVisitorPort();
byte[] clientTargetIp = nettyProxyMsg.getClientTargetIp();
byte[] clientTargetPort = nettyProxyMsg.getClientTargetPort();
byte[] visitorId = nettyProxyMsg.getVisitorId();
// 真实服务通道
Channel realChannel = NettyRealIdContext.getVisitor(new String(visitorId));
if (realChannel == null) {
log.error("无法获取访客:{} 真实服务", new String(visitorId));
return;
}
// 把数据转到真实服务
ByteBuf buf = channel.config().getAllocator().buffer(nettyProxyMsg.getData().length);
buf.writeBytes(nettyProxyMsg.getData());
realChannel.writeAndFlush(buf);
}
}

View File

@ -0,0 +1,55 @@
package wu.framework.middleground.under.cloud.heartbeat.client.netty.advanced;
import com.alibaba.fastjson.JSONObject;
import wu.framework.middleground.cloud.heartbeat.common.ChannelContext;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.advanced.client.AbstractDistributeConnectSuccessNotificationTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.utils.ChannelAttributeKeyUtils;
import wu.framework.middleground.under.cloud.heartbeat.client.application.ClientNettyConfigApplication;
import wu.framework.middleground.under.cloud.heartbeat.client.netty.config.NettyServerProperties;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.nio.charset.StandardCharsets;
import java.util.List;
/**
* 客户端连接成功通知
*/
@Slf4j
@Component
public class DistributeConnectSuccessNotificationTypeAdvanced extends AbstractDistributeConnectSuccessNotificationTypeAdvanced <NettyProxyMsg>{
private final ClientNettyConfigApplication clientNettyConfigApplication;
private final NettyServerProperties nettyServerProperties;
public DistributeConnectSuccessNotificationTypeAdvanced(ClientNettyConfigApplication clientNettyConfigApplication, NettyServerProperties nettyServerProperties) {
this.clientNettyConfigApplication = clientNettyConfigApplication;
this.nettyServerProperties = nettyServerProperties;
}
/**
* 处理当前数据
*
* @param channel 当前通道
* @param msg 通道数据
*/
@Override
protected void doHandler(Channel channel, NettyProxyMsg msg) {
log.warn("客户端ID{},客户端:{}连接成功", new String(msg.getClientId()), new String(msg.getData()));
// 缓存当前通道
String clientId = nettyServerProperties.getClientId();
NettyProxyMsg nettyMsg = new NettyProxyMsg();
nettyMsg.setClientId(clientId.getBytes(StandardCharsets.UTF_8));
ChannelContext.push(channel, nettyMsg);
ChannelAttributeKeyUtils.buildClientId(channel,clientId);
// 存储其他客户端状态
List<String> clientIdList = JSONObject.parseArray(new String(msg.getData()), String.class);
for (String tenantId : clientIdList) {
clientNettyConfigApplication.clientOnLine(tenantId);
}
}
}

View File

@ -0,0 +1,44 @@
package wu.framework.middleground.under.cloud.heartbeat.client.netty.advanced;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.advanced.client.AbstractDistributeDisconnectTypeAdvanced;
import wu.framework.middleground.under.cloud.heartbeat.client.application.ClientNettyConfigApplication;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* 服务端处理客户端断开连接处理
* TYPE_DISCONNECT
*/
@Slf4j
@Component
public class DistributeDisconnectTypeAdvanced extends AbstractDistributeDisconnectTypeAdvanced <NettyProxyMsg> {
private final ClientNettyConfigApplication clientNettyConfigApplication;
public DistributeDisconnectTypeAdvanced(ClientNettyConfigApplication clientNettyConfigApplication) {
this.clientNettyConfigApplication = clientNettyConfigApplication;
}
/**
* 处理当前数据
*
* @param channel 当前通道
* @param msg 通道数据
*/
@Override
public void doHandler(Channel channel, NettyProxyMsg msg) {
// 服务下线
byte[] data = msg.getData();
byte[] clientId = msg.getClientId();
String tenantId = new String(clientId);
log.warn("客户端:{}下线",tenantId);
clientNettyConfigApplication.clientOffLine(tenantId);
}
}

View File

@ -0,0 +1,34 @@
package wu.framework.middleground.under.cloud.heartbeat.client.netty.advanced;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.advanced.client.AbstractDistributeStagingClosedTypeAdvanced;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* 服务端下发暂存关闭消息处理
*/
@Slf4j
@Component
public class DistributeStagingClosedTypeAdvanced extends AbstractDistributeStagingClosedTypeAdvanced <NettyProxyMsg>{
/**
* 处理当前数据
*
* @param channel 当前通道
* @param msg 通道数据
*/
@Override
protected void doHandler(Channel channel, NettyProxyMsg msg) {
String clientId = new String(msg.getClientId());
log.info("客户端:{}离线暂存关闭", clientId);
// 修改redis 客户端暂存状态
// String stagingStatusKey = StagingConfigKeyConstant.getStagingStatusKey(clientId);
// stringRedisTemplate.opsForValue().set(stagingStatusKey, StagingStatus.CLOSED.name());
}
}

View File

@ -0,0 +1,37 @@
package wu.framework.middleground.under.cloud.heartbeat.client.netty.advanced;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.advanced.client.AbstractDistributeStagingOpenedTypeAdvanced;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* 服务端下发暂存开启消息处理
*/
@Slf4j
@Component
public class DistributeStagingOpenedTypeAdvanced extends AbstractDistributeStagingOpenedTypeAdvanced<NettyProxyMsg>{
public DistributeStagingOpenedTypeAdvanced() {
}
/**
* 处理当前数据
*
* @param channel 当前通道
* @param msg 通道数据
*/
@Override
protected void doHandler(Channel channel, NettyProxyMsg msg) {
String clientId = new String(msg.getClientId());
log.info("客户端:{}离线暂存开启", new String(msg.getClientId()));
// 修改redis 客户端暂存状态
// String stagingStatusKey = StagingConfigKeyConstant.getStagingStatusKey(clientId);
// stringRedisTemplate.opsForValue().set(stagingStatusKey, StagingStatus.OPENED.name());
}
}

View File

@ -0,0 +1,82 @@
package wu.framework.middleground.under.cloud.heartbeat.client.netty.config;
import wu.framework.middleground.cloud.heartbeat.common.advanced.ChannelTypeAdvanced;
import wu.framework.middleground.under.cloud.heartbeat.client.application.ClientNettyConfigApplication;
import wu.framework.middleground.under.cloud.heartbeat.client.netty.socket.NettyClientSocket;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* description 自动配置
*
* @author 吴佳伟
* @date 2023/09/12 18:22
*/
@Slf4j
@Configuration
public class AutoConfiguration implements CommandLineRunner {
private final ServerProperties serverProperties;
private final NettyServerProperties nettyServerProperties;
private final ClientNettyConfigApplication clientNettyConfigApplication;
private final List<ChannelTypeAdvanced> channelTypeAdvancedList; // 处理服务端发送过来的数据类型
ThreadPoolExecutor NETTY_CLIENT_EXECUTOR = new ThreadPoolExecutor(1, 1, 200, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<>(1));
public AutoConfiguration(ServerProperties serverProperties,
NettyServerProperties nettyServerProperties,
ClientNettyConfigApplication clientNettyConfigApplication,
List<ChannelTypeAdvanced> channelTypeAdvancedList) {
this.serverProperties = serverProperties;
this.nettyServerProperties = nettyServerProperties;
this.clientNettyConfigApplication = clientNettyConfigApplication;
this.channelTypeAdvancedList = channelTypeAdvancedList;
}
@Bean(destroyMethod = "shutdown")
public NettyClientSocket nettyServerSocket() {
String inetHost = nettyServerProperties.getInetHost();
int inetPort = nettyServerProperties.getInetPort();
String clientId = nettyServerProperties.getClientId();
return new NettyClientSocket(inetHost, inetPort, clientId, clientNettyConfigApplication, channelTypeAdvancedList);
}
/**
* @param args
* @throws Exception
*/
@Override
public void run(String... args) throws Exception {
String inetHost = nettyServerProperties.getInetHost();
int inetPort = nettyServerProperties.getInetPort();
String clientId = nettyServerProperties.getClientId();
NettyClientSocket nettyClientSocket = new NettyClientSocket(inetHost, inetPort, clientId, clientNettyConfigApplication, channelTypeAdvancedList);
Thread thread = new Thread(() -> {
try {
nettyClientSocket.newConnect2Server();
} catch (Exception e) {
throw new RuntimeException(e);
}
});
log.info("当前服务连接Netty客户端:{},Netty端口:{}", inetHost, inetPort);
NETTY_CLIENT_EXECUTOR.execute(thread);
}
}

View File

@ -0,0 +1,31 @@
package wu.framework.middleground.under.cloud.heartbeat.client.netty.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* netty 客户服务端地址配置属性
*/
@ConfigurationProperties(prefix = NettyServerProperties.PREFIX, ignoreUnknownFields = true)
@Configuration
@Data
public class NettyServerProperties {
public static final String PREFIX = "spring.middleground.netty";
/**
* 服务端地址
*/
private String inetHost = "127.0.0.1";
/**
* 服务端端口
*/
private int inetPort = 7001;
/**
* 服务端path
*/
private String inetPath = "middleground-on-cloud-heartbeat-server";
/**
* 客户端ID
*/
private String clientId = "1024";
}

View File

@ -0,0 +1,45 @@
package wu.framework.middleground.under.cloud.heartbeat.client.netty.filter;
import wu.framework.middleground.cloud.heartbeat.common.adapter.ChannelTypeAdapter;
import wu.framework.middleground.cloud.heartbeat.common.decoder.NettyProxyMsgDecoder;
import wu.framework.middleground.cloud.heartbeat.common.encoder.NettyProxyMsgEncoder;
import wu.framework.middleground.under.cloud.heartbeat.client.netty.handler.NettyClientHandler;
import wu.framework.middleground.under.cloud.heartbeat.client.netty.socket.NettyClientSocket;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleStateHandler;
public class NettyClientFilter extends ChannelInitializer<SocketChannel> {
private final ChannelTypeAdapter channelTypeAdapter;
private final NettyClientSocket nettyClientSocket;
public NettyClientFilter(ChannelTypeAdapter channelTypeAdapter, NettyClientSocket nettyClientSocket) {
this.channelTypeAdapter = channelTypeAdapter;
this.nettyClientSocket = nettyClientSocket;
}
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
/* * 解码和编码,应和服务端一致 * */
// pipeline.addLast(new NettyMsgDecoder(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("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
//入参说明: 读超时时间写超时时间所有类型的超时时间时间格式
//因为服务端设置的超时时间是5秒所以设置4秒
pipeline.addLast(new IdleStateHandler(0, 4, 0));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("doHandler", new NettyClientHandler(channelTypeAdapter,nettyClientSocket)); //客户端的逻辑
}
}

View File

@ -0,0 +1,30 @@
package wu.framework.middleground.under.cloud.heartbeat.client.netty.filter;
import wu.framework.middleground.under.cloud.heartbeat.client.netty.handler.NettyClientRealHandler;
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;
public class NettyClientRealFilter extends ChannelInitializer<SocketChannel> {
/**
* This method will be called once the {@link Channel} was registered. After the method returns this instance
* will be removed from the {@link ChannelPipeline} of the {@link Channel}.
*
* @param ch the {@link Channel} which was registered.
* @throws Exception is thrown if an error occurs. In that case it will be handled by
* {@link #exceptionCaught(ChannelHandlerContext, Throwable)} which will by default close
* the {@link Channel}.
*/
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new NettyClientRealHandler());
// // 解码编码
// 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());
}
}

View File

@ -0,0 +1,43 @@
package wu.framework.middleground.under.cloud.heartbeat.client.netty.filter;
import wu.framework.middleground.cloud.heartbeat.common.adapter.ChannelTypeAdapter;
import wu.framework.middleground.cloud.heartbeat.common.decoder.NettyProxyMsgDecoder;
import wu.framework.middleground.cloud.heartbeat.common.encoder.NettMsgEncoder;
import wu.framework.middleground.cloud.heartbeat.common.encoder.NettyProxyMsgEncoder;
import wu.framework.middleground.under.cloud.heartbeat.client.netty.handler.NettyClientVisitorRealHandler;
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;
/**
* netty 客户端连接真实服服务端访客拦截器
*/
public class NettyClientVisitorRealFilter extends ChannelInitializer<SocketChannel> {
private final ChannelTypeAdapter channelTypeAdapter;
public NettyClientVisitorRealFilter(ChannelTypeAdapter channelTypeAdapter) {
this.channelTypeAdapter = channelTypeAdapter;
}
/**
* This method will be called once the {@link Channel} was registered. After the method returns this instance
* will be removed from the {@link ChannelPipeline} of the {@link Channel}.
*
* @param ch the {@link Channel} which was registered.
* @throws Exception is thrown if an error occurs. In that case it will be handled by
* {@link #exceptionCaught(ChannelHandlerContext, Throwable)} which will by default close
* the {@link Channel}.
*/
@Override
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 NettyProxyMsgEncoder());
pipeline.addLast(new NettyClientVisitorRealHandler(channelTypeAdapter));
}
}

View File

@ -0,0 +1,25 @@
package wu.framework.middleground.under.cloud.heartbeat.client.netty.handler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import java.util.Date;
public class HeartBeatClientHandler extends ChannelInboundHandlerAdapter {
private int lossConnectCount = 0;
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
System.out.println("客户端循环心跳监测发送: " + new Date());
if (evt instanceof IdleStateEvent) {
IdleStateEvent event = (IdleStateEvent) evt;
if (event.state() == IdleState.WRITER_IDLE) {
ctx.writeAndFlush("biubiu");
}
}
}
}

View File

@ -0,0 +1,120 @@
package wu.framework.middleground.under.cloud.heartbeat.client.netty.handler;
import wu.framework.middleground.cloud.heartbeat.common.MessageType;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.adapter.ChannelTypeAdapter;
import wu.framework.middleground.under.cloud.heartbeat.client.netty.socket.NettyClientSocket;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.EventLoop;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
* description
*
* @author 吴佳伟
* @date 2023/09/13 10:29
*/
@Slf4j
public class NettyClientHandler extends SimpleChannelInboundHandler<NettyProxyMsg> {
private final ChannelTypeAdapter channelTypeAdapter;
private final NettyClientSocket nettyClientSocket;
public NettyClientHandler(ChannelTypeAdapter channelTypeAdapter, NettyClientSocket nettyClientSocket) {
this.channelTypeAdapter = channelTypeAdapter;
this.nettyClientSocket = nettyClientSocket;
}
/**
* @param ctx the {@link ChannelHandlerContext} which this {@link SimpleChannelInboundHandler}
* belongs to
* @param msg the message to handle
*/
@Override
protected void channelRead0(ChannelHandlerContext ctx, NettyProxyMsg msg) {
// log.info("" + count + "" + ",客户端接受的消息:" + msg);
// log.info("" + count + "" + ",客户端接受的消息内容:" + new String(msg.getData()));
// count++;
// 接收服务端或者是代理端的信息
Channel channel = ctx.channel();
// log.info("type:{},clientId:{},data:{}",msg.getType(),new String(msg.getClientId()),new String(msg.getData()));
channelTypeAdapter.handler(channel, msg);
}
/**
* 建立连接时
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
log.info("建立连接时:" + new Date());
ctx.fireChannelActive();
String clientId = nettyClientSocket.getClientId();
// 处理客户端连接成功
Channel channel = ctx.channel();
NettyProxyMsg nettyMsg = new NettyProxyMsg();
nettyMsg.setType(MessageType.REPORT_CLIENT_CONNECT_SUCCESS);
nettyMsg.setClientId(clientId);
channelTypeAdapter.handler(channel, nettyMsg);
}
/**
* 关闭连接时
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
log.info("关闭连接时:" + new Date());
final EventLoop eventLoop = ctx.channel().eventLoop();
eventLoop.schedule(() -> {
try {
nettyClientSocket.newConnect2Server();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}, 1L, TimeUnit.SECONDS);
super.channelInactive(ctx);
}
/**
* 心跳请求处理 * 每4秒发送一次心跳请求; *
*/
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object obj) throws Exception {
if (obj instanceof IdleStateEvent) {
IdleStateEvent event = (IdleStateEvent) obj;
if (IdleState.WRITER_IDLE.equals(event.state())) { //如果写通道处于空闲状态,就发送心跳命令
String clientId = nettyClientSocket.getClientId();
NettyProxyMsg nettyMsg = new NettyProxyMsg();
nettyMsg.setType(MessageType.TYPE_HEARTBEAT);
nettyMsg.setData(clientId.getBytes(StandardCharsets.UTF_8));
nettyMsg.setClientId(clientId.getBytes(StandardCharsets.UTF_8));
ctx.writeAndFlush(nettyMsg);// 发送心跳数据
} else if (event.state() == IdleState.WRITER_IDLE) { // 如果检测到写空闲状态关闭连接
// 离线暂存通知
String clientId = nettyClientSocket.getClientId();
Channel channel = ctx.channel();
NettyProxyMsg nettyMsg = new NettyProxyMsg();
nettyMsg.setType(MessageType.DISTRIBUTE_CLIENT_DISCONNECTION_NOTIFICATION);
nettyMsg.setClientId(clientId.getBytes(StandardCharsets.UTF_8));
channelTypeAdapter.handler(channel, nettyMsg);
ctx.close();
}
} else {
super.userEventTriggered(ctx, obj);
}
}
}

View File

@ -0,0 +1,81 @@
package wu.framework.middleground.under.cloud.heartbeat.client.netty.handler;
import wu.framework.middleground.cloud.heartbeat.common.MessageType;
import wu.framework.middleground.cloud.heartbeat.common.NettyCommunicationIdContext;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.utils.ChannelAttributeKeyUtils;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;
/**
* 来自客户端 真实服务器返回的数据请求
*/
@Slf4j
public class NettyClientRealHandler extends SimpleChannelInboundHandler<ByteBuf> {
@Override
public void channelRead0(ChannelHandlerContext ctx, ByteBuf buf) throws Exception {
// 客户端发送真实数据到代理了
byte[] bytes = new byte[buf.readableBytes()];
buf.readBytes(bytes);
log.debug("接收客户端真实服务数据:{}", new String(bytes));
String visitorId = ChannelAttributeKeyUtils.getVisitorId(ctx.channel());
// 访客通信通道 上报服务端代理完成
Channel visitorChannel = NettyCommunicationIdContext.getVisitor(visitorId);
NettyProxyMsg returnMessage = new NettyProxyMsg();
returnMessage.setType(MessageType.REPORT_CLIENT_TRANSFER);
returnMessage.setVisitorId(visitorId);
returnMessage.setData(bytes);
visitorChannel.writeAndFlush(returnMessage);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
String clientId = ChannelAttributeKeyUtils.getClientId(ctx.channel());
String visitorId = ChannelAttributeKeyUtils.getVisitorId(ctx.channel());
// 客户端真实通信通道
Channel visitor = NettyCommunicationIdContext.getVisitor(visitorId);
if (visitor != null) {
// 上报关闭这个客户端的访客通道
NettyProxyMsg closeVisitorMsg = new NettyProxyMsg();
closeVisitorMsg.setType(MessageType.REPORT_SINGLE_CLIENT_CLOSE_VISITOR);
closeVisitorMsg.setVisitorId(visitorId);
visitor.writeAndFlush(closeVisitorMsg);
}
super.channelInactive(ctx);
}
@Override
public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
// String vid = ctx.channel().attr(Constant.VID).get();
// if (StringUtil.isNullOrEmpty(vid)) {
// super.channelWritabilityChanged(ctx);
// return;
// }
// Channel proxyChannel = Constant.vpc.get(vid);
// if (proxyChannel != null) {
// proxyChannel.config().setOption(ChannelOption.AUTO_READ, ctx.channel().isWritable());
// }
super.channelWritabilityChanged(ctx);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
}
}

View File

@ -0,0 +1,63 @@
package wu.framework.middleground.under.cloud.heartbeat.client.netty.handler;
import wu.framework.middleground.cloud.heartbeat.common.ChannelContext;
import wu.framework.middleground.cloud.heartbeat.common.MessageType;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.adapter.ChannelTypeAdapter;
import wu.framework.middleground.cloud.heartbeat.common.utils.ChannelAttributeKeyUtils;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class NettyClientVisitorRealHandler extends SimpleChannelInboundHandler<NettyProxyMsg> {
private final ChannelTypeAdapter channelTypeAdapter;
public NettyClientVisitorRealHandler(ChannelTypeAdapter channelTypeAdapter) {
this.channelTypeAdapter = channelTypeAdapter;
}
@Override
public void channelRead0(ChannelHandlerContext ctx, NettyProxyMsg nettyProxyMsg) throws Exception {
Channel channel = ctx.channel();
channelTypeAdapter.handler(channel, nettyProxyMsg);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
String clientId = ChannelAttributeKeyUtils.getClientId(ctx.channel());
String visitorId = ChannelAttributeKeyUtils.getVisitorId(ctx.channel());
// 关闭访客
ChannelContext.ClientChannel clientChannel = ChannelContext.get(clientId);
if (clientChannel != null) {
Channel channel = clientChannel.getChannel();
// 上报关闭这个客户端的访客通道
NettyProxyMsg closeVisitorMsg = new NettyProxyMsg();
closeVisitorMsg.setType(MessageType.REPORT_SINGLE_CLIENT_CLOSE_VISITOR);
closeVisitorMsg.setVisitorId(visitorId);
channel.writeAndFlush(closeVisitorMsg);
}
super.channelInactive(ctx);
}
@Override
public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
super.channelWritabilityChanged(ctx);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
}
}

View File

@ -0,0 +1,54 @@
package wu.framework.middleground.under.cloud.heartbeat.client.netty.listener;
import wu.framework.middleground.cloud.heartbeat.common.constant.RedisChannelConstant;
import wu.framework.middleground.under.cloud.heartbeat.client.netty.config.NettyServerProperties;
import wu.framework.middleground.under.cloud.heartbeat.client.rpc.StagingNoticeApiRpc;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* 客户端暂存开启关闭通知
*
* @see RedisChannelConstant#REDIS_CLIENT_STAGING_OPENED_OR_CLOSED_CHANNEL
*/
@Slf4j
@Component
public class ClientStagingOpenedOrClosedRedisListener {
private final StagingNoticeApiRpc stagingNoticeApiRpc;
private final NettyServerProperties nettyServerProperties;
public ClientStagingOpenedOrClosedRedisListener(StagingNoticeApiRpc stagingNoticeApiRpc, NettyServerProperties nettyServerProperties) {
this.stagingNoticeApiRpc = stagingNoticeApiRpc;
this.nettyServerProperties = nettyServerProperties;
}
// /**
// * 使用redis监听注解监听数据
// *
// * @param consumerRecord 客户端暂存开启关闭通知
// */
// @EasyRedisListener(topics = RedisChannelConstant.REDIS_CLIENT_STAGING_OPENED_OR_CLOSED_CHANNEL)
// public void subscription(ConsumerRecord<String, ClientStagingRedisChannelBo> consumerRecord, Acknowledgment acknowledgment) {
// ClientStagingRedisChannelBo payload = consumerRecord.payload();
// String clientId = payload.getClientId();
// // 如果客户端ID为空默认当前客户端
// if (ObjectUtils.isEmpty(clientId)) {
// clientId = nettyServerProperties.getClientId();
// }
// StagingStatus stagingStatus = payload.getStagingStatus();
// log.info("客户端:【{}】暂存:【{}】通知", clientId, stagingStatus);
//
//
// if (StagingStatus.OPENED.equals(stagingStatus)) {
// stagingNoticeApiRpc.stagingOpened(clientId);
// } else if (StagingStatus.CLOSED.equals(stagingStatus)) {
// stagingNoticeApiRpc.stagingClosed(clientId);
// }
// acknowledgment.acknowledge();
// }
}

View File

@ -0,0 +1,176 @@
package wu.framework.middleground.under.cloud.heartbeat.client.netty.socket;
import wu.framework.middleground.cloud.heartbeat.common.*;
import wu.framework.middleground.cloud.heartbeat.common.adapter.ChannelTypeAdapter;
import wu.framework.middleground.cloud.heartbeat.common.advanced.ChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.utils.ChannelAttributeKeyUtils;
import wu.framework.middleground.under.cloud.heartbeat.client.netty.config.NettyServerProperties;
import wu.framework.middleground.under.cloud.heartbeat.client.netty.filter.NettyClientRealFilter;
import wu.framework.middleground.under.cloud.heartbeat.client.netty.filter.NettyClientVisitorRealFilter;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 客户端连接真实服务
*/
@Slf4j
public class NettyClientRealSocket {
static EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
/**
* 连接真实服务
*
* @param internalNetworkPenetrationRealClient 访客信息
* @param nettyServerProperties 服务端地址信息
*/
public static void buildRealServer(InternalNetworkPenetrationRealClient internalNetworkPenetrationRealClient,
NettyServerProperties nettyServerProperties,
List<ChannelTypeAdvanced> channelTypeAdvancedList) {
buildNewRealServer(internalNetworkPenetrationRealClient, nettyServerProperties, channelTypeAdvancedList);
}
/**
* @param internalNetworkPenetrationRealClient 访客信息
* @param nettyServerProperties 服务端地址信息
*/
private static void buildNewRealServer(InternalNetworkPenetrationRealClient internalNetworkPenetrationRealClient,
NettyServerProperties nettyServerProperties,
List<ChannelTypeAdvanced> channelTypeAdvancedList) {
try {
String clientTargetIp = internalNetworkPenetrationRealClient.getClientTargetIp();
Integer clientTargetPort = internalNetworkPenetrationRealClient.getClientTargetPort();
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class)
.handler(new NettyClientRealFilter());
bootstrap.connect(clientTargetIp, clientTargetPort).addListener((ChannelFutureListener) future -> {
if (future.isSuccess()) {
// 客户端链接真实服务成功 设置自动读写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);
// 客户端真实通道
NettyRealIdContext.pushVisitor(realChannel, visitorId);
// 绑定访客ID到当前真实通道属性
ChannelAttributeKeyUtils.buildVisitorId(realChannel, visitorId);
ChannelAttributeKeyUtils.buildClientId(realChannel, clientId);
// 通知服务端访客连接成功
// 新建一个通道处理
newVisitorConnect2Server(internalNetworkPenetrationRealClient, nettyServerProperties, channelTypeAdvancedList);
// 是否等 服务端相应访客通道已经可以自动读写
// realChannel.config().setOption(ChannelOption.AUTO_READ, true);
// 模拟发送
String byteData = "GET /swagger-ui/index.html HTTP/1.1\n" +
"Host: 127.0.0.1:19080\n" +
"Connection: keep-alive\n" +
"Cache-Control: max-age=0\n" +
"sec-ch-ua: \"Not_A Brand\";v=\"8\", \"Chromium\";v=\"120\", \"Google Chrome\";v=\"120\"\n" +
"sec-ch-ua-mobile: ?0\n" +
"sec-ch-ua-platform: \"macOS\"\n" +
"Upgrade-Insecure-Requests: 1\n" +
"User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36\n" +
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\n" +
"Sec-Fetch-Site: none\n" +
"Sec-Fetch-Mode: navigate\n" +
"Sec-Fetch-User: ?1\n" +
"Sec-Fetch-Dest: document\n" +
"Accept-Encoding: gzip, deflate, br\n" +
"Accept-Language: zh-CN,zh;q=0.9\n" +
"Cookie: XXL_JOB_LOGIN_IDENTITY=7b226964223a312c22757365726e616d65223a2261646d696e222c2270617373776f7264223a226531306164633339343962613539616262653536653035376632306638383365222c22726f6c65223a312c227065726d697373696f6e223a6e756c6c7d; Hm_lvt_173e771eef816c412396d2cb4fe2d632=1703040917\n";
// ChannelContext.ClientChannel clientChannel = ChannelContext.get(String.valueOf(visitorPort).getBytes(StandardCharsets.UTF_8));
// Channel channel = clientChannel.getChannel();
// channel.writeAndFlush(byteData.getBytes(StandardCharsets.UTF_8));
// future.channel().attr(Constant.VID).set(internalNetworkPenetrationRealClient);
// Constant.vrc.put(internalNetworkPenetrationRealClient, future.channel());
// ProxySocket.connectProxyServer(internalNetworkPenetrationRealClient);
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 创建访客连接服务端
*
* @param internalNetworkPenetrationRealClient 内网穿透信息
* @param nettyServerProperties 服务端配置信息
* @param channelTypeAdvancedList 处理器适配器
* @throws InterruptedException 异常
*/
protected static void newVisitorConnect2Server(InternalNetworkPenetrationRealClient internalNetworkPenetrationRealClient,
NettyServerProperties nettyServerProperties,
List<ChannelTypeAdvanced> channelTypeAdvancedList) throws InterruptedException {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup)
.channel(NioSocketChannel.class)
.handler(new NettyClientVisitorRealFilter(new ChannelTypeAdapter(channelTypeAdvancedList)))
;
String inetHost = nettyServerProperties.getInetHost();
int inetPort = nettyServerProperties.getInetPort();
String clientId = nettyServerProperties.getClientId();
String visitorId = internalNetworkPenetrationRealClient.getVisitorId();
Integer visitorPort = internalNetworkPenetrationRealClient.getVisitorPort();
String clientTargetIp = internalNetworkPenetrationRealClient.getClientTargetIp();
Integer clientTargetPort = internalNetworkPenetrationRealClient.getClientTargetPort();
log.info("客户端新建访客通道 连接服务端IP:{},连接服务端端口:{}", inetHost, inetPort);
ChannelFuture future = bootstrap.connect(inetHost, inetPort);
log.info("使用的租户ID:" + clientId);
future.addListener((ChannelFutureListener) futureListener -> {
Channel channel = futureListener.channel();
if (futureListener.isSuccess()) {
NettyProxyMsg myMsg = new NettyProxyMsg();
myMsg.setType(MessageType.REPORT_SINGLE_CLIENT_REAL_CONNECT);
myMsg.setClientId(clientId);
myMsg.setVisitorPort(visitorPort);
myMsg.setClientTargetIp(clientTargetIp);
myMsg.setClientTargetPort(clientTargetPort);
myMsg.setVisitorId(visitorId);
channel.writeAndFlush(myMsg);
// 绑定客户端真实通信通道
NettyCommunicationIdContext.pushVisitor(channel,visitorId);
ChannelAttributeKeyUtils.buildVisitorId(channel, visitorId);
ChannelAttributeKeyUtils.buildClientId(channel, clientId);
// 客户端真实通道自动读写打开
Channel visitor = NettyRealIdContext.getVisitor(visitorId);
visitor.config().setOption(ChannelOption.AUTO_READ, true);
} else {
log.info("每隔2s重连....");
// 离线
channel.eventLoop().schedule(() -> {
try {
newVisitorConnect2Server(internalNetworkPenetrationRealClient, nettyServerProperties, channelTypeAdvancedList);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, 2, TimeUnit.SECONDS);
}
});
}
}

View File

@ -0,0 +1,114 @@
package wu.framework.middleground.under.cloud.heartbeat.client.netty.socket;
import wu.framework.middleground.cloud.heartbeat.common.MessageType;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.adapter.ChannelTypeAdapter;
import wu.framework.middleground.cloud.heartbeat.common.advanced.ChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.utils.ChannelAttributeKeyUtils;
import wu.framework.middleground.under.cloud.heartbeat.client.application.ClientNettyConfigApplication;
import wu.framework.middleground.under.cloud.heartbeat.client.netty.filter.NettyClientFilter;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 客户端连接服务端
*/
@Slf4j
public class NettyClientSocket {
/**
* 服务端host
*/
private final String inetHost;
/**
* 服务端端口
*/
private final int inetPort;
/**
* 当前客户端id
*/
@Getter
private final String clientId;
/**
* nacos配置信息处理应用
*/
@Getter
private final ClientNettyConfigApplication clientNettyConfigApplication;
private final List<ChannelTypeAdvanced> channelTypeAdvancedList; // 处理服务端发送过来的数据类型
private static final EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
public NettyClientSocket(String inetHost, int inetPort, String clientId, ClientNettyConfigApplication clientNettyConfigApplication, List<ChannelTypeAdvanced> channelTypeAdvancedList) {
this.inetHost = inetHost;
this.inetPort = inetPort;
this.clientId = clientId;
this.clientNettyConfigApplication = clientNettyConfigApplication;
this.channelTypeAdvancedList = channelTypeAdvancedList;
}
public void newConnect2Server() throws InterruptedException {
newConnect2Server(inetHost, inetPort, clientId, clientNettyConfigApplication);
}
protected void newConnect2Server(String inetHost, int inetPort, String clientId, ClientNettyConfigApplication clientNettyConfigApplication) throws InterruptedException {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup)
.channel(NioSocketChannel.class)
.handler(new NettyClientFilter(new ChannelTypeAdapter(channelTypeAdvancedList),this))
;
log.info("连接服务端IP:{},连接服务端端口:{}", inetHost, inetPort);
ChannelFuture future = bootstrap.connect(inetHost, inetPort);
Channel channel = future.channel();
log.info("使用的租户ID:" + clientId);
future.addListener((ChannelFutureListener) futureListener -> {
if (futureListener.isSuccess()) {
log.info("连接服务端成功");
// 告诉服务端这条连接是client的连接
NettyProxyMsg nettyMsg = new NettyProxyMsg();
nettyMsg.setType(MessageType.REPORT_CLIENT_CONNECT_SUCCESS);
nettyMsg.setClientId(clientId);
nettyMsg.setData(( clientId ).getBytes());
ChannelAttributeKeyUtils.buildClientId(channel,clientId);
channel.writeAndFlush(nettyMsg);
// 在线
clientNettyConfigApplication.clientOnLine(clientId);
} else {
log.info("每隔2s重连....");
// 离线
clientNettyConfigApplication.clientOffLine(clientId);
futureListener.channel().eventLoop().schedule(() -> {
try {
newConnect2Server(inetHost, inetPort, clientId, clientNettyConfigApplication);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, 2, TimeUnit.SECONDS);
}
});
}
/**
* 关闭连接
*/
public void shutdown() {
if ((eventLoopGroup != null) && (!eventLoopGroup.isShutdown())) {
eventLoopGroup.shutdownGracefully();
}
}
}

View File

@ -0,0 +1,67 @@
package wu.framework.middleground.under.cloud.heartbeat.client.rpc;
import com.wu.framework.database.lazy.web.plus.stereotype.LazyApplication;
import com.wu.framework.database.lazy.web.plus.stereotype.LazyRpc;
import com.wu.framework.response.Result;
import com.wu.framework.response.ResultFactory;
import wu.framework.middleground.cloud.heartbeat.common.ChannelContext;
import wu.framework.middleground.cloud.heartbeat.common.MessageType;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import io.netty.channel.Channel;
import java.nio.charset.StandardCharsets;
import java.util.List;
@LazyRpc
public class StagingNoticeApiRpc {
/**
* 前提当前客户端曾经有过离线而后上线了但是呢现在有暂存的数据因此暂存是打开的所以这个时候可以通知服务端让其告知其他客户户我暂存了
* 通知自己暂存了
*
* @param clientId 租户ID
* @return
*/
public Result<Void> stagingOpened(String clientId) {
List<ChannelContext.ClientChannel> clientChannels = ChannelContext.get();
for (ChannelContext.ClientChannel clientChannel : clientChannels) {
// 上报 当前通道暂存开启了
Channel channel = clientChannel.getChannel();
NettyProxyMsg nettyMsg = new NettyProxyMsg();
nettyMsg.setType(MessageType.REPORT_CLIENT_STAGING_OPENED);
nettyMsg.setData((clientId.toString()
.getBytes(StandardCharsets.UTF_8)));
nettyMsg.setClientId((clientId.toString()
.getBytes(StandardCharsets.UTF_8)));
channel.writeAndFlush(nettyMsg);
}
return ResultFactory.successOf();
}
/**
* 暂存恢复
*
* @param clientId 租户ID
* @return
*/
public Result<Void> stagingClosed(String clientId) {
List<ChannelContext.ClientChannel> clientChannels = ChannelContext.get();
for (ChannelContext.ClientChannel clientChannel : clientChannels) {
// 上报 当前通道暂存关闭了
Channel channel = clientChannel.getChannel();
NettyProxyMsg nettyMsg = new NettyProxyMsg();
nettyMsg.setType(MessageType.REPORT_CLIENT_STAGING_CLOSED);
nettyMsg.setData((clientId.toString()
.getBytes(StandardCharsets.UTF_8)));
nettyMsg.setClientId((clientId.toString()
.getBytes(StandardCharsets.UTF_8)));
channel.writeAndFlush(nettyMsg);
}
return ResultFactory.successOf();
}
}

View File

@ -0,0 +1,17 @@
spring:
middleground:
netty:
# inet-host: 192.168.17.221
# inet-port: 4923
# inet-path: middleground-on-cloud-heartbeat-server
inet-host: 127.0.0.1 # 服务端地址
inet-port: 7001 #服务端端口
inet-path: middleground-on-cloud-heartbeat-server
client-id: local # 客户端ID
data:
redis:
host: 192.168.17.221
port: 30553
password: laihui
database: 2

View File

@ -0,0 +1,7 @@
server:
port: 6004
spring:
profiles:
active: dev

View File

@ -0,0 +1,12 @@
spring:
application:
name: middleground-under-cloud-heartbeat-client
cloud:
nacos:
discovery:
server-addr: 192.168.17.221:30569
config:
server-addr: 192.168.17.221:30569

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>top.wu2020</groupId>
<artifactId>lazy-cloud-network</artifactId>
<version>1.2.1-JDK17-SNAPSHOT</version>
</parent>
<artifactId>lazy-cloud-heartbeat-common</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
</dependency>
<dependency>
<groupId>top.wu2020</groupId>
<artifactId>wu-framework-web</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,193 @@
package wu.framework.middleground.cloud.heartbeat.common;
import io.netty.channel.Channel;
import io.netty.channel.ChannelId;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
/**
* 通道上下文
*/
@Slf4j
public class ChannelContext {
private final static ConcurrentHashMap<ChannelId/*channelId*/, ClientChannelImpl/*通道*/>
channelIdClientChannelDTOConcurrentHashMap = new ConcurrentHashMap<>();
/**
* 新增通道
*
* @param channel 通道
* @param nettyMsg 通道中的信息
*/
public static void push(Channel channel, NettyProxyMsg nettyMsg) {
ChannelId channelId = channel.id();
byte[] clientId = nettyMsg.getClientId();
ClientChannelImpl clientChannelImpl = new ClientChannelImpl();
clientChannelImpl.setChannelId(channelId);
clientChannelImpl.setChannel(channel);
clientChannelImpl.setClientId(clientId);
channelIdClientChannelDTOConcurrentHashMap.put(channelId, clientChannelImpl);
}
/**
* 新增通道
*
* @param channel 通道
* @param clientId 客户端ID
*/
public static void push(Channel channel, byte[] clientId) {
ChannelId channelId = channel.id();
ClientChannelImpl clientChannelImpl = new ClientChannelImpl();
clientChannelImpl.setChannelId(channelId);
clientChannelImpl.setChannel(channel);
clientChannelImpl.setClientId(clientId);
channelIdClientChannelDTOConcurrentHashMap.put(channelId, clientChannelImpl);
}
/**
* 获取所有通道
*
* @return 返回所有通道信息
*/
public static List<ClientChannel> get() {
return new ArrayList<>(channelIdClientChannelDTOConcurrentHashMap.values());
}
/**
* 根据通道ID获取通道信息
*
* @param channelId 通道ID
* @return 通道信息
*/
public static ClientChannel get(ChannelId channelId) {
if (channelIdClientChannelDTOConcurrentHashMap.containsKey(channelId)) {
return channelIdClientChannelDTOConcurrentHashMap.get(channelId);
} else {
log.error("无法通过通道ID[" + channelId + "]获取通道信息");
return null;
}
}
/**
* 根据通道ID获取通道信息
*
* @param clientId 客户端ID
* @return 通道信息
*/
public static ClientChannel get(byte[] clientId) {
if (channelIdClientChannelDTOConcurrentHashMap
.values().stream()
.anyMatch(clientChannelImpl -> new String(clientChannelImpl.getClientId()).equals(new String(clientId)))) {
return channelIdClientChannelDTOConcurrentHashMap
.values()
.stream()
.filter(clientChannelImpl -> new String(clientChannelImpl.getClientId()).equals(new String(clientId)))
.findFirst().get();
} else {
log.error("无法通过客户端ID[" + new String(clientId) + "]获取通道信息");
return null;
}
}
/**
* 根据通道ID获取通道信息
*
* @param clientId 客户端ID
* @return 通道信息
*/
public static ChannelContext.ClientChannel get(String clientId) {
return get(clientId.getBytes(StandardCharsets.UTF_8));
}
/**
* 通过客户端通道ID移除客户端通道
*
* @param channelId 客户端通道ID
*/
public static void remove(ChannelId channelId) {
if (channelIdClientChannelDTOConcurrentHashMap.containsKey(channelId)) {
channelIdClientChannelDTOConcurrentHashMap.remove(channelId);
} else {
// log warm
log.warn("无法通过客户端通道ID:[{}]移除客户端", channelId);
}
}
/**
* 通过客户端ID移除客户端通道
*
* @param clientId 客户端ID
*/
public static void remove(byte[] clientId) {
ClientChannel clientChannel = get(clientId);
if (clientChannel != null) {
channelIdClientChannelDTOConcurrentHashMap.remove(clientChannel.getChannelId());
} else {
// log warm
log.warn("无法通过客户ID:[{}]移除客户端", new String(clientId));
}
}
/**
* 客户端通道信息
*/
public interface ClientChannel {
/**
* 客户端ID
*/
byte[] getClientId();
/**
* 通道ID
*/
ChannelId getChannelId();
/**
* 通道
*/
Channel getChannel();
}
}
/**
* 客户端通道信息
*/
@Data
class ClientChannelImpl implements ChannelContext.ClientChannel {
/**
* 客户端ID
*/
private byte[] clientId;
/**
* 通道ID
*/
private ChannelId channelId;
/**
* 通道
*/
private Channel channel;
@Override
public String toString() {
return "ClientChannelImpl{" +
"clientId=" + new String(clientId) +
", channelId=" + channelId.asLongText() +
'}';
}
}

View File

@ -0,0 +1,41 @@
package wu.framework.middleground.cloud.heartbeat.common;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* describe 内网穿透映射 真实客户端
*
* @author Jia wei Wu
* @date 2023/12/29 05:21 下午
**/
@Data
@Accessors(chain = true)
public class InternalNetworkPenetrationRealClient {
/**
* 客户端ID
*/
private String clientId;
/**
* 客户端目标地址
*/
private String clientTargetIp;
/**
* 客户端目标端口
*/
private Integer clientTargetPort;
/**
* 访问端口
*/
private Integer visitorPort;
/**
* 访客ID
*/
private String visitorId;
}

View File

@ -0,0 +1,136 @@
package wu.framework.middleground.cloud.heartbeat.common;
import wu.framework.middleground.cloud.heartbeat.common.advanced.AbstractChannelHeartbeatTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.advanced.client.*;
import wu.framework.middleground.cloud.heartbeat.common.advanced.server.*;
import wu.framework.middleground.cloud.heartbeat.common.enums.MessageTypeEnums;
/**
* @see MessageTypeEnums
* -128~ 127
*/
public class MessageType {
/**
* 心跳
*
* @see MessageTypeEnums#TYPE_HEARTBEAT
* @see AbstractChannelHeartbeatTypeAdvanced
*/
public static final byte TYPE_HEARTBEAT = 0X00;
/**
* 客户端上报连接成功
*
* @see MessageTypeEnums#REPORT_CLIENT_CONNECT_SUCCESS
* @see AbstractReportConnectSuccessTypeAdvanced
*/
public static final byte REPORT_CLIENT_CONNECT_SUCCESS = 0X01;
/**
* 上报 客户端断开连接
*
* @see MessageTypeEnums#REPORT_CLIENT_DISCONNECTION
* @see AbstractReportDisconnectTypeAdvanced
*/
public static final byte REPORT_CLIENT_DISCONNECTION = 0X02;
/**
* 客户端上报暂存开启
*
* @see MessageTypeEnums#REPORT_CLIENT_STAGING_OPENED
* @see AbstractReportStagingOpenedTypeAdvanced
*/
public static final byte REPORT_CLIENT_STAGING_OPENED = 0X03;
/**
* 客户端上报暂存关闭
*
* @see MessageTypeEnums#REPORT_CLIENT_STAGING_CLOSED
* @see AbstractReportStagingClosedTypeAdvanced
*/
public static final byte REPORT_CLIENT_STAGING_CLOSED = 0X04;
/**
* 上报 客户端数据传输内网穿透数据回传
*
* @see MessageTypeEnums#REPORT_CLIENT_TRANSFER
* @see AbstractReportChannelTransferTypeAdvanced
*/
public static final byte REPORT_CLIENT_TRANSFER = 0X05;
/**
* 上报 客户端创建需要代理的真实端口成功
*
* @see MessageTypeEnums#REPORT_SINGLE_CLIENT_REAL_CONNECT
* @see AbstractReportSingleClientRealConnectTypeAdvanced
*/
public static final byte REPORT_SINGLE_CLIENT_REAL_CONNECT = 0X06;
/**
* 上报 客户端关闭一个访客通道
*
* @see MessageTypeEnums#REPORT_SINGLE_CLIENT_CLOSE_VISITOR
* @see AbstractReportSingleClientCloseVisitorTypeAdvanced
*/
public static final byte REPORT_SINGLE_CLIENT_CLOSE_VISITOR = 0X08;
/**
* 下发 客户端接收连接成功通知
*
* @see MessageTypeEnums#DISTRIBUTE_CLIENT_CONNECTION_SUCCESS_NOTIFICATION
* @see AbstractDistributeConnectSuccessNotificationTypeAdvanced
*/
public static final byte DISTRIBUTE_CLIENT_CONNECTION_SUCCESS_NOTIFICATION = -0X01;
/**
* 下发 客户端断开连接通知
*
* @see MessageTypeEnums#DISTRIBUTE_CLIENT_DISCONNECTION_NOTIFICATION
* @see AbstractDistributeDisconnectTypeAdvanced
*/
public static final byte DISTRIBUTE_CLIENT_DISCONNECTION_NOTIFICATION = -0X02;
/**
* 下发 客户端暂存开启通知
*
* @see MessageTypeEnums#DISTRIBUTE_CLIENT_STAGING_OPENED_NOTIFICATION
* @see AbstractDistributeStagingOpenedTypeAdvanced
*/
public static final byte DISTRIBUTE_CLIENT_STAGING_OPENED_NOTIFICATION = -0X03;
/**
* 下发 客户端暂存关闭通知
*
* @see MessageTypeEnums#DISTRIBUTE_CLIENT_STAGING_CLOSED_NOTIFICATION
* @see AbstractDistributeStagingClosedTypeAdvanced
*/
public static final byte DISTRIBUTE_CLIENT_STAGING_CLOSED_NOTIFICATION = -0X04;
/**
* 下发 客户端数据传输(内网穿透数据发送)
*
* @see MessageTypeEnums#DISTRIBUTE_CLIENT_TRANSFER
* @see AbstractDistributeChannelTransferTypeAdvanced
*/
public static final byte DISTRIBUTE_CLIENT_TRANSFER = -0X05;
/**
* 下发 客户端创建需要代理的真实端口
*
* @see MessageTypeEnums#DISTRIBUTE_SINGLE_CLIENT_REAL_CONNECT
* @see AbstractDistributeSingleClientRealConnectTypeAdvanced
*/
public static final byte DISTRIBUTE_SINGLE_CLIENT_REAL_CONNECT = -0X06;
/**
* 下发 客户端代理的真实端口自动读写
*
* @see MessageTypeEnums#DISTRIBUTE_SINGLE_CLIENT_REAL_CONNECT_AUTO_READ
* @see AbstractDistributeSingleClientRealAutoReadConnectTypeAdvanced
*/
public static final byte DISTRIBUTE_SINGLE_CLIENT_REAL_CONNECT_AUTO_READ = -0X07;
/**
* 下发 客户端关闭代理服务通道
*
* @see MessageTypeEnums#DISTRIBUTE_SINGLE_CLIENT_REAL_CLOSE_VISITOR
* @see AbstractDistributeSingleClientRealCloseVisitorTypeAdvanced
*/
public static final byte DISTRIBUTE_SINGLE_CLIENT_REAL_CLOSE_VISITOR = -0X08;
}

View File

@ -0,0 +1,71 @@
package wu.framework.middleground.cloud.heartbeat.common;
import io.netty.channel.Channel;
import java.util.concurrent.ConcurrentHashMap;
/**
* 通信通道对应上下文
*/
public class NettyCommunicationIdContext {
protected static final ConcurrentHashMap<String, Object> COMMUNICATION = new ConcurrentHashMap<>();
/**
* 添加访客
*
* @param visitorId 访客id
* @param visitor 访客
*/
public static <T> void pushVisitor(T visitor, String visitorId) {
COMMUNICATION.put(visitorId, visitor);
}
/**
* 通过访客端口获取访客
*
* @param visitorId 访客id
* @param <T> 访客范型
* @return 访客
*/
public static <T> T getVisitor(String visitorId) {
return (T) COMMUNICATION.get(visitorId);
}
/**
* 通过访客端口获取访客
*
* @param visitorId 访客id
* @param <T> 访客范型
* @return 访客
*/
public static <T> T getVisitor(byte[] visitorId) {
return getVisitor(new String(visitorId));
}
/**
* 移除访客
*
* @param visitorId 访客ID
*/
public static void clear(String visitorId) {
Channel visitor = getVisitor(visitorId);
if (visitor != null) {
COMMUNICATION.remove(visitorId);
visitor.close();
}
}
/**
* 移除访客
*
* @param visitorId 访客ID
*/
public static void clear(byte[] visitorId) {
clear(new String(visitorId));
}
}

View File

@ -0,0 +1,39 @@
package wu.framework.middleground.cloud.heartbeat.common;
import lombok.Getter;
import lombok.Setter;
import java.util.Arrays;
@Setter
@Getter
public class NettyMsg {
// body 长度 type 1 clientId 4 data 4
public static final int bodyLength = 9;
/**
* 数据类型
*
* @see MessageType
* byte长度 1
*/
private byte type;
/**
* 客户端ID
* byte[] 长度 4
*/
private byte[] clientId;
/**
* 消息传输数据
* byte[] 长度 4
*/
private byte[] data;
@Override
public String toString() {
return "NettyProxyMsg [type=" + type + ", data=" + Arrays.toString(data) + ",clientId=" + Arrays.toString(clientId) + "]";
}
}

View File

@ -0,0 +1,111 @@
package wu.framework.middleground.cloud.heartbeat.common;
import lombok.Getter;
import lombok.Setter;
import java.nio.charset.StandardCharsets;
/**
* netty 代理请求数据
*/
@Setter
@Getter
public class NettyProxyMsg {
// body 长度 type 1 clientId 4 clientTargetIp 4 clientTargetPort 4 visitorPort 4 visitorId 4 data 4
public static final int bodyLength = 1 + 4 + 4 + 4 + 4 + 4 + 4;
/**
* 数据类型
*
* @see MessageType
* byte长度 1
*/
private byte type;
/**
* 客户端ID
* byte[] 长度 4
*/
private byte[] clientId;
/**
* 客户端目标地址
* byte[] 长度 4
*/
private byte[] clientTargetIp;
/**
* 客户端目标端口
* byte[] 长度 4
*/
private byte[] clientTargetPort;
/**
* 客户端目使用的代理端口
* byte[] 长度 4
*/
private byte[] visitorPort;
/**
* 访客ID
* byte[] 长度 4
*/
private byte[] visitorId;
/**
* 消息传输数据
* byte[] 长度 4
*/
private byte[] data;
@Override
public String toString() {
return "NettyProxyMsg [type=" + type +
",clientId=" + (clientId == null ? null : new String(clientId)) +
",clientTargetIp=" + (clientTargetIp == null ? null : new String(clientTargetIp)) +
",clientTargetPort=" + (clientTargetPort == null ? null : new String(clientTargetPort)) +
",visitorPort=" + (visitorPort == null ? null : new String(visitorPort)) +
"]";
}
public void setClientId(byte[] clientId) {
this.clientId = clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId.getBytes(StandardCharsets.UTF_8);
}
public void setClientTargetIp(byte[] clientTargetIp) {
this.clientTargetIp = clientTargetIp;
}
public void setClientTargetIp(String clientTargetIp) {
this.clientTargetIp = clientTargetIp.getBytes(StandardCharsets.UTF_8);
}
public void setClientTargetPort(Integer clientTargetPort) {
this.clientTargetPort = String.valueOf(clientTargetPort).getBytes(StandardCharsets.UTF_8);
}
public void setClientTargetPort(byte[] clientTargetPort) {
this.clientTargetPort = clientTargetPort;
}
public void setVisitorPort(byte[] visitorPort) {
this.visitorPort = visitorPort;
}
public void setVisitorPort(Integer visitorPort) {
this.visitorPort = String.valueOf(visitorPort).getBytes(StandardCharsets.UTF_8);
}
public void setVisitorId(String visitorId) {
this.visitorId = visitorId.getBytes(StandardCharsets.UTF_8);
}
public void setVisitorId(byte[] visitorId) {
this.visitorId = visitorId;
}
}

View File

@ -0,0 +1,71 @@
package wu.framework.middleground.cloud.heartbeat.common;
import io.netty.channel.Channel;
import java.util.concurrent.ConcurrentHashMap;
/**
* 真实通道对应上下文
*/
public class NettyRealIdContext {
protected static final ConcurrentHashMap<String, Object> REAL = new ConcurrentHashMap<>();
/**
* 添加访客
*
* @param visitorId 访客id
* @param visitor 访客
*/
public static <T> void pushVisitor(T visitor, String visitorId) {
REAL.put(visitorId, visitor);
}
/**
* 通过访客端口获取访客
*
* @param visitorId 访客id
* @param <T> 访客范型
* @return 访客
*/
public static <T> T getVisitor(String visitorId) {
return (T) REAL.get(visitorId);
}
/**
* 通过访客端口获取访客
*
* @param visitorId 访客id
* @param <T> 访客范型
* @return 访客
*/
public static <T> T getVisitor(byte[] visitorId) {
return getVisitor(new String(visitorId));
}
/**
* 移除访客
*
* @param visitorId 访客ID
*/
public static void clear(String visitorId) {
Channel visitor = getVisitor(visitorId);
if (visitor != null) {
REAL.remove(visitorId);
visitor.close();
}
}
/**
* 移除访客
*
* @param visitorId 访客ID
*/
public static void clear(byte[] visitorId) {
clear(new String(visitorId));
}
}

View File

@ -0,0 +1,35 @@
package wu.framework.middleground.cloud.heartbeat.common;
import java.util.concurrent.ConcurrentHashMap;
/**
* 访客端口对应上下文
*/
public class NettyVisitorContext {
protected static final ConcurrentHashMap<Integer, Object> VISITOR_PORT = new ConcurrentHashMap<>();
/**
* 添加访客
*
* @param visitorPort 访客端口
* @param visitor 访客
*/
public static <T> void pushVisitor(Integer visitorPort, T visitor) {
VISITOR_PORT.put(visitorPort, visitor);
}
/**
* 通过访客端口获取访客
*
* @param visitorPort 访客端口
* @param <T> 访客范型
* @return 访客
*/
public static <T> T getVisitor(Integer visitorPort) {
return (T) VISITOR_PORT.get(visitorPort);
}
}

View File

@ -0,0 +1,72 @@
package wu.framework.middleground.cloud.heartbeat.common;
import io.netty.channel.Channel;
import java.util.concurrent.ConcurrentHashMap;
/**
* 访客ID对应上下文
*/
@Deprecated
public class NettyVisitorIdContext {
protected static final ConcurrentHashMap<String, Object> VISITOR_ID = new ConcurrentHashMap<>();
/**
* 添加访客
*
* @param visitorId 访客id
* @param visitor 访客
*/
public static <T> void pushVisitor(T visitor, String visitorId) {
VISITOR_ID.put(visitorId, visitor);
}
/**
* 通过访客端口获取访客
*
* @param visitorId 访客id
* @param <T> 访客范型
* @return 访客
*/
public static <T> T getVisitor(String visitorId) {
return (T) VISITOR_ID.get(visitorId);
}
/**
* 通过访客端口获取访客
*
* @param visitorId 访客id
* @param <T> 访客范型
* @return 访客
*/
public static <T> T getVisitor(byte[] visitorId) {
return getVisitor(new String(visitorId));
}
/**
* 移除访客
*
* @param visitorId 访客ID
*/
public static void clear(String visitorId) {
Channel visitor = getVisitor(visitorId);
if (visitor != null) {
VISITOR_ID.remove(visitorId);
visitor.close();
}
}
/**
* 移除访客
*
* @param visitorId 访客ID
*/
public static void clear(byte[] visitorId) {
clear(new String(visitorId));
}
}

View File

@ -0,0 +1,36 @@
package wu.framework.middleground.cloud.heartbeat.common.adapter;
import wu.framework.middleground.cloud.heartbeat.common.advanced.ChannelTypeAdvanced;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
/**
* 通道类型适配器
*/
@Slf4j
public class ChannelTypeAdapter {
protected final List<ChannelTypeAdvanced> channelTypeAdvancedList;
public ChannelTypeAdapter(List<ChannelTypeAdvanced> channelTypeAdvancedList) {
this.channelTypeAdvancedList = channelTypeAdvancedList;
}
/**
* 处理当前数据
*
* @param msg 通道数据
*/
public void handler(Channel channel, Object msg) {
for (ChannelTypeAdvanced channelTypeAdvanced : channelTypeAdvancedList) {
if (channelTypeAdvanced.support(msg)) {
// log.info("处理器:{},客户端:{}, 处理类型:{}",channelTypeAdvanced.getClass(),new String(msg.getClientId()),msg.getType());
channelTypeAdvanced.handler(channel, msg);
return;
}
}
}
}

View File

@ -0,0 +1,25 @@
package wu.framework.middleground.cloud.heartbeat.common.advanced;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.enums.MessageTypeEnums;
/**
* 服务端 处理客户端心跳
* TYPE_HEARTBEAT
*/
public abstract class AbstractChannelHeartbeatTypeAdvanced<MSG> extends AbstractChannelTypeAdvanced<NettyProxyMsg> implements ChannelTypeAdvanced {
/**
* 是否支持当前类型
*
* @param msg 通道数据
* @return 布尔类型
*/
@Override
public boolean doSupport(NettyProxyMsg msg) {
return MessageTypeEnums.TYPE_HEARTBEAT.getTypeByte() == msg.getType();
}
}

View File

@ -0,0 +1,68 @@
package wu.framework.middleground.cloud.heartbeat.common.advanced;
import io.netty.channel.Channel;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Objects;
public abstract class AbstractChannelTypeAdvanced<MSG> implements ChannelTypeAdvanced {
/**
* 处理当前数据
*
* @param channel 当前通道
* @param msg 通道数据
*/
protected abstract void doHandler(Channel channel, MSG msg);
/**
* 处理当前数据
*
* @param channel 当前通道
* @param msg 通道数据
*/
@Override
public void handler(Channel channel, Object msg) {
doHandler(channel, (MSG) msg);
}
protected abstract boolean doSupport(MSG msg);
/**
* 是否支持当前类型
*
* @param msg 通道数据
* @return 布尔类型
*/
@Override
public boolean support(Object msg) {
if (msg == null) return false;
if (!msg.getClass().isAssignableFrom(Objects.requireNonNull(getMsgTypes()))) {
return false;
}
return doSupport((MSG) msg);
}
/**
* 获取当前处理范型
*
* @return 范型
*/
private Class<?> getMsgTypes() {
Type superClassType = this.getClass().getGenericSuperclass();
if (superClassType instanceof ParameterizedType parameterizedType) {
Type[] actualTypes = parameterizedType.getActualTypeArguments();
// for (Type type : actualTypes) {
// System.out.println("范型类型:" + ((Class<?>) type).getName());
// }
return (Class<?>) actualTypes[0];
} else {
// System.out.println("未能获取到范型类型");
return null;
}
}
}

View File

@ -0,0 +1,33 @@
package wu.framework.middleground.cloud.heartbeat.common.advanced;
import wu.framework.middleground.cloud.heartbeat.common.MessageType;
import wu.framework.middleground.cloud.heartbeat.common.enums.MessageTypeEnums;
import io.netty.channel.Channel;
/**
* 通道不同数据类型处理器
*
* @see MessageType
* @see MessageTypeEnums
*/
public interface ChannelTypeAdvanced {
/**
* 处理当前数据
*
* @param channel 当前通道
* @param msg 通道数据
*/
void handler(Channel channel, Object msg);
/**
* 是否支持当前类型
*
* @param msg 通道数据
* @return 布尔类型
*/
boolean support(Object msg);
}

View File

@ -0,0 +1,27 @@
package wu.framework.middleground.cloud.heartbeat.common.advanced.client;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.advanced.AbstractChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.advanced.ChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.enums.MessageTypeEnums;
/**
* 客户端处理服务端下发数据
* DISTRIBUTE_CLIENT_TRANSFER
*/
public abstract class AbstractDistributeChannelTransferTypeAdvanced<MSG> extends AbstractChannelTypeAdvanced<NettyProxyMsg> implements ChannelTypeAdvanced {
/**
* 是否支持当前类型
*
* @param msg 通道数据
* @return 布尔类型
*/
@Override
public boolean doSupport(NettyProxyMsg msg) {
return MessageTypeEnums.DISTRIBUTE_CLIENT_TRANSFER.getTypeByte() == msg.getType();
}
}

View File

@ -0,0 +1,23 @@
package wu.framework.middleground.cloud.heartbeat.common.advanced.client;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.advanced.AbstractChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.advanced.ChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.enums.MessageTypeEnums;
/**
* 下发 客户端连接成功通知
*/
public abstract class AbstractDistributeConnectSuccessNotificationTypeAdvanced<MSG> extends AbstractChannelTypeAdvanced<NettyProxyMsg> implements ChannelTypeAdvanced {
/**
* 是否支持当前类型
*
* @param msg 通道数据
* @return 布尔类型
*/
@Override
public boolean doSupport(NettyProxyMsg msg) {
return MessageTypeEnums.DISTRIBUTE_CLIENT_CONNECTION_SUCCESS_NOTIFICATION.getTypeByte() == msg.getType();
}
}

View File

@ -0,0 +1,26 @@
package wu.framework.middleground.cloud.heartbeat.common.advanced.client;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.advanced.AbstractChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.advanced.ChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.enums.MessageTypeEnums;
/**
* 下发客户端断开连接通知
* DISTRIBUTE_CLIENT_DISCONNECTION_NOTIFICATION
*/
public abstract class AbstractDistributeDisconnectTypeAdvanced<MSG> extends AbstractChannelTypeAdvanced<NettyProxyMsg> implements ChannelTypeAdvanced {
/**
* 是否支持当前类型
*
* @param msg 通道数据
* @return 布尔类型
*/
@Override
public boolean doSupport(NettyProxyMsg msg) {
// 下发 客户端断开连接通知
return MessageTypeEnums.DISTRIBUTE_CLIENT_DISCONNECTION_NOTIFICATION.getTypeByte() == msg.getType();
}
}

View File

@ -0,0 +1,27 @@
package wu.framework.middleground.cloud.heartbeat.common.advanced.client;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.advanced.AbstractChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.advanced.ChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.enums.MessageTypeEnums;
/**
* 下发 客户端代理的真实端口自动读写
*
* @see MessageTypeEnums#DISTRIBUTE_SINGLE_CLIENT_REAL_CONNECT_AUTO_READ
*/
public abstract class AbstractDistributeSingleClientRealAutoReadConnectTypeAdvanced<MSG> extends AbstractChannelTypeAdvanced<NettyProxyMsg> implements ChannelTypeAdvanced {
/**
* 是否支持当前类型
*
* @param msg 通道数据
* @return 布尔类型
*/
@Override
public boolean doSupport(NettyProxyMsg msg) {
return MessageTypeEnums.DISTRIBUTE_SINGLE_CLIENT_REAL_CONNECT_AUTO_READ.getTypeByte() == msg.getType();
}
}

View File

@ -0,0 +1,25 @@
package wu.framework.middleground.cloud.heartbeat.common.advanced.client;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.advanced.AbstractChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.advanced.ChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.enums.MessageTypeEnums;
/**
* 下发 客户端关闭代理服务通道
*/
public abstract class AbstractDistributeSingleClientRealCloseVisitorTypeAdvanced<MSG> extends AbstractChannelTypeAdvanced<NettyProxyMsg> implements ChannelTypeAdvanced {
/**
* 是否支持当前类型
*
* @param msg 通道数据
* @return 布尔类型
*/
@Override
public boolean doSupport(NettyProxyMsg msg) {
return MessageTypeEnums.DISTRIBUTE_SINGLE_CLIENT_REAL_CLOSE_VISITOR.getTypeByte() == msg.getType();
}
}

View File

@ -0,0 +1,25 @@
package wu.framework.middleground.cloud.heartbeat.common.advanced.client;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.advanced.AbstractChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.advanced.ChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.enums.MessageTypeEnums;
/**
* 下发 客户端 创建真实连接
*/
public abstract class AbstractDistributeSingleClientRealConnectTypeAdvanced<MSG> extends AbstractChannelTypeAdvanced<NettyProxyMsg> implements ChannelTypeAdvanced {
/**
* 是否支持当前类型
*
* @param msg 通道数据
* @return 布尔类型
*/
@Override
public boolean doSupport(NettyProxyMsg msg) {
return MessageTypeEnums.DISTRIBUTE_SINGLE_CLIENT_REAL_CONNECT.getTypeByte() == msg.getType();
}
}

View File

@ -0,0 +1,25 @@
package wu.framework.middleground.cloud.heartbeat.common.advanced.client;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.advanced.AbstractChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.advanced.ChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.enums.MessageTypeEnums;
/**
* 下发 客户端暂存关闭
*/
public abstract class AbstractDistributeStagingClosedTypeAdvanced<MSG> extends AbstractChannelTypeAdvanced<NettyProxyMsg> implements ChannelTypeAdvanced {
/**
* 是否支持当前类型
*
* @param msg 通道数据
* @return 布尔类型
*/
@Override
public boolean doSupport(NettyProxyMsg msg) {
return MessageTypeEnums.DISTRIBUTE_CLIENT_STAGING_CLOSED_NOTIFICATION.getTypeByte() == msg.getType();
}
}

View File

@ -0,0 +1,25 @@
package wu.framework.middleground.cloud.heartbeat.common.advanced.client;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.advanced.AbstractChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.advanced.ChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.enums.MessageTypeEnums;
/**
* 下发 客户端暂存开启
*/
public abstract class AbstractDistributeStagingOpenedTypeAdvanced<MSG> extends AbstractChannelTypeAdvanced<NettyProxyMsg> implements ChannelTypeAdvanced {
/**
* 是否支持当前类型
*
* @param msg 通道数据
* @return 布尔类型
*/
@Override
public boolean doSupport(NettyProxyMsg msg) {
return MessageTypeEnums.DISTRIBUTE_CLIENT_STAGING_OPENED_NOTIFICATION.getTypeByte() == msg.getType();
}
}

View File

@ -0,0 +1,27 @@
package wu.framework.middleground.cloud.heartbeat.common.advanced.server;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.advanced.AbstractChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.advanced.ChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.enums.MessageTypeEnums;
/**
* 服务端处理客户端上报数据
* REPORT_CLIENT_STAGING_CLOSED
*/
public abstract class AbstractReportChannelTransferTypeAdvanced<MSG> extends AbstractChannelTypeAdvanced<NettyProxyMsg> implements ChannelTypeAdvanced {
/**
* 是否支持当前类型
*
* @param msg 通道数据
* @return 布尔类型
*/
@Override
public boolean doSupport(NettyProxyMsg msg) {
return MessageTypeEnums.REPORT_CLIENT_TRANSFER.getTypeByte() == msg.getType();
}
}

View File

@ -0,0 +1,23 @@
package wu.framework.middleground.cloud.heartbeat.common.advanced.server;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.advanced.AbstractChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.advanced.ChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.enums.MessageTypeEnums;
/**
* 客户端连接成功上报处理器
*/
public abstract class AbstractReportConnectSuccessTypeAdvanced<MSG> extends AbstractChannelTypeAdvanced<NettyProxyMsg> implements ChannelTypeAdvanced {
/**
* 是否支持当前类型
*
* @param msg 通道数据
* @return 布尔类型
*/
@Override
public boolean doSupport(NettyProxyMsg msg) {
return MessageTypeEnums.REPORT_CLIENT_CONNECT_SUCCESS.getTypeByte() == msg.getType();
}
}

View File

@ -0,0 +1,27 @@
package wu.framework.middleground.cloud.heartbeat.common.advanced.server;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.advanced.AbstractChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.advanced.ChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.enums.MessageTypeEnums;
/**
* 客户端上报断开连接通知
* DISTRIBUTE_CLIENT_DISCONNECTION_NOTIFICATION
*/
public abstract class AbstractReportDisconnectTypeAdvanced<MSG> extends AbstractChannelTypeAdvanced<NettyProxyMsg> implements ChannelTypeAdvanced {
/**
* 是否支持当前类型
*
* @param msg 通道数据
* @return 布尔类型
*/
@Override
public boolean doSupport(NettyProxyMsg msg) {
// 下发 客户端断开连接通知
return MessageTypeEnums.REPORT_CLIENT_DISCONNECTION.getTypeByte() == msg.getType();
}
}

View File

@ -0,0 +1,27 @@
package wu.framework.middleground.cloud.heartbeat.common.advanced.server;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.advanced.AbstractChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.advanced.ChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.enums.MessageTypeEnums;
/**
* 服务端处理客户端 关闭一个访客
* REPORT_SINGLE_CLIENT_CLOSE_VISITOR
*/
public abstract class AbstractReportSingleClientCloseVisitorTypeAdvanced<MSG> extends AbstractChannelTypeAdvanced<NettyProxyMsg> implements ChannelTypeAdvanced {
/**
* 是否支持当前类型
*
* @param msg 通道数据
* @return 布尔类型
*/
@Override
public boolean doSupport(NettyProxyMsg msg) {
return MessageTypeEnums.REPORT_SINGLE_CLIENT_CLOSE_VISITOR.getTypeByte() == msg.getType();
}
}

View File

@ -0,0 +1,27 @@
package wu.framework.middleground.cloud.heartbeat.common.advanced.server;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.advanced.AbstractChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.advanced.ChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.enums.MessageTypeEnums;
/**
* 服务端处理客户端绑定真实服务成功
* REPORT_SINGLE_CLIENT_REAL_CONNECT
*/
public abstract class AbstractReportSingleClientRealConnectTypeAdvanced<MSG> extends AbstractChannelTypeAdvanced<NettyProxyMsg> implements ChannelTypeAdvanced {
/**
* 是否支持当前类型
*
* @param msg 通道数据
* @return 布尔类型
*/
@Override
public boolean doSupport(NettyProxyMsg msg) {
return MessageTypeEnums.REPORT_SINGLE_CLIENT_REAL_CONNECT.getTypeByte() == msg.getType();
}
}

View File

@ -0,0 +1,29 @@
package wu.framework.middleground.cloud.heartbeat.common.advanced.server;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.advanced.AbstractChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.advanced.ChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.enums.MessageTypeEnums;
/**
* 客户端暂存通知
* 客户端离线后陷入暂存服务业务上使用
* 云端发送的消息此模式云端后者说服务端不需要处理
* CLIENT_STAGING
* 客户端上报暂存
*/
public abstract class AbstractReportStagingClosedTypeAdvanced<MSG> extends AbstractChannelTypeAdvanced<NettyProxyMsg> implements ChannelTypeAdvanced{
/**
* 是否支持当前类型
*
* @param msg 通道数据
* @return 布尔类型
*/
@Override
public boolean doSupport(NettyProxyMsg msg) {
return MessageTypeEnums.REPORT_CLIENT_STAGING_CLOSED.getTypeByte() == msg.getType();
}
}

View File

@ -0,0 +1,25 @@
package wu.framework.middleground.cloud.heartbeat.common.advanced.server;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import wu.framework.middleground.cloud.heartbeat.common.advanced.AbstractChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.advanced.ChannelTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.enums.MessageTypeEnums;
/**
* 上报客户端暂存开启
*/
public abstract class AbstractReportStagingOpenedTypeAdvanced<MSG> extends AbstractChannelTypeAdvanced<NettyProxyMsg> implements ChannelTypeAdvanced {
/**
* 是否支持当前类型
*
* @param msg 通道数据
* @return 布尔类型
*/
@Override
public boolean doSupport(NettyProxyMsg msg) {
return MessageTypeEnums.REPORT_CLIENT_STAGING_OPENED.getTypeByte() == msg.getType();
}
}

View File

@ -0,0 +1,46 @@
package wu.framework.middleground.cloud.heartbeat.common.constant;
import wu.framework.middleground.cloud.heartbeat.common.enums.NettyClientStatus;
/**
* 客户端配置 key 常量
*/
public class ClientConfigKeyUtils {
//
/**
* 客户端状态对应的key
*
* @see NettyClientStatus#ON_LINE
* @see NettyClientStatus#OFF_LINE
*/
public static final String CLIENT_STATUS_KEY = "middleground:cloud:netty:client:status";
/**
* 客户端ID存放的key
*/
public static final String CLIENT_ID_KEY = "middleground:cloud:netty:client:id";
/**
* 获取客户端对应的状态key
*
* @param clientId 客户端ID
* @return 客户端对应的状态key
*/
public static String getClientStatusKey(String clientId) {
return CLIENT_STATUS_KEY + ":" + clientId;
}
/**
* 获取 客户端ID对应的key
*
* @param clientId 客户端ID
* @return 客户端ID对应的key
*/
public static String getClientIdKey(String clientId) {
return CLIENT_ID_KEY + ":" + clientId;
}
}

View File

@ -0,0 +1,10 @@
package wu.framework.middleground.cloud.heartbeat.common.constant;
import io.netty.util.AttributeKey;
/**
* netty 通道属性 key常量
*/
public class NettyChannelAttributeKey {
public static final AttributeKey<String> CLIENT_ID_KEY = AttributeKey.newInstance("client_id");
}

View File

@ -0,0 +1,5 @@
package wu.framework.middleground.cloud.heartbeat.common.constant;
public class ProxyConfigConstant {
public static final String PREFIX ="spring.lazy.proxy";
}

View File

@ -0,0 +1,14 @@
package wu.framework.middleground.cloud.heartbeat.common.constant;
/**
* redis 通道
*/
public class RedisChannelConstant {
// 客户端离线或者在线通知通道
public static final String REDIS_CLIENT_ONLINE_OR_OFFLINE_CHANNEL = "REDIS_CLIENT_ONLINE_OR_OFFLINE_CHANNEL";
/**
* 客户端监听 客户端暂存开启关闭通道
*/
public static final String REDIS_CLIENT_STAGING_OPENED_OR_CLOSED_CHANNEL = "REDIS_CLIENT_STAGING_OPENED_OR_CLOSED_CHANNEL";
}

View File

@ -0,0 +1,53 @@
package wu.framework.middleground.cloud.heartbeat.common.decoder;
import wu.framework.middleground.cloud.heartbeat.common.NettyMsg;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
/**
* @see NettyMsg
* NettyMsg 对象解码
*/
public class NettyMsgDecoder extends LengthFieldBasedFrameDecoder {
public NettyMsgDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment,
int initialBytesToStrip) {
super(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip);
}
public NettyMsgDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment,
int initialBytesToStrip, boolean failFast) {
super(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip, failFast);
}
@Override
protected NettyMsg decode(ChannelHandlerContext ctx, ByteBuf in2) throws Exception {
ByteBuf in = (ByteBuf) super.decode(ctx, in2);
if (in == null) {
return null;
}
if (in.readableBytes() < 4) {
return null;
}
NettyMsg nettyMsg = new NettyMsg();
int bodyLength = in.readInt();
byte type = in.readByte();
nettyMsg.setType(type);
int clientIdLength = in.readInt();
byte[] clientId = new byte[clientIdLength];
in.readBytes(clientId);
nettyMsg.setClientId(clientId);
byte[] data = new byte[bodyLength - NettyMsg.bodyLength - clientIdLength];
in.readBytes(data);
nettyMsg.setData(data);
in.release();
return nettyMsg;
}
}

View File

@ -0,0 +1,152 @@
package wu.framework.middleground.cloud.heartbeat.common.decoder;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.TooLongFrameException;
import java.nio.ByteOrder;
/**
* @see NettyProxyMsg
* NettyProxyMsg 解码
*/
public class NettyProxyMsgDecoder extends LengthFieldBasedFrameDecoder {
/**
* Creates a new instance.
*
* @param maxFrameLength the maximum length of the frame. If the length of the frame is
* greater than this value, {@link TooLongFrameException} will be
* thrown.
* @param lengthFieldOffset the offset of the length field
* @param lengthFieldLength the length of the length field
*/
public NettyProxyMsgDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength) {
super(maxFrameLength, lengthFieldOffset, lengthFieldLength);
}
/**
* Creates a new instance.
*
* @param maxFrameLength the maximum length of the frame. If the length of the frame is
* greater than this value, {@link TooLongFrameException} will be
* thrown.
* @param lengthFieldOffset the offset of the length field
* @param lengthFieldLength the length of the length field
* @param lengthAdjustment the compensation value to add to the value of the length field
* @param initialBytesToStrip the number of first bytes to strip out from the decoded frame
*/
public NettyProxyMsgDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip) {
super(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip);
}
/**
* Creates a new instance.
*
* @param maxFrameLength the maximum length of the frame. If the length of the frame is
* greater than this value, {@link TooLongFrameException} will be
* thrown.
* @param lengthFieldOffset the offset of the length field
* @param lengthFieldLength the length of the length field
* @param lengthAdjustment the compensation value to add to the value of the length field
* @param initialBytesToStrip the number of first bytes to strip out from the decoded frame
* @param failFast If <tt>true</tt>, a {@link TooLongFrameException} is thrown as
* soon as the decoder notices the length of the frame will exceed
* <tt>maxFrameLength</tt> regardless of whether the entire frame
* has been read. If <tt>false</tt>, a {@link TooLongFrameException}
* is thrown after the entire frame that exceeds <tt>maxFrameLength</tt>
* has been read.
*/
public NettyProxyMsgDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip, boolean failFast) {
super(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip, failFast);
}
/**
* Creates a new instance.
*
* @param byteOrder the {@link ByteOrder} of the length field
* @param maxFrameLength the maximum length of the frame. If the length of the frame is
* greater than this value, {@link TooLongFrameException} will be
* thrown.
* @param lengthFieldOffset the offset of the length field
* @param lengthFieldLength the length of the length field
* @param lengthAdjustment the compensation value to add to the value of the length field
* @param initialBytesToStrip the number of first bytes to strip out from the decoded frame
* @param failFast If <tt>true</tt>, a {@link TooLongFrameException} is thrown as
* soon as the decoder notices the length of the frame will exceed
* <tt>maxFrameLength</tt> regardless of whether the entire frame
* has been read. If <tt>false</tt>, a {@link TooLongFrameException}
* is thrown after the entire frame that exceeds <tt>maxFrameLength</tt>
* has been read.
*/
public NettyProxyMsgDecoder(ByteOrder byteOrder, int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip, boolean failFast) {
super(byteOrder, maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip, failFast);
}
/**
* Create a frame out of the {@link ByteBuf} and return it.
*
* @param ctx the {@link ChannelHandlerContext} which this {@link ByteToMessageDecoder} belongs to
* @param in2 the {@link ByteBuf} from which to read data
* @return frame the {@link ByteBuf} which represent the frame or {@code null} if no frame could
* be created.
*/
@Override
protected NettyProxyMsg decode(ChannelHandlerContext ctx, ByteBuf in2) throws Exception {
// 解码顺序 body 长度 type 1 clientId 4 clientTargetIp 4 clientTargetPort 4 visitorPort 4 visitorId 4 data 4
ByteBuf in = (ByteBuf) super.decode(ctx, in2);
if (in == null) {
return null;
}
if (in.readableBytes() < 4) {
return null;
}
NettyProxyMsg nettyProxyMsg = new NettyProxyMsg();
int bodyLength = in.readInt();
byte type = in.readByte();
nettyProxyMsg.setType(type);
int clientIdLength = in.readInt();
byte[] clientIdBytes = new byte[clientIdLength];
in.readBytes(clientIdBytes);
nettyProxyMsg.setClientId(clientIdBytes);
int clientTargetIpLength = in.readInt();
byte[] clientTargetIpBytes = new byte[clientTargetIpLength];
in.readBytes(clientTargetIpBytes);
nettyProxyMsg.setClientTargetIp(clientTargetIpBytes);
int clientTargetPortLength = in.readInt();
byte[] clientTargetPortBytes = new byte[clientTargetPortLength];
in.readBytes(clientTargetPortBytes);
nettyProxyMsg.setClientTargetPort(clientTargetPortBytes);
int visitorPortLength = in.readInt();
byte[] visitorPortBytes = new byte[visitorPortLength];
in.readBytes(visitorPortBytes);
nettyProxyMsg.setVisitorPort(visitorPortBytes);
int visitorIdLength = in.readInt();
byte[] visitorIdBytes = new byte[visitorIdLength];
in.readBytes(visitorIdBytes);
nettyProxyMsg.setVisitorId(visitorIdBytes);
byte[] data = new byte[bodyLength - NettyProxyMsg.bodyLength -
clientIdLength -
clientTargetIpLength -
clientTargetPortLength -
visitorPortLength -
visitorIdLength];
in.readBytes(data);
nettyProxyMsg.setData(data);
in.release();
return nettyProxyMsg;
}
}

View File

@ -0,0 +1,48 @@
package wu.framework.middleground.cloud.heartbeat.common.encoder;
import wu.framework.middleground.cloud.heartbeat.common.NettyMsg;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
/**
* @see NettyProxyMsg
* NettyProxyMsg 对象编码
*/
public class NettMsgEncoder extends MessageToByteEncoder<NettyMsg> {
public NettMsgEncoder() {
}
@Override
protected void encode(ChannelHandlerContext ctx, NettyMsg nettyMsg, ByteBuf out) throws Exception {
// type 1 data 4 clientId 4
int bodyLength = NettyMsg.bodyLength;
byte[] clientIdBytes = nettyMsg.getClientId();
if (nettyMsg.getData() != null) {
bodyLength += nettyMsg.getData().length;
}
if (nettyMsg.getClientId() != null) {
bodyLength += nettyMsg.getClientId().length;
}
out.writeInt(bodyLength);
out.writeByte(nettyMsg.getType());
// 客户端ID
// 防止数据读错位置
if (clientIdBytes != null) {
out.writeInt(clientIdBytes.length);
out.writeBytes(clientIdBytes);
}else {
// 防止客户端ID未填写
out.writeInt(0x00);
}
if (nettyMsg.getData() != null) {
out.writeBytes(nettyMsg.getData());
}
}
}

View File

@ -0,0 +1,106 @@
package wu.framework.middleground.cloud.heartbeat.common.encoder;
import wu.framework.middleground.cloud.heartbeat.common.NettyProxyMsg;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
/**
* @see NettyProxyMsg
* NettyProxyMsg 编码
*/
public class NettyProxyMsgEncoder extends MessageToByteEncoder<NettyProxyMsg> {
/**
* Encode a message into a {@link ByteBuf}. This method will be called for each written message that can be handled
* by this encoder.
*
* @param ctx the {@link ChannelHandlerContext} which this {@link MessageToByteEncoder} belongs to
* @param msg the message to encode
* @param out the {@link ByteBuf} into which the encoded message will be written
*/
@Override
protected void encode(ChannelHandlerContext ctx, NettyProxyMsg msg, ByteBuf out) {
// body 长度 type 1 clientId 4 clientTargetIp 4 clientTargetPort 4 visitorPort 4 visitorId 4 data 4
int bodyLength = NettyProxyMsg.bodyLength;
byte typeBytes = msg.getType();
byte[] clientIdBytes = msg.getClientId();
byte[] clientTargetIpBytes = msg.getClientTargetIp();
byte[] clientTargetPortBytes = msg.getClientTargetPort();
byte[] visitorPortBytes = msg.getVisitorPort();
byte[] visitorIdBytes = msg.getVisitorId();
byte[] msgDataBytes = msg.getData();
if (clientIdBytes != null) {
bodyLength += clientIdBytes.length;
}
if (clientTargetIpBytes != null) {
bodyLength += clientTargetIpBytes.length;
}
if (clientTargetPortBytes != null) {
bodyLength += clientTargetPortBytes.length;
}
if (visitorPortBytes != null) {
bodyLength += visitorPortBytes.length;
}
if (visitorIdBytes != null) {
bodyLength += visitorIdBytes.length;
}
if (msgDataBytes != null) {
bodyLength += msgDataBytes.length;
}
out.writeInt(bodyLength);
out.writeByte(typeBytes);
// 防止数据读错位置 clientId
if (clientIdBytes != null) {
out.writeInt(clientIdBytes.length);
out.writeBytes(clientIdBytes);
} else {
// 防止客户端id 未填写
out.writeInt(0x00);
}
// 防止数据读错位置 clientTargetIp
if (clientTargetIpBytes != null) {
out.writeInt(clientTargetIpBytes.length);
out.writeBytes(clientTargetIpBytes);
} else {
// 防止客户端 目标IP未填写
out.writeInt(0x00);
}
// clientTargetPort
if (clientTargetPortBytes != null) {
out.writeInt(clientTargetPortBytes.length);
out.writeBytes(clientTargetPortBytes);
} else {
// 防止客户端目标端口未填写
out.writeInt(0x00);
}
// visitorPort
if (visitorPortBytes != null) {
out.writeInt(visitorPortBytes.length);
out.writeBytes(visitorPortBytes);
} else {
// 防止客户端 访客端口未填写
out.writeInt(0x00);
}
if (visitorIdBytes != null) {
out.writeInt(visitorIdBytes.length);
out.writeBytes(visitorIdBytes);
} else {
// 防止客户端 访客ID未填写
out.writeInt(0x00);
}
if (msgDataBytes != null) {
out.writeBytes(msgDataBytes);
}
}
}

View File

@ -0,0 +1,91 @@
package wu.framework.middleground.cloud.heartbeat.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import wu.framework.middleground.cloud.heartbeat.common.MessageType;
import wu.framework.middleground.cloud.heartbeat.common.advanced.AbstractChannelHeartbeatTypeAdvanced;
import wu.framework.middleground.cloud.heartbeat.common.advanced.client.*;
import wu.framework.middleground.cloud.heartbeat.common.advanced.server.*;
/**
* @see MessageType
*/
@Getter
@AllArgsConstructor
public enum MessageTypeEnums {
/**
* @see AbstractChannelHeartbeatTypeAdvanced
*/
TYPE_HEARTBEAT(MessageType.TYPE_HEARTBEAT, "心跳"),
/**
* @see AbstractReportConnectSuccessTypeAdvanced
*/
REPORT_CLIENT_CONNECT_SUCCESS(MessageType.REPORT_CLIENT_CONNECT_SUCCESS, "上报 客户端连接成功"),
/**
* @see AbstractReportDisconnectTypeAdvanced
*/
REPORT_CLIENT_DISCONNECTION(MessageType.REPORT_CLIENT_DISCONNECTION, "上报 客户端断开连接"),
/**
* @see AbstractReportStagingOpenedTypeAdvanced
*/
REPORT_CLIENT_STAGING_OPENED(MessageType.REPORT_CLIENT_STAGING_OPENED, "上报 客户端暂存开启"),
/**
* @see AbstractReportStagingClosedTypeAdvanced
*/
REPORT_CLIENT_STAGING_CLOSED(MessageType.REPORT_CLIENT_STAGING_CLOSED, "上报 客户端暂存关闭"),
/**
* @see AbstractReportChannelTransferTypeAdvanced
*/
REPORT_CLIENT_TRANSFER(MessageType.REPORT_CLIENT_TRANSFER, "上报 客户端数据传输(内网穿透数据回传)"),
/**
* @see AbstractReportSingleClientRealConnectTypeAdvanced
*/
REPORT_SINGLE_CLIENT_REAL_CONNECT(MessageType.REPORT_SINGLE_CLIENT_REAL_CONNECT, "上报 客户端创建需要代理的真实端口成功"),
/**
* @see AbstractReportSingleClientCloseVisitorTypeAdvanced
*/
REPORT_SINGLE_CLIENT_CLOSE_VISITOR(MessageType.REPORT_SINGLE_CLIENT_CLOSE_VISITOR, "上报 客户端关闭一个访客通道"),
/**
* @see AbstractDistributeConnectSuccessNotificationTypeAdvanced
*/
DISTRIBUTE_CLIENT_CONNECTION_SUCCESS_NOTIFICATION(MessageType.DISTRIBUTE_CLIENT_CONNECTION_SUCCESS_NOTIFICATION, "下发 客户端接收连接成功通知"),
/**
* @see AbstractDistributeDisconnectTypeAdvanced
*/
DISTRIBUTE_CLIENT_DISCONNECTION_NOTIFICATION(MessageType.DISTRIBUTE_CLIENT_DISCONNECTION_NOTIFICATION, "下发 客户端断开连接通知"),
/**
* @see AbstractDistributeStagingOpenedTypeAdvanced
*/
DISTRIBUTE_CLIENT_STAGING_OPENED_NOTIFICATION(MessageType.DISTRIBUTE_CLIENT_STAGING_OPENED_NOTIFICATION, "下发 客户端暂存开启通知"),
/**
* @see AbstractDistributeStagingClosedTypeAdvanced
*/
DISTRIBUTE_CLIENT_STAGING_CLOSED_NOTIFICATION(MessageType.DISTRIBUTE_CLIENT_STAGING_CLOSED_NOTIFICATION, "下发 客户端暂存关闭通知"),
/**
* @see AbstractDistributeChannelTransferTypeAdvanced
*/
DISTRIBUTE_CLIENT_TRANSFER(MessageType.DISTRIBUTE_CLIENT_TRANSFER, "下发 客户端数据传输(内网穿透数据发送)"),
/**
* @see AbstractDistributeSingleClientRealConnectTypeAdvanced
*/
DISTRIBUTE_SINGLE_CLIENT_REAL_CONNECT(MessageType.DISTRIBUTE_SINGLE_CLIENT_REAL_CONNECT, "下发 客户端创建需要代理的真实端口"),
/**
* @see AbstractDistributeSingleClientRealAutoReadConnectTypeAdvanced
*/
DISTRIBUTE_SINGLE_CLIENT_REAL_CONNECT_AUTO_READ(MessageType.DISTRIBUTE_SINGLE_CLIENT_REAL_CONNECT_AUTO_READ, "下发 客户端代理的真实端口自动读写"),
/**
* @see AbstractDistributeSingleClientRealCloseVisitorTypeAdvanced
*/
DISTRIBUTE_SINGLE_CLIENT_REAL_CLOSE_VISITOR(MessageType.DISTRIBUTE_SINGLE_CLIENT_REAL_CLOSE_VISITOR, "下发 客户端关闭代理服务通道"),
;
private final byte typeByte;
private final String desc;
}

View File

@ -0,0 +1,17 @@
package wu.framework.middleground.cloud.heartbeat.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* netty客户端 状态
*/
@AllArgsConstructor
@Getter
public enum NettyClientStatus {
ON_LINE("在线"),
OFF_LINE("离线");
private final String desc;
}

View File

@ -0,0 +1,18 @@
package wu.framework.middleground.cloud.heartbeat.common.state;
import lombok.Data;
/**
* 客户端在线状态
*/
@Data
public class ClientOnLineState {
/**
* 客户端ID
*/
private String clientId;
/**
* 在线状态
*/
private String onLineState;
}

View File

@ -0,0 +1,70 @@
package wu.framework.middleground.cloud.heartbeat.common.utils;
import io.netty.channel.Channel;
import io.netty.util.AttributeKey;
/**
* 通道属性绑定工具
*/
public class ChannelAttributeKeyUtils {
private static final AttributeKey<String> VISITOR_ID = AttributeKey.newInstance("visitorId");
private static final AttributeKey<String> CLIENT_ID = AttributeKey.newInstance("clientId");
/**
* 为通道绑定 访客属性
*
* @param channel 通道
* @param visitorId 访客ID
*/
public static void buildVisitorId(Channel channel, byte[] visitorId) {
channel.attr(VISITOR_ID).set(new String(visitorId));
}
/**
* 为通道绑定 访客属性
*
* @param channel 通道
* @param visitorId 访客ID
*/
public static void buildVisitorId(Channel channel, String visitorId) {
channel.attr(VISITOR_ID).set(visitorId);
}
/**
* 获取 通道中访客ID
* @param channel 通道
*/
public static String getVisitorId(Channel channel) {
return channel.attr(VISITOR_ID).get();
}
/**
* 为通道绑定 访客属性
*
* @param channel 通道
* @param clientId 客户端ID
*/
public static void buildClientId(Channel channel, byte[] clientId) {
channel.attr(CLIENT_ID).set(new String(clientId));
}
/**
* 为通道绑定 访客属性
*
* @param channel 通道
* @param clientId 客户端ID
*/
public static void buildClientId(Channel channel, String clientId) {
channel.attr(CLIENT_ID).set(clientId);
}
/**
* 获取 通道中访客ID
* @param channel 通道
*/
public static String getClientId(Channel channel) {
return channel.attr(CLIENT_ID).get();
}
}

View File

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>top.wu2020</groupId>
<artifactId>lazy-cloud-network</artifactId>
<version>1.2.1-JDK17-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>lazy-cloud-heartbeat-server</artifactId>
<description>云上心跳服务端</description>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>top.wu2020</groupId>
<artifactId>wu-framework-web</artifactId>
</dependency>
<!-- 通用心跳包 -->
<dependency>
<groupId>top.wu2020</groupId>
<artifactId>lazy-cloud-heartbeat-common</artifactId>
<version>1.2.1-JDK17-SNAPSHOT</version>
</dependency>
<!-- 数据库 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<dependency>
<groupId>top.wu2020</groupId>
<artifactId>wu-database-lazy-starter</artifactId>
</dependency>
<dependency>
<groupId>top.wu2020</groupId>
<artifactId>wu-database-lazy-plus-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.33</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,14 @@
package wu.framework.middleground.on.cloud.heartbeat.server.domain;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 云上云下-云上心跳服务器
*/
@SpringBootApplication
public class MiddlegroundOnCloudHeartbeatServer {
public static void main(String[] args) {
SpringApplication.run(MiddlegroundOnCloudHeartbeatServer.class,args);
}
}

View File

@ -0,0 +1,111 @@
package wu.framework.middleground.on.cloud.heartbeat.server.domain.application;
import wu.framework.middleground.on.cloud.heartbeat.server.domain.application.command.internal.network.penetration.mapping.*;
import wu.framework.middleground.on.cloud.heartbeat.server.domain.application.dto.InternalNetworkPenetrationMappingDTO;
import wu.framework.middleground.on.cloud.heartbeat.server.domain.model.internal.network.penetration.mapping.InternalNetworkPenetrationMapping;
import com.wu.framework.inner.lazy.database.expand.database.persistence.domain.LazyPage;
import com.wu.framework.response.Result;
import java.util.List;
/**
* describe 内网穿透映射
*
* @author Jia wei Wu
* @date 2023/12/29 05:21 下午
* @see com.wu.framework.inner.lazy.persistence.reverse.lazy.ddd.DefaultDDDLazyApplication
**/
public interface InternalNetworkPenetrationMappingApplication {
/**
* describe 新增内网穿透映射
*
* @param internalNetworkPenetrationMappingStoryCommand 新增内网穿透映射
* @return {@link Result<InternalNetworkPenetrationMapping>} 内网穿透映射新增后领域对象
* @author Jia wei Wu
* @date 2023/12/29 05:21 下午
**/
Result<InternalNetworkPenetrationMapping> story(InternalNetworkPenetrationMappingStoryCommand internalNetworkPenetrationMappingStoryCommand);
/**
* describe 批量新增内网穿透映射
*
* @param internalNetworkPenetrationMappingStoryCommandList 批量新增内网穿透映射
* @return {@link Result<List<InternalNetworkPenetrationMapping>>} 内网穿透映射新增后领域对象集合
* @author Jia wei Wu
* @date 2023/12/29 05:21 下午
**/
Result<List<InternalNetworkPenetrationMapping>> batchStory(List<InternalNetworkPenetrationMappingStoryCommand> internalNetworkPenetrationMappingStoryCommandList);
/**
* describe 更新内网穿透映射
*
* @param internalNetworkPenetrationMappingUpdateCommand 更新内网穿透映射
* @return {@link Result<InternalNetworkPenetrationMapping>} 内网穿透映射领域对象
* @author Jia wei Wu
* @date 2023/12/29 05:21 下午
**/
Result<InternalNetworkPenetrationMapping> updateOne(InternalNetworkPenetrationMappingUpdateCommand internalNetworkPenetrationMappingUpdateCommand);
/**
* describe 查询单个内网穿透映射
*
* @param internalNetworkPenetrationMappingQueryOneCommand 查询单个内网穿透映射
* @return {@link Result< InternalNetworkPenetrationMappingDTO >} 内网穿透映射DTO对象
* @author Jia wei Wu
* @date 2023/12/29 05:21 下午
**/
Result<InternalNetworkPenetrationMappingDTO> findOne(InternalNetworkPenetrationMappingQueryOneCommand internalNetworkPenetrationMappingQueryOneCommand);
/**
* describe 查询多个内网穿透映射
*
* @param internalNetworkPenetrationMappingQueryListCommand 查询多个内网穿透映射
* @return {@link Result <List<InternalNetworkPenetrationMappingDTO>>} 内网穿透映射DTO对象
* @author Jia wei Wu
* @date 2023/12/29 05:21 下午
**/
Result <List<InternalNetworkPenetrationMappingDTO>> findList(InternalNetworkPenetrationMappingQueryListCommand internalNetworkPenetrationMappingQueryListCommand);
/**
* describe 分页查询多个内网穿透映射
*
* @param internalNetworkPenetrationMappingQueryListCommand 分页查询多个内网穿透映射
* @return {@link Result <LazyPage<InternalNetworkPenetrationMappingDTO>>} 分页内网穿透映射DTO对象
* @author Jia wei Wu
* @date 2023/12/29 05:21 下午
**/
Result <LazyPage<InternalNetworkPenetrationMappingDTO>> findPage(int size,int current,InternalNetworkPenetrationMappingQueryListCommand internalNetworkPenetrationMappingQueryListCommand);
/**
* describe 删除内网穿透映射
*
* @param internalNetworkPenetrationMappingRemoveCommand 删除内网穿透映射
* @return {@link Result<InternalNetworkPenetrationMapping>} 内网穿透映射
* @author Jia wei Wu
* @date 2023/12/29 05:21 下午
**/
Result<InternalNetworkPenetrationMapping> remove(InternalNetworkPenetrationMappingRemoveCommand internalNetworkPenetrationMappingRemoveCommand);
/**
* 创建客户端的访问者
* @param clientId 客户端ID
*/
Result<Void> createVisitor(String clientId);
}

View File

@ -0,0 +1,116 @@
package wu.framework.middleground.on.cloud.heartbeat.server.domain.application;
import wu.framework.middleground.on.cloud.heartbeat.server.domain.application.command.netty.client.blacklist.*;
import wu.framework.middleground.on.cloud.heartbeat.server.domain.application.dto.NettyClientBlacklistDTO;
import wu.framework.middleground.on.cloud.heartbeat.server.domain.model.netty.client.blacklist.NettyClientBlacklist;
import com.wu.framework.inner.lazy.database.expand.database.persistence.domain.LazyPage;
import com.wu.framework.response.Result;
import java.util.List;
/**
* describe 客户端黑名单
*
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
* @see com.wu.framework.inner.lazy.persistence.reverse.lazy.ddd.DefaultDDDLazyApplication
**/
public interface NettyClientBlacklistApplication {
/**
* describe 新增客户端黑名单
*
* @param nettyClientBlacklistStoryCommand 新增客户端黑名单
* @return {@link Result<NettyClientBlacklist>} 客户端黑名单新增后领域对象
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
Result<NettyClientBlacklist> story(NettyClientBlacklistStoryCommand nettyClientBlacklistStoryCommand);
/**
* describe 批量新增客户端黑名单
*
* @param nettyClientBlacklistStoryCommandList 批量新增客户端黑名单
* @return {@link Result<List<NettyClientBlacklist>>} 客户端黑名单新增后领域对象集合
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
Result<List<NettyClientBlacklist>> batchStory(List<NettyClientBlacklistStoryCommand> nettyClientBlacklistStoryCommandList);
/**
* describe 更新客户端黑名单
*
* @param nettyClientBlacklistUpdateCommand 更新客户端黑名单
* @return {@link Result<NettyClientBlacklist>} 客户端黑名单领域对象
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
Result<NettyClientBlacklist> updateOne(NettyClientBlacklistUpdateCommand nettyClientBlacklistUpdateCommand);
/**
* describe 查询单个客户端黑名单
*
* @param nettyClientBlacklistQueryOneCommand 查询单个客户端黑名单
* @return {@link Result< NettyClientBlacklistDTO >} 客户端黑名单DTO对象
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
Result<NettyClientBlacklistDTO> findOne(NettyClientBlacklistQueryOneCommand nettyClientBlacklistQueryOneCommand);
/**
* describe 查询多个客户端黑名单
*
* @param nettyClientBlacklistQueryListCommand 查询多个客户端黑名单
* @return {@link Result <List<NettyClientBlacklistDTO>>} 客户端黑名单DTO对象
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
Result <List<NettyClientBlacklistDTO>> findList(NettyClientBlacklistQueryListCommand nettyClientBlacklistQueryListCommand);
/**
* describe 分页查询多个客户端黑名单
*
* @param nettyClientBlacklistQueryListCommand 分页查询多个客户端黑名单
* @return {@link Result <LazyPage<NettyClientBlacklistDTO>>} 分页客户端黑名单DTO对象
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
Result <LazyPage<NettyClientBlacklistDTO>> findPage(int size,int current,NettyClientBlacklistQueryListCommand nettyClientBlacklistQueryListCommand);
/**
* describe 删除客户端黑名单
*
* @param nettyClientBlacklistRemoveCommand 删除客户端黑名单
* @return {@link Result<NettyClientBlacklist>} 客户端黑名单
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
Result<NettyClientBlacklist> remove(NettyClientBlacklistRemoveCommand nettyClientBlacklistRemoveCommand);
/**
* describe 是否存在客户端黑名单
*
* @param nettyClientBlacklist 是否存在客户端黑名单
* @return {@link Result<Boolean>} 客户端黑名单是否存在
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
Result<Boolean> exists(NettyClientBlacklist nettyClientBlacklist);
}

View File

@ -0,0 +1,107 @@
package wu.framework.middleground.on.cloud.heartbeat.server.domain.application;
import com.wu.framework.inner.lazy.database.expand.database.persistence.domain.LazyPage;
import com.wu.framework.response.Result;
import wu.framework.middleground.on.cloud.heartbeat.server.domain.application.command.netty.client.state.*;
import wu.framework.middleground.on.cloud.heartbeat.server.domain.application.dto.NettyClientStateDTO;
import wu.framework.middleground.on.cloud.heartbeat.server.domain.model.netty.client.state.NettyClientState;
import java.util.List;
/**
* describe 客户端状态
*
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
* @see com.wu.framework.inner.lazy.persistence.reverse.lazy.ddd.DefaultDDDLazyApplication
**/
public interface NettyClientStateApplication {
/**
* describe 新增客户端状态
*
* @param nettyClientStateStoryCommand 新增客户端状态
* @return {@link Result< NettyClientState >} 客户端状态新增后领域对象
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
Result<NettyClientState> story(NettyClientStateStoryCommand nettyClientStateStoryCommand);
/**
* describe 批量新增客户端状态
*
* @param nettyClientStateStoryCommandList 批量新增客户端状态
* @return {@link Result<List<NettyClientState>>} 客户端状态新增后领域对象集合
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
Result<List<NettyClientState>> batchStory(List<NettyClientStateStoryCommand> nettyClientStateStoryCommandList);
/**
* describe 更新客户端状态
*
* @param nettyClientStateUpdateCommand 更新客户端状态
* @return {@link Result<NettyClientState>} 客户端状态领域对象
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
Result<NettyClientState> updateOne(NettyClientStateUpdateCommand nettyClientStateUpdateCommand);
/**
* describe 查询单个客户端状态
*
* @param nettyClientStateQueryOneCommand 查询单个客户端状态
* @return {@link Result< NettyClientStateDTO >} 客户端状态DTO对象
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
Result<NettyClientStateDTO> findOne(NettyClientStateQueryOneCommand nettyClientStateQueryOneCommand);
/**
* describe 查询多个客户端状态
*
* @param nettyClientStateQueryListCommand 查询多个客户端状态
* @return {@link Result <List<NettyClientStateDTO>>} 客户端状态DTO对象
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
Result <List<NettyClientStateDTO>> findList(NettyClientStateQueryListCommand nettyClientStateQueryListCommand);
/**
* describe 分页查询多个客户端状态
*
* @param nettyClientStateQueryListCommand 分页查询多个客户端状态
* @return {@link Result <LazyPage<NettyClientStateDTO>>} 分页客户端状态DTO对象
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
Result <LazyPage<NettyClientStateDTO>> findPage(int size, int current, NettyClientStateQueryListCommand nettyClientStateQueryListCommand);
/**
* describe 删除客户端状态
*
* @param nettyClientStateRemoveCommand 删除客户端状态
* @return {@link Result<NettyClientState>} 客户端状态
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
Result<NettyClientState> remove(NettyClientStateRemoveCommand nettyClientStateRemoveCommand);
}

View File

@ -0,0 +1,34 @@
package wu.framework.middleground.on.cloud.heartbeat.server.domain.application;
/**
* 云下心跳客户端操作nacos 配置
*/
public interface ServerNettyConfigApplication {
/**
* 客户端在线
* @param clientId 客户端ID
*/
void clientOnLine(String clientId);
/**
* 客户端离线
* @param clientId 客户端ID
*/
void clientOffLine(String clientId);
/**
* 客户端暂存关闭
* @param clientId 客户端ID
*/
void stagingClosed(String clientId);
/**
* 客户端暂存开启
* @param clientId 客户端ID
*/
void stagingOpened(String clientId);
}

View File

@ -0,0 +1,89 @@
package wu.framework.middleground.on.cloud.heartbeat.server.domain.application.assembler;
import wu.framework.middleground.on.cloud.heartbeat.server.domain.application.command.internal.network.penetration.mapping.*;
import wu.framework.middleground.on.cloud.heartbeat.server.domain.application.dto.InternalNetworkPenetrationMappingDTO;
import wu.framework.middleground.on.cloud.heartbeat.server.domain.model.internal.network.penetration.mapping.InternalNetworkPenetrationMapping;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
* describe 内网穿透映射
*
* @author Jia wei Wu
* @date 2023/12/29 05:21 下午
* @see com.wu.framework.inner.lazy.persistence.reverse.lazy.ddd.DefaultDDDLazyAssembler
**/
@Mapper
public interface InternalNetworkPenetrationMappingDTOAssembler {
/**
* describe MapStruct 创建的代理对象
*
* @author Jia wei Wu
* @date 2023/12/29 05:21 下午
**/
InternalNetworkPenetrationMappingDTOAssembler INSTANCE = Mappers.getMapper(InternalNetworkPenetrationMappingDTOAssembler.class);
/**
* describe 应用层存储入参转换成 领域对象
*
* @param internalNetworkPenetrationMappingStoryCommand 保存内网穿透映射对象
* @return {@link InternalNetworkPenetrationMapping} 内网穿透映射领域对象
* @author Jia wei Wu
* @date 2023/12/29 05:21 下午
**/
InternalNetworkPenetrationMapping toInternalNetworkPenetrationMapping(InternalNetworkPenetrationMappingStoryCommand internalNetworkPenetrationMappingStoryCommand);
/**
* describe 应用层更新入参转换成 领域对象
*
* @param internalNetworkPenetrationMappingUpdateCommand 更新内网穿透映射对象
* @return {@link InternalNetworkPenetrationMapping} 内网穿透映射领域对象
* @author Jia wei Wu
* @date 2023/12/29 05:21 下午
**/
InternalNetworkPenetrationMapping toInternalNetworkPenetrationMapping(InternalNetworkPenetrationMappingUpdateCommand internalNetworkPenetrationMappingUpdateCommand);
/**
* describe 应用层查询入参转换成 领域对象
*
* @param internalNetworkPenetrationMappingQueryOneCommand 查询单个内网穿透映射对象参数
* @return {@link InternalNetworkPenetrationMapping} 内网穿透映射领域对象
* @author Jia wei Wu
* @date 2023/12/29 05:21 下午
**/
InternalNetworkPenetrationMapping toInternalNetworkPenetrationMapping(InternalNetworkPenetrationMappingQueryOneCommand internalNetworkPenetrationMappingQueryOneCommand);
/**
* describe 应用层查询入参转换成 领域对象
*
* @param internalNetworkPenetrationMappingQueryListCommand 查询集合内网穿透映射对象参数
* @return {@link InternalNetworkPenetrationMapping} 内网穿透映射领域对象
* @author Jia wei Wu
* @date 2023/12/29 05:21 下午
**/
InternalNetworkPenetrationMapping toInternalNetworkPenetrationMapping(InternalNetworkPenetrationMappingQueryListCommand internalNetworkPenetrationMappingQueryListCommand);
/**
* describe 应用层删除入参转换成 领域对象
*
* @param internalNetworkPenetrationMappingRemoveCommand 删除内网穿透映射对象参数
* @return {@link InternalNetworkPenetrationMapping} 内网穿透映射领域对象
* @author Jia wei Wu
* @date 2023/12/29 05:21 下午
**/
InternalNetworkPenetrationMapping toInternalNetworkPenetrationMapping(InternalNetworkPenetrationMappingRemoveCommand internalNetworkPenetrationMappingRemoveCommand);
/**
* describe 持久层领域对象转换成DTO对象
*
* @param internalNetworkPenetrationMapping 内网穿透映射领域对象
* @return {@link InternalNetworkPenetrationMappingDTO} 内网穿透映射DTO对象
* @author Jia wei Wu
* @date 2023/12/29 05:21 下午
**/
InternalNetworkPenetrationMappingDTO fromInternalNetworkPenetrationMapping(InternalNetworkPenetrationMapping internalNetworkPenetrationMapping);
}

View File

@ -0,0 +1,89 @@
package wu.framework.middleground.on.cloud.heartbeat.server.domain.application.assembler;
import wu.framework.middleground.on.cloud.heartbeat.server.domain.application.command.netty.client.blacklist.*;
import wu.framework.middleground.on.cloud.heartbeat.server.domain.application.dto.NettyClientBlacklistDTO;
import wu.framework.middleground.on.cloud.heartbeat.server.domain.model.netty.client.blacklist.NettyClientBlacklist;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
* describe 客户端黑名单
*
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
* @see com.wu.framework.inner.lazy.persistence.reverse.lazy.ddd.DefaultDDDLazyAssembler
**/
@Mapper
public interface NettyClientBlacklistDTOAssembler {
/**
* describe MapStruct 创建的代理对象
*
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
NettyClientBlacklistDTOAssembler INSTANCE = Mappers.getMapper(NettyClientBlacklistDTOAssembler.class);
/**
* describe 应用层存储入参转换成 领域对象
*
* @param nettyClientBlacklistStoryCommand 保存客户端黑名单对象
* @return {@link NettyClientBlacklist} 客户端黑名单领域对象
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
NettyClientBlacklist toNettyClientBlacklist(NettyClientBlacklistStoryCommand nettyClientBlacklistStoryCommand);
/**
* describe 应用层更新入参转换成 领域对象
*
* @param nettyClientBlacklistUpdateCommand 更新客户端黑名单对象
* @return {@link NettyClientBlacklist} 客户端黑名单领域对象
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
NettyClientBlacklist toNettyClientBlacklist(NettyClientBlacklistUpdateCommand nettyClientBlacklistUpdateCommand);
/**
* describe 应用层查询入参转换成 领域对象
*
* @param nettyClientBlacklistQueryOneCommand 查询单个客户端黑名单对象参数
* @return {@link NettyClientBlacklist} 客户端黑名单领域对象
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
NettyClientBlacklist toNettyClientBlacklist(NettyClientBlacklistQueryOneCommand nettyClientBlacklistQueryOneCommand);
/**
* describe 应用层查询入参转换成 领域对象
*
* @param nettyClientBlacklistQueryListCommand 查询集合客户端黑名单对象参数
* @return {@link NettyClientBlacklist} 客户端黑名单领域对象
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
NettyClientBlacklist toNettyClientBlacklist(NettyClientBlacklistQueryListCommand nettyClientBlacklistQueryListCommand);
/**
* describe 应用层删除入参转换成 领域对象
*
* @param nettyClientBlacklistRemoveCommand 删除客户端黑名单对象参数
* @return {@link NettyClientBlacklist} 客户端黑名单领域对象
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
NettyClientBlacklist toNettyClientBlacklist(NettyClientBlacklistRemoveCommand nettyClientBlacklistRemoveCommand);
/**
* describe 持久层领域对象转换成DTO对象
*
* @param nettyClientBlacklist 客户端黑名单领域对象
* @return {@link NettyClientBlacklistDTO} 客户端黑名单DTO对象
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
NettyClientBlacklistDTO fromNettyClientBlacklist(NettyClientBlacklist nettyClientBlacklist);
}

View File

@ -0,0 +1,89 @@
package wu.framework.middleground.on.cloud.heartbeat.server.domain.application.assembler;
import wu.framework.middleground.on.cloud.heartbeat.server.domain.application.command.netty.client.state.*;
import wu.framework.middleground.on.cloud.heartbeat.server.domain.application.dto.NettyClientStateDTO;
import wu.framework.middleground.on.cloud.heartbeat.server.domain.model.netty.client.state.NettyClientState;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
* describe 客户端状态
*
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
* @see com.wu.framework.inner.lazy.persistence.reverse.lazy.ddd.DefaultDDDLazyAssembler
**/
@Mapper
public interface NettyClientStateDTOAssembler {
/**
* describe MapStruct 创建的代理对象
*
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
NettyClientStateDTOAssembler INSTANCE = Mappers.getMapper(NettyClientStateDTOAssembler.class);
/**
* describe 应用层存储入参转换成 领域对象
*
* @param nettyClientStateStoryCommand 保存客户端状态对象
* @return {@link NettyClientState} 客户端状态领域对象
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
NettyClientState toNettyClientState(NettyClientStateStoryCommand nettyClientStateStoryCommand);
/**
* describe 应用层更新入参转换成 领域对象
*
* @param nettyClientStateUpdateCommand 更新客户端状态对象
* @return {@link NettyClientState} 客户端状态领域对象
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
NettyClientState toNettyClientState(NettyClientStateUpdateCommand nettyClientStateUpdateCommand);
/**
* describe 应用层查询入参转换成 领域对象
*
* @param nettyClientStateQueryOneCommand 查询单个客户端状态对象参数
* @return {@link NettyClientState} 客户端状态领域对象
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
NettyClientState toNettyClientState(NettyClientStateQueryOneCommand nettyClientStateQueryOneCommand);
/**
* describe 应用层查询入参转换成 领域对象
*
* @param nettyClientStateQueryListCommand 查询集合客户端状态对象参数
* @return {@link NettyClientState} 客户端状态领域对象
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
NettyClientState toNettyClientState(NettyClientStateQueryListCommand nettyClientStateQueryListCommand);
/**
* describe 应用层删除入参转换成 领域对象
*
* @param nettyClientStateRemoveCommand 删除客户端状态对象参数
* @return {@link NettyClientState} 客户端状态领域对象
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
NettyClientState toNettyClientState(NettyClientStateRemoveCommand nettyClientStateRemoveCommand);
/**
* describe 持久层领域对象转换成DTO对象
*
* @param nettyClientState 客户端状态领域对象
* @return {@link NettyClientStateDTO} 客户端状态DTO对象
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
**/
NettyClientStateDTO fromNettyClientState(NettyClientState nettyClientState);
}

View File

@ -0,0 +1,82 @@
package wu.framework.middleground.on.cloud.heartbeat.server.domain.application.command.internal.network.penetration.mapping;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
/**
* describe 内网穿透映射
*
* @author Jia wei Wu
* @date 2023/12/29 05:21 下午
* @see com.wu.framework.inner.lazy.persistence.reverse.lazy.ddd.DefaultDDDLazyQueryListCommand
**/
@Data
@Accessors(chain = true)
@Schema(title = "internal_network_penetration_mapping_query_List_command",description = "内网穿透映射")
public class InternalNetworkPenetrationMappingQueryListCommand {
/**
*
* 客户端ID
*/
@Schema(description ="客户端ID",name ="clientId",example = "")
private String clientId;
/**
*
* 客户端目标地址
*/
@Schema(description ="客户端目标地址",name ="clientTargetIp",example = "")
private String clientTargetIp;
/**
*
* 客户端目标端口
*/
@Schema(description ="客户端目标端口",name ="clientTargetPort",example = "")
private Integer clientTargetPort;
/**
*
* 创建时间
*/
@Schema(description ="创建时间",name ="createTime",example = "")
private LocalDateTime createTime;
/**
*
* 主键自增
*/
@Schema(description ="主键自增",name ="id",example = "")
private Long id;
/**
*
* 是否删除 默认否
*/
@Schema(description ="是否删除 默认否",name ="isDeleted",example = "")
private Boolean isDeleted;
/**
*
* 修改时间
*/
@Schema(description ="修改时间",name ="updateTime",example = "")
private LocalDateTime updateTime;
/**
*
* 访问端口
*/
@Schema(description ="访问端口",name ="visitorPort",example = "")
private Integer visitorPort;
/**
*
* 描述
*/
@Schema(description ="描述",name ="describe",example = "")
private String describe;
}

View File

@ -0,0 +1,82 @@
package wu.framework.middleground.on.cloud.heartbeat.server.domain.application.command.internal.network.penetration.mapping;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
/**
* describe 内网穿透映射
*
* @author Jia wei Wu
* @date 2023/12/29 05:21 下午
* @see com.wu.framework.inner.lazy.persistence.reverse.lazy.ddd.DefaultDDDLazyQueryOneCommand
**/
@Data
@Accessors(chain = true)
@Schema(title = "internal_network_penetration_mapping_query_one_command",description = "内网穿透映射")
public class InternalNetworkPenetrationMappingQueryOneCommand {
/**
*
* 客户端ID
*/
@Schema(description ="客户端ID",name ="clientId",example = "")
private String clientId;
/**
*
* 客户端目标地址
*/
@Schema(description ="客户端目标地址",name ="clientTargetIp",example = "")
private String clientTargetIp;
/**
*
* 客户端目标端口
*/
@Schema(description ="客户端目标端口",name ="clientTargetPort",example = "")
private Integer clientTargetPort;
/**
*
* 创建时间
*/
@Schema(description ="创建时间",name ="createTime",example = "")
private LocalDateTime createTime;
/**
*
* 主键自增
*/
@Schema(description ="主键自增",name ="id",example = "")
private Long id;
/**
*
* 是否删除 默认否
*/
@Schema(description ="是否删除 默认否",name ="isDeleted",example = "")
private Boolean isDeleted;
/**
*
* 修改时间
*/
@Schema(description ="修改时间",name ="updateTime",example = "")
private LocalDateTime updateTime;
/**
*
* 访问端口
*/
@Schema(description ="访问端口",name ="visitorPort",example = "")
private Integer visitorPort;
/**
*
* 描述
*/
@Schema(description ="描述",name ="describe",example = "")
private String describe;
}

View File

@ -0,0 +1,82 @@
package wu.framework.middleground.on.cloud.heartbeat.server.domain.application.command.internal.network.penetration.mapping;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
/**
* describe 内网穿透映射
*
* @author Jia wei Wu
* @date 2023/12/29 05:21 下午
* @see com.wu.framework.inner.lazy.persistence.reverse.lazy.ddd.DefaultDDDLazyRemoveCommand
**/
@Data
@Accessors(chain = true)
@Schema(title = "internal_network_penetration_mapping_remove_command",description = "内网穿透映射")
public class InternalNetworkPenetrationMappingRemoveCommand {
/**
*
* 客户端ID
*/
@Schema(description ="客户端ID",name ="clientId",example = "")
private String clientId;
/**
*
* 客户端目标地址
*/
@Schema(description ="客户端目标地址",name ="clientTargetIp",example = "")
private String clientTargetIp;
/**
*
* 客户端目标端口
*/
@Schema(description ="客户端目标端口",name ="clientTargetPort",example = "")
private Integer clientTargetPort;
/**
*
* 创建时间
*/
@Schema(description ="创建时间",name ="createTime",example = "")
private LocalDateTime createTime;
/**
*
* 主键自增
*/
@Schema(description ="主键自增",name ="id",example = "")
private Long id;
/**
*
* 是否删除 默认否
*/
@Schema(description ="是否删除 默认否",name ="isDeleted",example = "")
private Boolean isDeleted;
/**
*
* 修改时间
*/
@Schema(description ="修改时间",name ="updateTime",example = "")
private LocalDateTime updateTime;
/**
*
* 访问端口
*/
@Schema(description ="访问端口",name ="visitorPort",example = "")
private Integer visitorPort;
/**
*
* 描述
*/
@Schema(description ="描述",name ="describe",example = "")
private String describe;
}

View File

@ -0,0 +1,82 @@
package wu.framework.middleground.on.cloud.heartbeat.server.domain.application.command.internal.network.penetration.mapping;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
/**
* describe 内网穿透映射
*
* @author Jia wei Wu
* @date 2023/12/29 05:21 下午
* @see com.wu.framework.inner.lazy.persistence.reverse.lazy.ddd.DefaultDDDLazyStoryCommand
**/
@Data
@Accessors(chain = true)
@Schema(title = "internal_network_penetration_mapping_story_command",description = "内网穿透映射")
public class InternalNetworkPenetrationMappingStoryCommand {
/**
*
* 客户端ID
*/
@Schema(description ="客户端ID",name ="clientId",example = "")
private String clientId;
/**
*
* 客户端目标地址
*/
@Schema(description ="客户端目标地址",name ="clientTargetIp",example = "")
private String clientTargetIp;
/**
*
* 客户端目标端口
*/
@Schema(description ="客户端目标端口",name ="clientTargetPort",example = "")
private Integer clientTargetPort;
/**
*
* 创建时间
*/
@Schema(description ="创建时间",name ="createTime",example = "")
private LocalDateTime createTime;
/**
*
* 主键自增
*/
@Schema(description ="主键自增",name ="id",example = "")
private Long id;
/**
*
* 是否删除 默认否
*/
@Schema(description ="是否删除 默认否",name ="isDeleted",example = "")
private Boolean isDeleted;
/**
*
* 修改时间
*/
@Schema(description ="修改时间",name ="updateTime",example = "")
private LocalDateTime updateTime;
/**
*
* 访问端口
*/
@Schema(description ="访问端口",name ="visitorPort",example = "")
private Integer visitorPort;
/**
*
* 描述
*/
@Schema(description ="描述",name ="describe",example = "")
private String describe;
}

View File

@ -0,0 +1,82 @@
package wu.framework.middleground.on.cloud.heartbeat.server.domain.application.command.internal.network.penetration.mapping;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
/**
* describe 内网穿透映射
*
* @author Jia wei Wu
* @date 2023/12/29 05:21 下午
* @see com.wu.framework.inner.lazy.persistence.reverse.lazy.ddd.DefaultDDDLazyUpdateCommand
**/
@Data
@Accessors(chain = true)
@Schema(title = "internal_network_penetration_mapping_update_command",description = "内网穿透映射")
public class InternalNetworkPenetrationMappingUpdateCommand {
/**
*
* 客户端ID
*/
@Schema(description ="客户端ID",name ="clientId",example = "")
private String clientId;
/**
*
* 客户端目标地址
*/
@Schema(description ="客户端目标地址",name ="clientTargetIp",example = "")
private String clientTargetIp;
/**
*
* 客户端目标端口
*/
@Schema(description ="客户端目标端口",name ="clientTargetPort",example = "")
private Integer clientTargetPort;
/**
*
* 创建时间
*/
@Schema(description ="创建时间",name ="createTime",example = "")
private LocalDateTime createTime;
/**
*
* 主键自增
*/
@Schema(description ="主键自增",name ="id",example = "")
private Long id;
/**
*
* 是否删除 默认否
*/
@Schema(description ="是否删除 默认否",name ="isDeleted",example = "")
private Boolean isDeleted;
/**
*
* 修改时间
*/
@Schema(description ="修改时间",name ="updateTime",example = "")
private LocalDateTime updateTime;
/**
*
* 访问端口
*/
@Schema(description ="访问端口",name ="visitorPort",example = "")
private Integer visitorPort;
/**
*
* 描述
*/
@Schema(description ="描述",name ="describe",example = "")
private String describe;
}

View File

@ -0,0 +1,56 @@
package wu.framework.middleground.on.cloud.heartbeat.server.domain.application.command.netty.client.blacklist;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
/**
* describe 客户端黑名单
*
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
* @see com.wu.framework.inner.lazy.persistence.reverse.lazy.ddd.DefaultDDDLazyQueryListCommand
**/
@Data
@Accessors(chain = true)
@Schema(title = "netty_client_blacklist_query_List_command",description = "客户端黑名单")
public class NettyClientBlacklistQueryListCommand {
/**
*
* 客户端ID
*/
@Schema(description ="客户端ID",name ="clientId",example = "")
private String clientId;
/**
*
* 创建时间
*/
@Schema(description ="创建时间",name ="createTime",example = "")
private LocalDateTime createTime;
/**
*
* 主键
*/
@Schema(description ="主键",name ="id",example = "")
private Long id;
/**
*
* 是否删除
*/
@Schema(description ="是否删除",name ="isDeleted",example = "")
private Boolean isDeleted;
/**
*
* 更新时间
*/
@Schema(description ="更新时间",name ="updateTime",example = "")
private LocalDateTime updateTime;
}

View File

@ -0,0 +1,56 @@
package wu.framework.middleground.on.cloud.heartbeat.server.domain.application.command.netty.client.blacklist;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
/**
* describe 客户端黑名单
*
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
* @see com.wu.framework.inner.lazy.persistence.reverse.lazy.ddd.DefaultDDDLazyQueryOneCommand
**/
@Data
@Accessors(chain = true)
@Schema(title = "netty_client_blacklist_query_one_command",description = "客户端黑名单")
public class NettyClientBlacklistQueryOneCommand {
/**
*
* 客户端ID
*/
@Schema(description ="客户端ID",name ="clientId",example = "")
private String clientId;
/**
*
* 创建时间
*/
@Schema(description ="创建时间",name ="createTime",example = "")
private LocalDateTime createTime;
/**
*
* 主键
*/
@Schema(description ="主键",name ="id",example = "")
private Long id;
/**
*
* 是否删除
*/
@Schema(description ="是否删除",name ="isDeleted",example = "")
private Boolean isDeleted;
/**
*
* 更新时间
*/
@Schema(description ="更新时间",name ="updateTime",example = "")
private LocalDateTime updateTime;
}

View File

@ -0,0 +1,56 @@
package wu.framework.middleground.on.cloud.heartbeat.server.domain.application.command.netty.client.blacklist;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
/**
* describe 客户端黑名单
*
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
* @see com.wu.framework.inner.lazy.persistence.reverse.lazy.ddd.DefaultDDDLazyRemoveCommand
**/
@Data
@Accessors(chain = true)
@Schema(title = "netty_client_blacklist_remove_command",description = "客户端黑名单")
public class NettyClientBlacklistRemoveCommand {
/**
*
* 客户端ID
*/
@Schema(description ="客户端ID",name ="clientId",example = "")
private String clientId;
/**
*
* 创建时间
*/
@Schema(description ="创建时间",name ="createTime",example = "")
private LocalDateTime createTime;
/**
*
* 主键
*/
@Schema(description ="主键",name ="id",example = "")
private Long id;
/**
*
* 是否删除
*/
@Schema(description ="是否删除",name ="isDeleted",example = "")
private Boolean isDeleted;
/**
*
* 更新时间
*/
@Schema(description ="更新时间",name ="updateTime",example = "")
private LocalDateTime updateTime;
}

View File

@ -0,0 +1,60 @@
package wu.framework.middleground.on.cloud.heartbeat.server.domain.application.command.netty.client.blacklist;
import com.wu.framework.response.mark.ValidType;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
/**
* describe 客户端黑名单
*
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
* @see com.wu.framework.inner.lazy.persistence.reverse.lazy.ddd.DefaultDDDLazyStoryCommand
**/
@Data
@Accessors(chain = true)
@Schema(title = "netty_client_blacklist_story_command",description = "客户端黑名单")
public class NettyClientBlacklistStoryCommand {
/**
*
* 客户端ID
*/
@NotNull(groups = ValidType.Create.class,message = "客户端ID不允许为空")
@Schema(description ="客户端ID",name ="clientId",example = "")
private String clientId;
/**
*
* 创建时间
*/
@Schema(description ="创建时间",name ="createTime",example = "")
private LocalDateTime createTime;
/**
*
* 主键
*/
@Schema(description ="主键",name ="id",example = "")
private Long id;
/**
*
* 是否删除
*/
@Schema(description ="是否删除",name ="isDeleted",example = "")
private Boolean isDeleted;
/**
*
* 更新时间
*/
@Schema(description ="更新时间",name ="updateTime",example = "")
private LocalDateTime updateTime;
}

View File

@ -0,0 +1,56 @@
package wu.framework.middleground.on.cloud.heartbeat.server.domain.application.command.netty.client.blacklist;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
/**
* describe 客户端黑名单
*
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
* @see com.wu.framework.inner.lazy.persistence.reverse.lazy.ddd.DefaultDDDLazyUpdateCommand
**/
@Data
@Accessors(chain = true)
@Schema(title = "netty_client_blacklist_update_command",description = "客户端黑名单")
public class NettyClientBlacklistUpdateCommand {
/**
*
* 客户端ID
*/
@Schema(description ="客户端ID",name ="clientId",example = "")
private String clientId;
/**
*
* 创建时间
*/
@Schema(description ="创建时间",name ="createTime",example = "")
private LocalDateTime createTime;
/**
*
* 主键
*/
@Schema(description ="主键",name ="id",example = "")
private Long id;
/**
*
* 是否删除
*/
@Schema(description ="是否删除",name ="isDeleted",example = "")
private Boolean isDeleted;
/**
*
* 更新时间
*/
@Schema(description ="更新时间",name ="updateTime",example = "")
private LocalDateTime updateTime;
}

View File

@ -0,0 +1,71 @@
package wu.framework.middleground.on.cloud.heartbeat.server.domain.application.command.netty.client.state;
import wu.framework.middleground.cloud.heartbeat.common.enums.NettyClientStatus;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
/**
* describe 客户端状态
*
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
* @see com.wu.framework.inner.lazy.persistence.reverse.lazy.ddd.DefaultDDDLazyQueryListCommand
**/
@Data
@Accessors(chain = true)
@Schema(title = "netty_client_state_query_List_command",description = "客户端状态")
public class NettyClientStateQueryListCommand {
/**
*
* 客户端ID
*/
@Schema(description ="客户端ID",name ="clientId",example = "")
private String clientId;
/**
*
* 创建时间
*/
@Schema(description ="创建时间",name ="createTime",example = "")
private LocalDateTime createTime;
/**
*
* 主键
*/
@Schema(description ="主键",name ="id",example = "")
private Long id;
/**
*
* 是否删除
*/
@Schema(description ="是否删除",name ="isDeleted",example = "")
private Boolean isDeleted;
/**
*
* 在线状态true在线false离线
*/
@Schema(description ="在线状态true在线false离线",name ="onLineState",example = "")
private NettyClientStatus onLineState;
/**
*
* 暂存状态开启关闭
*/
@Schema(description ="暂存状态(开启、关闭)",name ="staging",example = "")
private String stagingState;
/**
*
* 修改时间
*/
@Schema(description ="修改时间",name ="updateTime",example = "")
private LocalDateTime updateTime;
}

View File

@ -0,0 +1,71 @@
package wu.framework.middleground.on.cloud.heartbeat.server.domain.application.command.netty.client.state;
import wu.framework.middleground.cloud.heartbeat.common.enums.NettyClientStatus;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
/**
* describe 客户端状态
*
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
* @see com.wu.framework.inner.lazy.persistence.reverse.lazy.ddd.DefaultDDDLazyQueryOneCommand
**/
@Data
@Accessors(chain = true)
@Schema(title = "netty_client_state_query_one_command",description = "客户端状态")
public class NettyClientStateQueryOneCommand {
/**
*
* 客户端ID
*/
@Schema(description ="客户端ID",name ="clientId",example = "")
private String clientId;
/**
*
* 创建时间
*/
@Schema(description ="创建时间",name ="createTime",example = "")
private LocalDateTime createTime;
/**
*
* 主键
*/
@Schema(description ="主键",name ="id",example = "")
private Long id;
/**
*
* 是否删除
*/
@Schema(description ="是否删除",name ="isDeleted",example = "")
private Boolean isDeleted;
/**
*
* 在线状态true在线false离线
*/
@Schema(description ="在线状态true在线false离线",name ="onLineState",example = "")
private NettyClientStatus onLineState;
/**
*
* 暂存状态开启关闭
*/
@Schema(description ="暂存状态(开启、关闭)",name ="staging",example = "")
private String stagingState;
/**
*
* 修改时间
*/
@Schema(description ="修改时间",name ="updateTime",example = "")
private LocalDateTime updateTime;
}

View File

@ -0,0 +1,71 @@
package wu.framework.middleground.on.cloud.heartbeat.server.domain.application.command.netty.client.state;
import wu.framework.middleground.cloud.heartbeat.common.enums.NettyClientStatus;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
/**
* describe 客户端状态
*
* @author Jia wei Wu
* @date 2023/12/27 03:46 下午
* @see com.wu.framework.inner.lazy.persistence.reverse.lazy.ddd.DefaultDDDLazyRemoveCommand
**/
@Data
@Accessors(chain = true)
@Schema(title = "netty_client_state_remove_command",description = "客户端状态")
public class NettyClientStateRemoveCommand {
/**
*
* 客户端ID
*/
@Schema(description ="客户端ID",name ="clientId",example = "")
private String clientId;
/**
*
* 创建时间
*/
@Schema(description ="创建时间",name ="createTime",example = "")
private LocalDateTime createTime;
/**
*
* 主键
*/
@Schema(description ="主键",name ="id",example = "")
private Long id;
/**
*
* 是否删除
*/
@Schema(description ="是否删除",name ="isDeleted",example = "")
private Boolean isDeleted;
/**
*
* 在线状态true在线false离线
*/
@Schema(description ="在线状态true在线false离线",name ="onLineState",example = "")
private NettyClientStatus onLineState;
/**
*
* 暂存状态开启关闭
*/
@Schema(description ="暂存状态(开启、关闭)",name ="staging",example = "")
private String stagingState;
/**
*
* 修改时间
*/
@Schema(description ="修改时间",name ="updateTime",example = "")
private LocalDateTime updateTime;
}

Some files were not shown because too many files have changed in this diff Show More