=== 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:
@@ -14,6 +14,7 @@ namespace adas_core.Application.Subscriptions;
|
||||
/// <remarks>
|
||||
/// This service depends on an optional cache, a grouped observation service, a logger, and a lazily-initialized client message service to support its subscriber-related operations.
|
||||
/// </remarks>
|
||||
/// <!-- aidoc:v1 sig=01f4003 -->
|
||||
public class SubscriberGroupedService(
|
||||
ICacheService? cacheService,
|
||||
IGroupedObservationService groupedObservationService,
|
||||
@@ -48,6 +49,7 @@ public class SubscriberGroupedService(
|
||||
/// Returns a thread-safe snapshot of the grouped subscribers as a new list. The internal collection is locked during the copy to ensure consistency and prevent concurrent modification.
|
||||
/// </summary>
|
||||
/// <returns>A new <see cref="List{WsSubscriberGrouped}"/> containing a copy of the grouped subscribers.</returns>
|
||||
/// <!-- aidoc:v1 sig=6e3438d body=29d89cc -->
|
||||
public List<WsSubscriberGrouped> GetGrouped()
|
||||
{
|
||||
lock (_subscriberGrouped)
|
||||
@@ -60,6 +62,7 @@ public class SubscriberGroupedService(
|
||||
/// Removes all grouped observations associated with the specified patient identifier from the subscriber collection in a thread-safe manner.
|
||||
/// </summary>
|
||||
/// <param name="patientId">The string representation of the patient identifier used to locate and remove the matching grouped observations.</param>
|
||||
/// <!-- aidoc:v1 sig=60f9191 body=6bbfa2e -->
|
||||
public void RemoveGroupedObsByPatientId(string patientId)
|
||||
{
|
||||
lock (_subscriberGrouped)
|
||||
@@ -76,6 +79,10 @@ public class SubscriberGroupedService(
|
||||
/// </summary>
|
||||
/// <param name="patientId">objectId on db for Patient</param>
|
||||
/// <param name="newLocation"></param>
|
||||
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
|
||||
/// "Summary describes conditional removal logic distinguishing section vs box subscribers, but the code removes ALL wsSubscribers for the given patientId without any section/box differentiation." -->
|
||||
/// <!-- aidoc-review:v1 severity=high kind=mentions_removed_behavior
|
||||
/// "Summary mentions BoxSubscribers and SectionSubscribers with conditional behavior that does not exist in the code; CheckEmptySubscriberGroup is called but no selective filtering is performed." -->
|
||||
public void RemoveWsSubscriberByLocation(string patientId, PatientLocation? newLocation)
|
||||
{
|
||||
lock (_subscriberGrouped)
|
||||
@@ -100,6 +107,7 @@ public class SubscriberGroupedService(
|
||||
/// </summary>
|
||||
/// <param name="patientId">The patient identifier used to locate the subscriber groups to update.</param>
|
||||
/// <param name="wsIdToRemove">The WebSocket subscriber ID to remove from the matching subscriber and group collections.</param>
|
||||
/// <!-- aidoc:v1 sig=66711e2 body=1eb38c9 -->
|
||||
public void RemoveWsSubscriberPatientIdAndWsId(string patientId, string wsIdToRemove)
|
||||
{
|
||||
lock (_subscriberGrouped)
|
||||
@@ -139,6 +147,8 @@ public class SubscriberGroupedService(
|
||||
/// Object with properties to generate new grouped observations, clients using those
|
||||
/// grouped obsercations and the generated list of grouped observations
|
||||
/// </param>
|
||||
/// <!-- aidoc-review:v1 severity=medium kind=missing_returns
|
||||
/// "Method returns a List<string> describing what was removed (e.g. 'ws:{PatientId}-{Names}-{Regularity}-{Group.Count}' when the whole object is removed, or 'group:{key}' per removed group), but no <returns> tag exists." -->
|
||||
public List<string> CheckEmptySubscriberGroup(WsSubscriberGrouped? wsSubscriberGrouped)
|
||||
{
|
||||
lock (_subscriberGrouped)
|
||||
@@ -179,6 +189,7 @@ public class SubscriberGroupedService(
|
||||
/// Uses locking to ensure that concurrent calls do not corrupt the subscriber list.
|
||||
/// </summary>
|
||||
/// <param name="wsSubscriberGrouped">The grouped WebSocket subscriber instance to be added to the collection.</param>
|
||||
/// <!-- aidoc:v1 sig=38538c1 body=b4c236b -->
|
||||
public void AddSubscriberGrouped(WsSubscriberGrouped wsSubscriberGrouped)
|
||||
{
|
||||
lock (_subscriberGrouped)
|
||||
@@ -195,6 +206,7 @@ public class SubscriberGroupedService(
|
||||
/// <param name="timeZoneId">The optional time zone identifier applied to the new subscription when one is created.</param>
|
||||
/// <param name="connectionId">The unique identifier of the client connection being registered.</param>
|
||||
/// <param name="lastObsInGroup">The most recent observation in the group, used to initialize a new subscription.</param>
|
||||
/// <!-- aidoc:v1 sig=fbd3149 body=ea8c43a -->
|
||||
public void CheckOnSubscriptionGroup(GroupedField groupedField, ObjectId patientId, string? timeZoneId,
|
||||
string connectionId, GroupedObservation lastObsInGroup)
|
||||
{
|
||||
@@ -235,6 +247,7 @@ public class SubscriberGroupedService(
|
||||
/// </summary>
|
||||
/// <param name="wsgHashCode">The hash code used to identify the target subscriber group whose last grouped observation should be updated.</param>
|
||||
/// <param name="newGroupedObservation">The new <see cref="GroupedObservation"/> to set as the last grouped observation in the matched group.</param>
|
||||
/// <!-- aidoc:v1 sig=da02c06 body=39de597 -->
|
||||
public void UpdateLastGroupedObsInGroup(string wsgHashCode, GroupedObservation newGroupedObservation)
|
||||
{
|
||||
lock (_subscriberGrouped)
|
||||
@@ -247,6 +260,7 @@ public class SubscriberGroupedService(
|
||||
/// Creates the next empty grouped observation for the supplied WebSocket subscriber group and distributes it asynchronously to every subscriber in the group, applying the subscriber-specific group value resolved from the group mapping.
|
||||
/// </summary>
|
||||
/// <param name="ws">The grouped WebSocket subscriber context whose next empty observation is generated and whose subscribers will receive the notification.</param>
|
||||
/// <!-- aidoc:v1 sig=cabbfc3 body=1ebe417 -->
|
||||
private async Task AddEmptyObs(WsSubscriberGrouped ws)
|
||||
{
|
||||
var gobs = await groupedObservationService.CreateNextEmptyObs(ws);
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace adas_core.Application.Subscriptions;
|
||||
/// <summary>
|
||||
/// Represents a grouped WebSocket subscriber that aggregates and manages multiple related subscription registrations.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=fe6f386 -->
|
||||
public class WsSubscriberGrouped
|
||||
{
|
||||
private readonly EventHandler<string> _sendEvent;
|
||||
@@ -30,6 +31,8 @@ public class WsSubscriberGrouped
|
||||
/// <param name="lastGroupedObservationObs">The most recent <see cref="GroupedObservation"/> passed to <see cref="UpdateLastGo"/> to initialize the last-observation state.</param>
|
||||
/// <param name="sendEvent">The <see cref="EventHandler{String}"/> invoked by the timer to forward outgoing messages to the subscriber.</param>
|
||||
/// <!-- aidoc:v1 sig=16f9dfc body=cc103b1 -->
|
||||
/// <!-- aidoc-review:v1 severity=low kind=wrong_summary
|
||||
/// "Summary states the constructor 'starts the internal Timer', but Timer.Start() is only invoked when Regularity is not GroupedObservationEnum.Regularity.Times; in the 'Times' regularity case the timer is configured but not started." -->
|
||||
public WsSubscriberGrouped(ObjectId patientId, string wsId, string? timeZoneId,
|
||||
GroupedField gf, GroupedObservation lastGroupedObservationObs, EventHandler<string> sendEvent)
|
||||
{
|
||||
@@ -74,6 +77,7 @@ public class WsSubscriberGrouped
|
||||
/// Refreshes the cached last observations by matching each known name against the supplied grouped observation, falling back to the most recent observation when no match is found.
|
||||
/// </summary>
|
||||
/// <param name="lastGroupedObservationObs">The source grouped observation whose observations are searched to populate the last-observation cache.</param>
|
||||
/// <!-- aidoc:v1 sig=9a3db7f body=189f23b -->
|
||||
public void UpdateLastGo(GroupedObservation lastGroupedObservationObs)
|
||||
{
|
||||
LastGroupedObservationObs.Clear();
|
||||
@@ -150,6 +154,7 @@ public class WsSubscriberGrouped
|
||||
/// <summary>
|
||||
/// Restarts the timer by recalculating its interval through <c>SetUpTimerInterval</c> and then starting it.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=a307365 body=43d12e3 -->
|
||||
private void TimerReestart()
|
||||
{
|
||||
Timer.Interval = SetUpTimerInterval();
|
||||
@@ -160,6 +165,7 @@ public class WsSubscriberGrouped
|
||||
/// Calculates the timer interval in milliseconds until the next scheduled occurrence based on the configured <see cref="Regularity"/>, supporting Second, Minute, Day, and a default (Hour) case, and adds a per-regularity grace time.
|
||||
/// </summary>
|
||||
/// <returns>The number of milliseconds to wait until the next interval, including the grace time.</returns>
|
||||
/// <!-- aidoc:v1 sig=e8a752a body=602d58e -->
|
||||
private int SetUpTimerInterval()
|
||||
{
|
||||
var currentDateTime = DateTime.Now;
|
||||
@@ -230,6 +236,7 @@ public class WsSubscriberGrouped
|
||||
/// <summary>
|
||||
/// Provides static extension methods to enhance WebSocket subscriber functionality.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=1808a25 -->
|
||||
public static class WsSubscriberExtension
|
||||
{
|
||||
/// <summary>
|
||||
@@ -239,6 +246,7 @@ public static class WsSubscriberExtension
|
||||
/// <param name="r">The <see cref="GroupedField"/> to compare against the source.</param>
|
||||
/// <param name="patientId">The patient identifier to match against the source patient identifier.</param>
|
||||
/// <returns><c>true</c> if all compared properties are equal; otherwise, <c>false</c>.</returns>
|
||||
/// <!-- aidoc:v1 sig=d3fad4a body=13fa9d8 -->
|
||||
public static bool Compare(this WsSubscriberGrouped source, GroupedField r, ObjectId patientId)
|
||||
{
|
||||
return r.Regularity == source.Regularity &&
|
||||
@@ -256,6 +264,7 @@ public static class WsSubscriberExtension
|
||||
/// <param name="shift">The target shift list to compare.</param>
|
||||
/// <param name="sourceShift">The source shift list to compare against.</param>
|
||||
/// <returns><c>true</c> if both lists are null or if their sequence of strings is equal; otherwise, <c>false</c>.</returns>
|
||||
/// <!-- aidoc:v1 sig=71a6e44 body=3a82a4f -->
|
||||
private static bool CompareStringShiftList(List<string>? shift, List<string>? sourceShift)
|
||||
{
|
||||
if (shift != null && sourceShift != null) return sourceShift.SequenceEqual(shift);
|
||||
@@ -271,6 +280,7 @@ public static class WsSubscriberExtension
|
||||
/// <param name="name">The fallback candidate list of names to compare against <paramref name="sourceNames"/> when <paramref name="names"/> cannot be used.</param>
|
||||
/// <param name="sourceNames">The source list of names being compared.</param>
|
||||
/// <returns><c>true</c> if <paramref name="sourceNames"/> is a sequence match for either <paramref name="names"/> or <paramref name="name"/>; otherwise, <c>false</c>.</returns>
|
||||
/// <!-- aidoc:v1 sig=96b8c77 body=49d77d4 -->
|
||||
private static bool CompareNamesStringList(List<string> names, List<string> name, List<string> sourceNames)
|
||||
{
|
||||
if (!CollectionsUtils.IsEmptyOrNull(names) && sourceNames.SequenceEqual(names)) return true;
|
||||
@@ -281,6 +291,8 @@ public static class WsSubscriberExtension
|
||||
/// Check if the incoming observation affect to the group and is new info or is irrelevant
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <!-- aidoc-review:v1 severity=medium kind=missing_returns
|
||||
/// "The <returns> tag is present but contains no description; the reader cannot tell what true vs false means without reading the implementation" -->
|
||||
public static bool IsNewObservationRelevantForGroup(this WsSubscriberGrouped group, PatientObservation obs)
|
||||
{
|
||||
double.TryParse(obs.Value.ToString(), out var pobsValue);
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace adas_core.Application.Subscriptions;
|
||||
/// <summary>
|
||||
/// Represents a WebSocket subscriber identified by a unique string identifier.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=e5ef774 -->
|
||||
public class WsSubscriber(string id)
|
||||
{
|
||||
public string? UserName;
|
||||
|
||||
Reference in New Issue
Block a user