=== Summary: 675 files | 7 generated | 484 fresh | 4605 untracked | 4268 adopted | 355 marked | 466 validated-ok | 2+0 stale (sig+body) | 0 skipped | 0 failed | elapsed 11:08:11.442 (40091.44s) ===

This commit is contained in:
julian
2026-06-28 02:50:05 -07:00
parent a19fb90902
commit 586f02a2ca
654 changed files with 5260 additions and 0 deletions
@@ -28,6 +28,7 @@ namespace adas_core.Infrastructure.Services;
/// This class is the default implementation of <see cref="IRelayService"/>,
/// and can be substituted via dependency injection where the interface is required.
/// </remarks>
/// <!-- aidoc:v1 sig=699b195 -->
public class RelayService : IRelayService
{
private readonly List<RelayDevice> _devices = [];
@@ -74,6 +75,7 @@ public class RelayService : IRelayService
/// </summary>
/// <param name="relay">The relay to check, identified by its IP, port, and relay number used both as the cache key and as the target of the status request.</param>
/// <returns>A task that yields the resolved <see cref="RelayEnum.Status"/> of the relay, or <see cref="RelayEnum.Status.Unknown"/> when the status cannot be determined.</returns>
/// <!-- aidoc:v1 sig=a2d75fa body=4380852 -->
public async Task<RelayEnum.Status> CheckRelayStatus(Relay relay)
{
var cacheKey = Tuple.Create(relay.Ip, relay.Port, relay.RelayNumber);
@@ -123,6 +125,7 @@ public class RelayService : IRelayService
/// </summary>
/// <param name="relayId">The unique identifier of the relay whose status should be checked.</param>
/// <returns>The current <see cref="RelayEnum.Status"/> of the relay, or <see cref="RelayEnum.Status.Unknown"/> if no relay with the given ID exists.</returns>
/// <!-- aidoc:v1 sig=bba9f8d body=7f98d77 -->
public async Task<RelayEnum.Status> CheckRelayStatus(ObjectId relayId)
{
var relay = await _relayRepository.GetById(relayId);
@@ -134,6 +137,8 @@ public class RelayService : IRelayService
/// Asynchronously powers off the specified relay. Uses a cache to avoid redundant operations when the relay is already off, falls back to an HTTP request when no local relay device is available, and updates the cache after a successful power off.
/// </summary>
/// <param name="relay">The relay to power off, including its network address and relay number.</param>
/// <!-- aidoc-review:v1 severity=low kind=wrong_summary
/// "The summary states the cache is updated 'after a successful power off', but the cache update happens unconditionally without verifying that the power off operation actually succeeded (e.g., the awaited HTTP call is not checked for a success response)." -->
public async Task PowerOff(Relay relay)
{
var cacheKey = Tuple.Create(relay.Ip, relay.Port, relay.RelayNumber);
@@ -179,6 +184,7 @@ public class RelayService : IRelayService
/// Powers on the specified relay. If the relay is configured with a URL, sends a remote power-on request; otherwise, drives the relay device directly. Honors a caching layer to avoid redundant power-on commands when the relay is already reported as on.
/// </summary>
/// <param name="relay">The relay to power on, including driver, IP, port, relay number, and cache settings.</param>
/// <!-- aidoc:v1 sig=7f8cab9 body=56affe0 -->
public async Task PowerOn(Relay relay)
{
if (string.IsNullOrEmpty(relay.Driver) || string.IsNullOrEmpty(relay.Ip)) return;
@@ -232,6 +238,7 @@ public class RelayService : IRelayService
/// <param name="status">The manual relay status to apply.</param>
/// <param name="pocId">The identifier of the point of care device whose relay configuration should be updated.</param>
/// <param name="type">The relay type used to look up the target relay within the point of care's relay configuration.</param>
/// <!-- aidoc:v1 sig=82fad8b body=823e6e0 -->
public async Task SetManualRelay(RelayEnum.Status status, ObjectId pocId, RelayEnum.Type type)
{
try
@@ -259,6 +266,7 @@ public class RelayService : IRelayService
/// </summary>
/// <param name="relay">The unique identifier of the relay to look up.</param>
/// <returns>A task that resolves to the <see cref="Relay"/> if found, or <c>null</c> if no relay matches the supplied identifier.</returns>
/// <!-- aidoc:v1 sig=aa6ff57 body=51941e7 -->
public Task<Relay?> GetById(ObjectId relay)
{
return _relayRepository.GetById(relay);
@@ -268,6 +276,7 @@ public class RelayService : IRelayService
/// </summary>
/// <param name="relayList">The list of relay identifiers to look up. Can be null.</param>
/// <returns>A list of <see cref="Relay"/> objects corresponding to the provided identifiers, or an empty list if the input is null.</returns>
/// <!-- aidoc:v1 sig=ebc008d body=14fde35 -->
public List<Relay> GetRelayInList(List<ObjectId>? relayList)
{
if(relayList == null) return new List<Relay>();
@@ -280,6 +289,7 @@ public class RelayService : IRelayService
/// <param name="configurationRelayList">The optional list of <see cref="ObjectId"/> values identifying the configuration relays to filter; when <c>null</c>, the method short-circuits and returns an empty list.</param>
/// <param name="type">The relay type used to filter the matching relays within the supplied list.</param>
/// <returns>A <see cref="List{Relay}"/> containing the relays matching the specified <paramref name="type"/>, or an empty list if <paramref name="configurationRelayList"/> is <c>null</c>.</returns>
/// <!-- aidoc:v1 sig=8a36763 body=46b0859 -->
public List<Relay> GetRelayByTypeInList(List<ObjectId>? configurationRelayList, RelayEnum.Type type)
{
if(configurationRelayList == null) return new List<Relay>();
@@ -338,6 +348,7 @@ public class RelayService : IRelayService
/// <param name="request">The relay entity to insert, whose name is checked for duplicates prior to persistence.</param>
/// <returns>The inserted <see cref="Relay"/> entity returned by the repository, or <c>null</c> if the repository yields no result.</returns>
/// <exception cref="Exception">Thrown when a relay with the same name as <paramref name="request"/> already exists in the repository.</exception>
/// <!-- aidoc:v1 sig=d0333f5 body=0c77f19 -->
public async Task<Relay?> InsertRelay(Relay request)
{
var relayExist = await _relayRepository.GetByName(request.RelayName);
@@ -351,6 +362,7 @@ public class RelayService : IRelayService
/// <param name="objectId">The unique identifier of the relay to update.</param>
/// <param name="relay">The relay object containing the updated information.</param>
/// <returns>A task representing the asynchronous operation, containing the updated <see cref="Relay"/>, or <c>null</c> if no relay with the specified identifier was found.</returns>
/// <!-- aidoc:v1 sig=24b1fa0 body=cd48e45 -->
public Task<Relay?> UpdateRelayById(ObjectId objectId, Relay relay)
{
return _relayRepository.UpdateRelayAsync(objectId, relay);
@@ -417,6 +429,7 @@ public class RelayService : IRelayService
/// <returns>The existing or newly created <see cref="RelayDevice"/>, or <c>null</c> if the relay is missing a valid IP or port.</returns>
/// <exception cref="AdasException">Thrown when no constructor matching <see cref="Relay"/> and <see cref="RelaySettings"/> is found on the resolved driver type.</exception>
/// <exception cref="AdasException">Thrown when the resolved driver type cannot be instantiated into a <see cref="RelayDevice"/>.</exception>
/// <!-- aidoc:v1 sig=c05ea03 body=5b9a1de -->
private RelayDevice? GetRelayDevice(Relay relay)
{
if(relay.Ip.IsNullOrWhiteSpace() || relay.Port == 0) return null;
@@ -449,6 +462,7 @@ public class RelayService : IRelayService
/// </summary>
/// <param name="relay">The relay whose driver, IP, port, name, total count, username, and password are included in the request query string.</param>
/// <param name="builder">The URI builder whose query is updated with the relay parameters and whose resulting URI is used as the request target.</param>
/// <!-- aidoc:v1 sig=3c06d77 body=f99c21d -->
private async Task PowerRelay(Relay relay, UriBuilder builder)
{
var query = HttpUtility.ParseQueryString(builder.Query);
@@ -487,6 +501,7 @@ public class RelayService : IRelayService
/// </summary>
/// <param name="dictionary">The concurrent dictionary containing relay status entries keyed by a tuple of device ID, port, and an additional integer value.</param>
/// <returns>A string containing one formatted line per dictionary entry describing the device ID, port, and status.</returns>
/// <!-- aidoc:v1 sig=be16714 body=b812332 -->
private static string DictionaryToString(ConcurrentDictionary<Tuple<string, int, int>, RelayEnum.Status> dictionary)
{
var builder = new StringBuilder();
@@ -504,6 +519,7 @@ public class RelayService : IRelayService
/// </summary>
/// <param name="relay">The relay instance whose status should be queried; its IP, port, relay number, driver, credentials, and mode are used to build the request.</param>
/// <returns>The parsed <see cref="RelayEnum.Status"/> returned by the remote relay service, or <see cref="RelayEnum.Status.Unknown"/> if the request fails.</returns>
/// <!-- aidoc:v1 sig=3eb287a body=570413b -->
private async Task<RelayEnum.Status> GetRelayStatusByOr(Relay relay)
{
var cacheKey = Tuple.Create(relay.Ip, relay.Port, relay.RelayNumber);