Creado apartir del commit b888de6c92056de294456f581a56e25e734d4ab7 de develop
This commit is contained in:
@@ -0,0 +1,441 @@
|
||||
using System.Net;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using adas_core.Application.Services.Interfaces;
|
||||
using adas_core.Domain.Enums;
|
||||
using adas_core.Domain.Models;
|
||||
using adas_core.Domain.Models.AppSettings;
|
||||
using adas_core.Domain.Models.DTO;
|
||||
using adas_core.Domain.Models.MongoModels;
|
||||
using adas_core.Domain.Models.Recording;
|
||||
using adas_core.Domain.Models.Responses;
|
||||
using adas_core.Domain.Utils;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
using Serilog;
|
||||
using Patient = adas_core.Domain.Models.MongoModels.Patient;
|
||||
|
||||
namespace adas_core.Application.Services;
|
||||
|
||||
public class RecordingService : IRecordingService
|
||||
{
|
||||
private readonly IAuthService _authService;
|
||||
private readonly IClientMessageService _clientMessageService;
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly ILogger<RecordingService> _logger;
|
||||
private readonly Lazy<IPatientService> _patientService;
|
||||
private readonly IPublisherService _publisherService;
|
||||
private readonly RabbitMqSettings _rabbitMqSettings;
|
||||
private readonly RecordingSettings _recordingSettings;
|
||||
|
||||
private readonly bool _startRecordingWithoutPatientNumber;
|
||||
private readonly ISubscribersService _subscribersService;
|
||||
private readonly string? _url;
|
||||
|
||||
private AccessGrant? _accessGrant;
|
||||
|
||||
public RecordingService(IOptions<RabbitMqSettings> rabbitMqSettings,
|
||||
IOptions<RecordingSettings> recordingSettings,
|
||||
ILogger<RecordingService> logger,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
IPublisherService publisherService,
|
||||
IAuthService authService,
|
||||
IOptions<ApiSettings> apiSettings, IClientMessageService clientMessageService,
|
||||
ISubscribersService subscribersService,
|
||||
Lazy<IPatientService> patientService)
|
||||
{
|
||||
_logger = logger;
|
||||
_httpClient = httpClientFactory.CreateClient();
|
||||
|
||||
_accessGrant ??= new AccessGrant();
|
||||
_rabbitMqSettings = rabbitMqSettings.Value;
|
||||
_recordingSettings = recordingSettings.Value ??
|
||||
throw new Exception("RecordingSettings must be defined on appSettings");
|
||||
_httpClient.Timeout = new TimeSpan(0, 0, _recordingSettings.HttpClientTimeout);
|
||||
_url = _recordingSettings.RecordingApiUrl;
|
||||
_publisherService = publisherService;
|
||||
_authService = authService;
|
||||
_clientMessageService = clientMessageService;
|
||||
_subscribersService = subscribersService;
|
||||
_patientService = patientService;
|
||||
RecordingQueueName = _rabbitMqSettings.RecordingQueue;
|
||||
ErrorRecordingQueueName = $"{RecordingQueueName}_Error";
|
||||
|
||||
_startRecordingWithoutPatientNumber = apiSettings.Value.StartRecordingWithoutPatientNumber;
|
||||
}
|
||||
|
||||
private string RecordingQueueName { get; }
|
||||
private string ErrorRecordingQueueName { get; }
|
||||
|
||||
|
||||
public async Task<bool> SendCancelRecordingToRecordingApi(Patient patient, PointOfCare poc)
|
||||
{
|
||||
var token = await _authService.GetToken();
|
||||
if (string.IsNullOrEmpty(_url) || string.IsNullOrEmpty(token))
|
||||
throw new Exception(
|
||||
"send recording data to recording api require RecordingOrApiUrl defined and valid token");
|
||||
var body = JsonConvert.SerializeObject(GenerateRecordingData(patient, poc, DateTime.MinValue,
|
||||
null, null, null, null, AlarmEnum.Severity.None, ""));
|
||||
var request =
|
||||
new HttpRequestMessage(HttpMethod.Post,
|
||||
$"{_url}/videos/delete-video-in-progress") //las fechas no se mandan
|
||||
{
|
||||
Content = new StringContent(body, Encoding.UTF8)
|
||||
};
|
||||
request.Headers.TryAddWithoutValidation("Authorization", $"Bearer {token}");
|
||||
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
|
||||
var response = await _httpClient.SendAsync(request);
|
||||
_logger.LogDebug(
|
||||
"send cancel to recording api status code:{responseStatusCode} url: {url} body: {body}",
|
||||
response.StatusCode, _url, body);
|
||||
return response.IsSuccessStatusCode;
|
||||
}
|
||||
|
||||
public async Task SendRecordingData(Patient patient, PointOfCare poc, ManualRecording manualRecording,
|
||||
bool start)
|
||||
{
|
||||
await SendRecordingDataToQueue(patient, poc, manualRecording.Recording?.StartRecordingTime,
|
||||
manualRecording.Recording?.StopRecordingTime, null, null, AlarmEnum.Severity.None, null, start);
|
||||
}
|
||||
|
||||
public async Task<bool> SendAutoRecordingData(Patient patient, PointOfCare poc, RecordingData automaticRecording)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!Enum.TryParse<AlarmEnum.Name>(automaticRecording.AlarmName, out var alarmName))
|
||||
return false;
|
||||
|
||||
await SendRecordingDataToQueue(patient, poc, automaticRecording.StartRecordingTime,
|
||||
automaticRecording.StopRecordingTime, automaticRecording.EventTime,
|
||||
alarmName, automaticRecording.Severity, automaticRecording.AlarmDescription,
|
||||
type: AlarmEnum.Type.Auto);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Exception sending automatic recording data. Exception: {ex}", ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SendRecordingDataToQueue(Patient patient, PointOfCare poc, DateTime? date, DateTime? endDate,
|
||||
DateTime? eventDate, AlarmEnum.Name? alarmName, AlarmEnum.Severity severity, string? alarmDescription,
|
||||
bool start = true, AlarmEnum.Type type = AlarmEnum.Type.Manual)
|
||||
{
|
||||
if (!_startRecordingWithoutPatientNumber && string.IsNullOrEmpty(patient.PatientNumber))
|
||||
{
|
||||
_logger.LogError(
|
||||
"Error sending recording data to queue. Patient number is null or empty. PatientId: {patientId}",
|
||||
patient.PatientId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (poc.Status != StatusEnum.PointOfCare.InUse)
|
||||
throw new Exception($"Box does not contain patients:->{JsonConvert.SerializeObject(poc)}");
|
||||
|
||||
if (string.IsNullOrEmpty(alarmDescription)) alarmDescription = "UNKNOWN";
|
||||
|
||||
var retryCount = 1;
|
||||
|
||||
while (retryCount <= _rabbitMqSettings.MaxRetries)
|
||||
{
|
||||
try
|
||||
{
|
||||
ApiRequest recordingRequest = new()
|
||||
{
|
||||
Recording = GenerateRecordingData(patient, poc, date, endDate, eventDate, null, alarmName,
|
||||
severity, alarmDescription, type)
|
||||
};
|
||||
|
||||
_logger.LogDebug("Send recording data patient {patient}", patient);
|
||||
|
||||
await _publisherService.SendMessage(recordingRequest, RecordingQueueName);
|
||||
|
||||
|
||||
if (recordingRequest.Recording != null)
|
||||
_ = SendRecordingBroadcast([recordingRequest.Recording]);
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
catch (HttpRequestException ce)
|
||||
{
|
||||
retryCount++;
|
||||
_logger.LogError("Connection error sending recording data to queue. {ce} Retrying...", ce.Message);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError("Error sending recording data to queue.{eError} {eMessage} ", e, e.Message);
|
||||
await _publisherService.SendMessage(e.Message, ErrorRecordingQueueName);
|
||||
throw;
|
||||
}
|
||||
|
||||
if (retryCount == _rabbitMqSettings.MaxRetries)
|
||||
await _publisherService.SendMessage("Error: Connection retries exceeded.", ErrorRecordingQueueName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task<List<RecordingData>?> GetRecordings(int roomId)
|
||||
{
|
||||
var retryCount = 1;
|
||||
while (retryCount <= _rabbitMqSettings.MaxRetries)
|
||||
try
|
||||
{
|
||||
var token = await _authService.GetToken();
|
||||
if (string.IsNullOrEmpty(_recordingSettings.RecordingApiUrl) || string.IsNullOrEmpty(token))
|
||||
{
|
||||
Log.Warning(
|
||||
"Not recording url defined at recordingSettings or empty token, ignoring recordings");
|
||||
return null;
|
||||
}
|
||||
|
||||
var request = new HttpRequestMessage(HttpMethod.Get,
|
||||
$"{_recordingSettings.RecordingApiUrl}/videos/allInProgress/{roomId}");
|
||||
|
||||
request.Headers.TryAddWithoutValidation("Authorization", $"Bearer {token}");
|
||||
|
||||
var response = await _httpClient.SendAsync(request);
|
||||
_logger.LogDebug(
|
||||
"GetByCodeSysAndCode recordings to recording api status code:{responseStatusCode} url: {url} body",
|
||||
response.StatusCode, _url);
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
if (response.StatusCode == HttpStatusCode.Unauthorized)
|
||||
{
|
||||
_accessGrant = null;
|
||||
_logger.LogError(
|
||||
"error connecting to RecordingOrApi url:{requestRequestUri} errorCode: {responseStatusCode} error {responseContent} token: {}",
|
||||
request.RequestUri, response.StatusCode, response.Content,
|
||||
_accessGrant?.AccessToken ?? "not exist");
|
||||
}
|
||||
|
||||
else if (response.StatusCode == HttpStatusCode.NotFound)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
_logger.LogError(
|
||||
"error connecting to RecordingOrApi url:{requestRequestUri} errorCode: {responseStatusCode} error {responseContent}",
|
||||
request.RequestUri, response.StatusCode, response.Content);
|
||||
return [];
|
||||
}
|
||||
|
||||
if (retryCount == _rabbitMqSettings.MaxRetries)
|
||||
await _publisherService.SendMessage("Error: Connection retries exceeded.",
|
||||
ErrorRecordingQueueName);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
var records = JsonConvert.DeserializeObject<List<RecordingData>>(responseContent);
|
||||
|
||||
return records;
|
||||
}
|
||||
catch (HttpRequestException ce)
|
||||
{
|
||||
retryCount++;
|
||||
_logger.LogError(
|
||||
"Connection error sending recording data to queue. {ce} Retrying... {retryCount} of {maxRetrys}",
|
||||
ce.Message, retryCount, _rabbitMqSettings.MaxRetries);
|
||||
//return new List<RecordingData>();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError("Error getting recordings room: {roomId} error: {eMessage} ", roomId, e.Message);
|
||||
await _publisherService.SendMessage(e.Message, ErrorRecordingQueueName);
|
||||
return [];
|
||||
}
|
||||
|
||||
if (retryCount == _rabbitMqSettings.MaxRetries)
|
||||
{
|
||||
await _publisherService.SendMessage("Error: Connection retries exceeded.", ErrorRecordingQueueName);
|
||||
return null;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public async Task SaveRequestAsync(ApiRequest apiRequest)
|
||||
{
|
||||
var retryCount = 1;
|
||||
|
||||
while (retryCount <= _rabbitMqSettings.MaxRetries)
|
||||
{
|
||||
try
|
||||
{
|
||||
var token = await _authService.GetToken();
|
||||
|
||||
_logger.LogDebug("sending recording to Recording or api");
|
||||
var recordingRequest = apiRequest.Recording;
|
||||
var request = new HttpRequestMessage(HttpMethod.Post,
|
||||
$"{_recordingSettings.RecordingApiUrl}/videos/save-recording-data")
|
||||
{
|
||||
Content = new StringContent(JsonConvert.SerializeObject(recordingRequest), Encoding.UTF8)
|
||||
};
|
||||
request.Headers.TryAddWithoutValidation("Authorization", $"Bearer {token}");
|
||||
|
||||
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
|
||||
var response = await _httpClient.SendAsync(request);
|
||||
_logger.LogDebug("Save Request to recording api status code:{responseStatusCode}",
|
||||
response.StatusCode);
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
if (response.StatusCode == HttpStatusCode.Unauthorized) _accessGrant = null;
|
||||
|
||||
_logger.LogError(
|
||||
"error connecting to RecordingOrApi url:{requestRequestUri} errorCode: {responseStatusCode} error {responseContent}",
|
||||
request.RequestUri, response.StatusCode, response.Content);
|
||||
retryCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Response y en Data esta el videoDTO
|
||||
var resp = JsonConvert.DeserializeObject<Response<VideoDto>>(responseContent);
|
||||
var video = resp?.Data;
|
||||
if (video == null)
|
||||
return;
|
||||
|
||||
RecordingData recording = new()
|
||||
{
|
||||
StartRecordingTime = video.StartDate,
|
||||
StopRecordingTime = video.EndDate,
|
||||
EventTime = video.Date,
|
||||
RoomId = video.RoomId,
|
||||
AlarmType = video.Alarm,
|
||||
Store = video.Store,
|
||||
Status = video.VideoStatus.ToString(),
|
||||
Patient = new Domain.Models.Recording.Patient
|
||||
{
|
||||
FirstName = apiRequest.Patient?.FirstName ??
|
||||
apiRequest.Recording?.Patient?.FirstName ?? string.Empty,
|
||||
Id = apiRequest.PatientNumber ?? apiRequest.Recording?.Patient?.Id ?? string.Empty,
|
||||
LastName = apiRequest.Patient?.LastName ??
|
||||
apiRequest.Recording?.Patient?.LastName ?? string.Empty
|
||||
}
|
||||
};
|
||||
|
||||
_ = SendRecordingBroadcast([recording]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (HttpRequestException ce)
|
||||
{
|
||||
retryCount++;
|
||||
_logger.LogError("Connection error sending recording data to queue. {ce} Retrying...", ce.Message);
|
||||
await _publisherService.SendMessage(apiRequest, ErrorRecordingQueueName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError("Error sending recording request to Recording or {eMessage}", e.Message);
|
||||
await _publisherService.SendMessage(apiRequest, ErrorRecordingQueueName);
|
||||
await Task.FromException(e);
|
||||
}
|
||||
|
||||
if (retryCount > _rabbitMqSettings.MaxRetries)
|
||||
await _publisherService.SendMessage(
|
||||
$"Error: Connection retries exceeded. for api request: {apiRequest}", ErrorRecordingQueueName);
|
||||
}
|
||||
}
|
||||
|
||||
public Task SaveRequest(ApiRequest apiRequest)
|
||||
{
|
||||
//return Task.CompletedTask;
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private RecordingData? GenerateRecordingData(Patient patient, PointOfCare poc, DateTime? startDate,
|
||||
DateTime? endDate, DateTime? eventTime, int? minToExpired, AlarmEnum.Name? alarmName,
|
||||
AlarmEnum.Severity severity,
|
||||
string alarmDescription, AlarmEnum.Type alarm = AlarmEnum.Type.Manual)
|
||||
{
|
||||
if (patient.PatientNumber == null)
|
||||
{
|
||||
_logger.LogError("Error Generating Recording Data . Patient number is null: {patient}", patient);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
var roomId = poc.Configuration?.Id;
|
||||
if (roomId == null)
|
||||
{
|
||||
_logger.LogError("Error Generating Recording Data on roomId");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
var patientRecording = new Domain.Models.Recording.Patient
|
||||
{
|
||||
Id = patient.PatientNumber,
|
||||
FirstName = patient.Person?.FirstName ?? "X",
|
||||
LastName = $"{patient.Person?.SecondName} {patient.Person?.LastName}".TrimEnd()
|
||||
};
|
||||
|
||||
|
||||
if (!int.TryParse(roomId.ToString(), out var roomIdParsed))
|
||||
{
|
||||
_logger.LogError("Error Generating Recording Data on roomId parse: {roomId}", roomId);
|
||||
return null;
|
||||
}
|
||||
|
||||
var recordingData = new RecordingData
|
||||
{
|
||||
Patient = patientRecording,
|
||||
RoomId = roomIdParsed,
|
||||
StartRecordingTime = startDate,
|
||||
StopRecordingTime =
|
||||
endDate ?? (minToExpired != null ? DateTime.UtcNow.AddMinutes(minToExpired.Value) : null),
|
||||
EventTime = eventTime,
|
||||
AlarmType = alarm,
|
||||
Severity = severity,
|
||||
AlarmName = alarmName.HasValue ? EnumUtils.GetDescription(alarmName) : null,
|
||||
AlarmDescription = alarmDescription,
|
||||
Retry = 0
|
||||
};
|
||||
|
||||
recordingData.GenerateStore();
|
||||
return recordingData;
|
||||
}
|
||||
|
||||
|
||||
private async Task SendRecordingBroadcast(List<RecordingData> recording)
|
||||
{
|
||||
if (!recording.IsNullOrEmpty())
|
||||
{
|
||||
var patientNumber = recording[0].Patient?.Id;
|
||||
if (string.IsNullOrEmpty(patientNumber))
|
||||
{
|
||||
_logger.LogError("Box not found by RoomId {roomId}", recording[0].RoomId);
|
||||
return;
|
||||
}
|
||||
|
||||
var patient = await _patientService.Value.FindByPatientNumber(patientNumber);
|
||||
if (patient == null)
|
||||
return;
|
||||
|
||||
|
||||
var type = OperationType.RecordingStatus;
|
||||
|
||||
var subscribers = _subscribersService.GetSubscribers().Where(s =>
|
||||
s.SubscriptionType == SubscriptionEnum.WsType.Box && s.Box == patient.Location.Bed &&
|
||||
s.Section == patient.Location.UnitName).ToList();
|
||||
|
||||
foreach (var subscriber in subscribers)
|
||||
await _clientMessageService.SendAsync(subscriber.Id, type, recording);
|
||||
}
|
||||
}
|
||||
|
||||
protected static string Base64Encode(string plainText)
|
||||
{
|
||||
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
|
||||
return Convert.ToBase64String(plainTextBytes);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user