2025-09-10 15:36:49 +08:00
|
|
|
|
package com.tongran.agent.client.utils;
|
|
|
|
|
|
|
|
|
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
2025-09-26 12:57:31 +08:00
|
|
|
|
import org.snmp4j.smi.OID;
|
2025-09-10 15:36:49 +08:00
|
|
|
|
import oshi.hardware.NetworkIF;
|
|
|
|
|
|
|
|
|
|
|
|
import java.io.FileOutputStream;
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
|
import java.net.InetAddress;
|
|
|
|
|
|
import java.net.NetworkInterface;
|
|
|
|
|
|
import java.net.SocketException;
|
|
|
|
|
|
import java.net.UnknownHostException;
|
|
|
|
|
|
import java.time.LocalDateTime;
|
|
|
|
|
|
import java.time.ZoneId;
|
|
|
|
|
|
import java.time.temporal.ChronoUnit;
|
2025-09-26 14:13:19 +08:00
|
|
|
|
import java.util.*;
|
2025-09-10 15:36:49 +08:00
|
|
|
|
|
|
|
|
|
|
public class AgentUtil {
|
|
|
|
|
|
|
|
|
|
|
|
public static String getMotherboardUUID() {
|
|
|
|
|
|
String hostName = getHostname();
|
|
|
|
|
|
String primaryIp = getPrimaryIp();
|
|
|
|
|
|
// SystemInfo si = new SystemInfo();
|
|
|
|
|
|
// HardwareAbstractionLayer hal = si.getHardware();
|
|
|
|
|
|
// Baseboard baseboard = hal.getComputerSystem().getBaseboard();
|
|
|
|
|
|
// if(StringUtils.isNotBlank(baseboard.getSerialNumber())){
|
|
|
|
|
|
// return baseboard.getSerialNumber();
|
|
|
|
|
|
// }
|
|
|
|
|
|
return hostName+":"+primaryIp;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static String getHostname() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
return InetAddress.getLocalHost().getHostName();
|
|
|
|
|
|
} catch (UnknownHostException e) {
|
|
|
|
|
|
return "unknown-host";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取本机首选 IP 地址(通常是第一个非回环、非虚拟网卡的 IPv4 地址)
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static String getPrimaryIp() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
InetAddress localHost = InetAddress.getLocalHost();
|
|
|
|
|
|
String ip = localHost.getHostAddress();
|
|
|
|
|
|
|
|
|
|
|
|
// 如果是 127.x.x.x,说明可能 hosts 配置有问题,需要手动查找
|
|
|
|
|
|
if (ip.startsWith("127.")) {
|
|
|
|
|
|
return getExternalIp();
|
|
|
|
|
|
}
|
|
|
|
|
|
return ip;
|
|
|
|
|
|
} catch (UnknownHostException e) {
|
|
|
|
|
|
return "127.0.0.1";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取第一个非回环、非虚拟网卡的 IPv4 地址
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static String getExternalIp() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
|
|
|
|
|
|
while (interfaces.hasMoreElements()) {
|
|
|
|
|
|
NetworkInterface iface = interfaces.nextElement();
|
|
|
|
|
|
// 跳过虚拟网卡(如 docker, veth, lo)
|
|
|
|
|
|
if (iface.isLoopback() || iface.isVirtual() || !iface.isUp()) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
Enumeration<InetAddress> addresses = iface.getInetAddresses();
|
|
|
|
|
|
while (addresses.hasMoreElements()) {
|
|
|
|
|
|
InetAddress addr = addresses.nextElement();
|
|
|
|
|
|
if (addr.isLoopbackAddress()) {
|
|
|
|
|
|
continue; // 跳过 127.0.0.1
|
|
|
|
|
|
}
|
|
|
|
|
|
if (addr.getHostAddress().contains(":")) {
|
|
|
|
|
|
continue; // 跳过 IPv6
|
|
|
|
|
|
}
|
|
|
|
|
|
return addr.getHostAddress();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (SocketException e) {
|
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
|
}
|
|
|
|
|
|
return "127.0.0.1";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static String toJsonString(List<Map<String, String>> list) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
ObjectMapper mapper = new ObjectMapper();
|
|
|
|
|
|
return mapper.writeValueAsString(list);
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
throw new RuntimeException("JSON转换失败", e);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static void base64ToFile(String base64String, String filePath) throws IOException {
|
|
|
|
|
|
// 解码Base64字符串
|
|
|
|
|
|
byte[] decodedBytes = Base64.getDecoder().decode(base64String);
|
|
|
|
|
|
|
|
|
|
|
|
// 写入文件
|
|
|
|
|
|
try (FileOutputStream fos = new FileOutputStream(filePath)) {
|
|
|
|
|
|
fos.write(decodedBytes);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static String getInterfaceType(NetworkIF net) {
|
|
|
|
|
|
String name = net.getName().toLowerCase();
|
|
|
|
|
|
String displayName = net.getDisplayName().toLowerCase();
|
|
|
|
|
|
|
|
|
|
|
|
if (name.startsWith("eth") || name.startsWith("en") || displayName.contains("ethernet")) {
|
|
|
|
|
|
return "Ethernet";
|
|
|
|
|
|
} else if (name.startsWith("wlan") || name.startsWith("wl") || displayName.contains("wireless")) {
|
|
|
|
|
|
return "Wi-Fi";
|
|
|
|
|
|
} else if (name.startsWith("lo") || displayName.contains("loopback")) {
|
|
|
|
|
|
return "Loopback";
|
|
|
|
|
|
} else if (name.startsWith("ppp") || displayName.contains("point-to-point")) {
|
|
|
|
|
|
return "PPP";
|
|
|
|
|
|
} else if (name.startsWith("vmnet") || displayName.contains("virtual")) {
|
|
|
|
|
|
return "Virtual";
|
|
|
|
|
|
} else if (name.startsWith("tun") || name.startsWith("tap")) {
|
|
|
|
|
|
return "TUN/TAP";
|
|
|
|
|
|
} else if (name.startsWith("br") || displayName.contains("bridge")) {
|
|
|
|
|
|
return "Bridge";
|
|
|
|
|
|
} else if (name.startsWith("bond") || displayName.contains("bond")) {
|
|
|
|
|
|
return "Bond";
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return "Unknown";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取当前时间距离下一个“分钟为 0 或 5”的时间点还差多少毫秒
|
|
|
|
|
|
* 例如:xx:00, xx:05, xx:10, ..., xx:55
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static long millisecondsToNext5Minute() {
|
|
|
|
|
|
LocalDateTime now = LocalDateTime.now();
|
|
|
|
|
|
|
|
|
|
|
|
// 当前分钟
|
|
|
|
|
|
int minute = now.getMinute();
|
|
|
|
|
|
|
|
|
|
|
|
// 计算下一个 5 分钟整点(向上取整)
|
|
|
|
|
|
int nextMinute = ((minute / 5) + 1) * 5;
|
|
|
|
|
|
|
|
|
|
|
|
LocalDateTime nextTime;
|
|
|
|
|
|
if (nextMinute < 60) {
|
|
|
|
|
|
// 在当前小时内
|
|
|
|
|
|
nextTime = now.withMinute(nextMinute).withSecond(0).withNano(0);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 跨小时,如 10:58 → 11:00
|
|
|
|
|
|
nextTime = now.plusHours(1).withMinute(0).withSecond(0).withNano(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算相差的毫秒数
|
|
|
|
|
|
return ChronoUnit.MILLIS.between(now, nextTime);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取距离下一个分钟整点的毫秒数
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static long getMillisToNextMinute() {
|
|
|
|
|
|
LocalDateTime now = LocalDateTime.now();
|
|
|
|
|
|
|
|
|
|
|
|
// 获取下一个分钟整点时间
|
|
|
|
|
|
LocalDateTime nextMinute = now
|
|
|
|
|
|
.truncatedTo(ChronoUnit.MINUTES) // 截断到当前分钟
|
|
|
|
|
|
.plusMinutes(1); // 加1分钟
|
|
|
|
|
|
|
|
|
|
|
|
// 计算时间差(毫秒)
|
|
|
|
|
|
return ChronoUnit.MILLIS.between(now, nextMinute);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取距离下一个指定分钟整点的毫秒数
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static long getMillisToNextMinuteInterval(int intervalMinutes) {
|
|
|
|
|
|
if (intervalMinutes <= 0) {
|
|
|
|
|
|
throw new IllegalArgumentException("Interval must be positive");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocalDateTime now = LocalDateTime.now();
|
|
|
|
|
|
|
|
|
|
|
|
// 计算当前分钟在间隔中的位置
|
|
|
|
|
|
int currentMinute = now.getMinute();
|
|
|
|
|
|
int remainder = currentMinute % intervalMinutes;
|
|
|
|
|
|
|
|
|
|
|
|
// 计算需要增加的分钟数
|
|
|
|
|
|
int minutesToAdd = remainder == 0 ? intervalMinutes : intervalMinutes - remainder;
|
|
|
|
|
|
|
|
|
|
|
|
// 获取下一个间隔整点时间
|
|
|
|
|
|
LocalDateTime nextInterval = now
|
|
|
|
|
|
.truncatedTo(ChronoUnit.MINUTES) // 截断到当前分钟
|
|
|
|
|
|
.plusMinutes(minutesToAdd) // 增加到下一个整点
|
|
|
|
|
|
.withSecond(0) // 秒设为0
|
|
|
|
|
|
.withNano(0); // 纳秒设为0
|
|
|
|
|
|
|
|
|
|
|
|
return ChronoUnit.MILLIS.between(now, nextInterval);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static long roundMinutes(){
|
|
|
|
|
|
LocalDateTime now = LocalDateTime.now();
|
|
|
|
|
|
// 四舍五入到最近的5分钟
|
|
|
|
|
|
LocalDateTime roundedTime = now
|
|
|
|
|
|
.truncatedTo(ChronoUnit.MINUTES) // 先去掉秒和纳秒
|
|
|
|
|
|
.withMinute((int) (Math.round(now.getMinute() / 5.0) * 5))
|
|
|
|
|
|
.withSecond(0)
|
|
|
|
|
|
.withNano(0);
|
|
|
|
|
|
// 处理分钟进位的情况
|
|
|
|
|
|
if (roundedTime.getMinute() == 60) {
|
|
|
|
|
|
roundedTime = roundedTime.plusHours(1).withMinute(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
// 转换为10位时间戳
|
|
|
|
|
|
long timestamp = roundedTime.atZone(ZoneId.systemDefault()).toEpochSecond();
|
|
|
|
|
|
return timestamp;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-12 18:52:17 +08:00
|
|
|
|
public static LocalDateTime toLocalDateTime(long timestamp, boolean isSeconds) {
|
|
|
|
|
|
java.time.Instant instant = isSeconds ?
|
|
|
|
|
|
java.time.Instant.ofEpochSecond(timestamp) :
|
|
|
|
|
|
java.time.Instant.ofEpochMilli(timestamp);
|
|
|
|
|
|
|
|
|
|
|
|
return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-26 12:57:31 +08:00
|
|
|
|
public static String getLastOid(OID oid){
|
|
|
|
|
|
if(oid.size() > 0){
|
|
|
|
|
|
int lastValue = oid.get(oid.size() - 1);
|
|
|
|
|
|
return String.valueOf(lastValue);
|
|
|
|
|
|
}
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-26 14:13:19 +08:00
|
|
|
|
public static LinkedHashMap<String, String> swapMap(LinkedHashMap<String, String> original) {
|
|
|
|
|
|
LinkedHashMap<String, String> swapped = new LinkedHashMap<>();
|
|
|
|
|
|
for (Map.Entry<String, String> entry : original.entrySet()) {
|
|
|
|
|
|
if (entry.getValue() != null) { // 避免 null key
|
|
|
|
|
|
swapped.put(entry.getValue(), entry.getKey());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return swapped;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-10 15:36:49 +08:00
|
|
|
|
}
|