This commit is contained in:
jack ning
2025-07-24 20:50:42 +08:00
parent 745c7fc641
commit e94100ccef
27 changed files with 1731 additions and 803 deletions

View File

@@ -1,79 +0,0 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2024-05-11 18:14:28
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-07-24 19:56:39
* @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.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
* 联系270580156@qq.com
* Copyright (c) 2024 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.host;
import com.bytedesk.core.base.BaseEntity;
import com.bytedesk.core.constant.I18Consts;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
// import jakarta.persistence.EntityListeners;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;
/**
* Host entity for content categorization and organization
* Provides host functionality for various system entities
*
* Database Table: bytedesk_core_host
* Purpose: Stores host definitions, colors, and organization settings
*/
@Entity
@Data
@SuperBuilder
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@AllArgsConstructor
@NoArgsConstructor
// @EntityListeners({HostEntityListener.class})
@Table(name = "bytedesk_core_host")
public class HostEntity extends BaseEntity {
/**
* Name of the host
*/
private String name;
/**
* Description of the host
*/
@Builder.Default
private String description = I18Consts.I18N_DESCRIPTION;
/**
* Type of host (CUSTOMER, TICKET, ARTICLE, etc.)
*/
@Builder.Default
@Column(name = "host_type")
private String type = HostTypeEnum.CUSTOMER.name();
/**
* Color theme for the host display
*/
@Builder.Default
@Column(name = "host_color")
private String color = "red";
/**
* Display order of the host
*/
@Builder.Default
@Column(name = "host_order")
private Integer order = 0;
}

View File

@@ -1,44 +0,0 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2025-02-25 09:44:18
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-06-04 15:50:06
* @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.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
*
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.host;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import com.bytedesk.core.rbac.organization.OrganizationEntity;
import com.bytedesk.core.rbac.organization.event.OrganizationCreateEvent;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
@AllArgsConstructor
public class HostEventListener {
private final HostRestService hostRestService;
@Order(3)
@EventListener
public void onOrganizationCreateEvent(OrganizationCreateEvent event) {
OrganizationEntity organization = (OrganizationEntity) event.getSource();
String orgUid = organization.getUid();
log.info("thread - organization created: {}", organization.getName());
hostRestService.initHosts(orgUid);
}
}

View File

@@ -1,122 +0,0 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2025-03-11 08:54:35
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-06-04 17:12:37
* @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.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
*
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.host;
// import com.bytedesk.core.constant.I18Consts;
public class HostInitData {
/**
* Technical Support Hosts
* 技术支持标签
*/
public static final String[] TECHNICAL_SUPPORT = {
// I18Consts.I18N_PREFIX + "thread.host.technical_support", // parent
"技术支持", // parent
};
/**
* Service Request Hosts
* 服务请求标签
*/
public static final String[] SERVICE_REQUEST = {
// I18Consts.I18N_PREFIX + "thread.host.service_request", // parent
"服务请求", // parent
};
/**
* Consultation Hosts
* 咨询标签
*/
public static final String[] CONSULTATION = {
// I18Consts.I18N_PREFIX + "thread.host.consultation", // parent
"咨询", // parent
};
/**
* Complaint & Suggestion Hosts
* 投诉与建议标签
*/
public static final String[] COMPLAINT_SUGGESTION = {
// I18Consts.I18N_PREFIX + "thread.host.complaint_suggestion", // parent
"投诉建议", // parent
};
/**
* Operation & Maintenance Hosts
* 运维标签
*/
public static final String[] OPERATION_MAINTENANCE = {
// I18Consts.I18N_PREFIX + "thread.host.operation_maintenance", // parent
"运维", // parent
// 其他
// I18Consts.I18N_PREFIX + "thread.host.other",
"其他",
};
/**
* Helper method to determine if a host is a parent host
*
* @param host The host key to check
* @return true if it's a parent host
*/
public static boolean isParentHost(String host) {
return !host.contains(".");
}
/**
* Helper method to get parent host key for a child host
*
* @param childHost The child host key
* @return The parent host key
*/
public static String getParentHost(String childHost) {
if (isParentHost(childHost)) {
return null;
}
// 由于已将常量转为中文,此方法可能需要重新实现
// 这里仅保留基本结构,具体实现需要根据新的标签体系来调整
return null;
}
/**
* Get all hosts as a single array
*
* @return Array containing all hosts
*/
public static String[] getAllHosts() {
int totalLength = TECHNICAL_SUPPORT.length + SERVICE_REQUEST.length +
CONSULTATION.length + COMPLAINT_SUGGESTION.length +
OPERATION_MAINTENANCE.length;
String[] allHosts = new String[totalLength];
int index = 0;
System.arraycopy(TECHNICAL_SUPPORT, 0, allHosts, index, TECHNICAL_SUPPORT.length);
index += TECHNICAL_SUPPORT.length;
System.arraycopy(SERVICE_REQUEST, 0, allHosts, index, SERVICE_REQUEST.length);
index += SERVICE_REQUEST.length;
System.arraycopy(CONSULTATION, 0, allHosts, index, CONSULTATION.length);
index += CONSULTATION.length;
System.arraycopy(COMPLAINT_SUGGESTION, 0, allHosts, index, COMPLAINT_SUGGESTION.length);
index += COMPLAINT_SUGGESTION.length;
System.arraycopy(OPERATION_MAINTENANCE, 0, allHosts, index, OPERATION_MAINTENANCE.length);
return allHosts;
}
}

View File

@@ -1,30 +0,0 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2024-05-11 18:25:55
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-06-20 12:52:47
* @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.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
* 联系270580156@qq.com
* Copyright (c) 2024 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.host;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface HostRepository extends JpaRepository<HostEntity, Long>, JpaSpecificationExecutor<HostEntity> {
Optional<HostEntity> findByUid(String uid);
Boolean existsByUid(String uid);
Optional<HostEntity> findByNameAndOrgUidAndTypeAndDeletedFalse(String name, String orgUid, String type);
// Boolean existsByPlatform(String platform);
}

View File

@@ -1,42 +0,0 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2024-05-11 18:26:04
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-06-20 14:24:05
* @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.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
* 联系270580156@qq.com
* Copyright (c) 2024 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.host;
import com.bytedesk.core.base.BaseRequest;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;
@Data
@SuperBuilder
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@AllArgsConstructor
@NoArgsConstructor
public class HostRequest extends BaseRequest {
private String name;
private String description;
// @Builder.Default
// private String type = HostTypeEnum.CUSTOMER.name();
private String color;
private Integer order;
}

View File

@@ -1,44 +0,0 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2024-05-11 18:26:12
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-06-04 15:36:28
* @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.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
* 联系270580156@qq.com
* Copyright (c) 2024 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.host;
import com.bytedesk.core.base.BaseResponse;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;
@Data
@SuperBuilder
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@AllArgsConstructor
@NoArgsConstructor
public class HostResponse extends BaseResponse {
private String name;
private String description;
private String type;
private String color;
private Integer order;
}

View File

