198 lines
7.0 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;
// 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
},
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()
}
};
}
}