using AsbCloudApp.Requests; using AsbCloudApp.Services; using AsbCloudDb.Model; using Mapster; using Microsoft.EntityFrameworkCore; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace AsbCloudInfrastructure.Repository; public class WitsRecordRepository : IWitsRecordRepository where TEntity : AsbCloudDb.Model.WITS.RecordBase, ITelemetryData where TDto : AsbCloudApp.Data.ITelemetryData { private static readonly Random random = new Random((int)(DateTime.Now.Ticks % 0xFFFFFFFF)); private readonly DbSet dbset; private readonly IAsbCloudDbContext db; private readonly ITelemetryService telemetryService; private static readonly ConcurrentDictionary cache = new(); public WitsRecordRepository(IAsbCloudDbContext db, ITelemetryService telemetryService) { dbset = db.Set(); this.db = db; this.telemetryService = telemetryService; } public async Task<(DateTime begin, DateTime end, int count)?> GetStatAsync(int idTelemetry, CancellationToken token) { var timezoneHours = telemetryService.GetTimezone(idTelemetry).Hours; var stat = await dbset.Where(d => d.IdTelemetry == idTelemetry) .GroupBy(d => d.IdTelemetry) .Select(g => new Tuple(g.Min(d => d.DateTime), g.Max(d => d.DateTime), g.Count())) .FirstOrDefaultAsync(token); if (stat is null || stat.Item3 == 0) return null; return ( stat.Item1.ToRemoteDateTime(timezoneHours), stat.Item2.ToRemoteDateTime(timezoneHours), stat.Item3); } public async Task> GetAsync(int idTelemetry, DateTime begin, DateTime end, CancellationToken token) { var timezoneHours = telemetryService.GetTimezone(idTelemetry).Hours; var query = dbset .Where(d => d.IdTelemetry == idTelemetry) .Where(d => d.DateTime >= begin) .Where(d => d.DateTime <= end) .AsNoTracking(); var data = await query.ToListAsync(token); return data.Select(d => Convert(d, timezoneHours)); } private IQueryable BuildQuery(TelemetryPartDeleteRequest request) { var query = db.Set() .Where(o => o.IdTelemetry == request.IdTelemetry); if (request.LeDate is not null) { var leDate = request.LeDate.Value.ToUniversalTime(); query = query.Where(o => o.DateTime <= leDate); } if (request.GeDate is not null) { var geDate = request.GeDate.Value.ToUniversalTime(); query = query.Where(o => o.DateTime >= geDate); } return query; } public async Task DeleteAsync(TelemetryPartDeleteRequest request, CancellationToken token) { var query = BuildQuery(request); dbset.RemoveRange(query); return await db.SaveChangesAsync(token); } public TDto? GetLastOrDefault(int idTelemetry) => cache.GetValueOrDefault(idTelemetry); public async Task SaveDataAsync(int idTelemetry, IEnumerable dtos, CancellationToken token) { if (!dtos.Any()) return; cache.AddOrUpdate(idTelemetry, dtos.Last(), (_, _) => dtos.OrderBy(r => r.DateTime).Last()); var timezoneHours = telemetryService.GetTimezone(idTelemetry).Hours; var entities = dtos .DistinctBy(d => d.DateTime) .Select(dto => Convert(dto, idTelemetry, timezoneHours)); var dateMin = entities.Min(e => e.DateTime); var dateMax = entities.Max(e => e.DateTime); var existingEntities = await db.Set() .Where(e => e.IdTelemetry == idTelemetry) .Where(e => e.DateTime >= dateMin && e.DateTime <= dateMax) .Select(e => e.DateTime) .OrderBy(d => d) .ToArrayAsync(token); foreach (var entity in entities) { if (!existingEntities.Any(e => e == entity.DateTime)) { dbset.Add(entity); } else { var dt = entity.DateTime; entity.DateTime = new DateTimeOffset( dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, (dt.Millisecond + random.Next(1, 283)) % 1000, dt.Offset); dbset.Add(entity); } } await db.SaveChangesAsync(token); } private static short GetRecId(TDto dto) { var recid = dto switch { AsbCloudApp.Data.WITS.Record1Dto _ => 1, AsbCloudApp.Data.WITS.Record7Dto _ => 7, AsbCloudApp.Data.WITS.Record8Dto _ => 8, AsbCloudApp.Data.WITS.Record50Dto _ => 50, AsbCloudApp.Data.WITS.Record60Dto _ => 60, AsbCloudApp.Data.WITS.Record61Dto _ => 61, _ => 0, }; return (short)recid; } private static TEntity Convert(TDto dto, int idTelemetry, double timezoneHours) { var entity = dto.Adapt(); entity.Recid = GetRecId(dto); entity.IdTelemetry = idTelemetry; entity.DateTime = dto.DateTime.ToUtcDateTimeOffset(timezoneHours); return entity; } private static TDto Convert(TEntity entity, double timezoneHours) { var data = entity.Adapt(); data.DateTime = entity.DateTime.ToRemoteDateTime(timezoneHours); return data; } }