198 lines
7.0 KiB
C#
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()
|
|
}
|
|
};
|
|
}
|
|
}
|