初始化
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
package com.tongran.agent.client.netty;
|
||||
|
||||
import com.tongran.agent.client.netty.config.BaseNettyConfig;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Netty配置
|
||||
*/
|
||||
@Data
|
||||
@Configuration
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ConfigurationProperties(prefix = "tcp.netty.charge")
|
||||
public class AgentNettyConfig extends BaseNettyConfig {
|
||||
|
||||
private static final long serialVersionUID = -4284214721383107291L;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.tongran.agent.client.netty;
|
||||
|
||||
|
||||
import com.tongran.agent.client.netty.handler.AgentDecoderHandler;
|
||||
import com.tongran.agent.client.netty.handler.AgentDispatcherHandler;
|
||||
import com.tongran.agent.client.netty.handler.AgentEncoderHandler;
|
||||
import com.tongran.agent.client.netty.handler.TCPListenHandler;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.timeout.IdleStateHandler;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@Configuration
|
||||
public class AgentNettyServer extends BaseNettyServer {
|
||||
|
||||
@Resource
|
||||
private AgentNettyConfig config;
|
||||
|
||||
@Resource
|
||||
private TCPListenHandler tcpListenHandler;
|
||||
|
||||
@Resource
|
||||
private AgentDecoderHandler decoderHandler;
|
||||
|
||||
@Resource
|
||||
private AgentEncoderHandler encoderHandler;
|
||||
|
||||
@Resource
|
||||
private AgentDispatcherHandler dispatcherHandler;
|
||||
|
||||
|
||||
protected AgentNettyServer(AgentNettyConfig config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
@Bean(name = "NettyCharge", initMethod = "start", destroyMethod = "stop")
|
||||
BaseNettyServer run() {
|
||||
config.setHander(new ChannelInitializer<NioSocketChannel>() {
|
||||
@Override
|
||||
public void initChannel(NioSocketChannel ch) throws Exception {
|
||||
ch.pipeline().addLast(new IdleStateHandler(config.readerIdleTime, config.writerIdleTime, config.allIdleTime));// 心跳
|
||||
ch.pipeline().addLast(tcpListenHandler);// 监听器
|
||||
//入栈
|
||||
ch.pipeline().addLast(decoderHandler);//解码器
|
||||
//出栈
|
||||
ch.pipeline().addLast(encoderHandler);//加码器
|
||||
// 业务分发是入站最后一个处理器, 出站第一个处理器, 位置要放在最后
|
||||
ch.pipeline().addLast(businessGroup, dispatcherHandler);//业务分发 这里使用业务线程组
|
||||
}
|
||||
});
|
||||
return new AgentNettyServer(config);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package com.tongran.agent.client.netty;
|
||||
|
||||
import com.tongran.agent.client.netty.config.BaseNettyConfig;
|
||||
import com.tongran.agent.client.utils.AssertLog;
|
||||
import io.netty.bootstrap.AbstractBootstrap;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioChannelOption;
|
||||
import io.netty.channel.socket.nio.NioDatagramChannel;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.util.ResourceLeakDetector;
|
||||
import io.netty.util.concurrent.DefaultEventExecutorGroup;
|
||||
import io.netty.util.concurrent.DefaultThreadFactory;
|
||||
import io.netty.util.concurrent.EventExecutorGroup;
|
||||
import io.netty.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* 基础Netty服务
|
||||
*/
|
||||
public abstract class BaseNettyServer {
|
||||
|
||||
protected boolean isRunning;
|
||||
|
||||
protected BaseNettyConfig config;
|
||||
|
||||
protected EventLoopGroup bossGroup;
|
||||
|
||||
protected EventLoopGroup workerGroup;
|
||||
|
||||
protected EventExecutorGroup businessGroup;
|
||||
|
||||
protected BaseNettyServer(BaseNettyConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
protected AbstractBootstrap<?, ?> initializeTcp() {
|
||||
bossGroup = new NioEventLoopGroup(1, new DefaultThreadFactory(config.name, Thread.MAX_PRIORITY));
|
||||
workerGroup = new NioEventLoopGroup(config.workerCore, new DefaultThreadFactory(config.name, Thread.MAX_PRIORITY));
|
||||
if (config.businessCore > 0) {
|
||||
businessGroup = new DefaultEventExecutorGroup(config.businessCore);
|
||||
}
|
||||
ServerBootstrap serverBootstrap = new ServerBootstrap();
|
||||
serverBootstrap.group(bossGroup, workerGroup)
|
||||
.channel(NioServerSocketChannel.class)
|
||||
.childOption(ChannelOption.SO_REUSEADDR, true)
|
||||
.option(ChannelOption.SO_BACKLOG, 1024)
|
||||
.childOption(NioChannelOption.TCP_NODELAY, true)
|
||||
.childHandler(config.hander);
|
||||
//内存泄漏检测 开发推荐PARANOID 线上SIMPLE
|
||||
ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.SIMPLE);
|
||||
return serverBootstrap;
|
||||
}
|
||||
|
||||
protected AbstractBootstrap<?, ?> initializeUdp() {
|
||||
bossGroup = new NioEventLoopGroup(1, new DefaultThreadFactory(config.name, Thread.MAX_PRIORITY));
|
||||
if (config.businessCore > 0) {
|
||||
businessGroup = new DefaultEventExecutorGroup(config.businessCore);
|
||||
}
|
||||
return new Bootstrap()
|
||||
.group(bossGroup).channel(NioDatagramChannel.class)
|
||||
.option(NioChannelOption.SO_REUSEADDR, true)
|
||||
.option(NioChannelOption.SO_RCVBUF, 1024 * 1024 * 50)
|
||||
.handler(config.hander);
|
||||
}
|
||||
|
||||
public synchronized boolean start() {
|
||||
if (!config.enable) {
|
||||
return false;
|
||||
}
|
||||
if (isRunning) {
|
||||
AssertLog.info("======{}已经启动,port:{}======", config.name, config.port);
|
||||
return isRunning;
|
||||
}
|
||||
AbstractBootstrap<?, ?> bootstrap = config.isTcp ? initializeTcp() : initializeUdp();
|
||||
ChannelFuture future = bootstrap.bind(config.port).awaitUninterruptibly();
|
||||
future.channel().closeFuture().addListener(f -> {
|
||||
if (isRunning) {
|
||||
stop();
|
||||
}
|
||||
});
|
||||
if (future.cause() != null) {
|
||||
AssertLog.error("===启动失败===", future.cause());
|
||||
}
|
||||
if (isRunning = future.isSuccess()) {
|
||||
AssertLog.info("\n\n\t\t\t\t\t\t\t\t======{}启动成功,port:{}======\n", config.name, config.port);
|
||||
}
|
||||
return isRunning;
|
||||
}
|
||||
|
||||
public synchronized void stop() {
|
||||
if (!config.enable) {
|
||||
return;
|
||||
}
|
||||
isRunning = false;
|
||||
try {
|
||||
Future<?> future = this.workerGroup.shutdownGracefully().await();
|
||||
if (!future.isSuccess()) {
|
||||
AssertLog.error("workerGroup 无法正常停止:{}", future.cause());
|
||||
}
|
||||
future = this.bossGroup.shutdownGracefully().await();
|
||||
if (!future.isSuccess()) {
|
||||
AssertLog.error("bossGroup 无法正常停止:{}", future.cause());
|
||||
}
|
||||
future = this.businessGroup.shutdownGracefully().await();
|
||||
if (!future.isSuccess()) {
|
||||
AssertLog.error("businessGroup 无法正常停止:{}", future.cause());
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
AssertLog.info("\n\n\t\t\t\t\t\t\t\t======{} 已经停止,port:{}======\n", config.name, config.port);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.tongran.agent.client.netty.annotation;
|
||||
|
||||
import com.tongran.agent.client.core.enums.MsgEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 指明类为Agent消息
|
||||
*/
|
||||
@Component
|
||||
@Documented
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AgentDispatcher {
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
enum VersionEnum {
|
||||
V1("2026");
|
||||
public final String value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息ID
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
MsgEnum msgId();
|
||||
|
||||
/**
|
||||
* 消息版本 默认版本2025
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
VersionEnum version() default VersionEnum.V1;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String desc() default "";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.tongran.agent.client.netty.basics;
|
||||
|
||||
import com.tongran.agent.client.netty.annotation.AgentDispatcher;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Component
|
||||
@Order(1)
|
||||
public class AgentDispatcherManager implements ApplicationContextAware {
|
||||
|
||||
/**
|
||||
* 所有实现的包处理器
|
||||
*/
|
||||
private static Map<String, AgentHandler> MSG_HANDLER_MAP;
|
||||
|
||||
/**
|
||||
* 唤醒时 初始化 packHandlerMap
|
||||
*/
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
// 仅一次性初始化完成
|
||||
if (MSG_HANDLER_MAP == null) {
|
||||
MSG_HANDLER_MAP = new ConcurrentHashMap<>();
|
||||
Map<String, Object> handlers = applicationContext.getBeansWithAnnotation(AgentDispatcher.class);
|
||||
if (!CollectionUtils.isEmpty(handlers)) {
|
||||
handlers.values().forEach(tempHandler -> {
|
||||
boolean result = tempHandler.getClass().isAnnotationPresent(AgentDispatcher.class);
|
||||
if (result) {
|
||||
AgentDispatcher annotation = tempHandler.getClass().getAnnotation(AgentDispatcher.class);
|
||||
MSG_HANDLER_MAP.put(annotation.msgId().getValue() + "&" + annotation.version().value, (AgentHandler) tempHandler);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public AgentHandler getHandler(String msgIdVersion) {
|
||||
return MSG_HANDLER_MAP == null ? null : MSG_HANDLER_MAP.get(msgIdVersion);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.tongran.agent.client.netty.basics;
|
||||
|
||||
|
||||
import com.tongran.agent.client.netty.model.UpMsgResponse;
|
||||
|
||||
public interface AgentHandler {
|
||||
|
||||
/**
|
||||
* 处理终端传入的消息, 然后进行返回
|
||||
*
|
||||
* @return 需要发送给终端的消息
|
||||
*/
|
||||
|
||||
default UpMsgResponse upHandle(String data, String clientId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
default String downHandle(String data) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.tongran.agent.client.netty.config;
|
||||
|
||||
import com.tongran.agent.client.core.session.SessionManager;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.util.NettyRuntime;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 基础Netty配置
|
||||
*/
|
||||
@Data
|
||||
public class BaseNettyConfig implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -2736718499972710895L;
|
||||
|
||||
/**
|
||||
* 是否开启
|
||||
*/
|
||||
public Boolean enable = false;
|
||||
|
||||
/**
|
||||
* 是否TCP
|
||||
*/
|
||||
public Boolean isTcp = true;
|
||||
|
||||
/**
|
||||
* 服务名称
|
||||
*/
|
||||
public String name = "Netty";
|
||||
|
||||
/**
|
||||
* 端口号
|
||||
*/
|
||||
public Integer port = 11111;
|
||||
|
||||
public Integer workerCore = NettyRuntime.availableProcessors() * 2;
|
||||
|
||||
public Integer businessCore = Math.max(1, NettyRuntime.availableProcessors() >> 1);
|
||||
|
||||
public Integer readerIdleTime = 240;
|
||||
|
||||
public Integer writerIdleTime = 0;
|
||||
|
||||
public Integer allIdleTime = 0;
|
||||
|
||||
/**
|
||||
* netty Session管理
|
||||
*/
|
||||
public SessionManager sessionManager;
|
||||
|
||||
/**
|
||||
* netty Channel处理列表
|
||||
*/
|
||||
public ChannelHandler hander;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,484 @@
|
||||
package com.tongran.agent.client.netty.enpoint;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.alibaba.fastjson2.TypeReference;
|
||||
import com.tongran.agent.client.core.config.GlobalConfig;
|
||||
import com.tongran.agent.client.core.enums.MsgEnum;
|
||||
import com.tongran.agent.client.core.eo.AgentVersionUpdateEO;
|
||||
import com.tongran.agent.client.core.eo.ScriptPolicyEO;
|
||||
import com.tongran.agent.client.netty.annotation.AgentDispatcher;
|
||||
import com.tongran.agent.client.netty.basics.AgentHandler;
|
||||
import com.tongran.agent.client.netty.model.Message;
|
||||
import com.tongran.agent.client.netty.model.UpMsgResponse;
|
||||
import com.tongran.agent.client.scheduler.service.AdvancedAsyncDownloader;
|
||||
import com.tongran.agent.client.scheduler.service.AppInitializer;
|
||||
import com.tongran.agent.client.scheduler.service.AsyncCommandExecutor;
|
||||
import com.tongran.agent.client.scheduler.service.Java8FileDownloader;
|
||||
import com.tongran.agent.client.scheduler.task.SpecificTimeRequest;
|
||||
import com.tongran.agent.client.scheduler.task.SpecificTimeTaskService;
|
||||
import com.tongran.agent.client.service.AgentService;
|
||||
import com.tongran.agent.client.utils.AgentUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Component
|
||||
public class AgentEndpoint {
|
||||
|
||||
@Resource
|
||||
private AppInitializer appInitializer;
|
||||
|
||||
@Resource
|
||||
private SpecificTimeTaskService taskService;
|
||||
|
||||
@Resource
|
||||
private AgentService agentService;
|
||||
|
||||
|
||||
@AgentDispatcher(msgId = MsgEnum.注册)
|
||||
public class RegisterHandler implements AgentHandler {
|
||||
@Override
|
||||
public UpMsgResponse upHandle(String data, String clientId) {
|
||||
//更改全局变量
|
||||
JSONObject jsonObject = JSONObject.parseObject(data);
|
||||
if(jsonObject.containsKey("switchBoard")){
|
||||
String switchBoard = jsonObject.getString("switchBoard");
|
||||
jsonObject = JSONObject.parseObject(switchBoard);
|
||||
if(jsonObject.containsKey("community")){
|
||||
GlobalConfig.SWITCH_COMMUNITY = jsonObject.getString("community");
|
||||
}
|
||||
if(jsonObject.containsKey("ip")){
|
||||
GlobalConfig.SWITCH_IP = jsonObject.getString("ip");
|
||||
}
|
||||
if(jsonObject.containsKey("port")){
|
||||
GlobalConfig.SWITCH_PORT = jsonObject.getInteger("port");
|
||||
}
|
||||
if(jsonObject.containsKey("netOID")){
|
||||
String netOID = jsonObject.getString("netOID");
|
||||
LinkedHashMap<String, String> map = JSON.parseObject(netOID, new TypeReference<LinkedHashMap<String, String>>() {});
|
||||
GlobalConfig.SWITCH_NET_OID = map;
|
||||
}
|
||||
if(jsonObject.containsKey("moduleOID")){
|
||||
String moduleOID = jsonObject.getString("moduleOID");
|
||||
LinkedHashMap<String, String> map = JSON.parseObject(moduleOID, new TypeReference<LinkedHashMap<String, String>>() {});
|
||||
GlobalConfig.SWITCH_MODULE_OID = map;
|
||||
}
|
||||
if(jsonObject.containsKey("mpuOID")){
|
||||
String mpuOID = jsonObject.getString("mpuOID");
|
||||
LinkedHashMap<String, String> map = JSON.parseObject(mpuOID, new TypeReference<LinkedHashMap<String, String>>() {});
|
||||
GlobalConfig.SWITCH_MPU_OID = map;
|
||||
}
|
||||
if(jsonObject.containsKey("pwrOID")){
|
||||
String pwrOID = jsonObject.getString("pwrOID");
|
||||
LinkedHashMap<String, String> map = JSON.parseObject(pwrOID, new TypeReference<LinkedHashMap<String, String>>() {});
|
||||
GlobalConfig.SWITCH_PWR_OID = map;
|
||||
}
|
||||
if(jsonObject.containsKey("fanOID")){
|
||||
String fanOID = jsonObject.getString("fanOID");
|
||||
LinkedHashMap<String, String> map = JSON.parseObject(fanOID, new TypeReference<LinkedHashMap<String, String>>() {});
|
||||
GlobalConfig.SWITCH_FAN_OID = map;
|
||||
}
|
||||
if(jsonObject.containsKey("otherOID")){
|
||||
String otherOID = jsonObject.getString("otherOID");
|
||||
LinkedHashMap<String, String> map = JSON.parseObject(otherOID, new TypeReference<LinkedHashMap<String, String>>() {});
|
||||
GlobalConfig.SWITCH_OTHER_OID = map;
|
||||
}
|
||||
}
|
||||
GlobalConfig.isCollect = true;
|
||||
GlobalConfig.CLIENT_ID = clientId;
|
||||
//调用采集任务
|
||||
try {
|
||||
appInitializer.run();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
long timestamp = System.currentTimeMillis();
|
||||
timestamp = Math.round(timestamp / 1000.0);
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("resCode",1);
|
||||
json.put("resMag","");
|
||||
json.put("timestamp",timestamp);
|
||||
return UpMsgResponse.builder().clientId(clientId).dataType(MsgEnum.注册应答.getValue())
|
||||
.content(json.toString()).build();
|
||||
}
|
||||
}
|
||||
|
||||
@AgentDispatcher(msgId = MsgEnum.断开)
|
||||
public class DisconnectHandler implements AgentHandler {
|
||||
@Override
|
||||
public UpMsgResponse upHandle(String data, String clientId) {
|
||||
//更改全局变量
|
||||
GlobalConfig.isCollect = false;
|
||||
//调用采集任务
|
||||
try {
|
||||
appInitializer.run();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
long timestamp = System.currentTimeMillis();
|
||||
timestamp = Math.round(timestamp / 1000.0);
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("resCode",1);
|
||||
json.put("resMag","");
|
||||
json.put("timestamp",timestamp);
|
||||
return UpMsgResponse.builder().clientId(clientId).dataType(MsgEnum.断开应答.getValue())
|
||||
.content(json.toString()).build();
|
||||
}
|
||||
}
|
||||
|
||||
@AgentDispatcher(msgId = MsgEnum.开启系统采集)
|
||||
public class SysCollectStartHandler implements AgentHandler {
|
||||
@Override
|
||||
public UpMsgResponse upHandle(String data, String clientId) {
|
||||
//更改全局变量
|
||||
agentService.systemCollectStart(data);
|
||||
long timestamp = System.currentTimeMillis();
|
||||
timestamp = Math.round(timestamp / 1000.0);
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("resCode",1);
|
||||
json.put("resMag","");
|
||||
json.put("timestamp",timestamp);
|
||||
return UpMsgResponse.builder().dataType(MsgEnum.开启系统采集应答.getValue()).content(json.toString()).build();
|
||||
}
|
||||
}
|
||||
|
||||
@AgentDispatcher(msgId = MsgEnum.关闭系统采集)
|
||||
public class SysCollectStopHandler implements AgentHandler {
|
||||
@Override
|
||||
public UpMsgResponse upHandle(String data, String clientId) {
|
||||
//更改全局变量
|
||||
agentService.systemCollectStop();
|
||||
long timestamp = System.currentTimeMillis();
|
||||
timestamp = Math.round(timestamp / 1000.0);
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("resCode",1);
|
||||
json.put("resMag","");
|
||||
json.put("timestamp",timestamp);
|
||||
return UpMsgResponse.builder().dataType(MsgEnum.关闭系统采集应答.getValue()).content(json.toString()).build();
|
||||
}
|
||||
}
|
||||
|
||||
@AgentDispatcher(msgId = MsgEnum.开启交换机采集)
|
||||
public class SwitchCollectStartHandler implements AgentHandler {
|
||||
@Override
|
||||
public UpMsgResponse upHandle(String data, String clientId) {
|
||||
//更改全局变量
|
||||
agentService.switchCollectStart(data);
|
||||
long timestamp = System.currentTimeMillis();
|
||||
timestamp = Math.round(timestamp / 1000.0);
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("resCode",1);
|
||||
json.put("resMag","");
|
||||
json.put("timestamp",timestamp);
|
||||
return UpMsgResponse.builder().dataType(MsgEnum.开启交换机采集应答.getValue()).content(json.toString()).build();
|
||||
}
|
||||
}
|
||||
|
||||
@AgentDispatcher(msgId = MsgEnum.关闭交换机采集)
|
||||
public class SwitchCollectStopHandler implements AgentHandler {
|
||||
@Override
|
||||
public UpMsgResponse upHandle(String data, String clientId) {
|
||||
//更改全局变量
|
||||
agentService.switchCollectStop();
|
||||
long timestamp = System.currentTimeMillis();
|
||||
timestamp = Math.round(timestamp / 1000.0);
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("resCode",1);
|
||||
json.put("resMag","");
|
||||
json.put("timestamp",timestamp);
|
||||
return UpMsgResponse.builder().dataType(MsgEnum.关闭交换机采集应答.getValue()).content(json.toString()).build();
|
||||
}
|
||||
}
|
||||
|
||||
@AgentDispatcher(msgId = MsgEnum.告警设置)
|
||||
public class AlarmSetHandler implements AgentHandler {
|
||||
@Override
|
||||
public UpMsgResponse upHandle(String data, String clientId) {
|
||||
// //更改全局变量
|
||||
// JSONObject jsonObject = JSONObject.parseObject(data);
|
||||
// if(jsonObject.containsKey("switchBoard")){
|
||||
// String switchBoard = jsonObject.getString("switchBoard");
|
||||
// jsonObject = JSONObject.parseObject(switchBoard);
|
||||
// if(jsonObject.containsKey("community")){
|
||||
// GlobalConfig.SWITCH_COMMUNITY = jsonObject.getString("community");
|
||||
// }
|
||||
// if(jsonObject.containsKey("ip")){
|
||||
// GlobalConfig.SWITCH_IP = jsonObject.getString("ip");
|
||||
// }
|
||||
// if(jsonObject.containsKey("port")){
|
||||
// GlobalConfig.SWITCH_PORT = jsonObject.getInteger("port");
|
||||
// }
|
||||
// if(jsonObject.containsKey("netOID")){
|
||||
// String netOID = jsonObject.getString("netOID");
|
||||
// LinkedHashMap<String, String> map = JSON.parseObject(netOID, new TypeReference<LinkedHashMap<String, String>>() {});
|
||||
// GlobalConfig.SWITCH_NET_OID = map;
|
||||
// }
|
||||
// if(jsonObject.containsKey("moduleOID")){
|
||||
// String moduleOID = jsonObject.getString("moduleOID");
|
||||
// LinkedHashMap<String, String> map = JSON.parseObject(moduleOID, new TypeReference<LinkedHashMap<String, String>>() {});
|
||||
// GlobalConfig.SWITCH_MODULE_OID = map;
|
||||
// }
|
||||
// if(jsonObject.containsKey("mpuOID")){
|
||||
// String mpuOID = jsonObject.getString("mpuOID");
|
||||
// LinkedHashMap<String, String> map = JSON.parseObject(mpuOID, new TypeReference<LinkedHashMap<String, String>>() {});
|
||||
// GlobalConfig.SWITCH_MPU_OID = map;
|
||||
// }
|
||||
// if(jsonObject.containsKey("pwrOID")){
|
||||
// String pwrOID = jsonObject.getString("pwrOID");
|
||||
// LinkedHashMap<String, String> map = JSON.parseObject(pwrOID, new TypeReference<LinkedHashMap<String, String>>() {});
|
||||
// GlobalConfig.SWITCH_PWR_OID = map;
|
||||
// }
|
||||
// if(jsonObject.containsKey("fanOID")){
|
||||
// String fanOID = jsonObject.getString("fanOID");
|
||||
// LinkedHashMap<String, String> map = JSON.parseObject(fanOID, new TypeReference<LinkedHashMap<String, String>>() {});
|
||||
// GlobalConfig.SWITCH_FAN_OID = map;
|
||||
// }
|
||||
// if(jsonObject.containsKey("otherOID")){
|
||||
// String otherOID = jsonObject.getString("otherOID");
|
||||
// LinkedHashMap<String, String> map = JSON.parseObject(otherOID, new TypeReference<LinkedHashMap<String, String>>() {});
|
||||
// GlobalConfig.SWITCH_OTHER_OID = map;
|
||||
// }
|
||||
// }
|
||||
// GlobalConfig.isCollect = true;
|
||||
// GlobalConfig.CLIENT_ID = clientId;
|
||||
// //调用采集任务
|
||||
// try {
|
||||
// appInitializer.run();
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// JSONObject json = new JSONObject();
|
||||
// json.put("resCode",1);
|
||||
return UpMsgResponse.builder().clientId(clientId).dataType(MsgEnum.告警设置应答.getValue())
|
||||
.content("").build();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@AgentDispatcher(msgId = MsgEnum.执行脚本策略)
|
||||
public class ScriptPolicyHandler implements AgentHandler {
|
||||
@Override
|
||||
public UpMsgResponse upHandle(String data, String clientId) {
|
||||
ScriptPolicyEO policy = JSON.parseObject(data, ScriptPolicyEO.class);
|
||||
boolean isFalse = false;
|
||||
if(StringUtils.isNotBlank(policy.getFilePath())){
|
||||
if(AdvancedAsyncDownloader.createSingleDirectoryIfNotExists(policy.getFilePath())){
|
||||
if(CollectionUtil.isNotEmpty(policy.getFiles())){
|
||||
isFalse = true;
|
||||
for (ScriptPolicyEO.ScriptFile f : policy.getFiles()) {
|
||||
String finalSaveDir = policy.getFilePath();
|
||||
//文件类型:0、平台文件地址;1、外网HTTP(S)
|
||||
if(f.getFileType() == 0){
|
||||
String filePath = policy.getFilePath() + "/" + f.getFileName();
|
||||
// 移除Base64 URL前缀(如果存在)
|
||||
// if (f.getFileData().contains(",")) {
|
||||
// f.setFileData(f.getFileData().split(",")[1]);
|
||||
// }
|
||||
try {
|
||||
AgentUtil.base64ToFile(f.getFileData(), filePath);
|
||||
System.out.println("文件保存成功: " + filePath);
|
||||
isFalse = true;
|
||||
} catch (IOException e) {
|
||||
isFalse = false;
|
||||
System.err.println("文件保存失败: " + e.getMessage());
|
||||
}
|
||||
}else{
|
||||
Java8FileDownloader.DownloadResult result = Java8FileDownloader.downloadFile(f.getFileUrl(), finalSaveDir, f.getFileName());
|
||||
// 验证下载是否完成
|
||||
if (result.isSuccess()) {
|
||||
boolean isComplete = Java8FileDownloader.verifyFileCompletion(
|
||||
result.getFilePath(), result.getExpectedSize());
|
||||
if(isComplete){
|
||||
isFalse = true;
|
||||
System.out.println("下载完成: " + finalSaveDir+"/"+f.getFileName());
|
||||
}else{
|
||||
isFalse = false;
|
||||
System.err.println("下载失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//判断文件是否保存成功
|
||||
if(isFalse){
|
||||
if(CollectionUtil.isNotEmpty(policy.getCommands())){
|
||||
//执行方式:0、立即执行;1、定时执行;
|
||||
if(policy.getMethod() == 1){
|
||||
SpecificTimeRequest request = SpecificTimeRequest.builder()
|
||||
.taskId("")
|
||||
.taskName("")
|
||||
.taskData(policy.getCommands())
|
||||
.specificDateTime(policy.getPolicyTime())
|
||||
.clientId(clientId)
|
||||
.build();
|
||||
try {
|
||||
taskService.createSpecificTimeTask(request);
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("resCode",1);
|
||||
json.put("resMsg", "执行脚本策略定时任务保存成功");
|
||||
Message message = Message.builder().clientId(clientId).dataType(MsgEnum.执行脚本策略应答.getValue()).data(json.toString()).build();
|
||||
return UpMsgResponse.builder().clientId(clientId).dataType(MsgEnum.执行脚本策略应答.getValue()).content(json.toString()).build();
|
||||
} catch (Exception e) {
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("resCode",0);
|
||||
json.put("resMsg", "执行脚本策略定时任务保存失败");
|
||||
Message message = Message.builder().clientId(clientId).dataType(MsgEnum.执行脚本策略应答.getValue()).data(json.toString()).build();
|
||||
return UpMsgResponse.builder().clientId(clientId).dataType(MsgEnum.执行脚本策略应答.getValue()).content(json.toString()).build();
|
||||
}
|
||||
}else{
|
||||
List<Map<String,String>> list = new ArrayList<>();
|
||||
for (String command : policy.getCommands()) {
|
||||
Map<String,String> map = new HashMap<>();
|
||||
List<String> cmd = Arrays.asList(command.split("\\s+"));
|
||||
CompletableFuture<AsyncCommandExecutor.CommandResult> future =
|
||||
AsyncCommandExecutor.executeCommandAsync(
|
||||
cmd,
|
||||
60, TimeUnit.SECONDS);
|
||||
future.thenAccept(result -> {
|
||||
if (result.isSuccess()) {
|
||||
System.out.println("脚本执行成功");
|
||||
System.out.println("[成功resOut] " + result.getOutput());
|
||||
map.put("command",command);
|
||||
map.put("resOut",result.getOutput());
|
||||
} else {
|
||||
System.out.println("脚本执行失败");
|
||||
System.out.println("[失败resOut] " + result.getOutput());
|
||||
map.put("command",command);
|
||||
map.put("resOut",result.getOutput());
|
||||
}
|
||||
}).exceptionally(ex -> {
|
||||
System.err.println("执行失败: " + ex.getMessage());
|
||||
map.put("command",command);
|
||||
map.put("resOut","Policy execute filed");
|
||||
return null;
|
||||
});
|
||||
list.add(map);
|
||||
}
|
||||
if(CollectionUtil.isNotEmpty(list)){
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("resCode",1);
|
||||
json.put("resMsg", "");
|
||||
json.put("result", AgentUtil.toJsonString(list));
|
||||
return UpMsgResponse.builder().clientId(clientId).dataType(MsgEnum.执行脚本策略应答.getValue()).content(json.toString()).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("resCode",0);
|
||||
json.put("resMsg", "A执行脚本策略文件保存失败");
|
||||
return UpMsgResponse.builder().clientId(clientId).dataType(MsgEnum.执行脚本策略应答.getValue()).content(json.toString()).build();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@AgentDispatcher(msgId = MsgEnum.Agent版本更新)
|
||||
public class VersionUpdateHandler implements AgentHandler {
|
||||
@Override
|
||||
public UpMsgResponse upHandle(String data, String clientId) {
|
||||
AgentVersionUpdateEO versionUpdateEO = JSON.parseObject(data, AgentVersionUpdateEO.class);
|
||||
boolean isFalse = false;
|
||||
if(StringUtils.isNotBlank(versionUpdateEO.getFileUrl()) && StringUtils.isNotBlank(versionUpdateEO.getFilePath())){
|
||||
Java8FileDownloader.DownloadResult result = Java8FileDownloader.downloadFile(versionUpdateEO.getFileUrl(), versionUpdateEO.getFilePath(), "");
|
||||
// 验证下载是否完成
|
||||
if (result.isSuccess()) {
|
||||
boolean isComplete = Java8FileDownloader.verifyFileCompletion(
|
||||
result.getFilePath(), result.getExpectedSize());
|
||||
if(isComplete){
|
||||
isFalse = true;
|
||||
System.out.println("Agent版本更新下载完成");
|
||||
}else{
|
||||
isFalse = false;
|
||||
System.err.println("Agent版本更新下载失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
//判断文件是否保存成功
|
||||
if(isFalse){
|
||||
if(CollectionUtil.isNotEmpty(versionUpdateEO.getCommands())){
|
||||
//执行方式:0、立即执行;1、定时执行;
|
||||
if(versionUpdateEO.getMethod() == 1){
|
||||
SpecificTimeRequest request = SpecificTimeRequest.builder()
|
||||
.taskId("")
|
||||
.taskName("")
|
||||
.taskData(versionUpdateEO.getCommands())
|
||||
.specificDateTime(versionUpdateEO.getPolicyTime())
|
||||
.clientId(clientId)
|
||||
.dataType(MsgEnum.Agent版本更新应答.getValue())
|
||||
.build();
|
||||
try {
|
||||
taskService.createSpecificTimeTask(request);
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("resCode",1);
|
||||
json.put("resMsg", "Agent版本更新定时任务保存成功");
|
||||
// Message message = Message.builder().clientId(clientId).dataType(MsgEnum.Agent更新应答.getValue()).data(json.toString()).build();
|
||||
return UpMsgResponse.builder().clientId(clientId).dataType(MsgEnum.Agent版本更新应答.getValue()).content(json.toString()).build();
|
||||
} catch (Exception e) {
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("resCode",0);
|
||||
json.put("resMsg", "Agent版本更新定时任务保存失败");
|
||||
// Message message = Message.builder().clientId(clientId).dataType(MsgEnum.Agent更新应答.getValue()).data(json.toString()).build();
|
||||
return UpMsgResponse.builder().clientId(clientId).dataType(MsgEnum.Agent版本更新应答.getValue()).content(json.toString()).build();
|
||||
}
|
||||
}else{
|
||||
List<Map<String,String>> list = new ArrayList<>();
|
||||
for (String command : versionUpdateEO.getCommands()) {
|
||||
Map<String,String> map = new HashMap<>();
|
||||
List<String> cmd = Arrays.asList(command.split("\\s+"));
|
||||
CompletableFuture<AsyncCommandExecutor.CommandResult> future =
|
||||
AsyncCommandExecutor.executeCommandAsync(
|
||||
cmd,
|
||||
60, TimeUnit.SECONDS);
|
||||
future.thenAccept(result -> {
|
||||
if (result.isSuccess()) {
|
||||
System.out.println("脚本执行成功");
|
||||
System.out.println("[成功resOut] " + result.getOutput());
|
||||
map.put("command",command);
|
||||
map.put("resOut",result.getOutput());
|
||||
} else {
|
||||
System.out.println("脚本执行失败");
|
||||
System.out.println("[失败resOut] " + result.getOutput());
|
||||
map.put("command",command);
|
||||
map.put("resOut",result.getOutput());
|
||||
}
|
||||
}).exceptionally(ex -> {
|
||||
System.err.println("执行失败: " + ex.getMessage());
|
||||
map.put("command",command);
|
||||
map.put("resOut","Policy execute filed");
|
||||
return null;
|
||||
});
|
||||
list.add(map);
|
||||
}
|
||||
if(CollectionUtil.isNotEmpty(list)){
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("resCode",1);
|
||||
json.put("resMsg", "");
|
||||
json.put("result", AgentUtil.toJsonString(list));
|
||||
// Message message = Message.builder().clientId(clientId).dataType(MsgEnum.Agent版本更新应答.getValue()).data(json.toString()).build();
|
||||
return UpMsgResponse.builder().clientId(clientId).dataType(MsgEnum.Agent版本更新应答.getValue()).content(json.toString()).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("resCode",0);
|
||||
json.put("resMsg", "Agent版本更新文件保存失败");
|
||||
// Message message = Message.builder().clientId(clientId).dataType(MsgEnum.Agent版本更新应答.getValue()).data(json.toString()).build();
|
||||
return UpMsgResponse.builder().clientId(clientId).dataType(MsgEnum.Agent版本更新应答.getValue()).content(json.toString()).build();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package com.tongran.agent.client.netty.handler;
|
||||
|
||||
import cn.hutool.cache.Cache;
|
||||
import cn.hutool.cache.CacheUtil;
|
||||
import cn.hutool.core.date.DateUnit;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.tongran.agent.client.core.session.SessionManager;
|
||||
import com.tongran.agent.client.netty.annotation.AgentDispatcher;
|
||||
import com.tongran.agent.client.netty.basics.AgentDispatcherManager;
|
||||
import com.tongran.agent.client.netty.basics.AgentHandler;
|
||||
import com.tongran.agent.client.netty.model.Message;
|
||||
import com.tongran.agent.client.netty.model.UpMsgResponse;
|
||||
import com.tongran.agent.client.utils.AssertLog;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Objects;
|
||||
|
||||
@Component
|
||||
@ChannelHandler.Sharable
|
||||
public class AgentDecoderHandler extends ChannelInboundHandlerAdapter {
|
||||
|
||||
protected final SessionManager sessionManager;
|
||||
|
||||
@Resource
|
||||
private AgentDispatcherManager agentDispatcherManager;
|
||||
|
||||
public AgentDecoderHandler() {
|
||||
this.sessionManager = SessionManager.getInstance();
|
||||
}
|
||||
|
||||
// 用来临时保留没有处理过的请求报文
|
||||
private final Cache<String, String> lruCache = CacheUtil.newLRUCache(3000);
|
||||
|
||||
/**
|
||||
* 消息解码器
|
||||
*/
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) {
|
||||
// 检查是否为 ByteBuf(未解码的原始数据)
|
||||
if (msg instanceof ByteBuf) {
|
||||
ByteBuf byteBuf = (ByteBuf) msg;
|
||||
String messages = byteBuf.toString(CharsetUtil.UTF_8); // 指定字符集解码
|
||||
AssertLog.info("<<[up1]:IP:{},[up-content]==>{}", sessionManager.client(ctx),messages);
|
||||
|
||||
String content = "";
|
||||
boolean isClear = false;
|
||||
String tempMsg = lruCache.get(sessionManager.client(ctx));
|
||||
tempMsg = tempMsg == null ? "" : tempMsg;
|
||||
int tmpMsgSize = tempMsg.length();
|
||||
|
||||
boolean startsWith = messages.startsWith("agent-server:");
|
||||
boolean endsWith = messages.endsWith("@tong-ran");
|
||||
String ms = messages.replaceAll("agent-server:","");
|
||||
String[] arr_msg = ms.split("@tong-ran");
|
||||
if(startsWith){
|
||||
//判定是否整包
|
||||
if(arr_msg.length == 1){
|
||||
//判定是否拆包
|
||||
if(endsWith){
|
||||
lruCache.remove(sessionManager.client(ctx));
|
||||
tmpMsgSize = 0;
|
||||
content = arr_msg[0]+"@tong-ran";
|
||||
}else{
|
||||
lruCache.remove(sessionManager.client(ctx));
|
||||
tmpMsgSize = 0;
|
||||
content = arr_msg[0];
|
||||
lruCache.put(sessionManager.client(ctx), content, DateUnit.SECOND.getMillis() * 3000);
|
||||
}
|
||||
}
|
||||
//判定是否粘包
|
||||
if(arr_msg.length > 1){
|
||||
if(!endsWith){
|
||||
lruCache.remove(sessionManager.client(ctx));
|
||||
tmpMsgSize = 0;
|
||||
content = arr_msg[0]+"@tong-ran";
|
||||
lruCache.put(sessionManager.client(ctx), arr_msg[1], DateUnit.SECOND.getMillis() * 3000);
|
||||
}else{
|
||||
lruCache.remove(sessionManager.client(ctx));
|
||||
tmpMsgSize = 0;
|
||||
content = String.join("@tong-ran", arr_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tmpMsgSize > 0) {
|
||||
content = tempMsg + messages;
|
||||
endsWith = content.endsWith("@tong-ran");
|
||||
if(endsWith){
|
||||
isClear = true;
|
||||
}else{
|
||||
lruCache.remove(sessionManager.client(ctx));
|
||||
tmpMsgSize = 0;
|
||||
lruCache.put(sessionManager.client(ctx), content, DateUnit.SECOND.getMillis() * 3000);
|
||||
}
|
||||
|
||||
}
|
||||
AssertLog.info("<<[up2]:IP:{},[up-content]==>{}", sessionManager.client(ctx),content);
|
||||
endsWith = content.endsWith("@tong-ran");
|
||||
//判断是否是整包
|
||||
if(endsWith){
|
||||
String[] arr = content.split("@tong-ran");
|
||||
for (String message : arr) {
|
||||
JSONObject jsonObject = JSONObject.parseObject(message);
|
||||
String clientId = jsonObject.getString("clientId");
|
||||
String dataType = jsonObject.getString("dataType");
|
||||
AgentHandler msgHandler = agentDispatcherManager.getHandler(dataType + "&" + AgentDispatcher.VersionEnum.V1.value);
|
||||
if (ObjectUtil.isNotEmpty(msgHandler)) {
|
||||
UpMsgResponse response = msgHandler.upHandle(message, clientId );
|
||||
AssertLog.info("<<[up-after-handle]:clientId:{},type={},[handle-content]={}", response.getClientId(), dataType, message);
|
||||
if(Objects.nonNull(response)){
|
||||
Message agentMessage = Message.builder().build();
|
||||
agentMessage.setClientId(response.getClientId());
|
||||
agentMessage.setDataType(response.getDataType());
|
||||
agentMessage.setData(response.getContent());
|
||||
ctx.fireChannelRead(agentMessage);//传递到下一个handler
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isClear) {
|
||||
lruCache.remove(sessionManager.client(ctx));
|
||||
}
|
||||
byteBuf.release(); // 释放 ByteBuf 资源(重要!)
|
||||
} else {
|
||||
System.out.println("Unexpected message type: " + msg.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
//拆包
|
||||
public byte[] subByte(byte[] b, int off, int length) {
|
||||
byte[] bytes = new byte[length];
|
||||
System.arraycopy(b, off, bytes, 0, length);
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.tongran.agent.client.netty.handler;
|
||||
|
||||
import com.tongran.agent.client.core.session.Session;
|
||||
import com.tongran.agent.client.core.session.SessionManager;
|
||||
import com.tongran.agent.client.netty.model.Message;
|
||||
import com.tongran.agent.client.utils.AssertLog;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@ChannelHandler.Sharable
|
||||
public class AgentDispatcherHandler extends SimpleChannelInboundHandler<Message> {
|
||||
|
||||
protected final SessionManager sessionManager;
|
||||
|
||||
public AgentDispatcherHandler() {
|
||||
this.sessionManager = SessionManager.getInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, Message msg) {
|
||||
// AssertLog.info(">>>>>>[要处理的终端数据] {}", msg.toString());
|
||||
String clientId = msg.getClientId();
|
||||
if (StringUtils.isBlank(clientId)) {
|
||||
AssertLog.error("<<<<<<错误的信息from:{}", ctx.channel().remoteAddress());
|
||||
return;
|
||||
}
|
||||
Session session = Session.buildSession(ctx, clientId);
|
||||
sessionManager.put(clientId, session);
|
||||
if (StringUtils.isNotBlank(msg.getData())) {
|
||||
// AssertLog.info(">>>>>>[getSessionById的终端数据] {}", sessionManager.getSessionById(clientId));
|
||||
sessionManager.writeAndFlush(sessionManager.getSessionById(clientId).getChannel(), msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.tongran.agent.client.netty.handler;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.tongran.agent.client.core.session.SessionManager;
|
||||
import com.tongran.agent.client.netty.model.Message;
|
||||
import com.tongran.agent.client.utils.AssertLog;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelOutboundHandlerAdapter;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
@Component
|
||||
@ChannelHandler.Sharable
|
||||
public class AgentEncoderHandler extends ChannelOutboundHandlerAdapter {
|
||||
|
||||
protected final SessionManager sessionManager;
|
||||
|
||||
public AgentEncoderHandler() {
|
||||
this.sessionManager = SessionManager.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息解码器
|
||||
*/
|
||||
@Override
|
||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||
if (msg instanceof Message) {
|
||||
Message entity = (Message) msg;
|
||||
if (StringUtils.isBlank(entity.getData())) {
|
||||
AssertLog.error(">>[down]:IP:{},errorContent:{}", sessionManager.client(ctx), msg);
|
||||
return;
|
||||
}
|
||||
AssertLog.info(">>[down]:IP:{},[content]==>{}", sessionManager.client(ctx), entity.getData());
|
||||
// String json = JSON.toJSONString(entity);
|
||||
String json = "agent-client:"+ JSON.toJSONString(entity)+"@tong-ran";
|
||||
byte[] bytes = json.getBytes(StandardCharsets.UTF_8); // 显式指定 UTF-8
|
||||
// byte[] bytes = EscapeUtil.hexStringToByteArray(entity.getContent());
|
||||
ByteBuf buf = Unpooled.wrappedBuffer(bytes);
|
||||
ctx.write(buf, promise);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.tongran.agent.client.netty.handler;
|
||||
|
||||
import com.tongran.agent.client.core.config.GlobalConfig;
|
||||
import com.tongran.agent.client.core.session.SessionManager;
|
||||
import com.tongran.agent.client.scheduler.service.AppInitializer;
|
||||
import com.tongran.agent.client.utils.AssertLog;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.handler.timeout.IdleState;
|
||||
import io.netty.handler.timeout.IdleStateEvent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @Description: TCP消息适配器
|
||||
*/
|
||||
@Component
|
||||
@ChannelHandler.Sharable
|
||||
public class TCPListenHandler extends ChannelInboundHandlerAdapter {
|
||||
|
||||
@Resource
|
||||
private AppInitializer appInitializer;
|
||||
|
||||
private final SessionManager sessionManager;
|
||||
|
||||
public TCPListenHandler() {
|
||||
this.sessionManager = SessionManager.getInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) {
|
||||
AssertLog.info("<<<<<<[终端连接]{}", ctx.channel().remoteAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) {
|
||||
AssertLog.info(">>>>>>[断开连接]{}", sessionManager.client(ctx));
|
||||
sessionManager.remove(ctx.channel());
|
||||
try {
|
||||
GlobalConfig.isCollect = false;
|
||||
appInitializer.run();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) {
|
||||
if (e instanceof IOException) {
|
||||
AssertLog.info("<<<<<<[终端断开连接]{} {}", sessionManager.client(ctx), e.getMessage());
|
||||
} else {
|
||||
AssertLog.info(">>>>>>[消息处理异常]" + sessionManager.client(ctx), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
|
||||
if (evt instanceof IdleStateEvent) {
|
||||
IdleStateEvent event = (IdleStateEvent) evt;
|
||||
IdleState state = event.state();
|
||||
if (state == IdleState.READER_IDLE || state == IdleState.WRITER_IDLE || state == IdleState.ALL_IDLE) {
|
||||
AssertLog.warn(">>>>>>[终端心跳超时]{} {}", state, sessionManager.client(ctx));
|
||||
sessionManager.remove(ctx.channel());
|
||||
ctx.close();
|
||||
try {
|
||||
GlobalConfig.isCollect = false;
|
||||
appInitializer.run();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.tongran.agent.client.netty.handler;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.channel.socket.DatagramPacket;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @Description: UDP消息适配器
|
||||
*/
|
||||
@Component
|
||||
@ChannelHandler.Sharable
|
||||
public class UDPListenHandler extends ChannelInboundHandlerAdapter {
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) {
|
||||
DatagramPacket packet = (DatagramPacket) msg;
|
||||
ByteBuf buf = packet.content();
|
||||
buf.clear();// 暂未实现
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.tongran.agent.client.netty.model;
|
||||
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author egrias
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class Message implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -1267013167162440610L;
|
||||
|
||||
/**
|
||||
* clientId
|
||||
*/
|
||||
private String clientId;
|
||||
|
||||
/**
|
||||
* 数据类型:LOGIN、HEARTBEAT、CPU、MEMORY、SYSTEM、POINT、NET、DISK、DOCKER、SWITCHBOARD
|
||||
*/
|
||||
private String dataType;
|
||||
|
||||
/**
|
||||
* 发送内容
|
||||
*/
|
||||
private String data;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.tongran.agent.client.netty.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class UpMsgResponse {
|
||||
|
||||
|
||||
private String clientId;// 终端号
|
||||
|
||||
/**
|
||||
* type
|
||||
*/
|
||||
private String dataType;
|
||||
|
||||
private String content;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user