@@ -1,124 +0,0 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2024-05-11 18:25:36
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-07-24 19:55:50
* @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.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
* 联系270580156@qq.com
* Copyright (c) 2024 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.host;
import org.springframework.data.domain.Page;
import org.springframework.http.ResponseEntity;
// import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.context.annotation.Description;
import com.bytedesk.core.annotation.ActionAnnotation;
import com.bytedesk.core.base.BaseRestController;
import com.bytedesk.core.utils.JsonResult;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
@RestController
@RequestMapping("/api/v1/host")
@AllArgsConstructor
@Tag(name = "Host Management", description = "Host management APIs for organizing and categorizing content with hosts")
@Description("Host Management Controller - Content host and categorization APIs")
public class HostRestController extends BaseRestController<HostRequest> {
private final HostRestService hostRestService;
// @PreAuthorize(RolePermissions.ROLE_ADMIN)
@ActionAnnotation(title = "Host", action = "org query", description = "query host by org")
@Operation(summary = "Query Hosts by Organization", description = "Retrieve hosts for the current organization")
@Override
public ResponseEntity<?> queryByOrg(HostRequest request) {
Page<HostResponse> hosts = hostRestService.queryByOrg(request);
return ResponseEntity.ok(JsonResult.success(hosts));
}
@ActionAnnotation(title = "Host", action = "user query", description = "query host by user")
@Operation(summary = "Query Hosts by User", description = "Retrieve hosts for the current user")
@Override
public ResponseEntity<?> queryByUser(HostRequest request) {
Page<HostResponse> hosts = hostRestService.queryByUser(request);
return ResponseEntity.ok(JsonResult.success(hosts));
}
@ActionAnnotation(title = "Host", action = "query detail", description = "query host by uid")
@Operation(summary = "Query Host by UID", description = "Retrieve a specific host by its unique identifier")
@Override
public ResponseEntity<?> queryByUid(HostRequest request) {
HostResponse host = hostRestService.queryByUid(request);
return ResponseEntity.ok(JsonResult.success(host));
}
@ActionAnnotation(title = "Host", action = "create", description = "create host")
@Operation(summary = "Create Host", description = "Create a new host")
@Override
// @PreAuthorize("hasAuthority('TAG_CREATE')")
public ResponseEntity<?> create(HostRequest request) {
HostResponse host = hostRestService.create(request);
return ResponseEntity.ok(JsonResult.success(host));
}
@ActionAnnotation(title = "Host", action = "update", description = "update host")
@Operation(summary = "Update Host", description = "Update an existing host")
@Override
// @PreAuthorize("hasAuthority('TAG_UPDATE')")
public ResponseEntity<?> update(HostRequest request) {
HostResponse host = hostRestService.update(request);
return ResponseEntity.ok(JsonResult.success(host));
}
@ActionAnnotation(title = "Host", action = "delete", description = "delete host")
@Operation(summary = "Delete Host", description = "Delete a host")
@Override
// @PreAuthorize("hasAuthority('TAG_DELETE')")
public ResponseEntity<?> delete(HostRequest request) {
hostRestService.delete(request);
return ResponseEntity.ok(JsonResult.success());
}
@ActionAnnotation(title = "Host", action = "export", description = "export host")
@Operation(summary = "Export Hosts", description = "Export hosts to Excel format")
@Override
// @PreAuthorize("hasAuthority('TAG_EXPORT')")
@GetMapping("/export")
public Object export(HostRequest request, HttpServletResponse response) {
return exportTemplate(
request,
response,
hostRestService,
HostExcel.class,
"Host",
"host"
);
}
}

View File

@@ -1,221 +0,0 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2024-05-11 18:25:45
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-07-02 11:05:26
* @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.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
* 联系270580156@qq.com
* Copyright (c) 2024 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.host;
import java.util.Optional;
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 org.springframework.util.StringUtils;
import com.bytedesk.core.base.BaseRestServiceWithExcel;
import com.bytedesk.core.constant.BytedeskConsts;
import com.bytedesk.core.enums.LevelEnum;
import com.bytedesk.core.rbac.auth.AuthService;
import com.bytedesk.core.rbac.user.UserEntity;
import com.bytedesk.core.uid.UidUtils;
import com.bytedesk.core.utils.Utils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
@AllArgsConstructor
public class HostRestService extends BaseRestServiceWithExcel<HostEntity, HostRequest, HostResponse, HostExcel> {
private final HostRepository hostRepository;
private final ModelMapper modelMapper;
private final UidUtils uidUtils;
private final AuthService authService;
@Override
public Page<HostEntity> queryByOrgEntity(HostRequest request) {
Pageable pageable = request.getPageable();
Specification<HostEntity> spec = HostSpecification.search(request);
return hostRepository.findAll(spec, pageable);
}
@Override
public Page<HostResponse> queryByOrg(HostRequest request) {
Page<HostEntity> page = queryByOrgEntity(request);
return page.map(this::convertToResponse);
}
@Override
public Page<HostResponse> queryByUser(HostRequest request) {
UserEntity user = authService.getUser();
if (user == null) {
throw new RuntimeException("login first");
}
request.setUserUid(user.getUid());
//
return queryByOrg(request);
}
@Override
public HostResponse queryByUid(HostRequest request) {
Optional<HostEntity> optional = findByUid(request.getUid());
if (optional.isPresent()) {
HostEntity entity = optional.get();
return convertToResponse(entity);
} else {
throw new RuntimeException("Host not found");
}
}
@Cacheable(value = "host", key = "#uid", unless="#result==null")
@Override
public Optional<HostEntity> findByUid(String uid) {
return hostRepository.findByUid(uid);
}
@Cacheable(value = "host", key = "#name + '_' + #orgUid + '_' + #type", unless="#result==null")
public Optional<HostEntity> findByNameAndOrgUidAndType(String name, String orgUid, String type) {
return hostRepository.findByNameAndOrgUidAndTypeAndDeletedFalse(name, orgUid, type);
}
public Boolean existsByUid(String uid) {
return hostRepository.existsByUid(uid);
}
@Transactional
@Override
public HostResponse create(HostRequest request) {
// 判断是否已经存在
if (StringUtils.hasText(request.getUid()) && existsByUid(request.getUid())) {
return convertToResponse(findByUid(request.getUid()).get());
}
// 检查name+orgUid+type是否已经存在
if (StringUtils.hasText(request.getName()) && StringUtils.hasText(request.getOrgUid()) && StringUtils.hasText(request.getType())) {
Optional<HostEntity> host = findByNameAndOrgUidAndType(request.getName(), request.getOrgUid(), request.getType());
if (host.isPresent()) {
return convertToResponse(host.get());
}
}
//
UserEntity user = authService.getUser();
if (user != null) {
request.setUserUid(user.getUid());
}
//
HostEntity entity = modelMapper.map(request, HostEntity.class);
if (!StringUtils.hasText(request.getUid())) {
entity.setUid(uidUtils.getUid());
}
//
HostEntity savedEntity = save(entity);
if (savedEntity == null) {
throw new RuntimeException("Create host failed");
}
return convertToResponse(savedEntity);
}
@Transactional
@Override
public HostResponse update(HostRequest request) {
Optional<HostEntity> optional = hostRepository.findByUid(request.getUid());
if (optional.isPresent()) {
HostEntity entity = optional.get();
modelMapper.map(request, entity);
//
HostEntity savedEntity = save(entity);
if (savedEntity == null) {
throw new RuntimeException("Update host failed");
}
return convertToResponse(savedEntity);
}
else {
throw new RuntimeException("Host not found");
}
}
@Override
protected HostEntity doSave(HostEntity entity) {
return hostRepository.save(entity);
}
@Override
public HostEntity handleOptimisticLockingFailureException(ObjectOptimisticLockingFailureException e, HostEntity entity) {
try {
Optional<HostEntity> latest = hostRepository.findByUid(entity.getUid());
if (latest.isPresent()) {
HostEntity latestEntity = latest.get();
// 合并需要保留的数据
latestEntity.setName(entity.getName());
// latestEntity.setOrder(entity.getOrder());
// latestEntity.setDeleted(entity.isDeleted());
return hostRepository.save(latestEntity);
}
} catch (Exception ex) {
log.error("无法处理乐观锁冲突: {}", ex.getMessage(), ex);
throw new RuntimeException("无法处理乐观锁冲突: " + ex.getMessage(), ex);
}
return null;
}
@Transactional
@Override
public void deleteByUid(String uid) {
Optional<HostEntity> optional = hostRepository.findByUid(uid);
if (optional.isPresent()) {
optional.get().setDeleted(true);
save(optional.get());
// hostRepository.delete(optional.get());
}
else {
throw new RuntimeException("Host not found");
}
}
@Override
public void delete(HostRequest request) {
deleteByUid(request.getUid());
}
@Override
public HostResponse convertToResponse(HostEntity entity) {
return modelMapper.map(entity, HostResponse.class);
}
@Override
public HostExcel convertToExcel(HostEntity entity) {
return modelMapper.map(entity, HostExcel.class);
}
public void initHosts(String orgUid) {
// log.info("initThreadHost");
for (String host : HostInitData.getAllHosts()) {
HostRequest hostRequest = HostRequest.builder()
.uid(Utils.formatUid(orgUid, host))
.name(host)
.order(0)
.type(HostTypeEnum.THREAD.name())
.level(LevelEnum.ORGANIZATION.name())
.platform(BytedeskConsts.PLATFORM_BYTEDESK)
.orgUid(orgUid)
.build();
create(hostRequest);
}
}
}

