From c88cdf7ddc2fbe1d958e5fa18a730d99ca7f09d9 Mon Sep 17 00:00:00 2001 From: jack ning Date: Thu, 24 Jul 2025 21:24:08 +0800 Subject: [PATCH] update modules/core: mod 3 del 1 files --- .../bytedesk/core/server/ServerEntity.java | 7 +- .../core/server/ServerEventListener.java | 69 +++- .../core/server/ServerRestService.java | 389 ++++++++++++++---- .../bytedesk/core/server/ServerService.java | 314 -------------- 4 files changed, 375 insertions(+), 404 deletions(-) delete mode 100644 modules/core/src/main/java/com/bytedesk/core/server/ServerService.java diff --git a/modules/core/src/main/java/com/bytedesk/core/server/ServerEntity.java b/modules/core/src/main/java/com/bytedesk/core/server/ServerEntity.java index 8a32c2addd..3f7e80b645 100644 --- a/modules/core/src/main/java/com/bytedesk/core/server/ServerEntity.java +++ b/modules/core/src/main/java/com/bytedesk/core/server/ServerEntity.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-05-11 18:14:28 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2025-07-24 20:36:13 + * @LastEditTime: 2025-07-24 21:23:19 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -13,7 +13,8 @@ */ package com.bytedesk.core.server; -import com.bytedesk.core.base.BaseEntity; +import com.bytedesk.core.base.BaseEntityNoOrg; + import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.Table; @@ -42,7 +43,7 @@ import java.time.LocalDateTime; @AllArgsConstructor @NoArgsConstructor @Table(name = "bytedesk_core_server") -public class ServerEntity extends BaseEntity { +public class ServerEntity extends BaseEntityNoOrg { /** * Server hostname or identifier diff --git a/modules/core/src/main/java/com/bytedesk/core/server/ServerEventListener.java b/modules/core/src/main/java/com/bytedesk/core/server/ServerEventListener.java index efaec00b45..5649689601 100644 --- a/modules/core/src/main/java/com/bytedesk/core/server/ServerEventListener.java +++ b/modules/core/src/main/java/com/bytedesk/core/server/ServerEventListener.java @@ -13,8 +13,12 @@ */ package com.bytedesk.core.server; +import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; +import com.bytedesk.core.quartz.event.QuartzFiveMinEvent; +import com.bytedesk.core.uid.UidUtils; + import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -23,6 +27,69 @@ import lombok.extern.slf4j.Slf4j; @AllArgsConstructor public class ServerEventListener { - + private final ServerRestService serverRestService; + private final UidUtils uidUtils; + + /** + * 监听5分钟定时事件,更新服务器信息 + * @param event QuartzFiveMinEvent + */ + @EventListener + public void onQuartzFiveMinEvent(QuartzFiveMinEvent event) { + log.info("ServerEventListener: Processing 5-minute server update event"); + + try { + // 获取当前服务器指标 + ServerEntity currentMetrics = serverRestService.getCurrentServerMetrics(); + + // 查找当前服务器是否已存在 + String serverName = currentMetrics.getServerName(); + String orgUid = "system"; // 系统级服务器监控 + + // 尝试查找现有服务器记录 + ServerEntity existingServer = serverRestService.findByServerNameAndOrgUid(serverName, orgUid); + + if (existingServer != null) { + // 更新现有服务器信息 + existingServer.setCpuUsage(currentMetrics.getCpuUsage()); + existingServer.setMemoryUsage(currentMetrics.getMemoryUsage()); + existingServer.setDiskUsage(currentMetrics.getDiskUsage()); + existingServer.setTotalMemoryMb(currentMetrics.getTotalMemoryMb()); + existingServer.setUsedMemoryMb(currentMetrics.getUsedMemoryMb()); + existingServer.setUptimeSeconds(currentMetrics.getUptimeSeconds()); + existingServer.setLastHeartbeat(currentMetrics.getLastHeartbeat()); + existingServer.setOsInfo(currentMetrics.getOsInfo()); + existingServer.setJavaVersion(currentMetrics.getJavaVersion()); + + // 根据资源使用情况更新状态 + if (currentMetrics.getCpuUsage() > 90 || currentMetrics.getMemoryUsage() > 90 || currentMetrics.getDiskUsage() > 95) { + existingServer.setStatus(ServerStatusEnum.OVERLOADED.name()); + } else if (currentMetrics.getCpuUsage() > 80 || currentMetrics.getMemoryUsage() > 80 || currentMetrics.getDiskUsage() > 85) { + existingServer.setStatus(ServerStatusEnum.WARNING.name()); + } else { + existingServer.setStatus(ServerStatusEnum.ONLINE.name()); + } + + serverRestService.updateServer(existingServer); + log.debug("Updated server metrics for: {}", serverName); + } else { + // 创建新的服务器记录 + currentMetrics.setUid(uidUtils.getUid()); + currentMetrics.setOrgUid(orgUid); + currentMetrics.setServerIp(currentMetrics.getServerIp()); + currentMetrics.setType(ServerTypeEnum.APPLICATION.name()); + currentMetrics.setStatus(ServerStatusEnum.ONLINE.name()); + currentMetrics.setEnvironment("PROD"); + currentMetrics.setMonitoringEnabled(true); + + serverRestService.createServer(currentMetrics); + log.info("Created new server record for: {}", serverName); + } + + } catch (Exception e) { + log.error("Error updating server metrics: ", e); + } + } + } diff --git a/modules/core/src/main/java/com/bytedesk/core/server/ServerRestService.java b/modules/core/src/main/java/com/bytedesk/core/server/ServerRestService.java index 4e2d85b4a2..e3cf9d48fb 100644 --- a/modules/core/src/main/java/com/bytedesk/core/server/ServerRestService.java +++ b/modules/core/src/main/java/com/bytedesk/core/server/ServerRestService.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-05-11 18:14:28 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2025-07-24 20:51:19 + * @LastEditTime: 2025-07-24 21:02:57 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -21,11 +21,15 @@ import org.modelmapper.ModelMapper; import org.springframework.cache.annotation.Cacheable; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; import org.springframework.orm.ObjectOptimisticLockingFailureException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.time.ZonedDateTime; +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryMXBean; +import java.lang.management.OperatingSystemMXBean; +import java.time.LocalDateTime; import java.util.List; import java.util.Optional; @@ -39,15 +43,14 @@ import java.util.Optional; public class ServerRestService extends BaseRestService { private final ServerRepository serverRepository; - private final ServerService serverService; private final ModelMapper modelMapper; private final UidUtils uidUtils; // Helper method for internal use private Page queryByOrgEntity(ServerRequest request) { Pageable pageable = request.getPageable(); - // TODO: Implement ServerSpecification.search(request) - return serverRepository.findAll(pageable); + Specification spec = ServerSpecification.search(request); + return serverRepository.findAll(spec, pageable); } @Override @@ -81,10 +84,13 @@ public class ServerRestService extends BaseRestService optional = serverRepository.findByUid(request.getUid()); if (optional.isPresent()) { ServerEntity existingEntity = optional.get(); - updateEntityFromRequest(existingEntity, request); - existingEntity.setUpdatedAt(ZonedDateTime.now()); + existingEntity = modelMapper.map(request, ServerEntity.class); - ServerEntity savedEntity = serverService.updateServer(existingEntity); + ServerEntity savedEntity = save(existingEntity); + if (savedEntity == null) { + throw new RuntimeException("Update server failed"); + } return convertToResponse(savedEntity); } else { throw new RuntimeException("Server not found"); @@ -105,13 +113,236 @@ public class ServerRestService extends BaseRestService optional = serverRepository.findByUid(uid); + if (optional.isPresent()) { + ServerEntity server = optional.get(); + server.setDeleted(true); + serverRepository.save(server); + log.info("Deleted server: {}", server.getServerName()); + } } @Override public void delete(ServerRequest request) { deleteByUid(request.getUid()); } + + @Override + protected String getUidFromRequest(ServerRequest request) { + return request.getUid(); + } + + @Override + public ServerEntity doSave(ServerEntity entity) { + return serverRepository.save(entity); + } + + @Override + public ServerEntity handleOptimisticLockingFailureException(ObjectOptimisticLockingFailureException e, ServerEntity entity) { + log.warn("Optimistic locking failure for server: {}", entity.getUid()); + return entity; + } + + // ========== 从 ServerService 迁移的方法 ========== + + /** + * Find all servers for an organization + * @param orgUid organization UID + * @return List + */ + public List findByOrgUid(String orgUid) { + return serverRepository.findByOrgUidAndDeletedFalseOrderByCreatedAtDesc(orgUid); + } + + /** + * Find servers by type + * @param type server type + * @param orgUid organization UID + * @return List + */ + public List findByType(String type, String orgUid) { + return serverRepository.findByTypeAndOrgUidAndDeletedFalse(type, orgUid); + } + + /** + * Find servers by status + * @param status server status + * @param orgUid organization UID + * @return List + */ + public List findByStatus(String status, String orgUid) { + return serverRepository.findByStatusAndOrgUidAndDeletedFalse(status, orgUid); + } + + /** + * Find servers with high resource usage + * @param orgUid organization UID + * @return List + */ + public List findServersWithHighUsage(String orgUid) { + return serverRepository.findServersWithHighUsage(orgUid, 80.0, 80.0, 85.0); + } + + /** + * Find servers without recent heartbeat + * @param orgUid organization UID + * @param minutesThreshold minutes threshold for heartbeat + * @return List + */ + public List findServersWithoutRecentHeartbeat(String orgUid, int minutesThreshold) { + LocalDateTime cutoffTime = LocalDateTime.now().minusMinutes(minutesThreshold); + return serverRepository.findServersWithoutRecentHeartbeat(orgUid, cutoffTime); + } + + /** + * Update server heartbeat + * @param uid server UID + * @return updated server entity + */ + @Transactional + public Optional updateHeartbeat(String uid) { + Optional optional = serverRepository.findByUid(uid); + if (optional.isPresent()) { + ServerEntity server = optional.get(); + server.setLastHeartbeat(LocalDateTime.now()); + return Optional.of(serverRepository.save(server)); + } + return Optional.empty(); + } + + /** + * Update server resource usage + * @param uid server UID + * @param cpuUsage CPU usage percentage + * @param memoryUsage memory usage percentage + * @param diskUsage disk usage percentage + * @return updated server entity + */ + @Transactional + public Optional updateResourceUsage(String uid, Double cpuUsage, Double memoryUsage, Double diskUsage) { + Optional optional = serverRepository.findByUid(uid); + if (optional.isPresent()) { + ServerEntity server = optional.get(); + server.setCpuUsage(cpuUsage); + server.setMemoryUsage(memoryUsage); + server.setDiskUsage(diskUsage); + server.setLastHeartbeat(LocalDateTime.now()); + + // Update status based on resource usage + if (cpuUsage > 90 || memoryUsage > 90 || diskUsage > 95) { + server.setStatus(ServerStatusEnum.OVERLOADED.name()); + } else if (cpuUsage > 80 || memoryUsage > 80 || diskUsage > 85) { + server.setStatus(ServerStatusEnum.WARNING.name()); + } else { + server.setStatus(ServerStatusEnum.ONLINE.name()); + } + + return Optional.of(serverRepository.save(server)); + } + return Optional.empty(); + } + + /** + * Get current server metrics (for self-monitoring) + * @return ServerEntity with current metrics + */ + public ServerEntity getCurrentServerMetrics() { + OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean(); + MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean(); + + // Calculate memory usage + long totalMemory = memoryBean.getHeapMemoryUsage().getMax(); + long usedMemory = memoryBean.getHeapMemoryUsage().getUsed(); + double memoryUsagePercent = (double) usedMemory / totalMemory * 100; + + // Get CPU usage (approximate) + double cpuUsage = osBean.getSystemLoadAverage() * 100; + if (cpuUsage > 100) cpuUsage = 100; + + // Create server entity with current metrics + return ServerEntity.builder() + .serverName(System.getProperty("os.name") + " - " + System.getProperty("user.name")) + .serverIp("127.0.0.1") + .type(ServerTypeEnum.APPLICATION.name()) + .status(ServerStatusEnum.ONLINE.name()) + .cpuUsage(cpuUsage) + .memoryUsage(memoryUsagePercent) + .totalMemoryMb(totalMemory / (1024 * 1024)) + .usedMemoryMb(usedMemory / (1024 * 1024)) + .uptimeSeconds(ManagementFactory.getRuntimeMXBean().getUptime() / 1000) + .startTime(LocalDateTime.now().minusSeconds(ManagementFactory.getRuntimeMXBean().getUptime() / 1000)) + .lastHeartbeat(LocalDateTime.now()) + .osInfo(System.getProperty("os.name") + " " + System.getProperty("os.version")) + .javaVersion(System.getProperty("java.version")) + .environment("DEV") + .monitoringEnabled(true) + .build(); + } + + /** + * Find server by server name and organization UID + * @param serverName server name + * @param orgUid organization UID + * @return ServerEntity or null if not found + */ + public ServerEntity findByServerNameAndOrgUid(String serverName, String orgUid) { + Optional optional = serverRepository.findByServerNameAndOrgUidAndDeletedFalse(serverName, orgUid); + return optional.orElse(null); + } + + /** + * Create server entity directly + * @param serverEntity server entity to create + * @return created server entity + */ + @Transactional + public ServerEntity createServer(ServerEntity serverEntity) { + if (serverEntity.getUid() == null) { + serverEntity.setUid(uidUtils.getUid()); + } + return serverRepository.save(serverEntity); + } + + /** + * Update server entity directly + * @param serverEntity server entity to update + * @return updated server entity + */ + @Transactional + public ServerEntity updateServer(ServerEntity serverEntity) { + return serverRepository.save(serverEntity); + } + + /** + * Get server statistics for an organization + * @param orgUid organization UID + * @return ServerStatistics object + */ + public ServerStatistics getServerStatistics(String orgUid) { + List servers = findByOrgUid(orgUid); + + long totalServers = servers.size(); + long onlineServers = servers.stream() + .filter(s -> ServerStatusEnum.ONLINE.name().equals(s.getStatus())) + .count(); + long offlineServers = servers.stream() + .filter(s -> ServerStatusEnum.OFFLINE.name().equals(s.getStatus())) + .count(); + long warningServers = servers.stream() + .filter(s -> ServerStatusEnum.WARNING.name().equals(s.getStatus())) + .count(); + long overloadedServers = servers.stream() + .filter(s -> ServerStatusEnum.OVERLOADED.name().equals(s.getStatus())) + .count(); + + return ServerStatistics.builder() + .totalServers(totalServers) + .onlineServers(onlineServers) + .offlineServers(offlineServers) + .warningServers(warningServers) + .overloadedServers(overloadedServers) + .build(); + } @Override public ServerResponse convertToResponse(ServerEntity entity) { @@ -148,83 +379,69 @@ public class ServerRestService extends BaseRestService - */ - public Optional findByUid(String uid) { - return serverRepository.findByUid(uid); - } - - /** - * Find all servers for an organization - * @param orgUid organization UID - * @return List - */ - public List findByOrgUid(String orgUid) { - return serverRepository.findByOrgUidAndDeletedFalseOrderByCreatedAtDesc(orgUid); - } - - /** - * Find servers by type - * @param type server type - * @param orgUid organization UID - * @return List - */ - public List findByType(String type, String orgUid) { - return serverRepository.findByTypeAndOrgUidAndDeletedFalse(type, orgUid); - } - - /** - * Find servers by status - * @param status server status - * @param orgUid organization UID - * @return List - */ - public List findByStatus(String status, String orgUid) { - return serverRepository.findByStatusAndOrgUidAndDeletedFalse(status, orgUid); - } - - /** - * Find servers with high resource usage - * @param orgUid organization UID - * @return List - */ - public List findServersWithHighUsage(String orgUid) { - return serverRepository.findServersWithHighUsage(orgUid, 80.0, 80.0, 85.0); - } - - /** - * Find servers without recent heartbeat - * @param orgUid organization UID - * @param minutesThreshold minutes threshold for heartbeat - * @return List - */ - public List findServersWithoutRecentHeartbeat(String orgUid, int minutesThreshold) { - LocalDateTime cutoffTime = LocalDateTime.now().minusMinutes(minutesThreshold); - return serverRepository.findServersWithoutRecentHeartbeat(orgUid, cutoffTime); - } - - /** - * Update server heartbeat - * @param uid server UID - * @return updated server entity - */ - @Transactional - public Optional updateHeartbeat(String uid) { - Optional optional = serverRepository.findByUid(uid); - if (optional.isPresent()) { - ServerEntity server = optional.get(); - server.setLastHeartbeat(LocalDateTime.now()); - return Optional.of(serverRepository.save(server)); - } - return Optional.empty(); - } - - /** - * Update server resource usage - * @param uid server UID - * @param cpuUsage CPU usage percenservere - * @param memoryUsage memory usage percenservere - * @param diskUsage disk usage percenservere - * @return updated server entity - */ - @Transactional - public Optional updateResourceUsage(String uid, Double cpuUsage, Double memoryUsage, Double diskUsage) { - Optional optional = serverRepository.findByUid(uid); - if (optional.isPresent()) { - ServerEntity server = optional.get(); - server.setCpuUsage(cpuUsage); - server.setMemoryUsage(memoryUsage); - server.setDiskUsage(diskUsage); - server.setLastHeartbeat(LocalDateTime.now()); - - // Update status based on resource usage - if (cpuUsage > 90 || memoryUsage > 90 || diskUsage > 95) { - server.setStatus(ServerStatusEnum.OVERLOADED.name()); - } else if (cpuUsage > 80 || memoryUsage > 80 || diskUsage > 85) { - server.setStatus(ServerStatusEnum.WARNING.name()); - } else { - server.setStatus(ServerStatusEnum.ONLINE.name()); - } - - return Optional.of(serverRepository.save(server)); - } - return Optional.empty(); - } - - /** - * Get current server metrics (for self-monitoring) - * @return ServerEntity with current metrics - */ - public ServerEntity getCurrentServerMetrics() { - OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean(); - MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean(); - - // Calculate memory usage - long totalMemory = memoryBean.getHeapMemoryUsage().getMax(); - long usedMemory = memoryBean.getHeapMemoryUsage().getUsed(); - double memoryUsagePercent = (double) usedMemory / totalMemory * 100; - - // Get CPU usage (approximate) - double cpuUsage = osBean.getSystemLoadAverage() * 100; - if (cpuUsage > 100) cpuUsage = 100; - - // Create server entity with current metrics - return ServerEntity.builder() - .serverName(System.getProperty("os.name") + " - " + System.getProperty("user.name")) - .serverIp("127.0.0.1") - .type(ServerTypeEnum.APPLICATION.name()) - .status(ServerStatusEnum.ONLINE.name()) - .cpuUsage(cpuUsage) - .memoryUsage(memoryUsagePercent) - .totalMemoryMb(totalMemory / (1024 * 1024)) - .usedMemoryMb(usedMemory / (1024 * 1024)) - .uptimeSeconds(ManagementFactory.getRuntimeMXBean().getUptime() / 1000) - .startTime(LocalDateTime.now().minusSeconds(ManagementFactory.getRuntimeMXBean().getUptime() / 1000)) - .lastHeartbeat(LocalDateTime.now()) - .osInfo(System.getProperty("os.name") + " " + System.getProperty("os.version")) - .javaVersion(System.getProperty("java.version")) - .environment("DEV") - .monitoringEnabled(true) - .build(); - } - - /** - * Delete server (soft delete) - * @param uid server UID - */ - @Transactional - public void deleteServer(String uid) { - Optional optional = serverRepository.findByUid(uid); - if (optional.isPresent()) { - ServerEntity server = optional.get(); - server.setDeleted(true); - serverRepository.save(server); - log.info("Deleted server: {}", server.getServerName()); - } - } - - /** - * Get server statistics for an organization - * @param orgUid organization UID - * @return ServerStatistics object - */ - public ServerStatistics getServerStatistics(String orgUid) { - List servers = findByOrgUid(orgUid); - - long totalServers = servers.size(); - long onlineServers = servers.stream() - .filter(s -> ServerStatusEnum.ONLINE.name().equals(s.getStatus())) - .count(); - long offlineServers = servers.stream() - .filter(s -> ServerStatusEnum.OFFLINE.name().equals(s.getStatus())) - .count(); - long warningServers = servers.stream() - .filter(s -> ServerStatusEnum.WARNING.name().equals(s.getStatus())) - .count(); - long overloadedServers = servers.stream() - .filter(s -> ServerStatusEnum.OVERLOADED.name().equals(s.getStatus())) - .count(); - - return ServerStatistics.builder() - .totalServers(totalServers) - .onlineServers(onlineServers) - .offlineServers(offlineServers) - .warningServers(warningServers) - .overloadedServers(overloadedServers) - .build(); - } - - /** - * Server statistics data class - */ - public static class ServerStatistics { - private long totalServers; - private long onlineServers; - private long offlineServers; - private long warningServers; - private long overloadedServers; - - // Getters and setters - public long getTotalServers() { return totalServers; } - public void setTotalServers(long totalServers) { this.totalServers = totalServers; } - - public long getOnlineServers() { return onlineServers; } - public void setOnlineServers(long onlineServers) { this.onlineServers = onlineServers; } - - public long getOfflineServers() { return offlineServers; } - public void setOfflineServers(long offlineServers) { this.offlineServers = offlineServers; } - - public long getWarningServers() { return warningServers; } - public void setWarningServers(long warningServers) { this.warningServers = warningServers; } - - public long getOverloadedServers() { return overloadedServers; } - public void setOverloadedServers(long overloadedServers) { this.overloadedServers = overloadedServers; } - - // Builder pattern - public static ServerStatisticsBuilder builder() { - return new ServerStatisticsBuilder(); - } - - public static class ServerStatisticsBuilder { - private ServerStatistics statistics = new ServerStatistics(); - - public ServerStatisticsBuilder totalServers(long totalServers) { - statistics.totalServers = totalServers; - return this; - } - - public ServerStatisticsBuilder onlineServers(long onlineServers) { - statistics.onlineServers = onlineServers; - return this; - } - - public ServerStatisticsBuilder offlineServers(long offlineServers) { - statistics.offlineServers = offlineServers; - return this; - } - - public ServerStatisticsBuilder warningServers(long warningServers) { - statistics.warningServers = warningServers; - return this; - } - - public ServerStatisticsBuilder overloadedServers(long overloadedServers) { - statistics.overloadedServers = overloadedServers; - return this; - } - - public ServerStatistics build() { - return statistics; - } - } - } -} \ No newline at end of file