Files
adas-core/adas-core.module.ProxyDevices/Services/ProxyDeviceService.cs
T

110 lines
6.0 KiB
C#

using System.Net;
using adas_core.module.ProxyDevices.Devices;
using Microsoft.Extensions.Options;
namespace adas_core.module.ProxyDevices.Services;
/// <summary>
/// ProxyDeviceService is responsible for managing proxy devices, processing requests, and streaming data from the devices.
/// It uses a cache to store device instances for efficient retrieval and ensures that only enabled devices are processed.
/// The service handles HTTP requests and returns appropriate responses based on the device's availability and functionality.
/// </summary>
/// <param name="settings">The settings for the proxy devices, including their configuration and parameters.</param>
/// <!-- aidoc:v1 sig=f2b6616 -->
public class ProxyDeviceService(IOptions<ProxyDeviceSettings> settings) : IProxyDeviceService
{
/// <summary>
/// _cache is a dictionary that stores instances of IProxyDevice, keyed by their deviceId.
/// </summary>
private readonly Dictionary<string, IProxyDevice?> _cache = new();
/// <summary>
/// Process method takes a deviceId as input, retrieves the corresponding device from the cache or creates a new instance if it doesn't exist, and then calls the Process method of the device.
/// It returns an HttpResponseMessage based on the outcome of the operation, handling any exceptions that may occur during the process.
/// </summary>
/// <param name="deviceId">The unique identifier of the proxy device to be processed.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the HttpResponseMessage returned by the device's Process method.</returns>
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "Summary claims the method 'creates a new instance if it doesn't exist', but the code only returns a NotFound HttpResponseMessage when GetDevice returns null; no instance is ever created." -->
public async Task<HttpResponseMessage> Process(string deviceId)
{
try
{
var device = GetDevice(deviceId);
if (device == null)
return new HttpResponseMessage(HttpStatusCode.NotFound)
{ ReasonPhrase = $"Proxy device not found. deviceId:{deviceId}" };
return await device.Process();
}
catch (HttpRequestException e)
{
return new HttpResponseMessage(e.StatusCode ?? HttpStatusCode.NotFound) { ReasonPhrase = e.Message };
}
}
/// <summary>
/// Stream method takes a deviceId as input, retrieves the corresponding device from the cache or creates a new instance if it doesn't exist, and then calls the Stream method of the device.
/// </summary>
/// <param name="deviceId">The unique identifier of the proxy device to be streamed.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the HttpResponseMessage returned by the device's Stream method.</returns>
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "The summary states the method 'creates a new instance if [the device] doesn't exist', but the code only calls GetDevice(deviceId) and returns NotFound when the result is null, with no creation logic visible." -->
public async Task<HttpResponseMessage> Stream(string deviceId)
{
try
{
var device = GetDevice(deviceId);
if (device == null)
return new HttpResponseMessage(HttpStatusCode.NotFound)
{ ReasonPhrase = $"Proxy device not found. deviceId:{deviceId}" };
return await device.Stream();
}
catch (HttpRequestException e)
{
return new HttpResponseMessage(e.StatusCode ?? HttpStatusCode.NotFound) { ReasonPhrase = e.Message };
}
}
/// <summary>
/// Retrieves the proxy device instance corresponding to the given deviceId. If the device is not found or not enabled, an HttpRequestException is thrown.
/// </summary>
/// <param name="deviceId">The unique identifier of the proxy device to be retrieved.</param>
/// <returns>The proxy device instance corresponding to the given deviceId.</returns>
/// <exception cref="HttpRequestException">Thrown when the device is not found or not enabled.</exception>
/// <!-- aidoc-review:v1 severity=medium kind=missing_exception
/// "HttpRequestException is also thrown with HttpStatusCode.NotImplemented when the device type cannot be resolved via Type.GetType; the documentation only documents the 'not found or not enabled' case." -->
/// <!-- aidoc-review:v1 severity=medium kind=wrong_returns
/// "The return type is IProxyDevice? and the method can return null (e.g., when Activator.CreateInstance produces an instance that is not IProxyDevice), but the documentation describes it simply as 'The proxy device instance'." -->
private IProxyDevice? GetDevice(string deviceId)
{
var device = settings.Value.FirstOrDefault(d => d.Id == deviceId);
if (device is not { Enabled: true })
throw new HttpRequestException("Device not found or not enabled", null, HttpStatusCode.NotFound);
IProxyDevice? deviceInstance = null;
lock (_cache)
{
if (_cache.TryGetValue(deviceId, out var value))
{
deviceInstance = value;
}
else
{
var deviceType = Type.GetType("adas_core.module.ProxyDevices.Devices." + device.Type + "Device") ??
throw new HttpRequestException("Device not implemented", null,
HttpStatusCode.NotImplemented);
var instance = Activator.CreateInstance(deviceType);
if (instance is IProxyDevice proxyDevice)
{
deviceInstance = proxyDevice;
deviceInstance.Initialize(device.Parameters);
}
_cache.Add(deviceId, deviceInstance);
}
}
return deviceInstance;
}
}