View File

@@ -0,0 +1,185 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2024-05-11 18:14:28
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-07-24 20:36:13
* @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.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
* 联系270580156@qq.com
* Copyright (c) 2024 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.server;
import com.bytedesk.core.base.BaseEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;
import java.time.LocalDateTime;
/**
* Server entity for monitoring server resources and status
* Provides server monitoring functionality for system administration
*
* Database Table: bytedesk_core_server
* Purpose: Stores server information, resource usage, and monitoring data
*/
@Entity
@Data
@SuperBuilder
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "bytedesk_core_server")
public class ServerEntity extends BaseEntity {
/**
* Server hostname or identifier
*/
@Column(nullable = false)
private String serverName;
/**
* Server IP address
*/
private String serverIp;
/**
* Server type (APPLICATION, DATABASE, CACHE, etc.)
*/
@Builder.Default
@Column(name = "server_type")
private String type = ServerTypeEnum.APPLICATION.name();
/**
* Server status (ONLINE, OFFLINE, MAINTENANCE, etc.)
*/
@Builder.Default
@Column(name = "server_status")
private String status = ServerStatusEnum.ONLINE.name();
/**
* Server description
*/
@Column(name = "server_description")
private String description;
/**
* CPU usage percentage (0-100)
*/
@Builder.Default
private Double cpuUsage = 0.0;
/**
* Memory usage percentage (0-100)
*/
@Builder.Default
private Double memoryUsage = 0.0;
/**
* Total memory in MB
*/
private Long totalMemoryMb;
/**
* Used memory in MB
*/
private Long usedMemoryMb;
/**
* Disk usage percentage (0-100)
*/
@Builder.Default
private Double diskUsage = 0.0;
/**
* Total disk space in GB
*/
private Long totalDiskGb;
/**
* Used disk space in GB
*/
private Long usedDiskGb;
/**
* Server uptime in seconds
*/
private Long uptimeSeconds;
/**
* Server start time
*/
private LocalDateTime startTime;
/**
* Last heartbeat time
*/
private LocalDateTime lastHeartbeat;
/**
* Server port (if applicable)
*/
private Integer serverPort;
/**
* Operating system information
*/
private String osInfo;
/**
* Java version (if applicable)
*/
private String javaVersion;
/**
* Application version
*/
private String appVersion;
/**
* Environment (DEV, TEST, PROD, etc.)
*/
@Builder.Default
private String environment = "DEV";
/**
* Server location or data center
*/
private String location;
/**
* Monitoring enabled flag
*/
@Builder.Default
private Boolean monitoringEnabled = true;
/**
* Alert threshold for CPU usage
*/
@Builder.Default
private Double cpuAlertThreshold = 80.0;
/**
* Alert threshold for memory usage
*/
@Builder.Default
private Double memoryAlertThreshold = 80.0;
/**
* Alert threshold for disk usage
*/
@Builder.Default
private Double diskAlertThreshold = 85.0;
}

View File

