bla bla bla

This commit is contained in:
2026-10-27 22:04:28 +01:00
commit 334abce357
69 changed files with 10123 additions and 0 deletions
@@ -0,0 +1,24 @@
package com.htopweb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import oshi.util.GlobalConfig;
@SpringBootApplication
public class BackendApplication {
public static void main(String[] args) {
if (System.getProperty("os.name").toLowerCase().contains("win")) {
GlobalConfig.set(
GlobalConfig.OSHI_OS_WINDOWS_CPU_UTILITY,
true
);
}
SpringApplication.run(BackendApplication.class, args);
}
}
@@ -0,0 +1,13 @@
package com.htopweb.system;
public record ProcessInfoResponse(
int pid,
String name,
String state,
double cpuUsagePercent,
long residentMemoryBytes,
long virtualMemoryBytes,
long uptimeSeconds,
int threadCount
) {
}
@@ -0,0 +1,35 @@
package com.htopweb.system;
import com.htopweb.system.linux.LinuxDetailsResponse;
import com.htopweb.system.linux.LinuxDetailsService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/system")
public class SystemMetricsController {
private final SystemMetricsService _systemMetricsService;
private final LinuxDetailsService _linuxDetailsService;
public SystemMetricsController(
SystemMetricsService systemMetricsService,
LinuxDetailsService linuxDetailsService
) {
_systemMetricsService = systemMetricsService;
_linuxDetailsService = linuxDetailsService;
}
@GetMapping("/metrics")
public SystemMetricsResponse getMetrics() {
return _systemMetricsService.getMetrics();
}
@GetMapping("/linux")
public LinuxDetailsResponse getLinuxDetails() {
return _linuxDetailsService.getDetails();
}
}
@@ -0,0 +1,15 @@
package com.htopweb.system;
public record SystemMetricsResponse(
String operatingSystem,
String osVersion,
String hostname,
String processor,
int logicalProcessors,
double cpuUsagePercent,
long totalMemoryBytes,
long availableMemoryBytes,
long usedMemoryBytes,
double memoryUsagePercent
) {
}
@@ -0,0 +1,75 @@
package com.htopweb.system;
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.hardware.GlobalMemory;
import oshi.hardware.HardwareAbstractionLayer;
import oshi.software.os.OperatingSystem;
import org.springframework.stereotype.Service;
@Service
public class SystemMetricsService {
private final SystemInfo _systemInfo;
private final HardwareAbstractionLayer _hardware;
private final OperatingSystem _operatingSystem;
private final CentralProcessor _processor;
private final GlobalMemory _memory;
private long[] _previousCpuTicks;
public SystemMetricsService() {
_systemInfo = new SystemInfo();
_hardware = _systemInfo.getHardware();
_operatingSystem = _systemInfo.getOperatingSystem();
_processor = _hardware.getProcessor();
_memory = _hardware.getMemory();
_previousCpuTicks = _processor.getSystemCpuLoadTicks();
}
public synchronized SystemMetricsResponse getMetrics() {
long[] currentCpuTicks = _processor.getSystemCpuLoadTicks();
double cpuUsage = _processor.getSystemCpuLoadBetweenTicks(
_previousCpuTicks,
currentCpuTicks
);
_previousCpuTicks = currentCpuTicks;
if (Double.isNaN(cpuUsage) || Double.isInfinite(cpuUsage)) {
cpuUsage = 0.0;
}
// Task Manager displays system CPU usage in the 0–100% range.
cpuUsage = Math.max(0.0, Math.min(1.0, cpuUsage));
long totalMemory = _memory.getTotal();
long availableMemory = _memory.getAvailable();
long usedMemory = Math.max(0L, totalMemory - availableMemory);
double memoryUsage = totalMemory > 0
? (double) usedMemory / totalMemory * 100.0
: 0.0;
return new SystemMetricsResponse(
_operatingSystem.getFamily(),
_operatingSystem.getVersionInfo().getVersion(),
_operatingSystem.getNetworkParams().getHostName(),
_processor.getProcessorIdentifier().getName(),
_processor.getLogicalProcessorCount(),
round(cpuUsage * 100.0),
totalMemory,
availableMemory,
usedMemory,
round(memoryUsage)
);
}
private double round(double value) {
return Math.round(value * 10.0) / 10.0;
}
}
@@ -0,0 +1,25 @@
package com.htopweb.system;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/api/system")
public class SystemProcessesController {
private final SystemProcessesService _systemProcessesService;
public SystemProcessesController(
SystemProcessesService systemProcessesService
) {
_systemProcessesService = systemProcessesService;
}
@GetMapping("/processes")
public List<ProcessInfoResponse> getProcesses() {
return _systemProcessesService.getProcesses();
}
}
@@ -0,0 +1,85 @@
package com.htopweb.system;
import oshi.SystemInfo;
import oshi.software.os.OSProcess;
import oshi.software.os.OperatingSystem;
import org.springframework.stereotype.Service;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class SystemProcessesService {
private final OperatingSystem _operatingSystem;
private final int _logicalProcessorCount;
private final Map<Integer, OSProcess> _previousProcesses =
new HashMap<>();
public SystemProcessesService() {
SystemInfo systemInfo = new SystemInfo();
_operatingSystem = systemInfo.getOperatingSystem();
_logicalProcessorCount = Math.max(
1,
systemInfo.getHardware()
.getProcessor()
.getLogicalProcessorCount()
);
}
public synchronized List<ProcessInfoResponse> getProcesses() {
List<OSProcess> processes = _operatingSystem.getProcesses();
Map<Integer, OSProcess> currentProcesses = new HashMap<>();
List<ProcessInfoResponse> result = processes.stream()
.map(process -> {
int pid = process.getProcessID();
currentProcesses.put(pid, process);
OSProcess previous = _previousProcesses.get(pid);
double cpuUsage = 0.0;
if (pid != 0
&& previous != null
&& previous.getStartTime() == process.getStartTime()) {
cpuUsage = process.getProcessCpuLoadBetweenTicks(previous)
* 100.0 / _logicalProcessorCount;
cpuUsage = Math.max(0.0, Math.min(100.0, cpuUsage));
}
return new ProcessInfoResponse(
pid,
process.getName(),
process.getState().name(),
Math.round(cpuUsage * 10.0) / 10.0,
process.getResidentMemory(),
process.getVirtualSize(),
Math.max(
0L,
(System.currentTimeMillis()
- process.getStartTime()) / 1000
),
process.getThreadCount()
);
})
.sorted(
Comparator.comparingDouble(
ProcessInfoResponse::cpuUsagePercent
).reversed()
)
.toList();
_previousProcesses.clear();
_previousProcesses.putAll(currentProcesses);
return result;
}
}
@@ -0,0 +1,15 @@
package com.htopweb.system.linux;
public record LinuxDetailsResponse(
boolean linux,
String hostname,
String distribution,
String kernelVersion,
long uptimeSeconds,
double loadAverage1Min,
double loadAverage5Min,
double loadAverage15Min,
int logicalProcessors
) {
}
@@ -0,0 +1,64 @@
package com.htopweb.system.linux;
import oshi.SystemInfo;
import oshi.software.os.OperatingSystem;
import org.springframework.stereotype.Service;
import java.util.Locale;
@Service
public class LinuxDetailsService {
private final OperatingSystem _operatingSystem;
private final int _logicalProcessors;
private final oshi.hardware.CentralProcessor _processor;
public LinuxDetailsService() {
SystemInfo systemInfo = new SystemInfo();
_operatingSystem = systemInfo.getOperatingSystem();
_logicalProcessors = systemInfo.getHardware()
.getProcessor()
.getLogicalProcessorCount();
_processor = systemInfo.getHardware().getProcessor();
}
public LinuxDetailsResponse getDetails() {
boolean linux = System.getProperty("os.name", "")
.toLowerCase(Locale.ROOT)
.contains("linux");
String hostname = _operatingSystem.getNetworkParams().getHostName();
String distribution = _operatingSystem.getFamily();
String kernelVersion = _operatingSystem.getVersionInfo().getVersion();
long uptimeSeconds = _operatingSystem.getSystemUptime();
double[] loadAverages = _processor.getSystemLoadAverage(3);
return new LinuxDetailsResponse(
linux,
hostname,
distribution,
kernelVersion,
uptimeSeconds,
safeLoad(loadAverages, 0),
safeLoad(loadAverages, 1),
safeLoad(loadAverages, 2),
_logicalProcessors
);
}
private double safeLoad(double[] values, int index) {
if (values == null || values.length <= index
|| !Double.isFinite(values[index])
|| values[index] < 0) {
return -1.0;
}
return Math.round(values[index] * 100.0) / 100.0;
}
}