package com.sshmanager.controller; import com.sshmanager.entity.Connection; import com.sshmanager.entity.User; import com.sshmanager.repository.UserRepository; import com.sshmanager.service.ConnectionService; import com.sshmanager.service.SshService; import org.springframework.http.ResponseEntity; import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.Map; @RestController @RequestMapping("/api/monitor") public class MonitorController { private final ConnectionService connectionService; private final SshService sshService; private final UserRepository userRepository; public MonitorController(ConnectionService connectionService, SshService sshService, UserRepository userRepository) { this.connectionService = connectionService; this.sshService = sshService; this.userRepository = userRepository; } private Long getCurrentUserId(Authentication auth) { User user = userRepository.findByUsername(auth.getName()).orElseThrow(() -> new IllegalStateException("User not found")); return user.getId(); } @GetMapping("/{connectionId}") public ResponseEntity> getServerMetrics(@PathVariable Long connectionId, Authentication authentication) { try { Long userId = getCurrentUserId(authentication); Connection conn = connectionService.getConnectionForSsh(connectionId, userId); if (conn == null) { return ResponseEntity.notFound().build(); } String password = connectionService.getDecryptedPassword(conn); String privateKey = connectionService.getDecryptedPrivateKey(conn); String passphrase = connectionService.getDecryptedPassphrase(conn); Map metrics = new HashMap<>(); // 获取CPU使用率(兼容多种系统) try { double cpuUsage = 0; try { // 优先使用top String cpuOutput = sshService.executeCommand(conn, password, privateKey, passphrase, "top -bn1 2>/dev/null | grep 'Cpu(s)' | sed 's/.*, *\\([0-9.]*\\)%* id.*/\\1/' | awk '{print 100 - $1}'"); if (!cpuOutput.trim().isEmpty()) { cpuUsage = Double.parseDouble(cpuOutput.trim()); } else { throw new Exception("top command failed"); } } catch (Exception e) { // 备用方案:使用/proc/stat计算(需要两次采样,这里简化处理用vmstat) try { String vmstatOutput = sshService.executeCommand(conn, password, privateKey, passphrase, "vmstat 1 2 | tail -1 | awk '{print 100 - $15}'"); cpuUsage = Double.parseDouble(vmstatOutput.trim()); } catch (Exception e2) { throw new Exception("Both top and vmstat failed"); } } metrics.put("cpuUsage", Math.round(cpuUsage * 10.0) / 10.0); } catch (Exception e) { metrics.put("cpuUsage", null); } // 获取内存信息(兼容多种系统) try { long totalMem = 0; long usedMem = 0; try { // 优先使用free -b String memOutput = sshService.executeCommand(conn, password, privateKey, passphrase, "free -b 2>/dev/null | grep Mem"); if (!memOutput.trim().isEmpty()) { String[] memParts = memOutput.trim().split("\\s+"); if (memParts.length >= 3) { totalMem = Long.parseLong(memParts[1]); usedMem = Long.parseLong(memParts[2]); } } } catch (Exception e) { // 备用方案:从/proc/meminfo读取 String meminfoOutput = sshService.executeCommand(conn, password, privateKey, passphrase, "cat /proc/meminfo | grep -E 'MemTotal|MemAvailable'"); String[] lines = meminfoOutput.trim().split("\n"); if (lines.length >= 2) { totalMem = Long.parseLong(lines[0].replaceAll("\\D+", "")) * 1024; long availableMem = Long.parseLong(lines[1].replaceAll("\\D+", "")) * 1024; usedMem = totalMem - availableMem; } } if (totalMem > 0 && usedMem >= 0) { double memUsage = (double) usedMem / totalMem * 100; metrics.put("memTotal", totalMem); metrics.put("memUsed", usedMem); metrics.put("memUsage", Math.round(memUsage * 10.0) / 10.0); } else { throw new Exception("Failed to parse memory info"); } } catch (Exception e) { metrics.put("memTotal", null); metrics.put("memUsed", null); metrics.put("memUsage", null); } // 获取磁盘使用率 try { String diskOutput = sshService.executeCommand(conn, password, privateKey, passphrase, "df -P / | tail -1"); String[] diskParts = diskOutput.trim().split("\\s+"); int diskUsage = Integer.parseInt(diskParts[4].replace("%", "")); metrics.put("diskUsage", diskUsage); } catch (Exception e) { metrics.put("diskUsage", null); } // 获取系统负载 try { String loadOutput = sshService.executeCommand(conn, password, privateKey, passphrase, "cat /proc/loadavg"); String[] loadParts = loadOutput.trim().split("\\s+"); double load1 = Double.parseDouble(loadParts[0]); metrics.put("load1", load1); } catch (Exception e) { metrics.put("load1", null); } // 获取CPU核数 try { String cpuCountOutput = sshService.executeCommand(conn, password, privateKey, passphrase, "grep -c ^processor /proc/cpuinfo"); int cpuCores = Integer.parseInt(cpuCountOutput.trim()); metrics.put("cpuCores", cpuCores); } catch (Exception e) { metrics.put("cpuCores", null); } // 获取系统运行时间 try { String uptimeOutput = sshService.executeCommand(conn, password, privateKey, passphrase, "uptime -p"); metrics.put("uptime", uptimeOutput.trim().replace("up ", "")); } catch (Exception e) { // 尝试另一种uptime格式 try { String uptimeOutput = sshService.executeCommand(conn, password, privateKey, passphrase, "cat /proc/uptime | awk '{print $1}'"); double uptimeSeconds = Double.parseDouble(uptimeOutput.trim()); long days = (long) (uptimeSeconds / 86400); long hours = (long) ((uptimeSeconds % 86400) / 3600); long minutes = (long) ((uptimeSeconds % 3600) / 60); StringBuilder uptimeStr = new StringBuilder(); if (days > 0) uptimeStr.append(days).append("d "); if (hours > 0) uptimeStr.append(hours).append("h "); uptimeStr.append(minutes).append("m"); metrics.put("uptime", uptimeStr.toString().trim()); } catch (Exception e2) { metrics.put("uptime", null); } } return ResponseEntity.ok(metrics); } catch (Exception e) { Map error = new HashMap<>(); error.put("error", e.getMessage()); return ResponseEntity.badRequest().body(error); } } }