443 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Design Document: AMT Network Scanner
## Overview
本设计文档描述了机房远程控制系统中 AMT 网络扫描功能的技术实现方案。该系统采用前后端分离架构,使用 Spring Boot 构建后端服务Vue 3 构建前端界面。核心功能是通过 RMCP (Remote Management Control Protocol) Ping 协议扫描局域网中支持 Intel AMT 的设备,并使用异步多线程技术提高扫描效率。
系统将 Intel AMT SDK 中的 RMCPPing 模块移植到 Java 环境,实现跨平台的设备发现能力。扫描结果通过 WebSocket 实时推送到前端,提供流畅的用户体验。
## Architecture
### 系统架构图
```
┌─────────────────────────────────────────────────────────────┐
│ Frontend (Vue 3) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Scan Config │ │ Progress Bar │ │ Device List │ │
│ │ Component │ │ Component │ │ Component │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │ │ │ │
│ └──────────────────┴──────────────────┘ │
│ │ │
│ ┌───────▼────────┐ │
│ │ WebSocket │ │
│ │ Connection │ │
│ └───────┬────────┘ │
└────────────────────────────┼──────────────────────────────────┘
│ HTTP/WebSocket
┌────────────────────────────┼──────────────────────────────────┐
│ ┌───────▼────────┐ │
│ │ API Gateway │ │
│ │ (Controller) │ │
│ └───────┬────────┘ │
│ │ │
│ ┌─────────────┴─────────────┐ │
│ │ │ │
│ ┌───────▼────────┐ ┌───────▼────────┐ │
│ │ Scan Service │ │ Device Service │ │
│ └───────┬────────┘ └───────┬────────┘ │
│ │ │ │
│ ┌───────▼────────┐ ┌───────▼────────┐ │
│ │ RMCP Scanner │ │ Device Repo │ │
│ │ (Thread Pool) │ │ (JPA) │ │
│ └───────┬────────┘ └───────┬────────┘ │
│ │ │ │
│ ┌───────▼────────┐ ┌───────▼────────┐ │
│ │ AMT Detector │ │ Database │ │
│ │ (RMCP Ping) │ │ (MySQL) │ │
│ └────────────────┘ └────────────────┘ │
│ │
│ Backend (Spring Boot) │
└───────────────────────────────────────────────────────────────┘
```
### 技术栈
**后端:**
- Spring Boot 3.x
- Spring Web (RESTful API)
- Spring WebSocket (实时通信)
- Spring Data JPA (数据持久化)
- MySQL 8.x (数据库)
- Java 17+
- Lombok (简化代码)
**前端:**
- Vue 3
- Vite (构建工具)
- Element Plus (UI 组件库)
- Axios (HTTP 客户端)
- Pinia (状态管理)
## Components and Interfaces
### Backend Components
#### 1. ScanController
负责处理扫描相关的 HTTP 请求和 WebSocket 连接。
**接口:**
```java
@RestController
@RequestMapping("/api/scan")
public class ScanController {
// 启动扫描任务
@PostMapping("/start")
ResponseEntity<ScanTaskResponse> startScan(@RequestBody ScanRequest request);
// 获取扫描任务状态
@GetMapping("/status/{taskId}")
ResponseEntity<ScanStatus> getScanStatus(@PathVariable String taskId);
// 取消扫描任务
@PostMapping("/cancel/{taskId}")
ResponseEntity<Void> cancelScan(@PathVariable String taskId);
}
@Controller
public class ScanWebSocketController {
// WebSocket 端点,用于推送扫描进度
@MessageMapping("/scan/progress")
@SendTo("/topic/scan/{taskId}")
void sendProgress(ScanProgress progress);
}
```
#### 2. ScanService
核心业务逻辑层,协调扫描任务的执行。
**接口:**
```java
public interface ScanService {
// 创建并启动扫描任务
String startScan(String networkSegment, String subnetMask);
// 获取扫描任务状态
ScanStatus getStatus(String taskId);
// 取消扫描任务
void cancelScan(String taskId);
// 处理发现的设备
void handleDiscoveredDevice(AmtDevice device);
}
```
#### 3. RmcpScanner
多线程扫描引擎,负责并发执行 IP 地址检测。
**接口:**
```java
public class RmcpScanner {
// 扫描指定网段
CompletableFuture<ScanResult> scanNetwork(
String networkSegment,
String subnetMask,
ScanProgressCallback callback
);
// 检测单个 IP 是否支持 AMT
CompletableFuture<Optional<AmtDevice>> detectDevice(String ipAddress);
// 取消扫描
void cancelScan(String taskId);
}
```
#### 4. AmtDetector
AMT 设备检测器,实现 RMCP Ping 协议。
**接口:**
```java
public class AmtDetector {
// 发送 RMCP Ping 并解析响应
Optional<PlatformData> ping(String ipAddress, int timeout);
// 构建 RMCP Ping 数据包
byte[] buildRmcpPingPacket();
// 解析 RMCP Pong 响应
PlatformData parsePongResponse(byte[] response);
}
```
#### 5. DeviceService
设备管理服务,负责设备的 CRUD 操作。
**接口:**
```java
public interface DeviceService {
// 保存设备
AmtDevice saveDevice(AmtDevice device);
// 查询所有设备
List<AmtDevice> getAllDevices();
// 根据 IP 查询设备
Optional<AmtDevice> getDeviceByIp(String ipAddress);
// 删除设备
void deleteDevice(Long deviceId);
// 搜索设备
List<AmtDevice> searchDevices(String keyword);
}
```
#### 6. DeviceRepository
数据访问层,使用 Spring Data JPA。
**接口:**
```java
public interface DeviceRepository extends JpaRepository<AmtDevice, Long> {
Optional<AmtDevice> findByIpAddress(String ipAddress);
List<AmtDevice> findByIpAddressContaining(String keyword);
List<AmtDevice> findByProvisioningState(ProvisioningState state);
}
```
### Frontend Components
#### 1. ScanConfigComponent
扫描配置组件,用户输入网段和子网掩码。
**Props & Events:**
```typescript
interface ScanConfigProps {
// 无 props
}
interface ScanConfigEmits {
(e: 'start-scan', config: ScanConfig): void;
}
interface ScanConfig {
networkSegment: string; // 例如: "192.168.1.0"
subnetMask: string; // 例如: "255.255.255.0" 或 "/24"
}
```
#### 2. ProgressBarComponent
进度条组件,显示扫描进度。
**Props:**
```typescript
interface ProgressBarProps {
taskId: string;
progress: number; // 0-100
scannedCount: number;
totalCount: number;
foundDevices: number;
status: 'running' | 'completed' | 'cancelled' | 'error';
}
```
#### 3. DeviceListComponent
设备列表组件,展示已发现的设备。
**Props & Events:**
```typescript
interface DeviceListProps {
devices: AmtDevice[];
loading: boolean;
}
interface DeviceListEmits {
(e: 'delete-device', deviceId: number): void;
(e: 'refresh'): void;
}
```
## Data Models
### Backend Data Models
#### AmtDevice Entity
```java
@Entity
@Table(name = "amt_devices")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AmtDevice {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true, length = 15)
private String ipAddress;
@Column(nullable = false)
private Integer majorVersion;
@Column(nullable = false)
private Integer minorVersion;
@Enumerated(EnumType.STRING)
@Column(nullable = false, length = 20)
private ProvisioningState provisioningState;
@Column(nullable = false)
private LocalDateTime discoveredAt;
@Column(nullable = false)
private LocalDateTime lastSeenAt;
@Column(nullable = false)
private Boolean online;
@Column(length = 100)
private String hostname;
@Column(length = 500)
private String description;
}
```
#### ProvisioningState Enum
```java
public enum ProvisioningState {
PRE("Pre-provisioning"),
IN("In-provisioning"),
POST("Post-provisioning"),
UNKNOWN("Unknown");
private final String displayName;
ProvisioningState(String displayName) {
this.displayName = displayName;
}
public String getDisplayName() {
return displayName;
}
}
```
#### PlatformData DTO
```java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PlatformData {
private ProvisioningState provisioningState;
private Integer majorVersion;
private Integer minorVersion;
}
```
#### ScanRequest DTO
```java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ScanRequest {
@NotBlank(message = "Network segment is required")
@Pattern(regexp = "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$",
message = "Invalid IP address format")
private String networkSegment;
@NotBlank(message = "Subnet mask is required")
private String subnetMask; // 支持 "255.255.255.0" 或 "/24" 格式
}
```
#### ScanTaskResponse DTO
```java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ScanTaskResponse {
private String taskId;
private String status;
private Integer totalIpCount;
private LocalDateTime startTime;
}
```
#### ScanProgress DTO
```java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ScanProgress {
private String taskId;
private Integer scannedCount;
private Integer totalCount;
private Integer foundDevices;
private Double progressPercentage;
private String currentIp;
private AmtDevice latestDevice; // 最新发现的设备
}
```
#### ScanStatus DTO
```java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ScanStatus {
private String taskId;
private String status; // RUNNING, COMPLETED, CANCELLED, ERROR
private Integer scannedCount;
private Integer totalCount;
private Integer foundDevices;
private LocalDateTime startTime;
private LocalDateTime endTime;
private String errorMessage;
}
```
### Frontend Data Models
#### AmtDevice Interface
```typescript
export interface AmtDevice {
id: number;
ipAddress: string;
majorVersion: number;
minorVersion: number;
provisioningState: 'PRE' | 'IN' | 'POST' | 'UNKNOWN';
discoveredAt: string;
lastSeenAt: string;
online: boolean;
hostname?: string;
description?: string;
}
```
#### ScanConfig Interface
```typescript
export interface ScanConfig {
networkSegment: string;
subnetMask: string;
}
```
#### ScanProgress Interface
```typescript
export interface ScanProgress {
taskId: string;
scannedCount: number;
totalCount: number;
foundDevices: number;
progressPercentage: number;
currentIp: string;
latestDevice?: AmtDevice;
}
```