Commit bb6b50e3 by HlQ

[add] 服务器监控、服务监控添加,mqtt 回调地址添加

1 parent 2cd27500
Showing 32 changed files with 1482 additions and 0 deletions
package vion.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import vion.dto.AgentDTO;
import vion.model.RAgentService;
import vion.model.ServiceInfo;
import vion.service.IAgentService;
import vion.vo.AgentVO;
import java.util.List;
/**
* Agent
*/
@RestController
@RequestMapping("/api/agent")
@RequiredArgsConstructor
public class AgentController {
private final IAgentService agentService;
@GetMapping
@SaCheckPermission(value = "agent:list", orRole = "admin")
public Page<AgentVO> list(AgentDTO dto) {
return agentService.list(dto);
}
@GetMapping("/{id}")
@SaCheckPermission(value = "agent:query", orRole = "admin")
private AgentVO get(@PathVariable Long id) {
return agentService.getVOById(id);
}
@PostMapping("/{id}")
@SaCheckPermission(value = "agent:edit", orRole = "admin")
public String update(@PathVariable Long id, @RequestBody AgentDTO dto) {
dto.setId(id);
return agentService.update(dto);
}
@PostMapping("/upgrade/{id}")
@SaCheckPermission(value = "agent:upgrade", orRole = "admin")
public String upgradeCommand(@RequestBody AgentDTO dto) {
//todo
return "";
}
@GetMapping("/service/{uid}")
@SaCheckPermission(value = "agent:service:query", orRole = "admin")
public List<ServiceInfo> getServicesByUid(@PathVariable String uid) {
return agentService.getServicesByUid(uid);
}
@PostMapping("/service/{uid}")
@SaCheckPermission(value = "agent:service:save", orRole = "admin")
public String saveServicesByUid(@PathVariable String uid, @RequestBody List<ServiceInfo> serviceInfoList) {
return agentService.saveServicesByUid(uid, serviceInfoList);
}
@PostMapping("/service/{id}")
@SaCheckPermission(value = "agent:service:edit", orRole = "admin")
public String updateAgent2ServiceById(@PathVariable Long id, @RequestBody RAgentService rAgentService) {
return agentService.updateAgent2ServiceById(id, rAgentService);
}
@DeleteMapping("/service/{id}")
@SaCheckPermission(value = "agent:service:remove", orRole = "admin")
public String removeAgent2ServiceById(@PathVariable Long id) {
return agentService.removeAgent2ServiceById(id);
}
@PostMapping("/service/assign/{uid}")
@SaCheckPermission(value = "agent:service:assign", orRole = "admin")
public String assign(@PathVariable String uid, @RequestBody List<ServiceInfo> serviceInfoList) {
return agentService.assign(uid, serviceInfoList);
}
}
package vion.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.dromara.hutool.core.data.id.IdUtil;
import org.springframework.web.bind.annotation.*;
import vion.model.ServiceInfo;
import vion.service.IServiceInfoService;
/**
* 服务
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/service")
public class ServiceController {
private final IServiceInfoService serviceInfoService;
@GetMapping
@SaCheckPermission(value = "service:list", orRole = "admin")
public Page<ServiceInfo> list(ServiceInfo dto) {
return serviceInfoService.lambdaQuery(dto)
.orderByAsc(ServiceInfo::getCreateTime)
.orderByDesc(ServiceInfo::getUpdateTime)
.page(Page.of(dto.getPageNum(), dto.getPageSize()));
}
@GetMapping("/{id}")
@SaCheckPermission(value = "service:query", orRole = "admin")
public ServiceInfo get(@PathVariable Long id) {
return serviceInfoService.getById(id);
}
@PostMapping
@SaCheckPermission(value = "service:save", orRole = "admin")
public String save(@RequestBody ServiceInfo serviceInfo) {
serviceInfo.setUid(IdUtil.nanoId(16));
serviceInfoService.save(serviceInfo);
return "服务添加成功";
}
@PostMapping("/{id}")
@SaCheckPermission(value = "service:edit", orRole = "admin")
public String update(@PathVariable Long id, @RequestBody ServiceInfo serviceInfo) {
serviceInfo.setId(id);
serviceInfoService.updateById(serviceInfo);
return "服务更新成功";
}
@DeleteMapping("/{id}")
@SaCheckPermission(value = "service:remove", orRole = "admin")
public String remove(@PathVariable Long id) {
serviceInfoService.removeById(id);
return "服务删除成功";
}
}
package vion.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import vion.model.Upgrade;
import vion.service.IUpgradeService;
/**
* 升级包管理
*/
@RestController
@RequestMapping("/api/upgrade")
@RequiredArgsConstructor
public class UpgradeController {
private final IUpgradeService upgradeService;
@GetMapping
@SaCheckPermission(value = "upgrade:list", orRole = "admin")
public Page<Upgrade> list(Upgrade upgrade) {
return upgradeService.lambdaQuery(upgrade)
.orderByDesc(Upgrade::getBuildTime)
.page(Page.of(upgrade.getPageNum(), upgrade.getPageSize()));
}
@GetMapping("/{id}")
@SaCheckPermission(value = "upgrade:query", orRole = "admin")
public Upgrade get(@PathVariable Long id) {
return upgradeService.getById(id);
}
@PostMapping
@SaCheckPermission(value = "upgrade:save", orRole = "admin")
public String save(Upgrade upgrade) {
return upgradeService.saveAndFile(upgrade);
}
@PostMapping("/{id}")
@SaCheckPermission(value = "upgrade:edit", orRole = "admin")
public String update(@PathVariable Long id, Upgrade upgrade) {
upgrade.setId(id);
return upgradeService.update(upgrade);
}
@DeleteMapping("/{id}")
@SaCheckPermission(value = "upgrade:remove", orRole = "admin")
public String remove(@PathVariable Long id) {
return upgradeService.remove(id);
}
}
package vion.controller.mqtt;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import vion.model.Agent;
import vion.model.ServerInfo;
import vion.model.ServiceRecord;
import vion.model.Upgrade;
import vion.service.IAgentService;
import java.util.List;
/**
* @author vion
* @date 2024/10/16
*/
@RestController
@RequestMapping("/api/monitor")
@RequiredArgsConstructor
public class MonitorController {
private final IAgentService agentService;
@PostMapping("/reg")
public String reg(@RequestBody Agent agent) {
return agentService.reg(agent);
}
@GetMapping("/upgrade")
public Upgrade getUpgradeInfo(Short type) {
return agentService.getUpgradeInfo(type);
}
@PostMapping("/server")
public String recServerInfo(@RequestBody ServerInfo serverInfo) {
return agentService.recServerInfo(serverInfo);
}
@PostMapping("/service")
public String recServiceInfo(@RequestBody List<ServiceRecord> recList) {
return agentService.recServiceInfo(recList);
}
}
package vion.controller.mqtt;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import vion.dto.MqttAuthDTO;
import vion.service.IAgentService;
/**
* 与 mqtt server 交互调用的接口
*/
@Slf4j
@RestController
@RequestMapping("/api/mqtt")
@RequiredArgsConstructor
public class MqttController {
private final IAgentService agentService;
@PostMapping("/auth")
public ObjectNode auth(@RequestBody MqttAuthDTO dto) {
return agentService.auth(dto);
}
@PostMapping("/webhook/connected")
public void connected(@RequestBody JsonNode connectedInfo) {
agentService.connected(connectedInfo);
}
@PostMapping("/webhook/disconnect")
public void disconnect(@RequestBody JsonNode disconnectInfo) {
agentService.disconnect(disconnectInfo);
}
}
package vion.dto;
import lombok.Getter;
import lombok.Setter;
/**
* @author vion
* @date 2024/10/16
*/
@Getter
@Setter
public class AgentDTO extends BaseDTO {
private Long id;
/**
* 唯一id
*/
private String uid;
/**
* agent 版本号
*/
private String version;
/**
* 名称
*/
private String name;
/**
* 别名
*/
private String alias;
/**
* 主机名
*/
private String hostname;
/**
* 本地ip
*/
private String localIpaddr;
/**
* 公网ip
*/
private String ipaddr;
/**
* 归属地
*/
private String addr;
/**
* 0:离线 1:在线
*/
private Short status;
/**
* 备注
*/
private String remark;
}
\ No newline at end of file
package vion.dto;
import lombok.Getter;
import lombok.Setter;
/**
* @author vion
* @date 2024/10/15
*/
@Getter
@Setter
public class MqttAuthDTO {
private String clientid;
private String username;
private String password;
private String ipaddr;
private String topic;
private String prot;
}
package vion.mapper;
import com.github.yulichang.base.MPJBaseMapper;
import vion.model.Agent;
/**
* @author vion
* @date 2024/10/16
*/
public interface AgentMapper extends MPJBaseMapper<Agent> {
}
\ No newline at end of file
package vion.mapper;
import com.github.yulichang.base.MPJBaseMapper;
import vion.model.RAgentService;
/**
* @author vion
* @date 2024/10/22
*/
public interface RAgentServiceMapper extends MPJBaseMapper<RAgentService> {
}
\ No newline at end of file
package vion.mapper;
import com.github.yulichang.base.MPJBaseMapper;
import vion.model.ServerInfo;
/**
* @author vion
* @date 2024/10/21
*/
public interface ServerMapper extends MPJBaseMapper<ServerInfo> {
}
\ No newline at end of file
package vion.mapper;
import com.github.yulichang.base.MPJBaseMapper;
import vion.model.ServiceInfo;
/**
* @author vion
* @date 2024/10/22
*/
public interface ServiceInfoMapper extends MPJBaseMapper<ServiceInfo> {
}
\ No newline at end of file
package vion.mapper;
import com.github.yulichang.base.MPJBaseMapper;
import vion.model.ServiceRecord;
/**
* @author vion
* @date 2024/10/23
*/
public interface ServiceRecordMapper extends MPJBaseMapper<ServiceRecord> {
}
\ No newline at end of file
package vion.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import vion.model.Upgrade;
/**
* @author vion
* @date 2024/10/25
*/
public interface UpgradeMapper extends BaseMapper<Upgrade> {
}
\ No newline at end of file
package vion.model;
import com.baomidou.mybatisplus.annotation.*;
import io.github.linpeilie.annotations.AutoMapper;
import io.github.linpeilie.annotations.AutoMappers;
import lombok.Getter;
import lombok.Setter;
import vion.dto.AgentDTO;
import vion.vo.AgentVO;
import java.time.LocalDateTime;
/**
* @author vion
* @date 2024/10/16
*/
@Getter
@Setter
@TableName(value = "m_agent")
@AutoMappers({
@AutoMapper(target = AgentVO.class),
@AutoMapper(target = AgentDTO.class),
})
public class Agent {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 唯一id
*/
@TableField(value = "uid")
private String uid;
/**
* agent 版本号
*/
@TableField(value = "version")
private String version;
/**
* 用户名
*/
@TableField(value = "username")
private String username;
/**
* 密码
*/
@TableField(value = "password")
private String password;
/**
* 名称
*/
@TableField(value = "name", condition = SqlCondition.LIKE)
private String name;
/**
* 别名
*/
@TableField(value = "\"alias\"", condition = SqlCondition.LIKE)
private String alias;
/**
* 主机名
*/
@TableField(value = "hostname", condition = SqlCondition.LIKE)
private String hostname;
/**
* 本地ip
*/
@TableField(value = "local_ipaddr", condition = SqlCondition.LIKE)
private String localIpaddr;
/**
* 公网ip
*/
@TableField(value = "ipaddr", condition = SqlCondition.LIKE)
private String ipaddr;
/**
* 归属地
*/
@TableField(value = "addr", condition = SqlCondition.LIKE)
private String addr;
/**
* 0:离线 1:在线
*/
@TableField(value = "status")
private Short status;
/**
* 备注
*/
@TableField(value = "remark")
private String remark;
@TableField(value = "create_time", fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}
\ No newline at end of file
package vion.model;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalDateTime;
/**
* agent 和服务关联表
*/
@Getter
@Setter
@TableName(value = "mr_agent_service")
public class RAgentService {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@TableField(value = "agent_uid")
private String agentUid;
@TableField(value = "service_uid")
private String serviceUid;
/**
* 请求路径:http(s)://ip(:port)/path
*/
@TableField(value = "url")
private String url;
/**
* 请求方法
*/
@TableField(value = "\"method\"")
private String method;
/**
* 用户名
*/
@TableField(value = "username")
private String username;
/**
* 密码
*/
@TableField(value = "\"password\"")
private String password;
@TableField(value = "create_time", fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}
package vion.model;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Getter;
import lombok.Setter;
import vion.config.mp.JsonbTypeHandler;
import java.time.LocalDateTime;
/**
* 服务器信息
*/
@Getter
@Setter
@TableName(value = "m_server")
public class ServerInfo {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 唯一id
*/
@TableField(value = "uid")
private String uid;
/**
* 授权到期日期
*/
@TableField(value = "license_date")
private String licenseDate;
/**
* 操作系统
*/
@TableField(value = "os")
private String os;
/**
* 启动时间
*/
@TableField(value = "boot_time")
private LocalDateTime bootTime;
@TableField(exist = false)
private Long bootTimestamp;
/**
* 运行时间
*/
@TableField(value = "uptime")
private String uptime;
/**
* 时区
*/
@TableField(value = "\"offset\"")
private String offset;
/**
* 磁盘信息
*/
@TableField(value = "disk_info", typeHandler = JsonbTypeHandler.class)
private Object diskInfo;
/**
* 内存信息
*/
@TableField(value = "memory_info", typeHandler = JsonbTypeHandler.class)
private Object memoryInfo;
@TableField(value = "create_time", fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}
\ No newline at end of file
package vion.model;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Getter;
import lombok.Setter;
import vion.dto.BaseDTO;
import java.time.LocalDateTime;
/**
* 服务信息
*/
@Getter
@Setter
@TableName(value = "m_service")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ServiceInfo extends BaseDTO {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 唯一标识
*/
@TableField(value = "uid")
private String uid;
/**
* 名称
*/
@TableField(value = "name", condition = SqlCondition.LIKE)
private String name;
/**
* 请求路径:http(s)://ip(:port)/path
*/
@TableField(value = "url")
private String url;
/**
* 请求方法
*/
@TableField(value = "\"method\"")
private String method;
/**
* 监控类型:HTTP(s)
*/
@TableField(value = "\"type\"")
private String type;
/**
* 用户名
*/
@TableField(value = "username")
private String username;
/**
* 密码
*/
@TableField(value = "\"password\"")
private String password;
/**
* 描述
*/
@TableField(value = "description")
private String description;
@TableField(value = "create_time", fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}
\ No newline at end of file
package vion.model;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalDateTime;
/**
* 服务状态记录
*/
@Getter
@Setter
@TableName(value = "m_service_record")
public class ServiceRecord {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@TableField(value = "agent_uid")
private String agentUid;
@TableField(value = "service_uid")
private String serviceUid;
/**
* 服务名称
*/
@TableField(exist = false)
private String name;
/**
* 响应时长
*/
@TableField(value = "response_time")
private Long responseTime;
/**
* 状态
*/
@TableField(value = "\"status\"")
private Boolean status;
/**
* 监测时间
*/
@TableField(value = "monitor_time")
private LocalDateTime monitorTime;
@TableField(value = "create_time", fill = FieldFill.INSERT)
private LocalDateTime createTime;
}
\ No newline at end of file
package vion.model;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Getter;
import lombok.Setter;
import org.springframework.web.multipart.MultipartFile;
import vion.dto.BaseDTO;
import java.time.LocalDateTime;
/**
* 升级包信息
*/
@Getter
@Setter
@TableName(value = "m_upgrade")
public class Upgrade extends BaseDTO {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 名称
*/
@TableField(value = "name")
private String name;
/**
* 升级地址
*/
@TableField(value = "url")
private String url;
/**
* 版本号
*/
@TableField(value = "version")
private String version;
/**
* 升级包类型:1:store 2:mall
*/
@TableField(value = "\"type\"")
private Short type;
/**
* 打包时间,utc时间
*/
@TableField(value = "build_time")
private String buildTime;
/**
* sha256
*/
@TableField(value = "sha256")
private String sha256;
@TableField(value = "create_time", fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(exist = false)
public MultipartFile infile;
}
\ No newline at end of file
package vion.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.github.yulichang.base.MPJBaseService;
import org.springframework.web.bind.annotation.RequestBody;
import vion.dto.AgentDTO;
import vion.dto.MqttAuthDTO;
import vion.model.*;
import vion.vo.AgentVO;
import java.util.List;
/**
* @author vion
* @date 2024/10/16
*/
public interface IAgentService extends MPJBaseService<Agent> {
Page<AgentVO> list(AgentDTO dto);
AgentVO getVOById(Long id);
String update(AgentDTO dto);
List<ServiceInfo> getServicesByUid(String uid);
String saveServicesByUid(String uid, @RequestBody List<ServiceInfo> ServiceInfoList);
String updateAgent2ServiceById(Long id, RAgentService rAgentService);
String removeAgent2ServiceById(Long id);
String assign(String uid, List<ServiceInfo> serviceInfoList);
// region Agent 主动发送信息
String reg(Agent agent);
Upgrade getUpgradeInfo(Short type);
String recServerInfo(ServerInfo serverInfo);
String recServiceInfo(List<ServiceRecord> recList);
// endregion
// region Mqtt Server 回调接口
ObjectNode auth(MqttAuthDTO dto);
void connected(JsonNode connectedInfo);
void disconnect(JsonNode disconnectInfo);
// endregion
}
package vion.service;
import com.github.yulichang.base.MPJBaseService;
import vion.model.RAgentService;
/**
* @author vion
* @date 2024/10/22
*/
public interface IRAgentServiceService extends MPJBaseService<RAgentService> {
}
package vion.service;
import com.github.yulichang.base.MPJBaseService;
import vion.model.ServerInfo;
/**
* @author vion
* @date 2024/10/21
*/
public interface IServerService extends MPJBaseService<ServerInfo> {
}
\ No newline at end of file
package vion.service;
import com.github.yulichang.base.MPJBaseService;
import vion.model.ServiceInfo;
/**
* @author vion
* @date 2024/10/22
*/
public interface IServiceInfoService extends MPJBaseService<ServiceInfo> {
}
package vion.service;
import com.github.yulichang.base.MPJBaseService;
import vion.model.ServiceRecord;
/**
* @author vion
* @date 2024/10/23
*/
public interface IServiceRecordService extends MPJBaseService<ServiceRecord> {
}
package vion.service;
import com.baomidou.mybatisplus.extension.service.IService;
import vion.model.Upgrade;
/**
* @author vion
* @date 2024/10/25
*/
public interface IUpgradeService extends IService<Upgrade> {
String saveAndFile(Upgrade upgrade);
String update(Upgrade upgrade);
String remove(Long id);
}
package vion.service.impl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.iot.mqtt.codec.MqttQoS;
import net.dreamlu.iot.mqtt.spring.client.MqttClientTemplate;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.date.TimeUtil;
import org.dromara.hutool.core.lang.Opt;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.text.split.SplitUtil;
import org.dromara.hutool.core.util.ByteUtil;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.core.util.RandomUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vion.dto.AgentDTO;
import vion.dto.MqttAuthDTO;
import vion.mapper.AgentMapper;
import vion.model.*;
import vion.service.*;
import vion.utils.JsonUtil;
import vion.vo.AgentVO;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author vion
* @date 2024/10/16
*/
@Service
@Slf4j
@RequiredArgsConstructor
public class AgentServiceImpl extends MPJBaseServiceImpl<AgentMapper, Agent> implements IAgentService {
private final IServerService serverService;
private final IServiceInfoService serviceInfoService;
private final IServiceRecordService serviceRecordService;
private final IRAgentServiceService rAgentServiceService;
private final IUpgradeService upgradeService;
private final Converter converter;
private final MqttClientTemplate client;
@Override
public Page<AgentVO> list(AgentDTO dto) {
var wrapper = new MPJLambdaWrapper<>(converter.convert(dto, Agent.class))
.selectAll(Agent.class)
.selectAssociation(ServerInfo.class, AgentVO::getServerInfo)
.leftJoin(ServerInfo.class, ServerInfo::getUid, Agent::getUid)
.orderByAsc(Agent::getCreateTime);
var agentVOPage = this.selectJoinListPage(Page.of(dto.getPageNum(), dto.getPageSize()), AgentVO.class, wrapper);
Opt.ofEmptyAble(agentVOPage.getRecords())
.ifPresent(r -> {
var agentUidList = r.stream().map(AgentVO::getUid).toList();
var serviceRecordWrapper = new MPJLambdaWrapper<ServiceRecord>()
.select("DISTINCT on (agent_uid, service_uid) t.*")
.selectAs("si", ServiceInfo::getName, ServiceRecord::getName)
.leftJoin(ServiceInfo.class, "si", ServiceInfo::getUid, "t", ServiceRecord::getServiceUid)
.in(ServiceRecord::getAgentUid, agentUidList)
.eq(ServiceRecord::getStatus, false)
.orderByDesc(ServiceRecord::getAgentUid, ServiceRecord::getServiceUid, ServiceRecord::getMonitorTime);
var serviceRecordList = serviceRecordService.selectJoinList(ServiceRecord.class, serviceRecordWrapper);
var serviceNameMap = serviceRecordList.stream().collect(Collectors.groupingBy(ServiceRecord::getAgentUid, Collectors.mapping(ServiceRecord::getName, Collectors.joining(","))));
r.forEach(a -> a.setServiceName(serviceNameMap.get(a.getUid())));
});
return agentVOPage;
}
@Override
public AgentVO getVOById(Long id) {
var wrapper = new MPJLambdaWrapper<Agent>()
.selectAll(Agent.class)
.selectAsClass(ServiceInfo.class, AgentVO.class)
.leftJoin(ServiceInfo.class, ServiceInfo::getUid, Agent::getUid)
.eq(Agent::getId, id)
.orderByAsc(Agent::getCreateTime);
return this.selectJoinOne(AgentVO.class, wrapper);
}
@Override
public String update(AgentDTO dto) {
var agent = converter.convert(dto, Agent.class);
return this.updateById(agent) ? "更新成功" : "更新失败";
}
@Override
public List<ServiceInfo> getServicesByUid(String uid) {
var wrapper = new MPJLambdaWrapper<ServiceInfo>()
.selectAs(RAgentService::getId, ServiceInfo::getId)
.selectAs(ServiceInfo::getUid, ServiceInfo::getUid)
.selectAs(ServiceInfo::getName, ServiceInfo::getName)
.selectAs(ServiceInfo::getType, ServiceInfo::getType)
.selectAs(RAgentService::getUrl, ServiceInfo::getUrl)
.selectAs(RAgentService::getMethod, ServiceInfo::getMethod)
.selectAs(RAgentService::getUsername, ServiceInfo::getUsername)
.selectAs(RAgentService::getPassword, ServiceInfo::getPassword)
.selectAs(ServiceInfo::getDescription, ServiceInfo::getDescription)
.selectAs(RAgentService::getCreateTime, ServiceInfo::getCreateTime)
.selectAs(RAgentService::getUpdateTime, ServiceInfo::getUpdateTime)
.leftJoin(RAgentService.class, RAgentService::getServiceUid, ServiceInfo::getUid)
.eq(RAgentService::getAgentUid, uid)
.orderByAsc(ServiceInfo::getCreateTime);
var serviceInfoList = serviceInfoService.selectJoinList(ServiceInfo.class, wrapper);
return serviceInfoList;
}
@Override
@Transactional(rollbackFor = Exception.class)
public String saveServicesByUid(String uid, List<ServiceInfo> serviceInfoList) {
if (CollUtil.isNotEmpty(serviceInfoList)) {
var rAgentServiceList = serviceInfoList.stream().map(s -> {
var rAgentService = new RAgentService();
rAgentService.setAgentUid(uid);
rAgentService.setServiceUid(s.getUid());
rAgentService.setUrl(s.getUrl());
rAgentService.setMethod(s.getMethod());
rAgentService.setUsername(s.getUsername());
rAgentService.setPassword(s.getPassword());
return rAgentService;
}).toList();
rAgentServiceService.saveBatch(rAgentServiceList);
}
return "更新成功";
}
@Override
public String updateAgent2ServiceById(Long id, RAgentService rAgentService) {
return rAgentServiceService.updateById(rAgentService) ? "更新成功" : "更新失败";
}
@Override
public String removeAgent2ServiceById(Long id) {
return rAgentServiceService.removeById(id) ? "删除成功 : " : "删除失败";
}
@Override
public String assign(String uid, List<ServiceInfo> serviceInfoList) {
var servicesJson = JsonUtil.toJsonString(serviceInfoList);
String SERVICE_PUSH_TOPIC = "/SA/{}/service/push";
return client.publish(StrUtil.format(SERVICE_PUSH_TOPIC, uid), ByteUtil.toBytes(servicesJson, StandardCharsets.UTF_8), MqttQoS.QOS2) ? "服务列表下发成功" : "服务列表下发失败";
}
@Override
public String reg(Agent agent) {
agent.setStatus((short) 1);
if (StrUtil.isBlank(agent.getUid())) {
return "注册失败,Agent 唯一标识为空";
}
var one = this.lambdaQuery().eq(Agent::getUid, agent.getUid()).one();
if (ObjUtil.isNull(one)) {
agent.setUsername(RandomUtil.randomString(agent.getUid(), 8));
agent.setPassword(RandomUtil.randomString(12));
this.save(agent);
} else {
this.lambdaUpdate().eq(Agent::getUid, agent.getUid()).update(agent);
agent = one;
}
log.info("Agent 注册成功. clientid:{}, username:{}", agent.getUid(), agent.getUsername());
var wrapper = new MPJLambdaWrapper<ServiceInfo>()
.selectAs(ServiceInfo::getUid, ServiceInfo::getUid)
.selectAs(ServiceInfo::getName, ServiceInfo::getName)
.selectAs(ServiceInfo::getType, ServiceInfo::getType)
.selectAs(RAgentService::getUrl, ServiceInfo::getUrl)
.selectAs(RAgentService::getMethod, ServiceInfo::getMethod)
.selectAs(RAgentService::getUsername, ServiceInfo::getUsername)
.selectAs(RAgentService::getPassword, ServiceInfo::getPassword)
.leftJoin(RAgentService.class, RAgentService::getServiceUid, ServiceInfo::getUid)
.eq(RAgentService::getAgentUid, agent.getUid())
.orderByAsc(ServiceInfo::getCreateTime);
var serviceList = serviceInfoService.selectJoinList(ServiceInfo.class, wrapper);
return JsonUtil.createObj()
.put("clientid", agent.getUid())
.put("username", agent.getUsername())
.put("password", agent.getPassword())
.putPOJO("serviceList", serviceList)
.toString();
}
@Override
public Upgrade getUpgradeInfo(Short type) {
return upgradeService.lambdaQuery()
.eq(Upgrade::getType, type)
.orderByDesc(Upgrade::getBuildTime)
.last("limit 1")
.one();
}
@Override
public String recServerInfo(ServerInfo serverInfo) {
serverInfo.setBootTime(TimeUtil.of(serverInfo.getBootTimestamp() * 1000));
var one = serverService.lambdaQuery().eq(ServerInfo::getUid, serverInfo.getUid()).oneOpt();
if (one.isPresent()) {
return serverService.lambdaUpdate().eq(ServerInfo::getUid, serverInfo.getUid()).update(serverInfo) ? "success" : "error";
} else {
return serverService.save(serverInfo) ? "success" : "error";
}
}
@Override
public String recServiceInfo(List<ServiceRecord> recList) {
return serviceRecordService.saveBatch(recList) ? "success" : "error";
}
@Override
public ObjectNode auth(MqttAuthDTO dto) {
var clientid = dto.getClientid();
if (StrUtil.equals(clientid, "MS8011")) {
log.info("Monitor Server 认证成功. clientid: {}", dto.getClientid());
return JsonUtil.createObj().put("result", "allow")
.putPOJO("acl", JsonUtil.createArr()
.addPOJO(JsonUtil.createObj()
.put("action", "all")
.put("permission", "allow")
.put("topic", "#")));
}
var username = dto.getUsername();
var password = dto.getPassword();
var agent = this.lambdaQuery().eq(Agent::getUid, clientid)
.eq(Agent::getUsername, username)
.eq(Agent::getPassword, password)
.oneOpt();
if (agent.isEmpty()) {
log.info("Agent 认证成失败: {}", dto.getClientid());
return JsonUtil.createObj().put("result", "deny");
}
var obj = JsonUtil.createObj();
obj.put("result", "allow")
// todo expire_at 用法暂不清楚
// obj.put("expire_at", Instant.now().getEpochSecond() + 15);
.put("superuser", false)
.putPOJO("acl", JsonUtil.createArr()
.addPOJO(JsonUtil.createObj()
.put("action", "all")
.put("permission", "allow")
.put("topic", "#")));
log.info("Agent 认证成功. clientid: {}", dto.getClientid());
return obj;
}
@Override
public void connected(JsonNode connectedInfo) {
var clientid = connectedInfo.path("clientid").asText();
var ipaddr = connectedInfo.path("ipaddress").asText();
var ip = SplitUtil.split(ipaddr, ":").getFirst();
if (StrUtil.equals(clientid, "MS8011")) {
log.info("Monitor Server 连接 Mqtt Server 成功. clientid:{}, ip:{}", clientid, ip);
return;
}
this.lambdaUpdate().set(Agent::getStatus, 1).set(Agent::getIpaddr, ip).eq(Agent::getUid, clientid).update(new Agent());
log.info("Agent 连接 Mqtt Server 成功. clientid:{}, ip:{}", clientid, ip);
}
@Override
public void disconnect(JsonNode disconnectInfo) {
var clientid = disconnectInfo.path("clientid").asText();
var ipaddr = disconnectInfo.path("ipaddress").asText();
if (StrUtil.equals(clientid, "MS8011")) {
log.info("Monitor Server 断开连接 Mqtt Server 成功. clientid:{}", clientid);
return;
}
this.lambdaUpdate().set(Agent::getStatus, 0).eq(Agent::getUid, clientid).update();
log.info("Agent 断开连接 Mqtt Server. clientid:{}, ip:{}", clientid, ipaddr);
}
}
package vion.service.impl;
import com.github.yulichang.base.MPJBaseServiceImpl;
import org.springframework.stereotype.Service;
import vion.mapper.RAgentServiceMapper;
import vion.model.RAgentService;
import vion.service.IRAgentServiceService;
/**
* @author vion
* @date 2024/10/22
*/
@Service
public class RAgentServiceServiceImpl extends MPJBaseServiceImpl<RAgentServiceMapper, RAgentService> implements IRAgentServiceService {
}
package vion.service.impl;
import com.github.yulichang.base.MPJBaseServiceImpl;
import org.springframework.stereotype.Service;
import vion.mapper.ServerMapper;
import vion.model.ServerInfo;
import vion.service.IServerService;
/**
* @author vion
* @date 2024/10/21
*/
@Service
public class ServerServiceImpl extends MPJBaseServiceImpl<ServerMapper, ServerInfo> implements IServerService {
}
package vion.service.impl;
import com.github.yulichang.base.MPJBaseServiceImpl;
import org.springframework.stereotype.Service;
import vion.mapper.ServiceInfoMapper;
import vion.model.ServiceInfo;
import vion.service.IServiceInfoService;
/**
* @author vion
* @date 2024/10/22
*/
@Service
public class ServiceInfoServiceImpl extends MPJBaseServiceImpl<ServiceInfoMapper, ServiceInfo> implements IServiceInfoService {
}
package vion.service.impl;
import com.github.yulichang.base.MPJBaseServiceImpl;
import org.springframework.stereotype.Service;
import vion.mapper.ServiceRecordMapper;
import vion.model.ServiceRecord;
import vion.service.IServiceRecordService;
/**
* @author vion
* @date 2024/10/23
*/
@Service
public class ServiceRecordServiceImpl extends MPJBaseServiceImpl<ServiceRecordMapper, ServiceRecord> implements IServiceRecordService {
}
package vion.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.dromara.hutool.core.io.ManifestUtil;
import org.dromara.hutool.core.io.file.FileTypeUtil;
import org.dromara.hutool.core.io.file.FileUtil;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.lang.Opt;
import org.dromara.hutool.crypto.SecureUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import vion.mapper.UpgradeMapper;
import vion.model.Upgrade;
import vion.service.IUpgradeService;
import java.io.File;
import java.io.IOException;
import java.util.jar.Attributes;
/**
* @author vion
* @date 2024/10/25
*/
@Service
public class UpgradeServiceImpl extends ServiceImpl<UpgradeMapper, Upgrade> implements IUpgradeService {
@Value("${fileUrl:}")
private String fileUrl;
@Override
public String saveAndFile(Upgrade upgrade) {
try {
var infile = upgrade.getInfile();
Assert.notNull(infile, "升级包不能为空");
var type = FileTypeUtil.getType(infile.getInputStream());
Assert.notEquals(type, "jar", "上传的升级包类型不是jar");
// todo 测试文件保存
String path = fileUrl + FileUtil.FILE_SEPARATOR
+ "agent" + FileUtil.FILE_SEPARATOR
+ upgrade.getVersion() + FileUtil.FILE_SEPARATOR
+ infile.getOriginalFilename();
File file = FileUtil.touch(path);
infile.transferTo(file);
upgrade.setSha256(SecureUtil.sha256(file));
upgrade.setUrl(path);
var manifest = ManifestUtil.getManifest(file);
var version = manifest.getMainAttributes().getValue(Attributes.Name.IMPLEMENTATION_VERSION);
Assert.equals(version, upgrade.getVersion(), "升级包版本号不一致");
var name = manifest.getMainAttributes().getValue(Attributes.Name.IMPLEMENTATION_TITLE);
Assert.equals(version, upgrade.getName(), "升级包名称不一致");
upgrade.setVersion(version);
// 打包时间为 utc 时间
var buildTime = manifest.getMainAttributes().getValue("Build-Timestamp");
upgrade.setBuildTime(buildTime);
this.save(upgrade);
return "升级包添加成功";
} catch (IOException e) {
log.error("升级包保存出错");
}
return "升级包添加失败";
}
@Override
public String update(Upgrade upgrade) {
Opt.ofNullable(upgrade.getInfile())
.ifPresent(infile -> {
String path = fileUrl + FileUtil.FILE_SEPARATOR
+ "agent" + FileUtil.FILE_SEPARATOR
+ upgrade.getVersion() + FileUtil.FILE_SEPARATOR
+ infile.getOriginalFilename();
File file = FileUtil.touch(path);
infile.transferTo(file);
upgrade.setSha256(SecureUtil.sha256(file));
upgrade.setUrl(path);
var manifest = ManifestUtil.getManifest(file);
var version = manifest.getMainAttributes().getValue(Attributes.Name.IMPLEMENTATION_VERSION);
Assert.equals(version, upgrade.getVersion(), "版本号不一致");
upgrade.setVersion(version);
// 打包时间为 utc 时间
var buildTime = manifest.getMainAttributes().getValue("Build-Timestamp");
upgrade.setBuildTime(buildTime);
});
return this.updateById(upgrade) ? "升级包更新成功" : "升级包更新失败";
}
@Override
public String remove(Long id) {
var url = this.getById(id).getUrl();
FileUtil.del(url);
return this.removeById(id) ? "升级包删除成功" : "升级包删除失败";
}
}
package vion.vo;
import lombok.Getter;
import lombok.Setter;
import vion.model.ServerInfo;
import java.time.LocalDateTime;
/**
* @author vion
* @date 2024/10/16
*/
@Getter
@Setter
public class AgentVO {
private Long id;
/**
* 唯一id
*/
private String uid;
/**
* agent 版本号
*/
private String version;
/**
* 用户名
*/
private String username;
/**
* 名称
*/
private String name;
/**
* 别名
*/
private String alias;
/**
* 主机名
*/
private String hostname;
/**
* 本地ip
*/
private String localIpaddr;
/**
* 公网ip
*/
private String ipaddr;
/**
* 归属地
*/
private String addr;
/**
* 0:离线 1:在线
*/
private Short status;
/**
* 备注
*/
private String remark;
private LocalDateTime createTime;
private LocalDateTime updateTime;
private ServerInfo serverInfo;
/**
* 异常的服务名称
*/
private String serviceName;
}
\ No newline at end of file
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!