=== 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:
@@ -12,6 +12,7 @@ namespace adas_core.Infrastructure.Services;
|
||||
/// <summary>
|
||||
/// Represents a service that implements the <see cref="IPublisherService"/> contract, providing the concrete implementation of the publishing operations defined by the interface.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=2b6fa6f -->
|
||||
public class PublisherService : IPublisherService
|
||||
{
|
||||
private readonly ILogger<PublisherService> _logger;
|
||||
@@ -90,6 +91,7 @@ public class PublisherService : IPublisherService
|
||||
/// <param name="msg">The message payload to send to the queue.</param>
|
||||
/// <param name="queueName">The name of the target queue to which the message will be sent.</param>
|
||||
/// <returns><c>true</c> if the message was sent successfully; otherwise, <c>false</c>.</returns>
|
||||
/// <!-- aidoc:v1 sig=4a81ef7 body=ccacd65 -->
|
||||
public async Task<bool> SendMessage(string msg, string queueName)
|
||||
{
|
||||
try
|
||||
@@ -121,6 +123,7 @@ public class PublisherService : IPublisherService
|
||||
/// <param name="obj">The object to serialize and send to the queue.</param>
|
||||
/// <param name="queueName">The name of the destination queue.</param>
|
||||
/// <returns>A task that resolves to <c>true</c> if the message was sent successfully; otherwise, <c>false</c>.</returns>
|
||||
/// <!-- aidoc:v1 sig=9bcf9cc body=8c96ff0 -->
|
||||
public async Task<bool> SendMessage(object obj, string queueName)
|
||||
{
|
||||
var json = JsonConvert.SerializeObject(obj);
|
||||
@@ -133,6 +136,7 @@ public class PublisherService : IPublisherService
|
||||
/// <param name="obj">The message object expected to be a <c>Message<Error></c>. If it is not, the method returns <c>false</c> without sending anything.</param>
|
||||
/// <param name="queueName">The name of the queue to which the error message body will be sent. The queue is created if it does not already exist.</param>
|
||||
/// <returns>A <see cref="Task{Boolean}"/> that resolves to <c>true</c> when the error message is successfully sent, and <c>false</c> when the bus is null, the object is not a <c>Message<Error></c>, or an exception is raised while sending.</returns>
|
||||
/// <!-- aidoc:v1 sig=ad36809 body=f9fde02 -->
|
||||
public async Task<bool> SendMessageError(object obj, string queueName)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace adas_core.Infrastructure.Services;
|
||||
/// <summary>
|
||||
/// Provides functionality for receiving and processing incoming data, messages, or requests.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=0552406 -->
|
||||
public class ReceiverService
|
||||
{
|
||||
private readonly ILogger<ReceiverService> _logger;
|
||||
@@ -83,6 +84,7 @@ public class ReceiverService
|
||||
/// <summary>
|
||||
/// Registers all application queues defined in settings, including queues for observations, treatments, patients, pumps, appointments, recordings, recording alerts, and alarm observations, by adding each one through the <c>AddQueue</c> call.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=b14e3d9 body=1372d9f -->
|
||||
private void SetQueues()
|
||||
{
|
||||
AddQueue(_settings.ObservationsQueue);
|
||||
@@ -99,6 +101,7 @@ public class ReceiverService
|
||||
/// Adds a queue to the internal collection only when the supplied value is not null, empty, or whitespace; otherwise the call is ignored.
|
||||
/// </summary>
|
||||
/// <param name="queue">The queue identifier to add to the collection. Null, empty, or whitespace values are silently skipped.</param>
|
||||
/// <!-- aidoc:v1 sig=322aa1a body=bdf4bfa -->
|
||||
private void AddQueue(string? queue)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(queue))
|
||||
@@ -108,6 +111,7 @@ public class ReceiverService
|
||||
/// <summary>
|
||||
/// Attempts to establish a connection to RabbitMQ by disposing any existing bus, configuring EasyNetQ with the configured connection string, and registering consumers for all configured queues. If the connection fails, the failure is logged and a timer is scheduled to retry the connection after a five-second delay, recursively invoking the method when the timer elapses.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=417902d body=fbb9618 -->
|
||||
private void TryToConnect()
|
||||
{
|
||||
try
|
||||
@@ -145,6 +149,7 @@ public class ReceiverService
|
||||
/// <summary>
|
||||
/// Disposes the underlying bus instance if it implements <see cref="IDisposable"/>.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=21b17a7 body=232143f -->
|
||||
private void DisposeBus()
|
||||
{
|
||||
if (_bus is IDisposable disposable)
|
||||
@@ -194,6 +199,7 @@ public class ReceiverService
|
||||
/// </summary>
|
||||
/// <param name="queue">The queue name to resolve to its corresponding API request service.</param>
|
||||
/// <returns>The matching <see cref="IApiRequestService"/> instance if the queue is recognized; otherwise, <c>null</c>.</returns>
|
||||
/// <!-- aidoc:v1 sig=62d9eca body=23b1d5d -->
|
||||
private IApiRequestService? ResolveService(string queue)
|
||||
{
|
||||
return queue switch
|
||||
@@ -214,6 +220,7 @@ public class ReceiverService
|
||||
/// Asynchronously reprocesses messages from the specified error queue by deriving the target queue name from the routing key (with "Key" removed), resolving the associated service, and resubmitting the message. Operations are skipped when the bus is uninitialized, the derived queue name is empty, or no service is resolved.
|
||||
/// </summary>
|
||||
/// <param name="errorQueueName">The name of the error queue from which to reprocess messages.</param>
|
||||
/// <!-- aidoc:v1 sig=baa5e88 body=90bfb05 -->
|
||||
public async Task ProcessErrorQueue(string errorQueueName)
|
||||
{
|
||||
if (_bus == null)
|
||||
@@ -255,6 +262,7 @@ public class ReceiverService
|
||||
/// Sends EasyNetQ messages to a service implementing IApiRequestService
|
||||
/// Throws exception to trigger retry on failure
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=f5ba50e body=1be117a -->
|
||||
private void TryToParseAndSend(IMessage<string> msg, IApiRequestService service)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -45,6 +45,7 @@ public class SendAlertService(
|
||||
/// If the Rabbit connection string is not defined in the web config, an error is logged and an empty list is returned.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation. The task result contains a list of <see cref="Queue"/> objects, or an empty list if the Rabbit connection string is not configured.</returns>
|
||||
/// <!-- aidoc:v1 sig=8b94d31 body=8aa2b12 -->
|
||||
public async Task<List<Queue>> GetQueues()
|
||||
{
|
||||
if (_rabbitConnectionString != null) return await GetQueuesAsync();
|
||||
@@ -59,6 +60,7 @@ public class SendAlertService(
|
||||
/// Logs and suppresses any errors encountered while collecting the data, returning the successfully gathered metrics.
|
||||
/// </summary>
|
||||
/// <returns>A list of <see cref="Performance"/> entries containing the collected performance metrics; returns an empty list if all collection attempts fail.</returns>
|
||||
/// <!-- aidoc:v1 sig=2be2617 body=a3f4d4b -->
|
||||
public List<Performance> GetPerformance()
|
||||
{
|
||||
logger.LogDebug("Starting check performance data from hospitals");
|
||||
@@ -84,6 +86,7 @@ public class SendAlertService(
|
||||
/// Asynchronously retrieves a list of API clients by delegating to the underlying data retrieval method.
|
||||
/// </summary>
|
||||
/// <returns>A task representing the asynchronous operation, containing the list of <see cref="ApiClients"/> instances retrieved.</returns>
|
||||
/// <!-- aidoc:v1 sig=74b1e47 body=7ebcae0 -->
|
||||
public async Task<List<ApiClients>> GetApiClients()
|
||||
{
|
||||
return await GetApiClientsAsync();
|
||||
@@ -93,6 +96,7 @@ public class SendAlertService(
|
||||
/// Asynchronously retrieves statistics for the configured RabbitMQ error queues (recording, patients, treatments, observations, and pumps). Only queues with non-empty names are queried, duplicates are ignored, and any exception raised while connecting or fetching stats is logged and results in an empty list being returned.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation. The task result contains a list of <see cref="Queue"/> objects with the name, message count, and consumer count of each queried queue, or an empty list if an error occurs.</returns>
|
||||
/// <!-- aidoc:v1 sig=97010df body=95afb89 -->
|
||||
private async Task<List<Queue>> GetQueuesAsync()
|
||||
{
|
||||
logger.LogDebug("Starting check rabbitMQ data from hospitals");
|
||||
@@ -151,6 +155,7 @@ public class SendAlertService(
|
||||
/// Calculates usage from total processor time divided by processor count, and returns a default Performance instance if the underlying process query fails.
|
||||
/// </summary>
|
||||
/// <returns>A Performance object describing the CPU usage percentage, total capacity, and unit. If an error occurs, a default Performance instance is returned and the exception is logged.</returns>
|
||||
/// <!-- aidoc:v1 sig=a7e6e3d body=875a1c4 -->
|
||||
public Performance GetConsumedCpu()
|
||||
{
|
||||
Performance performance = new();
|
||||
@@ -180,6 +185,7 @@ public class SendAlertService(
|
||||
/// Retrieves the current RAM consumption in gigabytes, returning it as a Performance metric where the total and consumed values are reported as equal with a consumption percentage of 100. If an error occurs while retrieving the memory information, the exception is logged and an empty Performance object is returned.
|
||||
/// </summary>
|
||||
/// <returns>A Performance object representing the RAM usage in GB; returns an empty Performance object if the memory retrieval fails.</returns>
|
||||
/// <!-- aidoc:v1 sig=6b014f3 body=8c40f98 -->
|
||||
public Performance GetConsumedRam()
|
||||
{
|
||||
Performance performance = new();
|
||||
@@ -211,6 +217,7 @@ public class SendAlertService(
|
||||
/// </summary>
|
||||
/// <param name="drive">The drive whose storage consumption is to be measured.</param>
|
||||
/// <returns>A <see cref="Performance"/> instance containing the consumed storage, total storage, percentage consumed, and the unit (GB) for the drive.</returns>
|
||||
/// <!-- aidoc:v1 sig=d432443 body=b8cb174 -->
|
||||
public Performance GetConsumedStorage(DriveInfo drive)
|
||||
{
|
||||
Performance performance = new();
|
||||
@@ -258,6 +265,7 @@ public class SendAlertService(
|
||||
/// <returns>A list of <see cref="Performance"/> entries describing the consumed storage for each
|
||||
/// successfully processed drive; returns an empty list if no drives yield results or if an
|
||||
/// error occurs during enumeration.</returns>
|
||||
/// <!-- aidoc:v1 sig=1a15ba5 body=724e81c -->
|
||||
private List<Performance> GetConsumedStorages()
|
||||
{
|
||||
var list = new List<Performance>();
|
||||
@@ -292,6 +300,7 @@ public class SendAlertService(
|
||||
/// Returns an empty list if the underlying call returns null or fails; any exception is caught and logged without being rethrown.
|
||||
/// </summary>
|
||||
/// <returns>A task that resolves to the list of connected API clients, which may be empty if no clients were retrieved.</returns>
|
||||
/// <!-- aidoc:v1 sig=3d33350 body=519c9d5 -->
|
||||
private async Task<List<ApiClients>> GetApiClientsAsync()
|
||||
{
|
||||
logger.LogDebug("Starting check conected clients from hospitals");
|
||||
@@ -317,6 +326,10 @@ public class SendAlertService(
|
||||
/// Asynchronously retrieves the list of connected WebSocket API clients, handling any errors by logging them and returning an empty <see cref="ApiClients"/> instance as a fallback.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="Task{TResult}"/> that resolves to an <see cref="ApiClients"/> instance representing the connected WebSocket subscribers.</returns>
|
||||
/// <!-- aidoc-review:v1 severity=high kind=stale_summary
|
||||
/// "The summary states the method 'retrieves the list of connected WebSocket API clients', but the actual retrieval code (`webSocketHandler.GetSubscribersConected()`) is commented out. The method only ever constructs a new empty ApiClients and returns it." -->
|
||||
/// <!-- aidoc-review:v1 severity=high kind=wrong_returns
|
||||
/// "The <returns> tag documents a non-nullable ApiClients instance, but the method's return type is Task<ApiClients?> (nullable)." -->
|
||||
private Task<ApiClients?> GetWebSocketClients()
|
||||
{
|
||||
ApiClients apiClients = new();
|
||||
|
||||
Reference in New Issue
Block a user