Creado apartir del commit b888de6c92056de294456f581a56e25e734d4ab7 de develop
This commit is contained in:
@@ -0,0 +1,299 @@
|
||||
using System.Timers;
|
||||
using adas_core.Domain.Enums;
|
||||
using adas_core.Domain.Models;
|
||||
using adas_core.Domain.Models.GroupedObservations;
|
||||
using adas_core.Domain.Utils;
|
||||
using MongoDB.Bson;
|
||||
using Serilog;
|
||||
using static adas_core.Domain.Models.GroupedObservation;
|
||||
using Timer = System.Timers.Timer;
|
||||
|
||||
namespace adas_core.Application.Subscriptions;
|
||||
|
||||
/**
|
||||
* This class is used to group the subscribers by the same group
|
||||
*/
|
||||
public class WsSubscriberGrouped
|
||||
{
|
||||
private readonly EventHandler<string> _sendEvent;
|
||||
|
||||
public WsSubscriberGrouped(ObjectId patientId, string wsId, string? timeZoneId,
|
||||
GroupedField gf, GroupedObservation lastGroupedObservationObs, EventHandler<string> sendEvent)
|
||||
{
|
||||
_sendEvent = sendEvent;
|
||||
if (WsSubscriber.ToList().FirstOrDefault(s => s == wsId) == null) WsSubscriber.Add(wsId);
|
||||
|
||||
TimeZoneId = timeZoneId ?? "Romance Standard Time";
|
||||
PatientId = patientId;
|
||||
Names = CollectionsUtils.IfEmptyOrNull(gf.Names, [gf.Name ?? string.Empty]);
|
||||
Max = gf.Max;
|
||||
Since = gf.Since;
|
||||
StartTimeShift = gf.StartTimeShift;
|
||||
Regularity = gf.Regularity;
|
||||
Result = gf.Result;
|
||||
Group.Add(wsId, gf.Group ?? string.Empty);
|
||||
UpdateLastGo(lastGroupedObservationObs);
|
||||
HashCode = CryptoAdas.CreateMd5GroupedObs(gf, patientId);
|
||||
|
||||
Timer = new Timer
|
||||
{
|
||||
Interval = SetUpTimerInterval()
|
||||
};
|
||||
Timer.Elapsed += Timer_Elapsed;
|
||||
if (Regularity != GroupedObservationEnum.Regularity.Times) Timer.Start();
|
||||
}
|
||||
|
||||
public List<string> WsSubscriber { get; set; } = [];
|
||||
public ObjectId PatientId { get; set; }
|
||||
public List<string> Names { get; set; }
|
||||
public int Max { get; set; }
|
||||
public GroupedObservationEnum.Regularity? Regularity { get; set; }
|
||||
public List<GroupedObservationEnum.Result> Result { get; set; }
|
||||
public GroupedObservationEnum.Since Since { get; set; }
|
||||
public List<string> StartTimeShift { get; set; }
|
||||
public string HashCode { get; set; }
|
||||
public string TimeZoneId { get; set; }
|
||||
public List<GroupedObservationObs> LastGroupedObservationObs { get; set; } = [];
|
||||
public Dictionary<string, string> Group { get; set; } = new();
|
||||
public Timer Timer { get; set; }
|
||||
|
||||
public void UpdateLastGo(GroupedObservation lastGroupedObservationObs)
|
||||
{
|
||||
LastGroupedObservationObs.Clear();
|
||||
foreach (var name in Names)
|
||||
{
|
||||
var lastObs = lastGroupedObservationObs.Observations.LastOrDefault(c => c.Name == name);
|
||||
if (lastObs != null)
|
||||
{
|
||||
LastGroupedObservationObs.Add(lastObs);
|
||||
}
|
||||
else
|
||||
{
|
||||
lastObs = lastGroupedObservationObs.Observations.LastOrDefault();
|
||||
if (lastObs != null) LastGroupedObservationObs.Add(lastObs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Timer_Elapsed(object? sender, ElapsedEventArgs e)
|
||||
{
|
||||
var currentDateTime = DateTime.Now;
|
||||
Timer.Stop();
|
||||
try
|
||||
{
|
||||
bool hasCurrentObs;
|
||||
|
||||
switch (Regularity)
|
||||
{
|
||||
case GroupedObservationEnum.Regularity.Second:
|
||||
// Filtra observaciones con el mismo segundo actual
|
||||
hasCurrentObs = LastGroupedObservationObs.Any(obs => obs.Time.Second == currentDateTime.Second
|
||||
&& obs.Time.Minute == currentDateTime.Minute
|
||||
&& obs.Time.Hour == currentDateTime.Hour
|
||||
&& obs.Time.Date == currentDateTime.Date);
|
||||
break;
|
||||
|
||||
case GroupedObservationEnum.Regularity.Minute:
|
||||
// Filtra observaciones con el mismo minuto actual
|
||||
hasCurrentObs = LastGroupedObservationObs.Any(obs => obs.Time.Minute == currentDateTime.Minute
|
||||
&& obs.Time.Hour == currentDateTime.Hour
|
||||
&& obs.Time.Date == currentDateTime.Date);
|
||||
break;
|
||||
|
||||
case GroupedObservationEnum.Regularity.Day:
|
||||
// Filtra observaciones con la misma fecha actual (día completo)
|
||||
hasCurrentObs = LastGroupedObservationObs.Any(obs => obs.Time.Date == currentDateTime.Date);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Filtra observaciones con la misma hora actual
|
||||
hasCurrentObs = LastGroupedObservationObs.Any(obs => obs.Time.Hour == currentDateTime.Hour
|
||||
&& obs.Time.Date == currentDateTime.Date);
|
||||
break;
|
||||
}
|
||||
|
||||
// Si no hay al menos una observación que coincide, invoca el evento
|
||||
if (!hasCurrentObs) _sendEvent(this, HashCode);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning(
|
||||
$"Exception on WsSubsciptor for patient: {PatientId} message: {ex.Message} exception: {ex}");
|
||||
}
|
||||
|
||||
TimerReestart();
|
||||
}
|
||||
|
||||
private void TimerReestart()
|
||||
{
|
||||
Timer.Interval = SetUpTimerInterval();
|
||||
Timer.Start();
|
||||
}
|
||||
|
||||
private int SetUpTimerInterval()
|
||||
{
|
||||
var currentDateTime = DateTime.Now;
|
||||
int graceTime;
|
||||
DateTime nextIntervalTime;
|
||||
|
||||
switch (Regularity)
|
||||
{
|
||||
case GroupedObservationEnum.Regularity.Second:
|
||||
nextIntervalTime = new DateTime(
|
||||
currentDateTime.Year,
|
||||
currentDateTime.Month,
|
||||
currentDateTime.Day,
|
||||
currentDateTime.Hour,
|
||||
currentDateTime.Minute,
|
||||
currentDateTime.Second
|
||||
).AddSeconds(1);
|
||||
graceTime = 500;
|
||||
break;
|
||||
|
||||
case GroupedObservationEnum.Regularity.Minute:
|
||||
nextIntervalTime = new DateTime(
|
||||
currentDateTime.Year,
|
||||
currentDateTime.Month,
|
||||
currentDateTime.Day,
|
||||
currentDateTime.Hour,
|
||||
currentDateTime.Minute,
|
||||
0
|
||||
).AddMinutes(1);
|
||||
graceTime = 30000;
|
||||
break;
|
||||
|
||||
case GroupedObservationEnum.Regularity.Day:
|
||||
nextIntervalTime = new DateTime(
|
||||
currentDateTime.Year,
|
||||
currentDateTime.Month,
|
||||
currentDateTime.Day,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
).AddDays(1);
|
||||
graceTime = 60000;
|
||||
break;
|
||||
|
||||
default:
|
||||
nextIntervalTime = new DateTime(
|
||||
currentDateTime.Year,
|
||||
currentDateTime.Month,
|
||||
currentDateTime.Day,
|
||||
currentDateTime.Hour,
|
||||
0,
|
||||
0
|
||||
).AddHours(1);
|
||||
graceTime = 30000;
|
||||
break;
|
||||
}
|
||||
|
||||
var timeSpanToNextInterval = nextIntervalTime - currentDateTime;
|
||||
Log.Information(
|
||||
"Obs {Obs}, currentDateTime: {CurrentDateTime}, nextIntervalTime: {NextIntervalTime}, timeSpanToNextInterval: {TimeSpanToNextInterval}, timeSpanToNextInterval.TotalMilliseconds+graceTime: {Tt}",
|
||||
Group, currentDateTime, nextIntervalTime, timeSpanToNextInterval,
|
||||
(int)timeSpanToNextInterval.TotalMilliseconds + graceTime);
|
||||
|
||||
return (int)timeSpanToNextInterval.TotalMilliseconds + graceTime;
|
||||
}
|
||||
}
|
||||
|
||||
public static class WsSubscriberExtension
|
||||
{
|
||||
public static bool Compare(this WsSubscriberGrouped source, GroupedField r, ObjectId patientId)
|
||||
{
|
||||
return r.Regularity == source.Regularity &&
|
||||
r.Since == source.Since &&
|
||||
CompareStringShiftList(r.StartTimeShift, source.StartTimeShift) &&
|
||||
r.Max == source.Max &&
|
||||
r.Result.SequenceEqual(source.Result) &&
|
||||
patientId.ToString() == source.PatientId.ToString() &&
|
||||
CompareNamesStringList(r.Names, [r.Name ?? string.Empty], source.Names);
|
||||
}
|
||||
|
||||
private static bool CompareStringShiftList(List<string>? shift, List<string>? sourceShift)
|
||||
{
|
||||
if (shift != null && sourceShift != null) return sourceShift.SequenceEqual(shift);
|
||||
if (shift == null && sourceShift == null) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool CompareNamesStringList(List<string> names, List<string> name, List<string> sourceNames)
|
||||
{
|
||||
if (!CollectionsUtils.IsEmptyOrNull(names) && sourceNames.SequenceEqual(names)) return true;
|
||||
return !CollectionsUtils.IsEmptyOrNull(name) && sourceNames.SequenceEqual(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the incoming observation affect to the group and is new info or is irrelevant
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static bool IsNewObservationRelevantForGroup(this WsSubscriberGrouped group, PatientObservation obs)
|
||||
{
|
||||
double.TryParse(obs.Value.ToString(), out var pobsValue);
|
||||
switch (group.Regularity)
|
||||
{
|
||||
case GroupedObservationEnum.Regularity.Shift:
|
||||
case GroupedObservationEnum.Regularity.Hour:
|
||||
var obsInThisHour = group.LastGroupedObservationObs.Where(c =>
|
||||
new DateTime(c.Time.Year, c.Time.Month, c.Time.Day, c.Time.Hour, 0, 0) ==
|
||||
new DateTime(obs.Time.Year, obs.Time.Month, obs.Time.Day, obs.Time.Hour, 0, 0) && !c.IsFilled);
|
||||
//Obs is in grouped time, don't generate group for observation outside of range
|
||||
|
||||
|
||||
//Change to don't cut is obs time is a future
|
||||
var obsInTime = DateTime.UtcNow.AddHours(group.Max) > obs.Time &&
|
||||
DateTime.UtcNow.AddHours(group.Max * -1) < obs.Time;
|
||||
//future data is relevant because maybe nothing is inserted in the same hour after it and we cant lose it
|
||||
/* if (DateTime.UtcNow.AddHours(group.Max) > obs.time)
|
||||
{
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
if (!obsInTime) return false;
|
||||
var groupedObservationObsEnumerable = obsInThisHour.ToList();
|
||||
if (!groupedObservationObsEnumerable.Any() && obsInTime) return true;
|
||||
|
||||
//If obs in this hour check if is relevant by Result
|
||||
if (groupedObservationObsEnumerable.Any())
|
||||
foreach (var result in group.Result)
|
||||
switch (result)
|
||||
{
|
||||
case GroupedObservationEnum.Result.Max:
|
||||
var value = groupedObservationObsEnumerable.Max(s => s.Max?.Value);
|
||||
var parsed = double.TryParse(value?.ToString(), out var valueParsed);
|
||||
//actual value is higher, is relevant
|
||||
if (parsed && pobsValue > valueParsed) return true;
|
||||
break;
|
||||
case GroupedObservationEnum.Result.Min:
|
||||
var minValue = groupedObservationObsEnumerable.Min(s => s.Min?.Value);
|
||||
var isParsed = double.TryParse(minValue?.ToString(), out var minValueParsed);
|
||||
//actual value is higher, is relevant
|
||||
if (isParsed && pobsValue < minValueParsed) return true;
|
||||
break;
|
||||
case GroupedObservationEnum.Result.Last:
|
||||
var lastObsInTime = groupedObservationObsEnumerable.OrderBy(t => t.Last?.Time).First();
|
||||
//is the new latest in the hour, relevant
|
||||
if (lastObsInTime.Time < obs.Time) return true;
|
||||
break;
|
||||
case GroupedObservationEnum.Result.LastFilled:
|
||||
var lastFilledObsInTime = groupedObservationObsEnumerable
|
||||
.OrderBy(t => t.LastFilled?.Time).First();
|
||||
//is the new latest in the hour, relevant
|
||||
if (lastFilledObsInTime.Time < obs.Time) return true;
|
||||
break;
|
||||
//always is relevant because SUM everything in the hour
|
||||
//TODO halfHour should check if any obs already in the halfHour
|
||||
case GroupedObservationEnum.Result.Sum:
|
||||
case GroupedObservationEnum.Result.Average:
|
||||
case GroupedObservationEnum.Result.HalfHour:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
default:
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user