feat(image): 添加获取 VNC信息功能并优化镜像相关服务
- 在 DeviceImageMappingRes 中添加父镜像名称和创建时间字段 - 优化 DeviceImageMappingService 中镜像信息查询逻辑- 在 ExternalApiClient 中添加获取VNC 信息的接口 - 在 ImageVirtualMachinesController 中添加获取 VNC 信息的控制器方法- 在 ImageVirtualMachinesService接口中添加获取 VNC 信息的方法 - 实现 ImageVirtualMachinesServiceImpl 中获取 VNC 信息的逻辑 - 新增 VncData 类用于存储 VNC 信息master
parent
65365b2a86
commit
3c8d1b833b
|
|
@ -13,10 +13,7 @@ import com.unisinsight.project.service.ImageVirtualMachinesService;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
@ -154,6 +151,13 @@ public class ImageVirtualMachinesController {
|
||||||
log.info("终端卸载文件请求参数为:{}", JSONUtil.toJsonStr(req));
|
log.info("终端卸载文件请求参数为:{}", JSONUtil.toJsonStr(req));
|
||||||
return service.removeIso(req);
|
return service.removeIso(req);
|
||||||
}
|
}
|
||||||
|
@ApiOperation(value = "获取VNC信息")
|
||||||
|
@GetMapping("/vnc")
|
||||||
|
public Result<?> getVncData(@RequestParam("vmName") String vmName) {
|
||||||
|
|
||||||
|
log.info("获取VNC信息请求参数为:{}", vmName);
|
||||||
|
return service.getVncData(vmName);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @TableName device_image_mapping
|
* @TableName device_image_mapping
|
||||||
|
|
@ -60,6 +61,19 @@ public class DeviceImageMappingRes implements Serializable {
|
||||||
@ApiModelProperty("镜像源文件名称")
|
@ApiModelProperty("镜像源文件名称")
|
||||||
private String imageFileName;
|
private String imageFileName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 父镜像名称
|
||||||
|
*/
|
||||||
|
@JsonProperty(value = "parent_image_name")
|
||||||
|
@ApiModelProperty("父镜像名称")
|
||||||
|
private String parentImageName;
|
||||||
|
/**
|
||||||
|
* 父镜像名称
|
||||||
|
*/
|
||||||
|
@JsonProperty(value = "create_time")
|
||||||
|
@ApiModelProperty("创建时间")
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 还原方式
|
* 还原方式
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.unisinsight.project.entity.res;
|
||||||
|
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author : ch
|
||||||
|
* @version : 1.0
|
||||||
|
* @ClassName : VncData
|
||||||
|
* @Description :
|
||||||
|
* @DATE : Created in 9:41 2025/9/8
|
||||||
|
* <pre> Copyright: Copyright(c) 2025 </pre>
|
||||||
|
* <pre> Company : 紫光汇智信息技术有限公司 </pre>
|
||||||
|
* Modification History:
|
||||||
|
* Date Author Version Discription
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* 2025/09/08 ch 1.0 Why & What is modified: <修改原因描述> *
|
||||||
|
*/
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Data
|
||||||
|
public class VncData {
|
||||||
|
|
||||||
|
@JsonProperty("host")
|
||||||
|
private String host;
|
||||||
|
@JsonProperty("port")
|
||||||
|
private Integer port;
|
||||||
|
@JsonProperty("url")
|
||||||
|
private String url;
|
||||||
|
@JsonProperty("websocket_url")
|
||||||
|
private String websocketUrl;
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@ import com.unisinsight.project.config.FeignConfig;
|
||||||
import com.unisinsight.project.entity.dto.*;
|
import com.unisinsight.project.entity.dto.*;
|
||||||
import com.unisinsight.project.entity.req.*;
|
import com.unisinsight.project.entity.req.*;
|
||||||
import com.unisinsight.project.entity.res.ImageStatusRes;
|
import com.unisinsight.project.entity.res.ImageStatusRes;
|
||||||
|
import com.unisinsight.project.entity.res.VncData;
|
||||||
import org.springframework.cloud.openfeign.FeignClient;
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
|
@ -90,5 +91,7 @@ public interface ExternalApiClient {
|
||||||
|
|
||||||
@GetMapping("/api/v1/network/bridge-interfaces")
|
@GetMapping("/api/v1/network/bridge-interfaces")
|
||||||
ApiResponse<List<BridgeInterfaceDTO>> getBridgeInterfaces();
|
ApiResponse<List<BridgeInterfaceDTO>> getBridgeInterfaces();
|
||||||
|
@GetMapping("/api/v1/vm/{vmName}/vnc")
|
||||||
|
ApiResponse<VncData> getVncData(@PathVariable("vmName") String vmName);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ public class ClientNotificationServiceImpl extends NotificationServiceGrpc.Notif
|
||||||
private final ConcurrentHashMap<String, StreamObserver<NotificationMessage>> clientStreamMap =
|
private final ConcurrentHashMap<String, StreamObserver<NotificationMessage>> clientStreamMap =
|
||||||
new ConcurrentHashMap<>();
|
new ConcurrentHashMap<>();
|
||||||
private final static int MAX_CLIENT_COUNT = 1000;
|
private final static int MAX_CLIENT_COUNT = 1000;
|
||||||
|
public static final String DEFAULT_USER = "NexOS";
|
||||||
// 生成客户端连接key的工具方法
|
// 生成客户端连接key的工具方法
|
||||||
private String generateClientKey(String clientId, String clientUser) {
|
private String generateClientKey(String clientId, String clientUser) {
|
||||||
return clientId + "#" + clientUser;
|
return clientId + "#" + clientUser;
|
||||||
|
|
@ -70,15 +70,7 @@ public class ClientNotificationServiceImpl extends NotificationServiceGrpc.Notif
|
||||||
return; // 避免继续执行后续逻辑
|
return; // 避免继续执行后续逻辑
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtil.isEmpty(clientUser)) {
|
clientUser= StringUtil.isEmpty(clientUser) ? DEFAULT_USER : clientUser;
|
||||||
NotificationMessage errMsg = NotificationMessage.newBuilder()
|
|
||||||
.setCode(HttpStatus.BAD_REQUEST.value())
|
|
||||||
.setMsg("client_user不能为空")
|
|
||||||
.build();
|
|
||||||
responseObserver.onNext(errMsg);
|
|
||||||
responseObserver.onCompleted();
|
|
||||||
return; // 避免继续执行后续逻辑
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info("客户端连接:client_sn:[{}],client_user: [{}]", clientSn, clientUser);
|
log.info("客户端连接:client_sn:[{}],client_user: [{}]", clientSn, clientUser);
|
||||||
|
|
||||||
|
|
@ -93,11 +85,12 @@ public class ClientNotificationServiceImpl extends NotificationServiceGrpc.Notif
|
||||||
final io.grpc.Context context = io.grpc.Context.current();
|
final io.grpc.Context context = io.grpc.Context.current();
|
||||||
|
|
||||||
// 注册一个取消监听器来监听客户端断开连接
|
// 注册一个取消监听器来监听客户端断开连接
|
||||||
|
String finalClientUser = clientUser;
|
||||||
context.addListener(context1 -> {
|
context.addListener(context1 -> {
|
||||||
// 客户端断开连接时的处理逻辑
|
// 客户端断开连接时的处理逻辑
|
||||||
log.info("通过Context监听到客户端断开连接: {}, 用户: {}", clientSn, clientUser);
|
log.info("通过Context监听到客户端断开连接: {}, 用户: {}", clientSn, finalClientUser);
|
||||||
removeClientConnection(clientSn, clientUser);
|
removeClientConnection(clientSn, finalClientUser);
|
||||||
log.info("清理客户端连接: {}#{}, 剩余客户端数: {}", clientSn, clientUser, clientStreamMap.size());
|
log.info("清理客户端连接: {}#{}, 剩余客户端数: {}", clientSn, finalClientUser, clientStreamMap.size());
|
||||||
}, executorService);
|
}, executorService);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,5 +61,7 @@ public interface ImageVirtualMachinesService extends IService<ImageVirtualMachin
|
||||||
Result<?> removeIso(ImageVirtualMachinesReq req);
|
Result<?> removeIso(ImageVirtualMachinesReq req);
|
||||||
|
|
||||||
Result<?> attachIso(ImageVirtualMachinesReq req);
|
Result<?> attachIso(ImageVirtualMachinesReq req);
|
||||||
|
|
||||||
|
Result<?> getVncData(String vmName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,23 +7,18 @@ import cn.hutool.json.JSONUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import com.unisinsight.project.entity.dao.DeviceImageMapping;
|
import com.unisinsight.project.entity.dao.*;
|
||||||
import com.unisinsight.project.entity.dao.Image;
|
|
||||||
import com.unisinsight.project.entity.dao.ImageDesktop;
|
|
||||||
import com.unisinsight.project.entity.dao.UserDeviceGroup;
|
|
||||||
import com.unisinsight.project.entity.req.DeviceImageMappingReq;
|
import com.unisinsight.project.entity.req.DeviceImageMappingReq;
|
||||||
import com.unisinsight.project.entity.res.DeviceImageMappingRes;
|
import com.unisinsight.project.entity.res.DeviceImageMappingRes;
|
||||||
import com.unisinsight.project.exception.Result;
|
import com.unisinsight.project.exception.Result;
|
||||||
import com.unisinsight.project.mapper.DeviceImageMappingMapper;
|
import com.unisinsight.project.mapper.*;
|
||||||
import com.unisinsight.project.mapper.ImageDesktopMapper;
|
|
||||||
import com.unisinsight.project.mapper.ImageMapper;
|
|
||||||
import com.unisinsight.project.mapper.UserDeviceGroupMapper;
|
|
||||||
import com.unisinsight.project.service.DeviceImageMappingService;
|
import com.unisinsight.project.service.DeviceImageMappingService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
@ -43,6 +38,8 @@ public class DeviceImageMappingServiceImpl extends ServiceImpl<DeviceImageMappin
|
||||||
@Resource
|
@Resource
|
||||||
private ImageDesktopMapper imageDesktopMapper;
|
private ImageDesktopMapper imageDesktopMapper;
|
||||||
@Resource
|
@Resource
|
||||||
|
private ImageVirtualMachinesMapper imageVirtualMachinesMapper;
|
||||||
|
@Resource
|
||||||
private UserDeviceGroupMapper groupMapper;
|
private UserDeviceGroupMapper groupMapper;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -64,11 +61,21 @@ public class DeviceImageMappingServiceImpl extends ServiceImpl<DeviceImageMappin
|
||||||
if (CollectionUtil.isNotEmpty(imageIds)) {
|
if (CollectionUtil.isNotEmpty(imageIds)) {
|
||||||
LambdaQueryWrapper<ImageDesktop> imageLambdaQueryWrapper = new LambdaQueryWrapper<ImageDesktop>().in(ImageDesktop::getId, imageIds);
|
LambdaQueryWrapper<ImageDesktop> imageLambdaQueryWrapper = new LambdaQueryWrapper<ImageDesktop>().in(ImageDesktop::getId, imageIds);
|
||||||
List<ImageDesktop> images = imageDesktopMapper.selectList(imageLambdaQueryWrapper);
|
List<ImageDesktop> images = imageDesktopMapper.selectList(imageLambdaQueryWrapper);
|
||||||
|
List<Integer> imageVirtualIdList = images.stream().map(ImageDesktop::getImageVirtualId).filter(Objects::nonNull).collect(Collectors.toList());
|
||||||
|
LambdaQueryWrapper<ImageVirtualMachines> imageVirtualMachinesLambdaQueryWrapper = new LambdaQueryWrapper<ImageVirtualMachines>().in(ImageVirtualMachines::getId, imageVirtualIdList);
|
||||||
|
List<ImageVirtualMachines> imageVirtualMachines = imageVirtualMachinesMapper.selectList(imageVirtualMachinesLambdaQueryWrapper);
|
||||||
|
Map<Long, String> imageVirtualMachinesMap = imageVirtualMachines.stream().collect(Collectors.toMap(ImageVirtualMachines::getId, ImageVirtualMachines::getImageName));
|
||||||
|
|
||||||
if (CollectionUtil.isNotEmpty(images)) {
|
if (CollectionUtil.isNotEmpty(images)) {
|
||||||
deviceImageMappingRes.forEach(deviceImage -> images.forEach(image -> {
|
deviceImageMappingRes.forEach(deviceImage -> images.forEach(image -> {
|
||||||
if (ObjectUtil.isNotEmpty(deviceImage.getImageId()) && image.getId().equals(deviceImage.getImageId())) {
|
if (ObjectUtil.isNotEmpty(deviceImage.getImageId()) && image.getId().equals(deviceImage.getImageId())) {
|
||||||
deviceImage.setImageName(image.getDesktopName());
|
deviceImage.setImageName(image.getDesktopName());
|
||||||
deviceImage.setImageFileName(image.getDesktopName()+"."+image.getDesktopType());
|
deviceImage.setImageFileName(image.getDesktopName()+"."+image.getDesktopType());
|
||||||
|
deviceImage.setCreateTime(image.getCreateTime());
|
||||||
|
// 设置父镜像名称
|
||||||
|
if (image.getImageVirtualId() != null) {
|
||||||
|
deviceImage.setParentImageName(imageVirtualMachinesMap.get(image.getImageVirtualId().longValue()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import com.unisinsight.project.entity.req.*;
|
||||||
import com.unisinsight.project.entity.res.ImageStatusRes;
|
import com.unisinsight.project.entity.res.ImageStatusRes;
|
||||||
import com.unisinsight.project.entity.res.ImageVirtualMachinesRes;
|
import com.unisinsight.project.entity.res.ImageVirtualMachinesRes;
|
||||||
import com.unisinsight.project.entity.res.PageResult;
|
import com.unisinsight.project.entity.res.PageResult;
|
||||||
|
import com.unisinsight.project.entity.res.VncData;
|
||||||
import com.unisinsight.project.exception.BaseErrorCode;
|
import com.unisinsight.project.exception.BaseErrorCode;
|
||||||
import com.unisinsight.project.exception.Result;
|
import com.unisinsight.project.exception.Result;
|
||||||
import com.unisinsight.project.feign.ExternalApiClient;
|
import com.unisinsight.project.feign.ExternalApiClient;
|
||||||
|
|
@ -323,7 +324,7 @@ public class ImageVirtualMachinesServiceImpl extends ServiceImpl<ImageVirtualMac
|
||||||
imageDesktop.setDesktopName(fileName);
|
imageDesktop.setDesktopName(fileName);
|
||||||
imageDesktop.setDesktopType(type);
|
imageDesktop.setDesktopType(type);
|
||||||
//制作中
|
//制作中
|
||||||
imageDesktop.setPublishStatus("0");
|
imageDesktop.setPublishStatus(0);
|
||||||
imageDesktop.setStoragePath(detFile);
|
imageDesktop.setStoragePath(detFile);
|
||||||
imageDesktop.setImageVirtualId(Math.toIntExact(req.getId()));
|
imageDesktop.setImageVirtualId(Math.toIntExact(req.getId()));
|
||||||
imageDesktop.setOsVersion(imageVirtualMachines.getOsVersion());
|
imageDesktop.setOsVersion(imageVirtualMachines.getOsVersion());
|
||||||
|
|
@ -428,7 +429,7 @@ public class ImageVirtualMachinesServiceImpl extends ServiceImpl<ImageVirtualMac
|
||||||
updateWrapper.eq(ImageDesktop::getDesktopName, fileName);
|
updateWrapper.eq(ImageDesktop::getDesktopName, fileName);
|
||||||
Long fileSize = externalTorrentClient.getFileSize(detFilePath);
|
Long fileSize = externalTorrentClient.getFileSize(detFilePath);
|
||||||
log.info("det文件大小: {} 字节", fileSize);
|
log.info("det文件大小: {} 字节", fileSize);
|
||||||
updateWrapper.set(ImageDesktop::getPublishStatus, "1");
|
updateWrapper.set(ImageDesktop::getPublishStatus, 1);
|
||||||
updateWrapper.set(ImageDesktop::getFileSize, fileSize);
|
updateWrapper.set(ImageDesktop::getFileSize, fileSize);
|
||||||
updateWrapper.set(ImageDesktop::getPublishTime, DateUtil.date());
|
updateWrapper.set(ImageDesktop::getPublishTime, DateUtil.date());
|
||||||
//转化bt
|
//转化bt
|
||||||
|
|
@ -578,5 +579,14 @@ public class ImageVirtualMachinesServiceImpl extends ServiceImpl<ImageVirtualMac
|
||||||
return Result.successResult();
|
return Result.successResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<?> getVncData(String vmName) {
|
||||||
|
ApiResponse<VncData> vncData = externalApiClient.getVncData(vmName);
|
||||||
|
if ("200".equals(vncData.getCode())){
|
||||||
|
return Result.successResult(vncData.getData());
|
||||||
|
}
|
||||||
|
return Result.errorResultMessage(BaseErrorCode.HTTP_ERROR_CODE_500, vncData.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue