- 添加OsDevice模型和OsDevicesController - 实现WindowsScannerService用于网络扫描和WMI查询 - 添加AMT设备UUID查询功能(从CIM_ComputerSystemPackage获取PlatformGUID) - 实现PlatformGUID到标准UUID格式的转换(字节序转换) - 修复HardwareInfoRepository保存UUID的问题 - 前端添加OS设备管理页面和UUID获取/刷新按钮 - 添加数据库迁移脚本
208 lines
7.5 KiB
C#
208 lines
7.5 KiB
C#
using AmtScanner.Api.Data;
|
||
using AmtScanner.Api.Models;
|
||
using AmtScanner.Api.Repositories;
|
||
|
||
namespace AmtScanner.Api.Services;
|
||
|
||
public interface IHardwareInfoService
|
||
{
|
||
Task<HardwareInfoDto> GetHardwareInfoAsync(long deviceId, bool forceRefresh = false);
|
||
Task<List<BatchHardwareInfoResult>> GetBatchHardwareInfoAsync(List<long> deviceIds, bool forceRefresh = false);
|
||
}
|
||
|
||
public class HardwareInfoService : IHardwareInfoService
|
||
{
|
||
private readonly IHardwareInfoRepository _repository;
|
||
private readonly IAmtHardwareQueryService _hardwareQueryService;
|
||
private readonly IServiceScopeFactory _scopeFactory;
|
||
private readonly ILogger<HardwareInfoService> _logger;
|
||
private readonly TimeSpan _cacheExpiration = TimeSpan.FromHours(24);
|
||
|
||
public HardwareInfoService(
|
||
IHardwareInfoRepository repository,
|
||
IAmtHardwareQueryService hardwareQueryService,
|
||
IServiceScopeFactory scopeFactory,
|
||
ILogger<HardwareInfoService> logger)
|
||
{
|
||
_repository = repository;
|
||
_hardwareQueryService = hardwareQueryService;
|
||
_scopeFactory = scopeFactory;
|
||
_logger = logger;
|
||
}
|
||
|
||
public async Task<HardwareInfoDto> GetHardwareInfoAsync(long deviceId, bool forceRefresh = false)
|
||
{
|
||
// Check cache
|
||
var cached = await _repository.GetByDeviceIdAsync(deviceId);
|
||
|
||
if (cached != null && !forceRefresh &&
|
||
DateTime.UtcNow - cached.LastUpdated < _cacheExpiration)
|
||
{
|
||
_logger.LogInformation("Returning cached hardware info for device {DeviceId}", deviceId);
|
||
return MapToDto(cached);
|
||
}
|
||
|
||
// Query from device
|
||
_logger.LogInformation("Querying hardware info from device {DeviceId}", deviceId);
|
||
|
||
using var scope = _scopeFactory.CreateScope();
|
||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||
var credentialService = scope.ServiceProvider.GetRequiredService<ICredentialService>();
|
||
|
||
var device = await context.AmtDevices.FindAsync(deviceId);
|
||
if (device == null)
|
||
{
|
||
throw new Exception($"Device {deviceId} not found");
|
||
}
|
||
|
||
var credential = await credentialService.GetDefaultCredentialAsync();
|
||
if (credential == null)
|
||
{
|
||
throw new Exception("No default credential found");
|
||
}
|
||
|
||
var password = credentialService.DecryptPassword(credential.Password);
|
||
|
||
// Determine open ports from device IP (simplified)
|
||
var openPorts = new List<int>();
|
||
if (device.IpAddress.EndsWith("111"))
|
||
{
|
||
openPorts.Add(16992); // HTTP
|
||
openPorts.Add(623);
|
||
}
|
||
else if (device.IpAddress.EndsWith("112"))
|
||
{
|
||
openPorts.Add(16993); // HTTPS
|
||
}
|
||
else
|
||
{
|
||
// Default: try both
|
||
openPorts.Add(16992);
|
||
openPorts.Add(16993);
|
||
}
|
||
|
||
var hardwareInfo = await _hardwareQueryService.QueryHardwareInfoAsync(
|
||
device.IpAddress,
|
||
credential.Username,
|
||
password,
|
||
openPorts);
|
||
|
||
hardwareInfo.DeviceId = deviceId;
|
||
|
||
// 如果查询到了 UUID,保存到 AmtDevice
|
||
if (!string.IsNullOrEmpty(hardwareInfo.SystemUuid) && device.SystemUuid != hardwareInfo.SystemUuid)
|
||
{
|
||
device.SystemUuid = hardwareInfo.SystemUuid;
|
||
context.AmtDevices.Update(device);
|
||
await context.SaveChangesAsync();
|
||
_logger.LogInformation("Updated device {DeviceId} with UUID: {Uuid}", deviceId, hardwareInfo.SystemUuid);
|
||
}
|
||
|
||
// Save to cache
|
||
await _repository.SaveAsync(hardwareInfo);
|
||
|
||
// Reload to get the saved entity with ID
|
||
cached = await _repository.GetByDeviceIdAsync(deviceId);
|
||
|
||
return MapToDto(cached!);
|
||
}
|
||
|
||
public async Task<List<BatchHardwareInfoResult>> GetBatchHardwareInfoAsync(
|
||
List<long> deviceIds,
|
||
bool forceRefresh = false)
|
||
{
|
||
var results = new List<BatchHardwareInfoResult>();
|
||
var semaphore = new SemaphoreSlim(10); // Max 10 concurrent queries
|
||
|
||
var tasks = deviceIds.Select(async deviceId =>
|
||
{
|
||
await semaphore.WaitAsync();
|
||
try
|
||
{
|
||
var data = await GetHardwareInfoAsync(deviceId, forceRefresh);
|
||
return new BatchHardwareInfoResult
|
||
{
|
||
DeviceId = deviceId,
|
||
Success = true,
|
||
Data = data
|
||
};
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "Failed to get hardware info for device {DeviceId}", deviceId);
|
||
return new BatchHardwareInfoResult
|
||
{
|
||
DeviceId = deviceId,
|
||
Success = false,
|
||
Error = ex.Message
|
||
};
|
||
}
|
||
finally
|
||
{
|
||
semaphore.Release();
|
||
}
|
||
});
|
||
|
||
results = (await Task.WhenAll(tasks)).ToList();
|
||
return results;
|
||
}
|
||
|
||
private HardwareInfoDto MapToDto(HardwareInfo hardwareInfo)
|
||
{
|
||
return new HardwareInfoDto
|
||
{
|
||
DeviceId = hardwareInfo.DeviceId,
|
||
IpAddress = hardwareInfo.Device.IpAddress,
|
||
LastUpdated = hardwareInfo.LastUpdated,
|
||
SystemInfo = new SystemInfoDto
|
||
{
|
||
Manufacturer = hardwareInfo.SystemManufacturer,
|
||
Model = hardwareInfo.SystemModel,
|
||
SerialNumber = hardwareInfo.SystemSerialNumber,
|
||
Uuid = hardwareInfo.SystemUuid
|
||
},
|
||
Processor = new ProcessorInfoDto
|
||
{
|
||
Model = hardwareInfo.ProcessorModel,
|
||
Cores = hardwareInfo.ProcessorCores,
|
||
Threads = hardwareInfo.ProcessorThreads,
|
||
MaxClockSpeed = hardwareInfo.ProcessorMaxClockSpeed,
|
||
CurrentClockSpeed = hardwareInfo.ProcessorCurrentClockSpeed
|
||
},
|
||
Memory = new MemoryInfoDto
|
||
{
|
||
TotalCapacity = hardwareInfo.TotalMemoryBytes,
|
||
TotalCapacityGB = hardwareInfo.TotalMemoryBytes.HasValue
|
||
? (int)(hardwareInfo.TotalMemoryBytes.Value / 1024 / 1024 / 1024)
|
||
: null,
|
||
Modules = hardwareInfo.MemoryModules.Select(m => new MemoryModuleDto
|
||
{
|
||
Slot = m.SlotLocation,
|
||
Capacity = m.CapacityBytes,
|
||
CapacityGB = m.CapacityBytes.HasValue
|
||
? (int)(m.CapacityBytes.Value / 1024 / 1024 / 1024)
|
||
: null,
|
||
Speed = m.SpeedMHz,
|
||
Type = m.MemoryType,
|
||
Manufacturer = m.Manufacturer,
|
||
PartNumber = m.PartNumber,
|
||
SerialNumber = m.SerialNumber
|
||
}).ToList()
|
||
},
|
||
Storage = new StorageInfoDto
|
||
{
|
||
Devices = hardwareInfo.StorageDevices.Select(d => new StorageDeviceDto
|
||
{
|
||
DeviceId = d.DeviceId,
|
||
Model = d.Model,
|
||
Capacity = d.CapacityBytes,
|
||
CapacityGB = d.CapacityBytes.HasValue
|
||
? (int)(d.CapacityBytes.Value / 1024 / 1024 / 1024)
|
||
: null,
|
||
InterfaceType = d.InterfaceType
|
||
}).ToList()
|
||
}
|
||
};
|
||
}
|
||
}
|