using AsbCloudApp.Data; using AsbCloudApp.Services; using AsbCloudDb.Model; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Configuration; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace AsbCloudInfrastructure.Services.SAUB { public class TelemetryTracker : ITelemetryTracker { class TrackerStat { //public int Id { get; set; } public string RemoteUid { get; set; } /// /// Время последнего запроса (по времени сервера) /// public DateTimeOffset LastTimeServer { get; set; } /// /// Дата первых данных в БД /// public DateTimeOffset TelemetryDateUtcMin { get; set; } /// /// Дата последних данных в БД /// public DateTimeOffset TelemetryDateUtcMax { get; set; } } private readonly ConcurrentDictionary telemetriesStats; public TelemetryTracker(IConfiguration configuration, IMemoryCache memoryCache) { // TODO: make this background work var contextOptions = new DbContextOptionsBuilder() .UseNpgsql(configuration.GetConnectionString("DefaultConnection")) .Options; var db = new AsbCloudDbContext(contextOptions); var cacheTelemetry = memoryCache.GetOrCreateBasic(db.Set()); var keyValuePairs = new Dictionary(cacheTelemetry.Count()); foreach (var telemetry in cacheTelemetry) { var date = telemetry.Info?.DrillingStartDate ?? ParseDateFromUidOrDefault(telemetry.RemoteUid, DateTimeOffset.MinValue); keyValuePairs[telemetry.RemoteUid] = new TrackerStat { RemoteUid = telemetry.RemoteUid, TelemetryDateUtcMin = date, TelemetryDateUtcMax = date, LastTimeServer = date, }; } telemetriesStats = new ConcurrentDictionary(keyValuePairs); Task.Run(async () => { db.Database.SetCommandTimeout(2 * 60); var dates = await db.TelemetryDataSaub .GroupBy(d => d.IdTelemetry) .Select(g => new { IdTelemetry = g.Key, DateMax = g.Max(d => d.DateTime), DateMin = g.Min(d => d.DateTime), }) .AsNoTracking() .ToListAsync() .ConfigureAwait(false); var oldRequests = dates.Select(t => new { Uid = cacheTelemetry.FirstOrDefault(c => c.Id == t.IdTelemetry)?.RemoteUid, t.DateMax, t.DateMin, }).Where(s => !string.IsNullOrEmpty(s.Uid)); foreach (var oldReq in oldRequests) { var telemetryStat = telemetriesStats.GetOrAdd(oldReq.Uid, (uid) => new TrackerStat { RemoteUid = uid }); telemetryStat.TelemetryDateUtcMin = oldReq.DateMin; telemetryStat.TelemetryDateUtcMax = oldReq.DateMax; telemetryStat.LastTimeServer = oldReq.DateMax; } }).ContinueWith((t) => { db.Dispose(); return t; }); } private static DateTimeOffset ParseDateFromUidOrDefault(string remoteUid, DateTimeOffset defaultValue = default) { //example: uid = 20211102_173407926 if (string.IsNullOrEmpty(remoteUid) || remoteUid.Length != 18) return defaultValue; if (DateTime.TryParseExact(remoteUid, "yyyyMMdd_HHmmssfff", System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.AssumeUniversal, out DateTime parsedDate)) return parsedDate; return defaultValue; } public void SaveRequestDate(string uid, DateTimeOffset remoteDate) { var stat = telemetriesStats.GetOrAdd(uid, _ => new TrackerStat { RemoteUid = uid, TelemetryDateUtcMin = remoteDate } ); stat.LastTimeServer = DateTime.Now; if (stat.TelemetryDateUtcMax.ToUniversalTime() < remoteDate.ToUniversalTime()) stat.TelemetryDateUtcMax = remoteDate; } public DateTimeOffset GetLastTelemetryDateByUid(string uid) => telemetriesStats.GetValueOrDefault(uid)?.TelemetryDateUtcMax ?? default; public DatesRangeDto GetTelemetryDateRangeByUid(string uid) { var stat = telemetriesStats.GetValueOrDefault(uid); var range = new DatesRangeDto { From = stat?.TelemetryDateUtcMin.UtcDateTime ?? default, To = stat?.TelemetryDateUtcMax.UtcDateTime ?? default, }; return range; } public IEnumerable GetTransmittingTelemetriesUids() => telemetriesStats.Keys; } }