2021-09-17 16:24:01 +05:00
|
|
|
|
using AsbCloudApp.Data;
|
|
|
|
|
using AsbCloudApp.Services;
|
|
|
|
|
using AsbCloudDb.Model;
|
2021-11-15 14:56:11 +05:00
|
|
|
|
using AsbCloudDb;
|
2021-09-17 16:24:01 +05:00
|
|
|
|
using AsbCloudInfrastructure.Services.Cache;
|
|
|
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
2021-11-13 18:47:11 +05:00
|
|
|
|
using System.Diagnostics;
|
2021-09-17 16:24:01 +05:00
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
namespace AsbCloudInfrastructure.Services
|
|
|
|
|
{
|
2022-01-05 17:50:45 +05:00
|
|
|
|
public abstract class TelemetryDataBaseService<TDto, TModel> : ITelemetryDataService<TDto>
|
2021-09-17 16:24:01 +05:00
|
|
|
|
where TDto : AsbCloudApp.Data.ITelemetryData
|
|
|
|
|
where TModel : class, AsbCloudDb.Model.ITelemetryData
|
|
|
|
|
{
|
|
|
|
|
private readonly IAsbCloudDbContext db;
|
|
|
|
|
private readonly ITelemetryService telemetryService;
|
|
|
|
|
protected readonly CacheTable<Telemetry> cacheTelemetry;
|
|
|
|
|
protected readonly CacheTable<TelemetryUser> cacheTelemetryUsers;
|
|
|
|
|
protected readonly CacheTable<Well> cacheWells;
|
|
|
|
|
|
2021-09-23 10:53:48 +05:00
|
|
|
|
public TelemetryDataBaseService(
|
2021-09-17 16:24:01 +05:00
|
|
|
|
IAsbCloudDbContext db,
|
|
|
|
|
ITelemetryService telemetryService,
|
|
|
|
|
CacheDb cacheDb)
|
|
|
|
|
{
|
|
|
|
|
this.db = db;
|
|
|
|
|
this.telemetryService = telemetryService;
|
|
|
|
|
cacheTelemetry = cacheDb.GetCachedTable<Telemetry>((AsbCloudDbContext)db);
|
|
|
|
|
cacheTelemetryUsers = cacheDb.GetCachedTable<TelemetryUser>((AsbCloudDbContext)db);
|
|
|
|
|
cacheWells = cacheDb.GetCachedTable<Well>((AsbCloudDbContext)db);
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-15 14:56:11 +05:00
|
|
|
|
public virtual async Task<int> UpdateDataAsync(string uid, IEnumerable<TDto> dtos, CancellationToken token = default)
|
2021-09-17 16:24:01 +05:00
|
|
|
|
{
|
|
|
|
|
if (dtos == default || !dtos.Any())
|
|
|
|
|
return 0;
|
2021-11-15 14:56:11 +05:00
|
|
|
|
|
2021-11-13 18:47:11 +05:00
|
|
|
|
var dtosList = dtos.OrderBy(d => d.Date).ToList();
|
2021-10-28 10:56:18 +05:00
|
|
|
|
|
2021-11-13 18:47:11 +05:00
|
|
|
|
var dtoMinDate = dtosList.First().Date;
|
|
|
|
|
var dtoMaxDate = dtosList.Last().Date;
|
|
|
|
|
|
|
|
|
|
if (dtosList.Count > 1)
|
|
|
|
|
{
|
|
|
|
|
var duplicates = new List<TDto>(8);
|
|
|
|
|
for (int i = 1; i < dtosList.Count; i++)
|
2021-11-15 14:56:11 +05:00
|
|
|
|
if (dtosList[i].Date - dtosList[i-1].Date < TimeSpan.FromMilliseconds(100))
|
2021-11-13 18:47:11 +05:00
|
|
|
|
duplicates.Add(dtosList[i - 1]);
|
2021-11-15 14:56:11 +05:00
|
|
|
|
foreach (var duplicate in duplicates)
|
2021-11-13 18:47:11 +05:00
|
|
|
|
dtosList.Remove(duplicate);
|
|
|
|
|
}
|
2022-01-10 18:12:31 +05:00
|
|
|
|
|
|
|
|
|
var idTelemetry = telemetryService.GetOrCreateTelemetryIdByUid(uid);
|
|
|
|
|
var timezone = telemetryService.GetTimezone(idTelemetry);
|
2021-12-30 17:05:44 +05:00
|
|
|
|
|
|
|
|
|
var entities = dtosList.Select(dto => {
|
2022-01-05 17:50:45 +05:00
|
|
|
|
var entity = Convert(dto, timezone.Hours);
|
2021-12-30 17:05:44 +05:00
|
|
|
|
entity.IdTelemetry = idTelemetry;
|
|
|
|
|
return entity;
|
2021-11-15 14:56:11 +05:00
|
|
|
|
});
|
2021-09-17 16:24:01 +05:00
|
|
|
|
|
2022-04-01 17:55:44 +05:00
|
|
|
|
var entityMaxDate = entities.Max(e => e.DateTime);
|
2021-12-24 10:38:14 +05:00
|
|
|
|
telemetryService.SaveRequestDate(uid, entityMaxDate);
|
|
|
|
|
|
2021-11-15 14:56:11 +05:00
|
|
|
|
var dbset = db.Set<TModel>();
|
2021-12-24 13:00:16 +05:00
|
|
|
|
var stopwatch = Stopwatch.StartNew();
|
2021-11-13 18:47:11 +05:00
|
|
|
|
try
|
2021-09-17 16:24:01 +05:00
|
|
|
|
{
|
2021-11-17 15:54:01 +05:00
|
|
|
|
return await db.Database.ExecInsertOrUpdateAsync(dbset, entities, token).ConfigureAwait(false);
|
2021-11-13 18:47:11 +05:00
|
|
|
|
}
|
2021-11-15 14:56:11 +05:00
|
|
|
|
catch(Exception ex)
|
2021-11-13 18:47:11 +05:00
|
|
|
|
{
|
2021-12-24 13:00:16 +05:00
|
|
|
|
stopwatch.Stop();
|
2021-12-30 17:05:44 +05:00
|
|
|
|
Trace.WriteLine($"Fail to save data telemetry " +
|
2021-12-24 13:00:16 +05:00
|
|
|
|
$"uid: {uid}, " +
|
|
|
|
|
$"idTelemetry {idTelemetry}, " +
|
|
|
|
|
$"count: {entities.Count()}, " +
|
2022-04-01 17:55:44 +05:00
|
|
|
|
$"dataDate: {entities.FirstOrDefault()?.DateTime}, " +
|
2021-12-24 13:00:16 +05:00
|
|
|
|
$"dbSaveDurationTime:{stopwatch.ElapsedMilliseconds}ms. " +
|
|
|
|
|
$"Message: {ex.Message}");
|
2021-11-15 14:56:11 +05:00
|
|
|
|
return 0;
|
2021-09-17 16:24:01 +05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual async Task<IEnumerable<TDto>> GetAsync(int idWell,
|
|
|
|
|
DateTime dateBegin = default, double intervalSec = 600d,
|
2022-01-05 17:50:45 +05:00
|
|
|
|
int approxPointsCount = 1024, CancellationToken token = default)
|
2021-09-17 16:24:01 +05:00
|
|
|
|
{
|
|
|
|
|
var well = cacheWells.FirstOrDefault(w => w.Id == idWell);
|
2021-10-27 17:48:19 +05:00
|
|
|
|
if (well?.IdTelemetry is null)
|
2021-09-17 16:24:01 +05:00
|
|
|
|
return default;
|
|
|
|
|
|
2021-11-22 11:30:08 +05:00
|
|
|
|
var idTelemetry = well?.IdTelemetry ?? default;
|
|
|
|
|
|
2022-01-05 17:50:45 +05:00
|
|
|
|
var timezone = telemetryService.GetTimezone(idTelemetry);
|
2021-12-30 17:05:44 +05:00
|
|
|
|
|
2021-12-03 17:34:24 +05:00
|
|
|
|
var filterByDateEnd = dateBegin != default;
|
2021-12-30 17:05:44 +05:00
|
|
|
|
DateTimeOffset dateBeginUtc;
|
2021-10-27 17:48:19 +05:00
|
|
|
|
if (dateBegin == default)
|
2021-10-28 11:12:03 +05:00
|
|
|
|
{
|
2022-01-05 17:50:45 +05:00
|
|
|
|
dateBeginUtc = telemetryService.GetLastTelemetryDate(idTelemetry, true);
|
2021-12-30 17:05:44 +05:00
|
|
|
|
if (dateBeginUtc != default)
|
|
|
|
|
dateBeginUtc = dateBeginUtc.AddSeconds(-intervalSec);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-01-05 17:50:45 +05:00
|
|
|
|
dateBeginUtc = dateBegin.ToUtcDateTimeOffset(timezone.Hours);
|
2021-12-30 17:05:44 +05:00
|
|
|
|
}
|
2021-09-17 16:24:01 +05:00
|
|
|
|
|
2021-12-30 17:05:44 +05:00
|
|
|
|
if (dateBeginUtc == default)
|
|
|
|
|
dateBeginUtc = DateTime.UtcNow.AddSeconds(-intervalSec);
|
2021-10-28 11:12:03 +05:00
|
|
|
|
|
2021-12-30 17:05:44 +05:00
|
|
|
|
var dateEnd = dateBeginUtc.AddSeconds(intervalSec);
|
2021-09-17 16:24:01 +05:00
|
|
|
|
var dbSet = db.Set<TModel>();
|
|
|
|
|
|
2021-11-22 11:30:08 +05:00
|
|
|
|
var query = dbSet
|
|
|
|
|
.Where(d => d.IdTelemetry == idTelemetry
|
2022-04-01 17:55:44 +05:00
|
|
|
|
&& d.DateTime >= dateBeginUtc);
|
2021-12-03 17:34:24 +05:00
|
|
|
|
|
|
|
|
|
if (filterByDateEnd)
|
2022-04-01 17:55:44 +05:00
|
|
|
|
query = query.Where(d => d.DateTime <= dateEnd);
|
2021-09-17 16:24:01 +05:00
|
|
|
|
|
|
|
|
|
var fullDataCount = await query.CountAsync(token)
|
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
|
|
|
|
|
|
if (fullDataCount == 0)
|
|
|
|
|
return default;
|
|
|
|
|
|
|
|
|
|
if (fullDataCount > 1.75 * approxPointsCount)
|
|
|
|
|
{
|
|
|
|
|
var m = (int)Math.Round(1d * fullDataCount / approxPointsCount);
|
2021-12-01 11:08:25 +05:00
|
|
|
|
|
|
|
|
|
switch (m)
|
|
|
|
|
{
|
|
|
|
|
//case var i when i <= 1: // тут для полноты, но никогда не сработает из-за условия выше
|
|
|
|
|
// break;
|
|
|
|
|
case var i when i < 10:
|
2022-04-01 17:55:44 +05:00
|
|
|
|
query = query.Where((d) => d.DateTime.Second % m == 0);
|
2021-12-01 11:08:25 +05:00
|
|
|
|
break;
|
|
|
|
|
case var i when i < 30:
|
2022-04-01 17:55:44 +05:00
|
|
|
|
query = query.Where((d) => (d.DateTime.Minute * 60 + d.DateTime.Second) % m == 0);
|
2021-12-01 11:08:25 +05:00
|
|
|
|
break;
|
|
|
|
|
case var i when i < 600:
|
2022-04-01 17:55:44 +05:00
|
|
|
|
query = query.Where((d) => ((d.DateTime.Hour * 60 + d.DateTime.Minute) * 60 + d.DateTime.Second) % m == 0);
|
2021-12-01 11:08:25 +05:00
|
|
|
|
break;
|
|
|
|
|
default:
|
2022-04-01 17:55:44 +05:00
|
|
|
|
query = query.Where((d) => (((d.DateTime.DayOfYear * 24 + d.DateTime.Hour) * 60 + d.DateTime.Minute) * 60 + d.DateTime.Second) % m == 0);
|
2021-12-01 11:08:25 +05:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-17 16:24:01 +05:00
|
|
|
|
if (m > 1)
|
2022-04-01 17:55:44 +05:00
|
|
|
|
query = query.Where((d) => (((d.DateTime.DayOfYear*24 + d.DateTime.Hour)*60 + d.DateTime.Minute)*60 + d.DateTime.Second) % m == 0);
|
2021-09-17 16:24:01 +05:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-29 17:05:27 +05:00
|
|
|
|
var entities = await query
|
2022-04-01 17:55:44 +05:00
|
|
|
|
.OrderBy(d=>d.DateTime)
|
2021-09-29 17:05:27 +05:00
|
|
|
|
.AsNoTracking()
|
|
|
|
|
.ToListAsync(token)
|
|
|
|
|
.ConfigureAwait(false);
|
2021-09-17 16:24:01 +05:00
|
|
|
|
|
2022-01-05 17:50:45 +05:00
|
|
|
|
var dtos = entities.Select(e => Convert(e, timezone.Hours));
|
|
|
|
|
|
2021-09-17 16:24:01 +05:00
|
|
|
|
return dtos;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-05 17:50:45 +05:00
|
|
|
|
public abstract TDto Convert(TModel src, double timezoneOffset);
|
2021-09-17 16:24:01 +05:00
|
|
|
|
|
2022-01-05 17:50:45 +05:00
|
|
|
|
public abstract TModel Convert(TDto src, double timezoneOffset);
|
2022-01-10 18:12:31 +05:00
|
|
|
|
|
|
|
|
|
private static double AssumeTimezoneOffset(DateTime nearToCurrentDate)
|
|
|
|
|
{
|
|
|
|
|
var offset = 5d;
|
|
|
|
|
if (nearToCurrentDate.Kind == DateTimeKind.Unspecified)
|
|
|
|
|
{
|
|
|
|
|
var now = DateTime.UtcNow;
|
|
|
|
|
var minutes = 60 * (now.Hour - nearToCurrentDate.Hour) + now.Minute - nearToCurrentDate.Minute;
|
|
|
|
|
var minutesPositive = (1440_0000 + minutes) % 1440; //60*24
|
|
|
|
|
var halfsHours = Math.Round(1d * minutesPositive / 30d); // quarters are ignored
|
|
|
|
|
var hours = halfsHours / 2;
|
|
|
|
|
offset = hours < 12 ? hours : 24 - hours;
|
|
|
|
|
}
|
|
|
|
|
if (nearToCurrentDate.Kind == DateTimeKind.Local)
|
|
|
|
|
offset = TimeZoneInfo.Local.BaseUtcOffset.TotalHours;
|
|
|
|
|
|
|
|
|
|
return offset;
|
|
|
|
|
}
|
2021-09-17 16:24:01 +05:00
|
|
|
|
}
|
|
|
|
|
}
|