@@ -11,14 +11,14 @@
*
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.host;
package com.bytedesk.core.server;
import org.springframework.stereotype.Component;
import org.springframework.util.SerializationUtils;
import com.bytedesk.core.config.BytedeskEventPublisher;
import com.bytedesk.core.host.event.HostCreateEvent;
import com.bytedesk.core.host.event.HostUpdateEvent;
import com.bytedesk.core.server.event.ServerCreateEvent;
import com.bytedesk.core.server.event.ServerUpdateEvent;
import com.bytedesk.core.utils.ApplicationContextHolder;
import jakarta.persistence.PostPersist;
@@ -28,24 +28,24 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
public class HostEntityListener {
public class ServerEntityListener {
@PostPersist
public void onPostPersist(HostEntity host) {
log.info("onPostPersist: {}", host);
HostEntity cloneHost = SerializationUtils.clone(host);
public void onPostPersist(ServerEntity server) {
log.info("onPostPersist: {}", server);
ServerEntity cloneServer = SerializationUtils.clone(server);
//
BytedeskEventPublisher bytedeskEventPublisher = ApplicationContextHolder.getBean(BytedeskEventPublisher.class);
bytedeskEventPublisher.publishEvent(new HostCreateEvent(cloneHost));
bytedeskEventPublisher.publishEvent(new ServerCreateEvent(cloneServer));
}
@PostUpdate
public void onPostUpdate(HostEntity host) {
log.info("onPostUpdate: {}", host);
HostEntity cloneHost = SerializationUtils.clone(host);
public void onPostUpdate(ServerEntity server) {
log.info("onPostUpdate: {}", server);
ServerEntity cloneServer = SerializationUtils.clone(server);
//
BytedeskEventPublisher bytedeskEventPublisher = ApplicationContextHolder.getBean(BytedeskEventPublisher.class);
bytedeskEventPublisher.publishEvent(new HostUpdateEvent(cloneHost));
bytedeskEventPublisher.publishEvent(new ServerUpdateEvent(cloneServer));
}
}

View File

@@ -1,20 +1,28 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2024-07-23 17:02:46
* @Date: 2025-02-25 09:44:18
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-03-11 08:57:11
* @LastEditTime: 2025-07-24 20:45:51
* @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.
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
* 联系270580156@qq.com
* Copyright (c) 2024 by bytedesk.com, All Rights Reserved.
*
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.host;
package com.bytedesk.core.server;
public enum HostTypeEnum {
THREAD,
CUSTOMER,
TICKET
import org.springframework.stereotype.Component;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
@AllArgsConstructor
public class ServerEventListener {
}

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-08-01 06:18:10
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-07-04 18:00:51
* @LastEditTime: 2025-07-24 20:37:52
* @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.
@@ -11,12 +11,9 @@
* 联系270580156@qq.com
* Copyright (c) 2024 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.host;
import java.time.ZonedDateTime;
package com.bytedesk.core.server;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import lombok.Data;
@@ -25,23 +22,14 @@ import lombok.Data;
* https://github.com/alibaba/easyexcel
*/
@Data
public class HostExcel {
public class ServerExcel {
@ExcelProperty(index = 0, value = "标签名称")
@ExcelProperty(index = 0, value = "服务器名称")
@ColumnWidth(20)
private String name;
private String serverName;
@ExcelProperty(index = 1, value = "类型")
@ExcelProperty(index = 1, value = "服务器IP")
@ColumnWidth(20)
private String type;
@ExcelProperty(index = 2, value = "颜色")
@ColumnWidth(20)
private String color;
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
@ExcelProperty(value = "创建时间", converter = com.bytedesk.core.converter.ZonedDateTimeConverter.class)
@ColumnWidth(25)
private ZonedDateTime createdAt;
private String serverIp;
}

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-11-06 21:43:58
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-06-04 17:09:29
* @LastEditTime: 2025-07-24 20:36:45
* @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.
@@ -11,32 +11,25 @@
* 联系270580156@qq.com
* Copyright (c) 2024 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.host;
package com.bytedesk.core.server;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.stereotype.Component;
import com.bytedesk.core.constant.BytedeskConsts;
import lombok.AllArgsConstructor;
@Component
@AllArgsConstructor
public class HostInitializer implements SmartInitializingSingleton {
private final HostRestService hostRestService;
public class ServerInitializer implements SmartInitializingSingleton {
@Override
public void afterSingletonsInstantiated() {
initPermissions();
// 创建默认的工单分类
String orgUid = BytedeskConsts.DEFAULT_ORGANIZATION_UID;
hostRestService.initHosts(orgUid);
}
private void initPermissions() {
// for (PermissionEnum permission : PermissionEnum.values()) {
// String permissionValue = HostPermissions.ARTICLE_PREFIX + permission.name();
// String permissionValue = ServerPermissions.ARTICLE_PREFIX + permission.name();
// authorityService.createForPlatform(permissionValue);
// }
}

View File

@@ -11,10 +11,10 @@
* 联系270580156@qq.com
* Copyright (c) 2024 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.host;
package com.bytedesk.core.server;
import com.bytedesk.core.base.BasePermissions;
public class HostPermissions extends BasePermissions {
public class ServerPermissions extends BasePermissions {
}

View File

@@ -0,0 +1,128 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2024-05-11 18:14:28
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-07-24 19:56:39
* @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.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
* 联系270580156@qq.com
* Copyright (c) 2024 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.server;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
/**
* Repository for ServerEntity
* Provides database operations for server monitoring data
*/
@Repository
public interface ServerRepository extends JpaRepository<ServerEntity, Long>, JpaSpecificationExecutor<ServerEntity> {
/**
* Find server by UID
* @param uid server UID
* @return Optional<ServerEntity>
*/
Optional<ServerEntity> findByUid(String uid);
/**
* Find server by server name and organization UID
* @param serverName server name
* @param orgUid organization UID
* @return Optional<ServerEntity>
*/
Optional<ServerEntity> findByServerNameAndOrgUidAndDeletedFalse(String serverName, String orgUid);
/**
* Find servers by organization UID
* @param orgUid organization UID
* @return List<ServerEntity>
*/
List<ServerEntity> findByOrgUidAndDeletedFalseOrderByCreatedAtDesc(String orgUid);
/**
* Find servers by type
* @param type server type
* @param orgUid organization UID
* @return List<ServerEntity>
*/
List<ServerEntity> findByTypeAndOrgUidAndDeletedFalse(String type, String orgUid);
/**
* Find servers by status
* @param status server status
* @param orgUid organization UID
* @return List<ServerEntity>
*/
List<ServerEntity> findByStatusAndOrgUidAndDeletedFalse(String status, String orgUid);
/**
* Find servers with high resource usage
* @param orgUid organization UID
* @param cpuThreshold CPU usage threshold
* @param memoryThreshold memory usage threshold
* @param diskThreshold disk usage threshold
* @return List<ServerEntity>
*/
@Query("SELECT s FROM ServerEntity s WHERE s.orgUid = :orgUid AND s.deleted = false " +
"AND (s.cpuUsage >= :cpuThreshold OR s.memoryUsage >= :memoryThreshold OR s.diskUsage >= :diskThreshold)")
List<ServerEntity> findServersWithHighUsage(@Param("orgUid") String orgUid,
@Param("cpuThreshold") Double cpuThreshold,
@Param("memoryThreshold") Double memoryThreshold,
@Param("diskThreshold") Double diskThreshold);
/**
* Find servers that haven't sent heartbeat recently
* @param orgUid organization UID
* @param cutoffTime cutoff time for heartbeat
* @return List<ServerEntity>
*/
@Query("SELECT s FROM ServerEntity s WHERE s.orgUid = :orgUid AND s.deleted = false " +
"AND (s.lastHeartbeat IS NULL OR s.lastHeartbeat < :cutoffTime)")
List<ServerEntity> findServersWithoutRecentHeartbeat(@Param("orgUid") String orgUid,
@Param("cutoffTime") LocalDateTime cutoffTime);
/**
* Count servers by status
* @param status server status
* @param orgUid organization UID
* @return count
*/
long countByStatusAndOrgUidAndDeletedFalse(String status, String orgUid);
/**
* Count servers by type
* @param type server type
* @param orgUid organization UID
* @return count
*/
long countByTypeAndOrgUidAndDeletedFalse(String type, String orgUid);
/**
* Find servers by environment
* @param environment environment (DEV, TEST, PROD, etc.)
* @param orgUid organization UID
* @return List<ServerEntity>
*/
List<ServerEntity> findByEnvironmentAndOrgUidAndDeletedFalse(String environment, String orgUid);
/**
* Find servers by location
* @param location server location
* @param orgUid organization UID
* @return List<ServerEntity>
*/
List<ServerEntity> findByLocationAndOrgUidAndDeletedFalse(String location, String orgUid);
}

View File

@@ -0,0 +1,184 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2024-05-11 18:14:28
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-07-24 20:36:13
* @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.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
* 联系270580156@qq.com
* Copyright (c) 2024 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.server;
import com.bytedesk.core.base.BaseRequest;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;
import java.time.LocalDateTime;
/**
* Server request DTO
* Used for server monitoring operations
*/
@Data
@SuperBuilder
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@AllArgsConstructor
@NoArgsConstructor
public class ServerRequest extends BaseRequest {
/**
* Server hostname or identifier
*/
private String serverName;
/**
* Server IP address
*/
private String serverIp;
/**
* Server type (APPLICATION, DATABASE, CACHE, etc.)
*/
@Builder.Default
private String serverType = ServerTypeEnum.APPLICATION.name();
/**
* Server status (ONLINE, OFFLINE, MAINTENANCE, etc.)
*/
@Builder.Default
private String serverStatus = ServerStatusEnum.ONLINE.name();
/**
* Server description
*/
private String description;
/**
* CPU usage percentage (0-100)
*/
@Builder.Default
private Double cpuUsage = 0.0;
/**
* Memory usage percentage (0-100)
*/
@Builder.Default
private Double memoryUsage = 0.0;
/**
* Total memory in MB
*/
private Long totalMemoryMb;
/**
* Used memory in MB
*/
private Long usedMemoryMb;
/**
* Disk usage percentage (0-100)
*/
@Builder.Default
private Double diskUsage = 0.0;
/**
* Total disk space in GB
*/
private Long totalDiskGb;
/**
* Used disk space in GB
*/
private Long usedDiskGb;
/**
* Server uptime in seconds
*/
private Long uptimeSeconds;
/**
* Server start time
*/
private LocalDateTime startTime;
/**
* Last heartbeat time
*/
private LocalDateTime lastHeartbeat;
/**
* Server port (if applicable)
*/
private Integer serverPort;
/**
* Operating system information
*/
private String osInfo;
/**
* Java version (if applicable)
*/
private String javaVersion;
/**
* Application version
*/
private String appVersion;
/**
* Environment (DEV, TEST, PROD, etc.)
*/
@Builder.Default
private String environment = "DEV";
/**
* Server location or data center
*/
private String location;
/**
* Monitoring enabled flag
*/
@Builder.Default
private Boolean monitoringEnabled = true;
/**
* Alert threshold for CPU usage
*/
@Builder.Default
private Double cpuAlertThreshold = 80.0;
/**
* Alert threshold for memory usage
*/
@Builder.Default
private Double memoryAlertThreshold = 80.0;
/**
* Alert threshold for disk usage
*/
@Builder.Default
private Double diskAlertThreshold = 85.0;
/**
* Search filters
*/
private String serverTypeFilter;
private String serverStatusFilter;
private String environmentFilter;
private String locationFilter;
private Boolean highUsageFilter; // true to show only servers with high resource usage
private Boolean offlineFilter; // true to show only offline servers
private Integer heartbeatThresholdMinutes; // minutes threshold for heartbeat check
}

View File

@@ -0,0 +1,303 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2024-05-11 18:14:28
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-07-24 20:48:23
* @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.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
* 联系270580156@qq.com
* Copyright (c) 2024 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.server;
import com.bytedesk.core.base.BaseResponse;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;
import java.time.LocalDateTime;
/**
* Server response DTO
* Used for server monitoring operations
*/
@Data
@SuperBuilder
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@AllArgsConstructor
@NoArgsConstructor
public class ServerResponse extends BaseResponse {
/**
* Server hostname or identifier
*/
private String serverName;
/**
* Server IP address
*/
private String serverIp;
/**
* Server type (APPLICATION, DATABASE, CACHE, etc.)
*/
private String serverType;
/**
* Server type display name
*/
private String serverTypeDisplay;
/**
* Server status (ONLINE, OFFLINE, MAINTENANCE, etc.)
*/
private String serverStatus;
/**
* Server status display name
*/
private String serverStatusDisplay;
/**
* Server description
*/
private String description;
/**
* CPU usage percentage (0-100)
*/
private Double cpuUsage;
/**
* Memory usage percentage (0-100)
*/
private Double memoryUsage;
/**
* Total memory in MB
*/
private Long totalMemoryMb;
/**
* Used memory in MB
*/
private Long usedMemoryMb;
/**
* Disk usage percentage (0-100)
*/
private Double diskUsage;
/**
* Total disk space in GB
*/
private Long totalDiskGb;
/**
* Used disk space in GB
*/
private Long usedDiskGb;
/**
* Server uptime in seconds
*/
private Long uptimeSeconds;
/**
* Server uptime formatted string (e.g., "2 days 3 hours 45 minutes")
*/
// private String uptimeFormatted;
/**
* Server start time
*/
private LocalDateTime startTime;
/**
* Server start time formatted string
*/
private String startTimeFormatted;
/**
* Last heartbeat time
*/
private LocalDateTime lastHeartbeat;
/**
* Last heartbeat time formatted string
*/
private String lastHeartbeatFormatted;
/**
* Server port (if applicable)
*/
private Integer serverPort;
/**
* Operating system information
*/
private String osInfo;
/**
* Java version (if applicable)
*/
private String javaVersion;
/**
* Application version
*/
private String appVersion;
/**
* Environment (DEV, TEST, PROD, etc.)
*/
private String environment;
/**
* Server location or data center
*/
private String location;
/**
* Monitoring enabled flag
*/
private Boolean monitoringEnabled;
/**
* Alert threshold for CPU usage
*/
private Double cpuAlertThreshold;
/**
* Alert threshold for memory usage
*/
private Double memoryAlertThreshold;
/**
* Alert threshold for disk usage
*/
private Double diskAlertThreshold;
/**
* Health status indicators
*/
private Boolean isHealthy;
private Boolean isOperational;
private Boolean hasHighCpuUsage;
private Boolean hasHighMemoryUsage;
private Boolean hasHighDiskUsage;
private Boolean hasRecentHeartbeat;
/**
* Status color for UI display
*/
// private String statusColor;
/**
* Status icon for UI display
*/
// private String statusIcon;
/**
* Get formatted uptime string
* @return formatted uptime string
*/
public String getUptimeFormatted() {
if (uptimeSeconds == null || uptimeSeconds <= 0) {
return "Unknown";
}
long days = uptimeSeconds / 86400;
long hours = (uptimeSeconds % 86400) / 3600;
long minutes = (uptimeSeconds % 3600) / 60;
if (days > 0) {
return String.format("%d days %d hours %d minutes", days, hours, minutes);
} else if (hours > 0) {
return String.format("%d hours %d minutes", hours, minutes);
} else {
return String.format("%d minutes", minutes);
}
}
/**
* Get status color for UI display
* @return status color
*/
public String getStatusColor() {
if (serverStatus == null) {
return "gray";
}
switch (serverStatus) {
case "ONLINE":
return "green";
case "OFFLINE":
return "red";
case "MAINTENANCE":
return "orange";
case "WARNING":
return "yellow";
case "OVERLOADED":
return "red";
case "ERROR":
return "red";
case "STARTING":
case "STOPPING":
case "RESTARTING":
return "blue";
default:
return "gray";
}
}
/**
* Get status icon for UI display
* @return status icon
*/
public String getStatusIcon() {
if (serverStatus == null) {
return "question-circle";
}
switch (serverStatus) {
case "ONLINE":
return "check-circle";
case "OFFLINE":
return "times-circle";
case "MAINTENANCE":
return "wrench";
case "WARNING":
return "exclamation-triangle";
case "OVERLOADED":
return "exclamation-circle";
case "ERROR":
return "times-circle";
case "STARTING":
return "play-circle";
case "STOPPING":
return "stop-circle";
case "RESTARTING":
return "sync";
default:
return "question-circle";
}
}
/**
* Check if server has high resource usage
* @return true if any resource usage is high
*/
public Boolean getHasHighResourceUsage() {
return (cpuUsage != null && cpuUsage > 80) ||
(memoryUsage != null && memoryUsage > 80) ||
(diskUsage != null && diskUsage > 85);
}
}

View File

@@ -0,0 +1,124 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2024-05-11 18:25:36
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-07-24 20:43:52
* @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.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
* 联系270580156@qq.com
* Copyright (c) 2024 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.server;
import org.springframework.data.domain.Page;
import org.springframework.http.ResponseEntity;
// import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.context.annotation.Description;
import com.bytedesk.core.annotation.ActionAnnotation;
import com.bytedesk.core.base.BaseRestController;
import com.bytedesk.core.utils.JsonResult;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
@RestController
@RequestMapping("/api/v1/server")
@AllArgsConstructor
@Tag(name = "Server Management", description = "Server management APIs for organizing and categorizing content with servers")
@Description("Server Management Controller - Content server and categorization APIs")
public class ServerRestController extends BaseRestController<ServerRequest> {
private final ServerRestService serverRestService;
// @PreAuthorize(RolePermissions.ROLE_ADMIN)
@ActionAnnotation(title = "标签", action = "组织查询", description = "query server by org")
@Operation(summary = "Query Servers by Organization", description = "Retrieve servers for the current organization")
@Override
public ResponseEntity<?> queryByOrg(ServerRequest request) {
Page<ServerResponse> servers = serverRestService.queryByOrg(request);
return ResponseEntity.ok(JsonResult.success(servers));
}
@ActionAnnotation(title = "标签", action = "用户查询", description = "query server by user")
@Operation(summary = "Query Servers by User", description = "Retrieve servers for the current user")
@Override
public ResponseEntity<?> queryByUser(ServerRequest request) {
Page<ServerResponse> servers = serverRestService.queryByUser(request);
return ResponseEntity.ok(JsonResult.success(servers));
}
@ActionAnnotation(title = "标签", action = "查询详情", description = "query server by uid")
@Operation(summary = "Query Server by UID", description = "Retrieve a specific server by its unique identifier")
@Override
public ResponseEntity<?> queryByUid(ServerRequest request) {
ServerResponse server = serverRestService.queryByUid(request);
return ResponseEntity.ok(JsonResult.success(server));
}
@ActionAnnotation(title = "标签", action = "新建", description = "create server")
@Operation(summary = "Create Server", description = "Create a new server")
@Override
// @PreAuthorize("hasAuthority('TAG_CREATE')")
public ResponseEntity<?> create(ServerRequest request) {
ServerResponse server = serverRestService.create(request);
return ResponseEntity.ok(JsonResult.success(server));
}
@ActionAnnotation(title = "标签", action = "更新", description = "update server")
@Operation(summary = "Update Server", description = "Update an existing server")
@Override
// @PreAuthorize("hasAuthority('TAG_UPDATE')")
public ResponseEntity<?> update(ServerRequest request) {
ServerResponse server = serverRestService.update(request);
return ResponseEntity.ok(JsonResult.success(server));
}
@ActionAnnotation(title = "标签", action = "删除", description = "delete server")
@Operation(summary = "Delete Server", description = "Delete a server")
@Override
// @PreAuthorize("hasAuthority('TAG_DELETE')")
public ResponseEntity<?> delete(ServerRequest request) {
serverRestService.delete(request);
return ResponseEntity.ok(JsonResult.success());
}
@ActionAnnotation(title = "标签", action = "导出", description = "export server")
@Operation(summary = "Export Servers", description = "Export servers to Excel format")
@Override
// @PreAuthorize("hasAuthority('TAG_EXPORT')")
@GetMapping("/export")
public Object export(ServerRequest request, HttpServletResponse response) {
return exportTemplate(
request,
response,
serverRestService,
ServerExcel.class,
"标签",
"server"
);
}
}

View File

@@ -0,0 +1,232 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2024-05-11 18:14:28
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-07-24 20:36:13
* @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.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
* 联系270580156@qq.com
* Copyright (c) 2024 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.server;
import com.bytedesk.core.base.BaseRestService;
import com.bytedesk.core.uid.UidUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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.orm.ObjectOptimisticLockingFailureException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.Optional;
/**
* REST service for server monitoring operations
* Provides CRUD operations and business logic for server management
*/
@Slf4j
@Service
@AllArgsConstructor
public class ServerRestService extends BaseRestService<ServerEntity, ServerRequest, ServerResponse> {
private final ServerRepository serverRepository;
private final ServerService serverService;
private final ModelMapper modelMapper;
private final UidUtils uidUtils;
// Helper method for internal use
private Page<ServerEntity> queryByOrgEntity(ServerRequest request) {
Pageable pageable = request.getPageable();
// TODO: Implement ServerSpecification.search(request)
return serverRepository.findAll(pageable);
}
@Override
public Page<ServerResponse> queryByOrg(ServerRequest request) {
Page<ServerEntity> page = queryByOrgEntity(request);
return page.map(this::convertToResponse);
}
@Override
public Page<ServerResponse> queryByUser(ServerRequest request) {
// For server monitoring, user query is same as org query
return queryByOrg(request);
}
@Override
public ServerResponse queryByUid(ServerRequest request) {
Optional<ServerEntity> optional = findByUid(request.getUid());
if (optional.isPresent()) {
ServerEntity entity = optional.get();
return convertToResponse(entity);
} else {
throw new RuntimeException("Server not found");
}
}
@Cacheable(value = "server", key = "#uid", unless="#result==null")
@Override
public Optional<ServerEntity> findByUid(String uid) {
return serverRepository.findByUid(uid);
}
@Override
public ServerResponse create(ServerRequest request) {
ServerEntity entity = convertToEntity(request);
entity.setUid(uidUtils.getUid());
entity.setCreatedAt(ZonedDateTime.now());
entity.setUpdatedAt(ZonedDateTime.now());
ServerEntity savedEntity = serverService.createServer(entity);
return convertToResponse(savedEntity);
}
@Override
public ServerResponse update(ServerRequest request) {
Optional<ServerEntity> optional = serverRepository.findByUid(request.getUid());
if (optional.isPresent()) {
ServerEntity existingEntity = optional.get();
updateEntityFromRequest(existingEntity, request);
existingEntity.setUpdatedAt(ZonedDateTime.now());
ServerEntity savedEntity = serverService.updateServer(existingEntity);
return convertToResponse(savedEntity);
} else {
throw new RuntimeException("Server not found");
}
}
@Override
public void deleteByUid(String uid) {
serverService.deleteServer(uid);
}
@Override
public void delete(ServerRequest request) {
deleteByUid(request.getUid());
}
@Override
public ServerResponse convertToResponse(ServerEntity entity) {
ServerResponse response = modelMapper.map(entity, ServerResponse.class);
// Set display names
if (entity.getType() != null) {
try {
ServerTypeEnum typeEnum = ServerTypeEnum.valueOf(entity.getType());
response.setServerTypeDisplay(typeEnum.getChineseName());
} catch (IllegalArgumentException e) {
response.setServerTypeDisplay(entity.getType());
}
}
if (entity.getStatus() != null) {
try {
ServerStatusEnum statusEnum = ServerStatusEnum.valueOf(entity.getStatus());
response.setServerStatusDisplay(statusEnum.getChineseName());
response.setIsHealthy(statusEnum.isHealthy());
response.setIsOperational(statusEnum.isOperational());
} catch (IllegalArgumentException e) {
response.setServerStatusDisplay(entity.getStatus());
}
}
// Set health indicators
response.setHasHighCpuUsage(entity.getCpuUsage() != null && entity.getCpuUsage() > 80);
response.setHasHighMemoryUsage(entity.getMemoryUsage() != null && entity.getMemoryUsage() > 80);
response.setHasHighDiskUsage(entity.getDiskUsage() != null && entity.getDiskUsage() > 85);
response.setHasRecentHeartbeat(entity.getLastHeartbeat() != null &&
entity.getLastHeartbeat().isAfter(java.time.LocalDateTime.now().minusMinutes(5)));
return response;
}
@Override
protected String getUidFromRequest(ServerRequest request) {
return request.getUid();
}
@Override
public ServerEntity doSave(ServerEntity entity) {
return serverRepository.save(entity);
}
@Override
protected ServerEntity handleOptimisticLockingFailureException(ObjectOptimisticLockingFailureException e, ServerEntity entity) {
log.warn("Optimistic locking failure for server: {}", entity.getUid());
return entity;
}
// Helper methods
private ServerEntity convertToEntity(ServerRequest request) {
ServerEntity entity = new ServerEntity();
entity.setServerName(request.getServerName());
entity.setServerIp(request.getServerIp());
entity.setType(request.getServerType());
entity.setStatus(request.getServerStatus());
entity.setDescription(request.getDescription());
entity.setCpuUsage(request.getCpuUsage());
entity.setMemoryUsage(request.getMemoryUsage());
entity.setTotalMemoryMb(request.getTotalMemoryMb());
entity.setUsedMemoryMb(request.getUsedMemoryMb());
entity.setDiskUsage(request.getDiskUsage());
entity.setTotalDiskGb(request.getTotalDiskGb());
entity.setUsedDiskGb(request.getUsedDiskGb());
entity.setUptimeSeconds(request.getUptimeSeconds());
entity.setStartTime(request.getStartTime());
entity.setLastHeartbeat(request.getLastHeartbeat());
entity.setServerPort(request.getServerPort());
entity.setOsInfo(request.getOsInfo());
entity.setJavaVersion(request.getJavaVersion());
entity.setAppVersion(request.getAppVersion());
entity.setEnvironment(request.getEnvironment());
entity.setLocation(request.getLocation());
entity.setMonitoringEnabled(request.getMonitoringEnabled());
entity.setCpuAlertThreshold(request.getCpuAlertThreshold());
entity.setMemoryAlertThreshold(request.getMemoryAlertThreshold());
entity.setDiskAlertThreshold(request.getDiskAlertThreshold());
entity.setOrgUid(request.getOrgUid());
entity.setDeleted(false);
return entity;
}
private void updateEntityFromRequest(ServerEntity entity, ServerRequest request) {
if (request.getServerName() != null) {
entity.setServerName(request.getServerName());
}
if (request.getServerType() != null) {
entity.setType(request.getServerType());
}
if (request.getServerStatus() != null) {
entity.setStatus(request.getServerStatus());
}
if (request.getDescription() != null) {
entity.setDescription(request.getDescription());
}
if (request.getCpuUsage() != null) {
entity.setCpuUsage(request.getCpuUsage());
}
if (request.getMemoryUsage() != null) {
entity.setMemoryUsage(request.getMemoryUsage());
}
if (request.getDiskUsage() != null) {
entity.setDiskUsage(request.getDiskUsage());
}
if (request.getEnvironment() != null) {
entity.setEnvironment(request.getEnvironment());
}
if (request.getLocation() != null) {
entity.setLocation(request.getLocation());
}
}
}

View File

@@ -0,0 +1,314 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2024-05-11 18:14:28
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-07-24 19:56:39
* @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.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
* 联系270580156@qq.com
* Copyright (c) 2024 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.server;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
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;
/**
* Service for server monitoring and management
* Provides business logic for server monitoring operations
*/
@Slf4j
@Service
@AllArgsConstructor
public class ServerService {
private final ServerRepository serverRepository;
/**
* Create a new server record
* @param serverEntity server entity to create
* @return created server entity
*/
@Transactional
public ServerEntity createServer(ServerEntity serverEntity) {
log.info("Creating server: {}", serverEntity.getServerName());
return serverRepository.save(serverEntity);
}
/**
* Update server information
* @param serverEntity server entity to update
* @return updated server entity
*/
@Transactional
public ServerEntity updateServer(ServerEntity serverEntity) {
log.info("Updating server: {}", serverEntity.getServerName());
return serverRepository.save(serverEntity);
}
/**
* Find server by UID
* @param uid server UID
* @return Optional<ServerEntity>
*/
public Optional<ServerEntity> findByUid(String uid) {
return serverRepository.findByUid(uid);
}
/**
* Find all servers for an organization
* @param orgUid organization UID
* @return List<ServerEntity>
*/
public List<ServerEntity> findByOrgUid(String orgUid) {
return serverRepository.findByOrgUidAndDeletedFalseOrderByCreatedAtDesc(orgUid);
}
/**
* Find servers by type
* @param type server type
* @param orgUid organization UID
* @return List<ServerEntity>
*/
public List<ServerEntity> findByType(String type, String orgUid) {
return serverRepository.findByTypeAndOrgUidAndDeletedFalse(type, orgUid);
}
/**
* Find servers by status
* @param status server status
* @param orgUid organization UID
* @return List<ServerEntity>
*/
public List<ServerEntity> findByStatus(String status, String orgUid) {
return serverRepository.findByStatusAndOrgUidAndDeletedFalse(status, orgUid);
}
/**
* Find servers with high resource usage
* @param orgUid organization UID
* @return List<ServerEntity>
*/
public List<ServerEntity> 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<ServerEntity>
*/
public List<ServerEntity> 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<ServerEntity> updateHeartbeat(String uid) {
Optional<ServerEntity> 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<ServerEntity> updateResourceUsage(String uid, Double cpuUsage, Double memoryUsage, Double diskUsage) {
Optional<ServerEntity> 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<ServerEntity> 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<ServerEntity> 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;
}
}
}
}

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-07-09 22:19:21
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-07-22 17:14:52
* @LastEditTime: 2025-07-24 20:39:01
* @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.
@@ -11,13 +11,12 @@
* 联系270580156@qq.com
* Copyright (c) 2024 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.host;
package com.bytedesk.core.server;
import java.util.ArrayList;
import java.util.List;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.StringUtils;
import com.bytedesk.core.base.BaseSpecification;
@@ -25,30 +24,14 @@ import jakarta.persistence.criteria.Predicate;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class HostSpecification extends BaseSpecification {
public class ServerSpecification extends BaseSpecification {
public static Specification<HostEntity> search(HostRequest request) {
public static Specification<ServerEntity> search(ServerRequest request) {
log.info("request: {} orgUid: {} pageNumber: {} pageSize: {}",
request, request.getOrgUid(), request.getPageNumber(), request.getPageSize());
return (root, query, criteriaBuilder) -> {
List<Predicate> predicates = new ArrayList<>();
predicates.addAll(getBasicPredicates(root, criteriaBuilder, request.getOrgUid()));
// name
if (StringUtils.hasText(request.getName())) {
predicates.add(criteriaBuilder.like(root.get("name"), "%" + request.getName() + "%"));
}
// description
if (StringUtils.hasText(request.getDescription())) {
predicates.add(criteriaBuilder.like(root.get("description"), "%" + request.getDescription() + "%"));
}
// type
if (StringUtils.hasText(request.getType())) {
predicates.add(criteriaBuilder.equal(root.get("type"), request.getType()));
}
//
if (StringUtils.hasText(request.getUserUid())) {
predicates.add(criteriaBuilder.equal(root.get("userUid"), request.getUserUid()));
}
//
return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
};

View File

@@ -0,0 +1,95 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2024-05-11 18:14:28
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-07-24 19:56:39
* @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.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
* 联系270580156@qq.com
* Copyright (c) 2024 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.server;
/**
* Server status enumeration
* Defines different statuses of servers
*/
public enum ServerStatusEnum {
ONLINE, // 在线运行
OFFLINE, // 离线
MAINTENANCE, // 维护中
STARTING, // 启动中
STOPPING, // 停止中
RESTARTING, // 重启中
ERROR, // 错误状态
WARNING, // 警告状态
DEGRADED, // 降级运行
OVERLOADED, // 过载
UNKNOWN; // 未知状态
/**
* Get Chinese name for the server status
* @return Chinese name
*/
public String getChineseName() {
switch (this) {
case ONLINE:
return "在线运行";
case OFFLINE:
return "离线";
case MAINTENANCE:
return "维护中";
case STARTING:
return "启动中";
case STOPPING:
return "停止中";
case RESTARTING:
return "重启中";
case ERROR:
return "错误状态";
case WARNING:
return "警告状态";
case DEGRADED:
return "降级运行";
case OVERLOADED:
return "过载";
case UNKNOWN:
return "未知状态";
default:
return this.name();
}
}
/**
* Check if server is healthy (online and not in error/warning states)
* @return true if healthy
*/
public boolean isHealthy() {
return this == ONLINE || this == DEGRADED;
}
/**
* Check if server is operational (can serve requests)
* @return true if operational
*/
public boolean isOperational() {
return this == ONLINE || this == DEGRADED || this == OVERLOADED;
}
/**
* Convert from string value to enum
* @param value string value
* @return ServerStatusEnum
*/
public static ServerStatusEnum fromValue(String value) {
for (ServerStatusEnum status : ServerStatusEnum.values()) {
if (status.name().equalsIgnoreCase(value)) {
return status;
}
}
throw new IllegalArgumentException("No ServerStatusEnum constant with value: " + value);
}
}

View File

@@ -0,0 +1,97 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2024-05-11 18:14:28
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-07-24 19:56:39
* @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.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
* 联系270580156@qq.com
* Copyright (c) 2024 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.server;
/**
* Server type enumeration
* Defines different types of servers in the system
*/
public enum ServerTypeEnum {
APPLICATION, // 应用服务器
DATABASE, // 数据库服务器
CACHE, // 缓存服务器
LOAD_BALANCER, // 负载均衡器
WEB_SERVER, // Web服务器
FILE_SERVER, // 文件服务器
MAIL_SERVER, // 邮件服务器
DNS_SERVER, // DNS服务器
PROXY_SERVER, // 代理服务器
MONITORING, // 监控服务器
BACKUP, // 备份服务器
GATEWAY, // 网关服务器
API_SERVER, // API服务器
MESSAGE_QUEUE, // 消息队列服务器
SEARCH_ENGINE, // 搜索引擎服务器
CDN, // CDN服务器
OTHER; // 其他类型
/**
* Get Chinese name for the server type
* @return Chinese name
*/
public String getChineseName() {
switch (this) {
case APPLICATION:
return "应用服务器";
case DATABASE:
return "数据库服务器";
case CACHE:
return "缓存服务器";
case LOAD_BALANCER:
return "负载均衡器";
case WEB_SERVER:
return "Web服务器";
case FILE_SERVER:
return "文件服务器";
case MAIL_SERVER:
return "邮件服务器";
case DNS_SERVER:
return "DNS服务器";
case PROXY_SERVER:
return "代理服务器";
case MONITORING:
return "监控服务器";
case BACKUP:
return "备份服务器";
case GATEWAY:
return "网关服务器";
case API_SERVER:
return "API服务器";
case MESSAGE_QUEUE:
return "消息队列服务器";
case SEARCH_ENGINE:
return "搜索引擎服务器";
case CDN:
return "CDN服务器";
case OTHER:
return "其他类型";
default:
return this.name();
}
}
/**
* Convert from string value to enum
* @param value string value
* @return ServerTypeEnum
*/
public static ServerTypeEnum fromValue(String value) {
for (ServerTypeEnum type : ServerTypeEnum.values()) {
if (type.name().equalsIgnoreCase(value)) {
return type;
}
}
throw new IllegalArgumentException("No ServerTypeEnum constant with value: " + value);
}
}

View File

@@ -11,26 +11,26 @@
*
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.host.event;
package com.bytedesk.core.server.event;
import org.springframework.context.ApplicationEvent;
import com.bytedesk.core.host.HostEntity;
import com.bytedesk.core.server.ServerEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
public class HostCreateEvent extends ApplicationEvent {
public class ServerCreateEvent extends ApplicationEvent {
private static final long serialVersionUID = 1L;
private HostEntity host;
private ServerEntity server;
public HostCreateEvent(HostEntity host) {
super(host);
this.host = host;
public ServerCreateEvent(ServerEntity server) {
super(server);
this.server = server;
}
}

View File

@@ -11,25 +11,25 @@
*
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.host.event;
package com.bytedesk.core.server.event;
import org.springframework.context.ApplicationEvent;
import com.bytedesk.core.host.HostEntity;
import com.bytedesk.core.server.ServerEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
public class HostDeleteEvent extends ApplicationEvent {
public class ServerDeleteEvent extends ApplicationEvent {
private static final long serialVersionUID = 1L;
private HostEntity host;
private ServerEntity server;
public HostDeleteEvent(HostEntity host) {
super(host);
this.host = host;
public ServerDeleteEvent(ServerEntity server) {
super(server);
this.server = server;
}
}

View File

@@ -11,26 +11,26 @@
*
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.host.event;
package com.bytedesk.core.server.event;
import org.springframework.context.ApplicationEvent;
import com.bytedesk.core.host.HostEntity;
import com.bytedesk.core.server.ServerEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
public class HostUpdateEvent extends ApplicationEvent {
public class ServerUpdateEvent extends ApplicationEvent {
private static final long serialVersionUID = 1L;
private HostEntity host;
private ServerEntity server;
public HostUpdateEvent(HostEntity host) {
super(host);
this.host = host;
public ServerUpdateEvent(ServerEntity server) {
super(server);
this.server = server;
}
}

View File

@@ -1,5 +1,5 @@
@NonNullApi
package com.bytedesk.core.host;
package com.bytedesk.core.server;
import org.springframework.lang.NonNullApi;