autocleanup

This commit is contained in:
Фролов 2021-04-23 10:21:25 +05:00
parent 6de9e7116e
commit fce20a2a10
61 changed files with 2182 additions and 337 deletions

View File

@ -13,7 +13,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleApp1", "ConsoleApp1\
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsbCloudDb", "AsbCloudDb\AsbCloudDb.csproj", "{40FBD29B-724B-4496-B5D9-1A5D14102456}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SaubPanelOnlineSender", "SaubPanelOnlineSender\SaubPanelOnlineSender.csproj", "{B156D582-4D32-4368-A103-687D15B9846C}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SaubPanelOnlineSender", "SaubPanelOnlineSender\SaubPanelOnlineSender.csproj", "{B156D582-4D32-4368-A103-687D15B9846C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SyncDicts", "SyncDicts\SyncDicts.csproj", "{39DA5EFF-D018-45AE-B0A0-A241B488660F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -45,6 +47,10 @@ Global
{B156D582-4D32-4368-A103-687D15B9846C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B156D582-4D32-4368-A103-687D15B9846C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B156D582-4D32-4368-A103-687D15B9846C}.Release|Any CPU.Build.0 = Release|Any CPU
{39DA5EFF-D018-45AE-B0A0-A241B488660F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{39DA5EFF-D018-45AE-B0A0-A241B488660F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{39DA5EFF-D018-45AE-B0A0-A241B488660F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{39DA5EFF-D018-45AE-B0A0-A241B488660F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -8,8 +8,4 @@
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AsbCloudDb\AsbCloudDb.csproj" />
</ItemGroup>
</Project>

View File

@ -1,8 +1,10 @@
using System;
using System.Text.Json.Serialization;
namespace AsbCloudApp.Data
{
/// <summary>
/// Сообщение получаемое по телеметрии и отправляемое в frontend
/// </summary>
public class DataSaubBaseDto
{
//[JsonPropertyName("date")]
@ -20,6 +22,11 @@ namespace AsbCloudApp.Data
/// </summary>
public int? Mode { get; set; }
/// <summary>
/// telemetry user
/// </summary>
public string User { get; set; }
/// <summary>
/// Глубина забоя
/// </summary>
@ -31,9 +38,19 @@ namespace AsbCloudApp.Data
public double? BitDepth { get; set; }
/// <summary>
/// Талевый блок. Высота
/// Талевый блок. Положение
/// </summary>
public double? BlockHeight { get; set; }
public double? BlockPosition { get; set; }
/// <summary>
/// Талевый блок. Мин положение
/// </summary>
public double? BlockPositionMin { get; set; }
/// <summary>
/// Талевый блок. Макс положение
/// </summary>
public double? BlockPositionMax { get; set; }
/// <summary>
/// Талевый блок. Скорость
@ -45,6 +62,21 @@ namespace AsbCloudApp.Data
/// </summary>
public double? BlockSpeedSp { get; set; }
/// <summary>
/// Талевый блок. Задание скорости для роторного бурения
/// </summary>
public double? BlockSpeedSpRotor { get; set; }
/// <summary>
/// Талевый блок. Задание скорости для режима слайда
/// </summary>
public double? BlockSpeedSpSlide { get; set; }
/// <summary>
/// Талевый блок. Задание скорости для проработки
/// </summary>
public double? BlockSpeedSpDevelop { get; set; }
/// <summary>
/// Давтение
/// </summary>
@ -57,6 +89,12 @@ namespace AsbCloudApp.Data
public double? PressureSp { get; set; }
public double? PressureSpRotor { get; set; }
public double? PressureSpSlide { get; set; }
public double? PressureSpDevelop { get; set; }
public double? PressureDeltaLimitMax { get; set; }
public double? AxialLoad { get; set; }

View File

@ -0,0 +1,12 @@
namespace AsbCloudApp.Data
{
public class EventDto
{
public int Id { get; set; }
public string Message { get; set; }
public int IdCategory { get; set; }
public string Tag { get; set; }
public int EventType { get; set; }
public int IdSound { get; set; }
}
}

View File

@ -0,0 +1,20 @@
using System;
namespace AsbCloudApp.Data
{
/// <summary>
/// Сообщение для frontend
/// </summary>
public class MessageDto
{
public int Id { get; set; }
public DateTime Date { get; set; }
public int CategoryId { get; set; }
public string User { get; set; }
public string Message { get; set; }
}
}

View File

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace AsbCloudApp.Data
{
/// <summary>
/// Контейнер для поддержки постраничного просмотра таблиц
/// </summary>
/// <typeparam name="T"></typeparam>
public class PaginationContainer<T>
{
public PaginationContainer()
{
Items = new List<T>(4);
}
public PaginationContainer(int capacity)
{
Items = new List<T>(capacity);
}
/// <summary>
/// Кол-во записей пропущеных с начала таблицы в запросе от api
/// </summary>
public int Skip { get; set; }
/// <summary>
/// Кол-во записей в запросе от api
/// </summary>
public int Take { get; set; }
/// <summary>
/// Кол-во записей всего в таблице
/// </summary>
public int Count { get; set; }
/// <summary>
/// Данные
/// </summary>
public List<T> Items { get; set; }
}
}

View File

@ -1,28 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace AsbCloudApp.Data
{
/// <summary>
/// Формат посылки от панели к облаку.
/// Панель копит у себя данные и при удачной отправке помечает как отправленные.
/// </summary>
public class TelemetryDataDto
{
public DateTime Date { get; set; }
/// <summary>
/// Версия ПО панели.
/// Нужна будет для разбора информации
/// </summary>
public string HmiVersion { get; set; }
public string UserName { get; set; }
public List<DataSaubBaseDto> DataSaub { get; set; }
/// TODO:
//public List<EventDto> EventsDictiotary { get; set; }
//public List<MessageDto> Messages { get; set; }
}
}

View File

@ -0,0 +1,9 @@
namespace AsbCloudApp.Data
{
public class TelemetryDto<T>
{
public string HmiVersion { get; set; }
public T Payload { get; set; }
}
}

View File

@ -1,14 +1,17 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace AsbCloudApp.Data
{
public class TelemetryInfoDto
{
public DateTime Date { get; set; }
public string TimeZoneId { get; set; }
public double TimeZoneOffsetTotalHours { get; set; }
public string Caption { get; set; }
public string Cluster { get; set; }
public string Deposit { get; set; }
public string HmiVersion { get; set; }
public string PlcVersion { get; set; }
public string Comment { get; set; }
}
}

View File

@ -0,0 +1,25 @@
using System;
namespace AsbCloudApp.Data
{
/// <summary>
/// Сообщение получаемое от телеметрии
/// </summary>
public class TelemetryMessageDto
{
public int Id { get; set; }
public DateTime Date { get; set; }
public int IdEvent { get; set; }
public int? State { get; set; }
public int? IdTelemetryUser { get; set; }
public string Arg0 { get; set; }
public string Arg1 { get; set; }
public string Arg2 { get; set; }
public string Arg3 { get; set; }
}
}

View File

@ -0,0 +1,15 @@
namespace AsbCloudApp.Data
{
public class TelemetryUserDto
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string Patronymic { get; set; }
public int Level { get; set; }
}
}

View File

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace AsbCloudApp.Data
namespace AsbCloudApp.Data
{
public class UserBaseDto
{

View File

@ -1,6 +1,6 @@
namespace AsbCloudApp.Data
{
public class UserDto: UserBaseDto
public class UserDto : UserBaseDto
{
public int Id { get; set; }

View File

@ -1,10 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace AsbCloudApp.Data
namespace AsbCloudApp.Data
{
public class UserTokenDto: UserBaseDto
public class UserTokenDto : UserBaseDto
{
public int Id { get; set; }
public string CustomerName { get; set; }

View File

@ -4,8 +4,10 @@ using System.Collections.Generic;
namespace AsbCloudApp.Services
{
public interface ITelemetryDataService
public interface IDataService
{
IEnumerable<DataSaubBaseDto> Get(int wellId, DateTime dateBegin = default, double intervalSec = 600d, int approxPointsCount = 1024);
void UpdateData(string uid, IEnumerable<DataSaubBaseDto> dtos);
}
}

View File

@ -1,6 +0,0 @@
namespace AsbCloudApp.Services
{
public interface IDepositService
{
}
}

View File

@ -0,0 +1,10 @@
using AsbCloudApp.Data;
using System.Collections.Generic;
namespace AsbCloudApp.Services
{
public interface IEventService
{
void Upsert(string uid, IEnumerable<EventDto> dtos);
}
}

View File

@ -0,0 +1,12 @@
using AsbCloudApp.Data;
using System;
using System.Collections.Generic;
namespace AsbCloudApp.Services
{
public interface IMessageService
{
PaginationContainer<MessageDto> GetMessages(int wellId, IEnumerable<int> categoryids = null, DateTime begin = default, DateTime end = default, int skip = 0, int take = 32);
void Insert(string uid, IEnumerable<TelemetryMessageDto> dtos);
}
}

View File

@ -1,16 +1,11 @@
using AsbCloudApp.Data;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudApp.Services
{
public interface ITelemetryService
{
int? GetWellIdByUid(string uid);
void UpdateData(string uid, TelemetryDataDto data);
int? GetWellIdByTelemetryUid(string uid);
int GetOrCreateTemetryIdByUid(string uid);
void UpdateInfo(string uid, TelemetryInfoDto info);
}
}

View File

@ -0,0 +1,10 @@
using AsbCloudApp.Data;
using System.Collections.Generic;
namespace AsbCloudApp.Services
{
public interface ITelemetryUserService
{
void Upsert(string uid, IEnumerable<TelemetryUserDto> dtos);
}
}

View File

@ -11,7 +11,7 @@ namespace AsbCloudDb.Model
//Scaffold-DbContext "Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True" Npgsql.EntityFrameworkCore.PostgreSQL -OutputDir Model -DataAnnotations
public partial class AsbCloudDbContext : DbContext, IAsbCloudDbContext
{
private readonly string connectionString;
//private readonly string connectionString;
public virtual DbSet<Cluster> Clusters { get; set; }
public virtual DbSet<Customer> Customers { get; set; }
public virtual DbSet<DataSaubBase> DataSaubBases { get; set; }
@ -36,13 +36,13 @@ namespace AsbCloudDb.Model
Database.EnsureCreated();
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseNpgsql(connectionString);
}
}
//protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
//{
// if (!optionsBuilder.IsConfigured)
// {
// optionsBuilder.UseNpgsql(connectionString);
// }
//}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
@ -76,25 +76,35 @@ namespace AsbCloudDb.Model
modelBuilder.Entity<TelemetryUser>(entity =>
{
entity.HasKey(nameof(TelemetryUser.IdTelemetry), nameof(TelemetryUser.IdUser));
entity.HasOne(d => d.Telemetry)
.WithMany()
.WithMany(p => p.Users)
.HasForeignKey(d => d.IdTelemetry)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("t_telemetry_user_t_telemetry_id_fk");
});
modelBuilder.Entity<Event>(entity =>
{
entity.HasKey(nameof(Event.IdTelemetry), nameof(Event.IdEvent));
entity.HasOne(d => d.Telemetry)
.WithMany(p => p.Events)
.HasForeignKey(d => d.IdTelemetry)
.HasConstraintName("t_event_t_telemetry_id_fk");
});
modelBuilder.Entity<UserRole>(entity =>
{
entity.HasData(new List<UserRole>{
new UserRole{ Id = 1, Caption = "Администратор", },
}); ;
});
});
modelBuilder.Entity<Customer>(entity =>
{
entity.HasData(new List<Customer>{
new Customer{ Id = 1, Caption = "\"ООО\" АСБ", },
}); ;
});
});
modelBuilder.Entity<User>(entity =>
@ -148,14 +158,14 @@ namespace AsbCloudDb.Model
modelBuilder.Entity<Deposit>(entity =>
{
entity.HasData(new List<Deposit> {
new Deposit{Id = 1, Caption = есторождение" },
new Deposit{Id = 1, Caption = /р 1" },
});
});
modelBuilder.Entity<Cluster>(entity =>
{
entity.HasData(new List<Cluster> {
new Cluster{Id = 1, Caption = "месторождение", IdDeposit = 1 },
new Cluster{Id = 1, Caption = "куст 1", IdDeposit = 1 },
});
});
@ -185,7 +195,7 @@ namespace AsbCloudDb.Model
.Where(e => e.Login == login);
public async Task<int> CreatePartitionAsync<TEntity>(string propertyName, int id, CancellationToken token = default)
where TEntity: class
where TEntity : class
{
var dbSet = Set<TEntity>();
var baseTableName = dbSet.EntityType.GetTableName();

View File

@ -8,7 +8,7 @@ using System.ComponentModel.DataAnnotations.Schema;
namespace AsbCloudDb.Model
{
[Table("t_cluster"), Comment("Кусты")]
public partial class Cluster: IId
public partial class Cluster : IId
{
public Cluster()
{

View File

@ -7,7 +7,7 @@ using System.ComponentModel.DataAnnotations.Schema;
namespace AsbCloudDb.Model
{
[Table("t_customer")]
public partial class Customer: IId
public partial class Customer : IId
{
public Customer()
{
@ -24,6 +24,7 @@ namespace AsbCloudDb.Model
[InverseProperty(nameof(User.Customer))]
public virtual ICollection<User> Users { get; set; }
[InverseProperty(nameof(Well.Customer))]
public virtual ICollection<Well> Wells { get; set; }
}

View File

@ -14,28 +14,66 @@ namespace AsbCloudDb.Model
[Key]
[Column("id")]
public int Id { get; set; }
[Column("id_telemetry")]
public int IdTelemetry { get; set; }
[Column("date", TypeName = "timestamp with time zone"), Comment("'2021-10-19 18:23:54+05'")]
public DateTime Date { get; set; }
[Column("mode"), Comment("Режим САУБ")]
public int? Mode { get; set; }
[Column("id_user"), Comment("Пользователь САУБ")]
public int? IdUser { get; set; }
[Column("well_depth"), Comment("Глубина забоя")]
public double? WellDepth { get; set; }
[Column("bit_depth"), Comment("Положение инструмента")]
public double? BitDepth { get; set; }
[Column("block_height"), Comment("Высота талевого блока")]
public double? BlockHeight { get; set; }
[Column("block_position"), Comment("Высота талевого блока")]
public double? BlockPosition { get; set; }
[Column("block_position_min"), Comment("Талевый блок. Мин положение")]
public double? BlockPositionMin { get; set; }
[Column("block_position_max"), Comment("Талевый блок. Макс положение")]
public double? BlockPositionMax { get; set; }
[Column("block_speed"), Comment("Скорость талевого блока")]
public double? BlockSpeed { get; set; }
[Column("block_speed_sp"), Comment("Скорости талевого блока. Задание")]
public double? BlockSpeedSp { get; set; }
[Column("block_speed_sp_rotor"), Comment("Талевый блок. Задание скорости для роторного бурения")]
public double? BlockSpeedSpRotor { get; set; }
[Column("block_speed_sp_slide"), Comment("Талевый блок. Задание скорости для режима слайда")]
public double? BlockSpeedSpSlide { get; set; }
[Column("block_speed_sp_develop"), Comment("Талевый блок. Задание скорости для проработки")]
public double? BlockSpeedSpDevelop { get; set; }
[Column("pressure"), Comment("Давление")]
public double? Pressure { get; set; }
[Column("pressure_idle"), Comment("Давление. Холостой ход")]
public double? PressureIdle { get; set; }
[Column("pressure_sp"), Comment("Давление. Задание")]
public double? PressureSp { get; set; }
[Column("pressure_sp_rotor"), Comment("Давление. Задание для роторного бурения")]
public double? PressureSpRotor { get; set; }
[Column("pressure_sp_slide"), Comment("Давление. Задание для режима слайда")]
public double? PressureSpSlide { get; set; }
[Column("pressure_sp_develop"), Comment("Давление. Задание для проработки")]
public double? PressureSpDevelop { get; set; }
[Column("pressure_delta_limit_max"), Comment("Давление дифф. Аварийное макс.")]
public double? PressureDeltaLimitMax { get; set; }
[Column("axial_load"), Comment("Осевая нагрузка")]

View File

@ -8,7 +8,7 @@ using System.ComponentModel.DataAnnotations.Schema;
namespace AsbCloudDb.Model
{
[Table("t_deposit"), Comment("Месторождение")]
public partial class Deposit: IId
public partial class Deposit : IId
{
public Deposit()
{

View File

@ -1,25 +1,35 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
#nullable disable
namespace AsbCloudDb.Model
{
[Keyless]
[Table("t_event"), Comment("Справочник событий. События формируют сообщения. Разделено по версиям посылок от телеметрии.")]
[Index(nameof(IdEvent), nameof(Version), Name = "t_event_pk", IsUnique = true)]
public partial class Event
{
[Column("id_event")]
public int? IdEvent { get; set; }
[Column("version"), Comment("Версия ПО отправляющей телеметрии.")]
[StringLength(64)]
public string Version { get; set; }
public int IdEvent { get; set; }
[Column("id_telemetry")]
public int IdTelemetry { get; set; }
[JsonIgnore]
[ForeignKey(nameof(IdTelemetry))]
[InverseProperty(nameof(Model.Telemetry.Events))]
public virtual Telemetry Telemetry { get; set; }
[Column("id_category")]
public int? IdCategory { get; set; }
public int IdCategory { get; set; }
[Column("message_template")]
public string MessageTemplate { get; set; }
public string MakeMessageText(Message message)
{
var args = new string[] { message.Arg0, message.Arg1, message.Arg2, message.Arg3 };
return string.Format(MessageTemplate, args);
}
}
}

View File

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace AsbCloudDb.Model
namespace AsbCloudDb.Model
{
public interface IId
{

View File

@ -8,33 +8,42 @@ using System.ComponentModel.DataAnnotations.Schema;
namespace AsbCloudDb.Model
{
[Table("t_message"), Comment("Сообщения на буровых")]
public partial class Message: IId
public partial class Message : IId
{
[Key]
[Column("id")]
public int Id { get; set; }
[Column("id_telemetry")]
public int? IdTelemetry { get; set; }
[Column("id_event")]
public int IdEvent { get; set; }
[Column("id_telemetry_user"), Comment("Пользователь панели отправляющей телеметрию. не пользователь облака.")]
public int? IdTelemetryUser { get; set; }
[Column("date", TypeName = "timestamp with time zone")]
public DateTime Date { get; set; }
[Column("state"), Comment("1 - сработало событие. 0 - событие пропало.")]
public int? State { get; set; }
[Column("arg0"), Comment("Аргумент №0 для вставки в шаблон сообщения")]
[StringLength(255)]
public string Arg0 { get; set; }
[Column("arg1")]
[StringLength(255)]
public string Arg1 { get; set; }
[Column("arg2")]
[StringLength(255)]
public string Arg2 { get; set; }
[Column("arg3")]
[StringLength(255)]
public string Arg3 { get; set; }
[Column("arg4")]
[StringLength(255)]
public string Arg4 { get; set; }
[ForeignKey(nameof(IdTelemetry))]
[InverseProperty(nameof(Model.Telemetry.Messages))]

View File

@ -10,8 +10,7 @@ namespace AsbCloudDb.Model
{
[Table("t_telemetry"), Comment("таблица привязки телеметрии от комплектов к конкретной скважине.")]
[Index(nameof(RemoteUid), Name = "t_telemetry_remote_uid_index")]
[Index(nameof(Version), Name = "t_telemetry_version_index")]
public partial class Telemetry: IId
public partial class Telemetry : IId
{
public Telemetry()
{
@ -23,21 +22,11 @@ namespace AsbCloudDb.Model
[Column("id")]
public int Id { get; set; }
[Column("remote_uid"), Comment("Идентификатор передающего устройства. Может посторяться в списке, так как комплекты оборудования переезжают от скв. к скв.")]
[Column("remote_uid"), Comment("Идентификатор передающего устройства. Может повторяться в списке, так как комплекты оборудования переезжают от скв. к скв.")]
public string RemoteUid { get; set; }
[Column("info", TypeName = "jsonb"), Comment("Информация с панели о скважине")]
public string Info { get; set; }
[Column("version"), Comment("Версия ПО панели отправляющей телеметрию")]
[StringLength(64)]
public string Version { get; set; }
[Column("last_data_saub", TypeName = "jsonb"), Comment("Информация с панели о скважине")]
public DataSaubBase LastDataSaub { get; set; }
[Column("time_zone", TypeName = "json"), Comment("Временная зона панели САУБ.")]
public TimeZoneInfo TimeZone { get; set; }
public TelemetryInfo Info { get; set; }
[InverseProperty(nameof(Model.Well.Telemetry))]
public virtual Well Well { get; set; }
@ -47,5 +36,12 @@ namespace AsbCloudDb.Model
[InverseProperty(nameof(Message.Telemetry))]
public virtual ICollection<Message> Messages { get; set; }
[InverseProperty(nameof(TelemetryUser.Telemetry))]
public virtual ICollection<TelemetryUser> Users { get; set; }
[InverseProperty(nameof(Event.Telemetry))]
public virtual ICollection<Event> Events { get; set; }
}
}

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace AsbCloudDb.Model
{
public class TelemetryInfo
{
public DateTime Date { get; set; }
public string TimeZoneId { get; set; }
public double TimeZoneOffsetTotalHours { get; set; }
public string Caption { get; set; }
public string Cluster { get; set; }
public string Deposit { get; set; }
public string HmiVersion { get; set; }
public string PlcVersion { get; set; }
public string Comment { get; set; }
}
}

View File

@ -1,34 +1,58 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
#nullable disable
namespace AsbCloudDb.Model
{
[Keyless]
[Table("t_telemetry_user"), Comment("Пользователи панели САУБ. Для сообщений.")]
[Index(nameof(IdUser), nameof(IdTelemetry), Name = "t_telemetry_user_pk", IsUnique = true)]
public partial class TelemetryUser
{
[Column("id_user")]
public int IdUser { get; set; }
[Column("id_telemetry")]
public int IdTelemetry { get; set; }
[JsonIgnore]
[ForeignKey(nameof(IdTelemetry))]
[InverseProperty(nameof(Model.Telemetry.Users))]
public virtual Telemetry Telemetry { get; set; }
[Column("name")]
[StringLength(255)]
public string Name { get; set; }
[Column("surname")]
[StringLength(255)]
public string Surname { get; set; }
[Column("patronymic")]
[StringLength(255)]
public string Patronymic { get; set; }
[Column("level")]
public int? Level { get; set; }
[ForeignKey(nameof(IdTelemetry))]
public virtual Telemetry Telemetry { get; set; }
public string MakeDisplayName()
{
if (!string.IsNullOrEmpty(Surname))
{
var s = Surname;
if (!string.IsNullOrEmpty(Name))
{
s += $"{Name[0]}.";
if (!string.IsNullOrEmpty(Patronymic))
s += $" {Patronymic[0]}.";
}
return s;
}
else
return $"User #{IdTelemetry}";
}
}
}

View File

@ -7,7 +7,7 @@ using System.ComponentModel.DataAnnotations.Schema;
namespace AsbCloudDb.Model
{
[Table("t_user"), Comment("Пользователи облака")]
public partial class User: IId
public partial class User : IId
{
[Key]
[Column("id")]
@ -34,15 +34,15 @@ namespace AsbCloudDb.Model
[Column("level")]
public int? Level { get; set; }
[Column("name")]
[Column("name"), Comment("имя")]
[StringLength(255)]
public string Name { get; set; }
[Column("surname")]
[Column("surname"), Comment("фамилия")]
[StringLength(255)]
public string Surname { get; set; }
[Column("patronymic")]
[Column("patronymic"), Comment("отчество")]
[StringLength(255)]
public string Patronymic { get; set; }
@ -53,5 +53,21 @@ namespace AsbCloudDb.Model
[ForeignKey(nameof(IdRole))]
[InverseProperty(nameof(Model.UserRole.Users))]
public virtual UserRole Role { get; set; }
public string MakeDisplayName()
{
if (string.IsNullOrEmpty(Surname))
return Login;
var s = Surname;
if (!string.IsNullOrEmpty(Name))
{
s += $"{Name[0]}.";
if (!string.IsNullOrEmpty(Patronymic))
s += $" {Patronymic[0]}.";
}
return s;
}
}
}

View File

@ -7,7 +7,7 @@ using System.ComponentModel.DataAnnotations.Schema;
namespace AsbCloudDb.Model
{
[Table("t_well"), Comment("скважины")]
public partial class Well: IId
public partial class Well : IId
{
[Key]
[Column("id")]

View File

@ -25,7 +25,10 @@ namespace AsbCloudInfrastructure
services.AddTransient<IAuthService, AuthService>();
services.AddTransient<IWellService, WellService>();
services.AddTransient<ITelemetryService, TelemetryService>();
services.AddTransient<ITelemetryDataService, TelemetryDataService>();
services.AddTransient<IDataService, DataService>();
services.AddTransient<IMessageService, MessageService>();
services.AddTransient<IEventService, EventService>();
services.AddTransient<ITelemetryUserService, TelemetryUserService>();
return services;
}
@ -34,6 +37,12 @@ namespace AsbCloudInfrastructure
{
cfg.CreateMap<DataSaubBase, DataSaubBaseDto>();
cfg.CreateMap<DataSaubBaseDto, DataSaubBase>();
cfg.CreateMap<Message, TelemetryMessageDto>();
cfg.CreateMap<TelemetryMessageDto, Message>();
cfg.CreateMap<TelemetryInfo, TelemetryInfoDto>();
cfg.CreateMap<TelemetryInfoDto, TelemetryInfo>();
}
}
}

View File

@ -1,16 +1,13 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Internal;
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Text;
using System.Collections.Generic;
namespace AsbCloudInfrastructure.Services.Cache
{
public class CacheDb
{
private ConcurrentDictionary<string, IEnumerable<object>> cache = new ConcurrentDictionary<string, IEnumerable<object>>();
private readonly ConcurrentDictionary<string, IEnumerable<object>> cache = new ConcurrentDictionary<string, IEnumerable<object>>();
public ICacheTable<TEntity> GetCachedTable<TEntity>(DbContext context)
where TEntity : class
@ -24,7 +21,7 @@ namespace AsbCloudInfrastructure.Services.Cache
return tableCache;
}
public void DropAll()=> cache.Clear();
public void DropAll() => cache.Clear();
public void Drop<TEntity>() => cache.Remove(typeof(TEntity).FullName, out _);
}

View File

@ -2,7 +2,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
@ -11,31 +10,30 @@ namespace AsbCloudInfrastructure.Services.Cache
class CacheTable<TEntity> : ICacheTable<TEntity> where TEntity : class
{
private readonly DbContext context;
private List<TEntity> entities;
private readonly List<TEntity> cached;
internal CacheTable(DbContext context, List<TEntity> entities)
{
this.context = context;
this.entities = entities;
this.cached = entities;
}
public TEntity this[int index] { get => entities.ElementAt(index); }
public TEntity this[int index] { get => cached.ElementAt(index); }
public int Refresh()
{
entities.Clear();
cached.Clear();
var dbEntities = context.Set<TEntity>().ToList();
entities.AddRange(dbEntities);
return entities.Count();
cached.AddRange(dbEntities);
return cached.Count();
}
public async Task<int> RefreshAsync(CancellationToken token = default)
{
entities.Clear();
cached.Clear();
var dbEntities = await context.Set<TEntity>().ToListAsync(token).ConfigureAwait(false);
entities.AddRange(dbEntities);
return entities.Count();
cached.AddRange(dbEntities);
return cached.Count();
}
private bool CheckRefresh(RefreshMode refreshMode)
@ -46,7 +44,7 @@ namespace AsbCloudInfrastructure.Services.Cache
return true;
}
if ((!entities.Any()) && (refreshMode == RefreshMode.IfResultEmpty))
if ((!cached.Any()) && (refreshMode == RefreshMode.IfResultEmpty))
{
Refresh();
return true;
@ -63,7 +61,7 @@ namespace AsbCloudInfrastructure.Services.Cache
return true;
}
if ((!entities.Any()) && (refreshMode == RefreshMode.IfResultEmpty))
if ((!cached.Any()) && (refreshMode == RefreshMode.IfResultEmpty))
{
await RefreshAsync(token);
return true;
@ -88,12 +86,12 @@ namespace AsbCloudInfrastructure.Services.Cache
{
bool isUpdated = CheckRefresh(refreshMode);
var result = entities.FirstOrDefault();
var result = cached.FirstOrDefault();
if (result == default && refreshMode == RefreshMode.IfResultEmpty && !isUpdated)
{
Refresh();
return entities.FirstOrDefault();
return cached.FirstOrDefault();
}
return result;
@ -103,12 +101,12 @@ namespace AsbCloudInfrastructure.Services.Cache
{
bool isUpdated = await CheckRefreshAsync(refreshMode, token);
var result = entities.FirstOrDefault();
var result = cached.FirstOrDefault();
if (result == default && refreshMode == RefreshMode.IfResultEmpty && !isUpdated)
{
await RefreshAsync(token);
return entities.FirstOrDefault();
return cached.FirstOrDefault();
}
return result;
@ -121,12 +119,12 @@ namespace AsbCloudInfrastructure.Services.Cache
{
bool isUpdated = CheckRefresh(refreshMode);
var result = entities.FirstOrDefault(predicate);
var result = cached.FirstOrDefault(predicate);
if (result == default && refreshMode == RefreshMode.IfResultEmpty && !isUpdated)
{
Refresh();
return entities.FirstOrDefault(predicate);
return cached.FirstOrDefault(predicate);
}
return result;
@ -136,12 +134,12 @@ namespace AsbCloudInfrastructure.Services.Cache
{
bool isUpdated = await CheckRefreshAsync(refreshMode, token);
var result = entities.FirstOrDefault(predicate);
var result = cached.FirstOrDefault(predicate);
if (result == default && refreshMode == RefreshMode.IfResultEmpty && !isUpdated)
{
await RefreshAsync(token);
return entities.FirstOrDefault(predicate);
return cached.FirstOrDefault(predicate);
}
return result;
@ -154,12 +152,12 @@ namespace AsbCloudInfrastructure.Services.Cache
{
bool isUpdated = CheckRefresh(refreshMode);
var result = entities.Where(predicate);
var result = cached.Where(predicate);
if (!result.Any() && refreshMode == RefreshMode.IfResultEmpty && !isUpdated)
{
Refresh();
return entities.Where(predicate);
return cached.Where(predicate);
}
return result;
@ -169,12 +167,12 @@ namespace AsbCloudInfrastructure.Services.Cache
{
bool isUpdated = await CheckRefreshAsync(refreshMode, token);
var result = entities.Where(predicate);
var result = cached.Where(predicate);
if (!result.Any() && refreshMode == RefreshMode.IfResultEmpty && !isUpdated)
{
await RefreshAsync(token);
return entities.Where(predicate);
return cached.Where(predicate);
}
return result;
@ -190,8 +188,8 @@ namespace AsbCloudInfrastructure.Services.Cache
mutation(dbEntity);
context.SaveChanges();
}
entities.RemoveAll(e => predicate(e));
entities.AddRange(dbEntities);
cached.RemoveAll(e => predicate(e));
cached.AddRange(dbEntities);
return dbEntities;
}
@ -205,15 +203,117 @@ namespace AsbCloudInfrastructure.Services.Cache
mutation(dbEntity);
await context.SaveChangesAsync(token).ConfigureAwait(false);
}
entities.RemoveAll(e => predicate(e));
entities.AddRange(dbEntities);
cached.RemoveAll(e => predicate(e));
cached.AddRange(dbEntities);
return dbEntities;
}
public TEntity Upsert(TEntity entity)
{
var dbSet = context.Set<TEntity>();
Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<TEntity> entityEntry;
if (cached.Contains(entity))
{
entityEntry = dbSet.Update(entity);
cached.Remove(entity);
}
else
{
entityEntry = dbSet.Add(entity);
}
context.SaveChanges();
cached.Add(entityEntry.Entity);
return entityEntry.Entity;
}
public async Task<TEntity> UpsertAsync(TEntity entity, CancellationToken token = default)
{
var dbSet = context.Set<TEntity>();
Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<TEntity> entityEntry;
if (cached.Contains(entity))
{
entityEntry = dbSet.Update(entity);
cached.Remove(entity);
}
else
{
entityEntry = dbSet.Add(entity);
}
await context.SaveChangesAsync(token).ConfigureAwait(false);
cached.Add(entityEntry.Entity);
return entityEntry.Entity;
}
public IEnumerable<TEntity> Upsert(IEnumerable<TEntity> entities)
{
var dbSet = context.Set<TEntity>();
var upsertedEntries = new List<Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<TEntity>>(entities.Count());
foreach (var entity in entities)
{
Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<TEntity> entityEntry;
if (cached.Contains(entity))
{
entityEntry = dbSet.Update(entity);
cached.Remove(entity);
}
else
{
entityEntry = dbSet.Add(entity);
}
upsertedEntries.Add(entityEntry);
}
context.SaveChanges();
var upserted = upsertedEntries.Select(e => e.Entity);
cached.AddRange(upserted);
return upserted;
}
public async Task<IEnumerable<TEntity>> UpsertAsync(IEnumerable<TEntity> entities, CancellationToken token = default)
{
var dbSet = context.Set<TEntity>();
var upsertedEntries = new List<Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<TEntity>>(entities.Count());
foreach (var entity in entities)
{
Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<TEntity> entityEntry;
if (cached.Contains(entity))
{
entityEntry = dbSet.Update(entity);
cached.Remove(entity);
}
else
{
entityEntry = dbSet.Add(entity);
}
upsertedEntries.Add(entityEntry);
}
await context.SaveChangesAsync(token).ConfigureAwait(false);
var upserted = upsertedEntries.Select(e => e.Entity);
cached.AddRange(upserted);
return upserted;
}
public void Remove(Func<TEntity, bool> predicate)
{
var dbSet = context.Set<TEntity>();
entities.RemoveAll(e => predicate(e));
cached.RemoveAll(e => predicate(e));
dbSet.RemoveRange(dbSet.Where(predicate));
context.SaveChanges();
return;
@ -222,7 +322,7 @@ namespace AsbCloudInfrastructure.Services.Cache
public async Task RemoveAsync(Func<TEntity, bool> predicate, CancellationToken token = default)
{
var dbSet = context.Set<TEntity>();
entities.RemoveAll(e => predicate(e));
cached.RemoveAll(e => predicate(e));
dbSet.RemoveRange(dbSet.Where(predicate));
await context.SaveChangesAsync(token).ConfigureAwait(false);
return;
@ -233,7 +333,7 @@ namespace AsbCloudInfrastructure.Services.Cache
var dbSet = context.Set<TEntity>();
var dbEntity = dbSet.Add(entity).Entity;
context.SaveChanges();
entities.Add(dbEntity);
cached.Add(dbEntity);
return dbEntity;
}
@ -242,7 +342,7 @@ namespace AsbCloudInfrastructure.Services.Cache
var dbSet = context.Set<TEntity>();
var dbEntity = dbSet.Add(entity).Entity;
await context.SaveChangesAsync(token).ConfigureAwait(false);
entities.Add(dbEntity);
cached.Add(dbEntity);
return dbEntity;
}
@ -253,7 +353,7 @@ namespace AsbCloudInfrastructure.Services.Cache
foreach (var item in newEntities)
dbEntities.Add(dbSet.Add(item).Entity);
context.SaveChanges();
entities.AddRange(dbEntities);
cached.AddRange(dbEntities);
return dbEntities;
}
@ -264,7 +364,7 @@ namespace AsbCloudInfrastructure.Services.Cache
foreach (var item in newEntities)
dbEntities.Add(dbSet.Add(item).Entity);
await context.SaveChangesAsync(token).ConfigureAwait(false);
entities.AddRange(dbEntities);
cached.AddRange(dbEntities);
return dbEntities;
}

View File

@ -17,6 +17,8 @@ namespace AsbCloudInfrastructure.Services.Cache
void Remove(Func<TEntity, bool> predicate);
IEnumerable<TEntity> Select(Func<TEntity, bool> predicate, RefreshMode refreshMode = RefreshMode.IfResultEmpty);
IEnumerable<TEntity> Update(Func<TEntity, bool> predicate, Action<TEntity> mutation);
TEntity Upsert(TEntity entity);
IEnumerable<TEntity> Upsert(IEnumerable<TEntity> entities);
//----- ASYNC ------
@ -33,5 +35,7 @@ namespace AsbCloudInfrastructure.Services.Cache
Task<IEnumerable<TEntity>> SelectAsync(Func<TEntity, bool> predicate, CancellationToken token = default);
Task<IEnumerable<TEntity>> SelectAsync(Func<TEntity, bool> predicate, RefreshMode refreshMode = RefreshMode.IfResultEmpty, CancellationToken token = default);
Task<IEnumerable<TEntity>> UpdateAsync(Func<TEntity, bool> predicate, Action<TEntity> mutation, CancellationToken token = default);
Task<TEntity> UpsertAsync(TEntity entity, CancellationToken token = default);
Task<IEnumerable<TEntity>> UpsertAsync(IEnumerable<TEntity> entities, CancellationToken token = default);
}
}

View File

@ -6,20 +6,21 @@ using AutoMapper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services
{
public class TelemetryDataService : ITelemetryDataService
public class DataService : IDataService
{
private IAsbCloudDbContext db;
private IMapper mapper;
private ICacheTable<Telemetry> cacheTelemetry;
private ICacheTable<Well> cacheWells;
private readonly IAsbCloudDbContext db;
private readonly ITelemetryService telemetryService;
private readonly IMapper mapper;
private readonly ICacheTable<Telemetry> cacheTelemetry;
private readonly ICacheTable<Well> cacheWells;
public TelemetryDataService(IAsbCloudDbContext db, CacheDb cacheDb, MapperConfiguration mapperConfiguration)
public DataService(IAsbCloudDbContext db, ITelemetryService telemetryService, CacheDb cacheDb, MapperConfiguration mapperConfiguration)
{
this.db = db;
this.telemetryService = telemetryService;
mapper = mapperConfiguration.CreateMapper();
cacheTelemetry = cacheDb.GetCachedTable<Telemetry>((AsbCloudDbContext)db);
cacheWells = cacheDb.GetCachedTable<Well>((AsbCloudDbContext)db);
@ -35,7 +36,7 @@ namespace AsbCloudInfrastructure.Services
if (telemetry is null)
return default;
if(dateBegin == default)
if (dateBegin == default)
dateBegin = DateTime.Now.AddSeconds(-intervalSec);
var datEnd = dateBegin.AddSeconds(intervalSec);
@ -64,5 +65,23 @@ namespace AsbCloudInfrastructure.Services
return result;
}
public void UpdateData(string uid, IEnumerable<DataSaubBaseDto> dtos)
{
var telemetryId = telemetryService.GetOrCreateTemetryIdByUid(uid);
if ((dtos != default) && (dtos.Count() > 0))
{
foreach (var item in dtos)
{
var dataSaub = mapper.Map<DataSaubBase>(item);
dataSaub.IdTelemetry = telemetryId;
db.DataSaubBases.Add(dataSaub);
}
db.SaveChanges();
}
}
}
}

View File

@ -1,19 +0,0 @@
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AutoMapper;
namespace AsbCloudInfrastructure.Services
{
public class DepositService : IDepositService
{
private readonly IAsbCloudDbContext db;
private readonly MapperConfiguration mapperConfiguration;
public DepositService(IAsbCloudDbContext db, MapperConfiguration mapperConfiguration)
{
this.db = db;
this.mapperConfiguration = mapperConfiguration;
}
}
}

View File

@ -0,0 +1,56 @@
using AsbCloudApp.Data;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Services.Cache;
using System.Collections.Generic;
using System.Linq;
namespace AsbCloudInfrastructure.Services
{
public class EventService : IEventService
{
private readonly IAsbCloudDbContext db;
private readonly ITelemetryService telemetryService;
private readonly ICacheTable<Event> cacheEvents;
public EventService(IAsbCloudDbContext db, CacheDb cacheDb, ITelemetryService telemetryService)
{
this.db = db;
this.telemetryService = telemetryService;
cacheEvents = cacheDb.GetCachedTable<Event>((AsbCloudDbContext)db);
}
public void Upsert(string uid, IEnumerable<EventDto> dtos)
{
if (dtos.Count() == 0)
return;
var telemetryId = telemetryService.GetOrCreateTemetryIdByUid(uid);
var ids = dtos.Select(e => e.Id).ToList();
var dbIds = (from e in db.Events
where e.IdTelemetry == telemetryId && ids.Contains(e.IdEvent)
select e.IdEvent).ToList();
foreach (var dto in dtos)
{
var entity = new Event
{
IdEvent = dto.Id,
IdTelemetry = telemetryId,
IdCategory = dto.IdCategory,
MessageTemplate = dto.Message
};
if (dbIds.Contains(dto.Id))
db.Events.Update(entity);
else
db.Events.Add(entity);
}
db.SaveChanges();
cacheEvents.Refresh();
}
}
}

View File

@ -0,0 +1,127 @@
using AsbCloudApp.Data;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Services.Cache;
using AutoMapper;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
namespace AsbCloudInfrastructure.Services
{
public class MessageService : IMessageService
{
private readonly IAsbCloudDbContext db;
private readonly ITelemetryService telemetryService;
private readonly IMapper mapper;
private readonly ICacheTable<Event> cacheEvents;
private readonly ICacheTable<TelemetryUser> cacheTUsers;
private readonly ICacheTable<Telemetry> cacheTelemetry;
private readonly ICacheTable<Well> cacheWells;
public MessageService(IAsbCloudDbContext db, CacheDb cacheDb, ITelemetryService telemetryService, MapperConfiguration mapperConfiguration)
{
this.db = db;
this.telemetryService = telemetryService;
mapper = mapperConfiguration.CreateMapper();
cacheEvents = cacheDb.GetCachedTable<Event>((AsbCloudDbContext)db);
cacheTUsers = cacheDb.GetCachedTable<TelemetryUser>((AsbCloudDbContext)db);
cacheTelemetry = cacheDb.GetCachedTable<Telemetry>((AsbCloudDbContext)db);
cacheWells = cacheDb.GetCachedTable<Well>((AsbCloudDbContext)db);
}
public PaginationContainer<MessageDto> GetMessages(int wellId, IEnumerable<int> categoryids = default, DateTime begin = default, DateTime end = default, int skip = 0, int take = 32)
{
var well = cacheWells.FirstOrDefault(w => w.Id == wellId);
if (well is null)
return null;
var telemetry = cacheTelemetry.FirstOrDefault(t => t.Id == well.Id);
if (telemetry is null)
return null;
var events = cacheEvents.Select(e => e.IdTelemetry == telemetry.Id);
if (events.Count() == 0)
return null;
var messages = from m in db.Messages
where m.IdTelemetry == telemetry.Id
&& m.State == 1
select m;
if ((categoryids != default) && (categoryids.Count() > 0))
{
var eventIds = from e in events
where categoryids.ToList().Contains(e.IdCategory)
select e.IdEvent;
if (eventIds.Count() == 0)
return null;
messages = messages.Where(m => eventIds.Contains(m.IdEvent));
}
var result = new PaginationContainer<MessageDto>() { Skip = skip, Take = take};
messages = messages.OrderByDescending(m => m.Date);
if (begin != default)
messages = messages.Where(m => m.Date >= begin);
if (end != default)
messages = messages.Where(m => m.Date <= end);
result.Count = messages.Count();
if (skip > 0)
messages = messages.Skip(skip);
var messagesList = messages.Take(take).ToList();
if (messagesList.Count == 0)
return result;
var users = cacheTUsers.Select(u => u.IdTelemetry == telemetry.Id);
foreach (var message in messagesList)
{
var messageDto = new MessageDto
{
Date = message.Date,
Id = message.Id,
User = users.FirstOrDefault(u => u.IdUser == message.IdTelemetryUser).MakeDisplayName(),
};
var e = events.FirstOrDefault(e => e.IdEvent == message.IdEvent);
if (e != null)
{
messageDto.CategoryId = e.IdCategory;
messageDto.Message = e.MakeMessageText(message);
}
result.Items.Add(messageDto);
}
return result;
}
public void Insert(string uid, IEnumerable<TelemetryMessageDto> dtos)
{
if (dtos.Count() == 0)
return;
var telemetryId = telemetryService.GetOrCreateTemetryIdByUid(uid);
foreach (var dto in dtos)
{
var entity = mapper.Map<Message>(dto);
entity.IdTelemetry = telemetryId;
db.Messages.Add(entity);
}
db.SaveChanges();
}
}
}

View File

@ -3,82 +3,47 @@ using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Services.Cache;
using AutoMapper;
using System.Text.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services
{
public class TelemetryService : ITelemetryService
{
private readonly IAsbCloudDbContext db;
private readonly IMapper mapper;
private readonly ICacheTable<Telemetry> cacheTelemetry;
private readonly ICacheTable<Well> cacheWell;
public TelemetryService(IAsbCloudDbContext db, CacheDb cacheDb, MapperConfiguration mapperConfiguration)
{
this.db = db;
mapper = mapperConfiguration.CreateMapper();
cacheTelemetry = cacheDb.GetCachedTable<Telemetry>((AsbCloudDbContext)db);
cacheWell = cacheDb.GetCachedTable<Well>((AsbCloudDbContext)db);
}
public int? GetWellIdByUid(string uid)
public int GetOrCreateTemetryIdByUid(string uid)
=> GetOrCreateTelemetryByUid(uid).Id;
public int? GetWellIdByTelemetryUid(string uid)
=> GetWellByTelemetryUid(uid)?.Id;
public void UpdateInfo(string uid, TelemetryInfoDto info)
{
var telemetry = GetOrCreateTelemetryByUid(uid);
telemetry.Info = mapper.Map<TelemetryInfo>(info);
cacheTelemetry.Upsert(telemetry);
}
private Well GetWellByTelemetryUid(string uid)
{
var tele = cacheTelemetry.FirstOrDefault(t => t.RemoteUid == uid, RefreshMode.IfResultEmpty);
if (tele is null)
return null;
return cacheWell.FirstOrDefault(w => w?.IdTelemetry == tele.Id)?.Id;
return cacheWell.FirstOrDefault(w => w?.IdTelemetry == tele.Id);
}
private Telemetry GetOrCreateTelemetry(string uid)
private Telemetry GetOrCreateTelemetryByUid(string uid)
=> cacheTelemetry.FirstOrDefault(t => t.RemoteUid == uid, RefreshMode.IfResultEmpty)
?? cacheTelemetry.Insert(new Telemetry{ RemoteUid = uid, });
?? cacheTelemetry.Insert(new Telemetry { RemoteUid = uid, });
public void UpdateData(string uid, TelemetryDataDto data)
{
var telemetry = GetOrCreateTelemetry(uid);
if ((data.DataSaub != default) && (data.DataSaub.Count() > 0))
{
DataSaubBase dataSaub = default;
foreach (var item in data.DataSaub)
{
dataSaub = mapper.Map<DataSaubBase>(item);
dataSaub.IdTelemetry = telemetry.Id;
db.DataSaubBases.Add(dataSaub);
}
if(dataSaub != default)
telemetry.LastDataSaub = dataSaub;
db.SaveChanges();
}
}
public void UpdateInfo(string uid, TelemetryInfoDto info)
{
var telemetry = cacheTelemetry.FirstOrDefault(t => t.RemoteUid == uid);
var infoJson = JsonSerializer.Serialize(info);
//TODO: update telemetry timezone
if (telemetry is null)
{
var newTelemetry = new Telemetry
{
RemoteUid = uid,
Info = infoJson,
};
telemetry = cacheTelemetry.Insert(newTelemetry);
}
else
cacheTelemetry.Update(t => t.RemoteUid == uid, t => t.Info = infoJson);
}
}
}

View File

@ -0,0 +1,58 @@
using AsbCloudApp.Data;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Services.Cache;
using System.Collections.Generic;
using System.Linq;
namespace AsbCloudInfrastructure.Services
{
public class TelemetryUserService : ITelemetryUserService
{
private readonly IAsbCloudDbContext db;
private readonly ITelemetryService telemetryService;
private readonly ICacheTable<TelemetryUser> cacheTUsers;
public TelemetryUserService(IAsbCloudDbContext db, CacheDb cacheDb, ITelemetryService telemetryService)
{
this.db = db;
this.telemetryService = telemetryService;
cacheTUsers = cacheDb.GetCachedTable<TelemetryUser>((AsbCloudDbContext)db);
}
public void Upsert(string uid, IEnumerable<TelemetryUserDto> dtos)
{
if (dtos.Count() == 0)
return;
var telemetryId = telemetryService.GetOrCreateTemetryIdByUid(uid);
var ids = dtos.Select(e => e.Id).ToList();
var dbIds = (from e in db.TelemetryUsers
where e.IdTelemetry == telemetryId && ids.Contains(e.IdUser)
select e.IdUser).ToList();
foreach (var dto in dtos)
{
var entity = new TelemetryUser
{
IdUser = dto.Id,
IdTelemetry = telemetryId,
Level = dto.Level,
Name = dto.Name,
Patronymic = dto.Patronymic,
Surname = dto.Surname,
};
if (dbIds.Contains(dto.Id))
db.TelemetryUsers.Update(entity);
else
db.TelemetryUsers.Add(entity);
}
db.SaveChanges();
cacheTUsers.Refresh();
}
}
}

View File

@ -10,12 +10,10 @@ namespace AsbCloudInfrastructure.Services
public class WellService : IWellService
{
private readonly IAsbCloudDbContext db;
private readonly MapperConfiguration mapperConfiguration;
public WellService(IAsbCloudDbContext db, MapperConfiguration mapperConfiguration)
public WellService(IAsbCloudDbContext db)
{
this.db = db;
this.mapperConfiguration = mapperConfiguration;
}
public IEnumerable<WellDto> GetWellsByCustomer(int idCustomer)
@ -34,9 +32,6 @@ namespace AsbCloudInfrastructure.Services
Deposit = well.Cluster.Deposit.Caption,
};
if (well.Telemetry?.LastDataSaub != default)
wellDto.LastData = mapperConfiguration.CreateMapper().Map<DataSaubBaseDto>(well.Telemetry.LastDataSaub);
return wellDto;
}
}

View File

@ -4,8 +4,6 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace AsbCloudWebApi.Controllers
{
@ -17,9 +15,9 @@ namespace AsbCloudWebApi.Controllers
[Authorize]
public class DataController : ControllerBase
{
private readonly ITelemetryDataService telemetryDataService;
private readonly IDataService telemetryDataService;
public DataController(ITelemetryDataService telemetryDataService)
public DataController(IDataService telemetryDataService)
{
this.telemetryDataService = telemetryDataService;
}
@ -38,7 +36,7 @@ namespace AsbCloudWebApi.Controllers
[ProducesResponseType(typeof(IEnumerable<DataSaubBaseDto>), (int)System.Net.HttpStatusCode.OK)]
public IActionResult Get(int wellId, DateTime begin = default, int intervalSec = 600, int approxPointsCount = 1024)
{
if(begin == default)
if (begin == default)
begin = DateTime.Now.AddSeconds(-intervalSec);
var content = telemetryDataService.Get(wellId, begin, intervalSec, approxPointsCount);
return Ok(content);

View File

@ -0,0 +1,45 @@
using AsbCloudApp.Data;
using AsbCloudApp.Services;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
namespace AsbCloudWebApi.Controllers
{
[Route("api/well")]
[ApiController]
public class MessageController : ControllerBase
{
private readonly IMessageService messageService;
public MessageController(IMessageService messageService)
{
this.messageService = messageService;
}
/// <summary>
/// Выдает список сообщений по скважине
/// </summary>
/// <param name="wellId">id скважины</param>
/// <param name="categoryids">список категорий</param>
/// <param name="begin">дата начала</param>
/// <param name="end">окончание</param>
/// <param name="skip">для пагинации кол-во записей пропустить</param>
/// <param name="take">для пагинации кол-во записей </param>
/// <returns>список сообщений по скважине</returns>
[HttpGet]
[Route("{wellId}/message")]
[ProducesResponseType(typeof(PaginationContainer<MessageDto>), (int)System.Net.HttpStatusCode.OK)]
public IActionResult Get(int wellId, [FromQuery] IEnumerable<int> categoryids = default, DateTime begin = default, DateTime end = default, int skip = 0, int take = 32)
{
if (take > 1024)
return BadRequest("limit mast be less then 1024");
if (begin > DateTime.Now)
begin = default;
var result = messageService.GetMessages(wellId, categoryids, begin, end, skip, take);
return Ok(result);
}
}
}

View File

@ -1,10 +1,8 @@
using AsbCloudApp.Data;
using AsbCloudApp.Services;
using AsbCloudWebApi.SignalR;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@ -18,12 +16,26 @@ namespace AsbCloudWebApi.Controllers
[ApiController]
public class TelemetryController : ControllerBase
{
private readonly IDataService DataService;
private readonly ITelemetryService telemetryService;
private readonly IMessageService messageService;
private readonly IEventService eventService;
private readonly ITelemetryUserService telemetryUserService;
private readonly IHubContext<TelemetryHub> telemetryHubContext;
public TelemetryController(ITelemetryService telemetryService, IHubContext<TelemetryHub> telemetryHubContext)
public TelemetryController(
ITelemetryService telemetryService,
IDataService DataService,
IMessageService messageService,
IEventService eventService,
ITelemetryUserService telemetryUserService,
IHubContext<TelemetryHub> telemetryHubContext)
{
this.DataService = DataService;
this.telemetryService = telemetryService;
this.messageService = messageService;
this.eventService = eventService;
this.telemetryUserService = telemetryUserService;
this.telemetryHubContext = telemetryHubContext;
}
@ -45,21 +57,66 @@ namespace AsbCloudWebApi.Controllers
/// Принимает данные от разных систем по скважине
/// </summary>
/// <param name="uid">Уникальный идентификатор отправителя</param>
/// <param name="data">Данные</param>
/// <param name="dtos">Данные</param>
/// <returns></returns>
[HttpPost]
[Route("{uid}/data")]
public IActionResult Data(string uid, [FromBody] TelemetryDataDto data)
public IActionResult Data(string uid, [FromBody] IEnumerable<DataSaubBaseDto> dtos)
{
telemetryService.UpdateData(uid, data);
var wellId = telemetryService.GetWellIdByTelemetryUid(uid);
DataService.UpdateData(uid, dtos);
var wellId = telemetryService.GetWellIdByUid(uid);
if (wellId != null && data.DataSaub?.Count > 0)
Task.Run(() => telemetryHubContext.Clients.Group($"well_{wellId}").SendAsync(nameof(ITelemetryHubClient.ReceiveDataSaub), data.DataSaub) );
if (wellId != null && dtos.Any())
Task.Run(() => telemetryHubContext.Clients.Group($"well_{wellId}").SendAsync(nameof(ITelemetryHubClient.ReceiveDataSaub), dtos));
return Ok();
}
/// <summary>
/// Принимает список новых сообщений от телеметрии
/// </summary>
/// <param name="uid">Уникальный идентификатор отправителя</param>
/// <param name="dtos">сообщения</param>
/// <returns></returns>
[HttpPost]
[Route("{uid}/message")]
public IActionResult Message(string uid, [FromBody] IEnumerable<TelemetryMessageDto> dtos)
{
var wellId = telemetryService.GetWellIdByTelemetryUid(uid);
messageService.Insert(uid, dtos);
if (dtos.Any())
Task.Run(() => telemetryHubContext.Clients.Group($"well_{wellId}").SendAsync(nameof(ITelemetryHubClient.ReceiveMessages), dtos));
return Ok();
}
/// <summary>
/// Принимает справочник событий
/// </summary>
/// <param name="uid">Уникальный идентификатор отправителя</param>
/// <param name="events">справочник событий</param>
/// <returns></returns>
[HttpPost]
[Route("{uid}/event")]
public IActionResult Events(string uid, [FromBody] List<EventDto> events)
{
eventService.Upsert(uid, events);
return Ok();
}
/// <summary>
/// Принимает справочник пользователей телеметрии
/// </summary>
/// <param name="uid">Уникальный идентификатор отправителя</param>
/// <param name="users">справочник пользователей телеметрии</param>
/// <returns></returns>
[HttpPost]
[Route("{uid}/user")]
public IActionResult Users(string uid, [FromBody] List<TelemetryUserDto> users)
{
telemetryUserService.Upsert(uid, users);
return Ok();
}
}
}

View File

@ -1,6 +1,5 @@
using AsbCloudInfrastructure.Services;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
@ -21,11 +20,12 @@ namespace AsbCloudWebApi
{
//c.CustomOperationIds(e => $"{e.ActionDescriptor.RouteValues["controller"]}_{e.HttpMethod}");
//c.CustomOperationIds(e => $"{e.HttpMethod}_{e.ActionDescriptor.Ac");
c.CustomOperationIds(e=> {
c.CustomOperationIds(e =>
{
return $"{e.ActionDescriptor.RouteValues["action"]}";
});
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Charging station", Version = "v1" });
c.SwaggerDoc("v1", new OpenApiInfo { Title = "ASB cloud web api", Version = "v1" });
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = @"JWT Authorization header using the Bearer scheme. Enter 'Bearer' [space] and then your token in the text input below. Example: 'Bearer 12345abcdef'",

View File

@ -1,13 +1,13 @@
using AsbCloudApp.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace AsbCloudWebApi.SignalR
{
public interface ITelemetryHubClient
{
Task ReceiveDataSaub(IEnumerable<DataSaubBaseDto> data);
Task ReceiveDataSaub(IEnumerable<DataSaubBaseDto> dtos);
Task ReceiveMessages(IEnumerable<MessageDto> dtos);
}
}

View File

@ -6,7 +6,7 @@
- синхронизация архива телеметрии
- мониторинг активно передающих скважин
- доделать секционирование.
- редуцирование архива телеметрии по принципу второй производной. Если вторая производная ~0, то промежуточные значения можно удалить.
- редуцирование выборки в контроллере. слишком большую выборку попробовать уменьшать оконными функиями, сохранять экстремумы и ближайшие к ним значения.

View File

@ -5,6 +5,6 @@
<title></title>
</head>
<body>
RAMAMBA!
</body>
</html>

View File

@ -0,0 +1,6 @@
Моменты в БД за которыми надо приглядывать.
Есть t_message для которой нет t_event | Ошибка синхронизации
Есть t_telemetry для которой нет t_well | Кто-то начал новое бурение или исправил название старого
2 t_telemetry с не уникальными uid
Провалы в непрерывной t_data.

View File

@ -1,17 +1,11 @@
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Services.Cache;
using AutoMapper;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace ConsoleApp1
{
public class A {
public class A
{
public int P1 { get; set; }
public int P2 { get; set; }
};
@ -26,10 +20,22 @@ namespace ConsoleApp1
{
static void Main(string[] args)
{
//var options = new DbContextOptionsBuilder<AsbCloudDbContext>()
// .UseNpgsql("Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True")
// .Options;
//var context = new AsbCloudDbContext(options);
var options = new DbContextOptionsBuilder<AsbCloudDbContext>()
.UseNpgsql("Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True")
.Options;
var context = new AsbCloudDbContext(options);
var e = new Event
{
IdEvent = 1,
IdTelemetry = 1,
IdCategory = 1,
MessageTemplate = "template",
};
context.Events.Update(e).State = EntityState.Added;
context.SaveChanges();
//var table = new Table
//{

View File

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace ConsoleApp1
{

View File

@ -3,8 +3,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp1
{
@ -72,7 +70,7 @@ namespace ConsoleApp1
Getter = Expression.Lambda<GetterDelegate>(Expression.Convert(callExpression, typeof(object)), instanceExpression).Compile();
}
public string PropertyName { get;}
public string PropertyName { get; }
public Type PropertyType { get; }
public string Id { get; }

View File

@ -1,7 +1,5 @@
using AsbCloudApp.Data;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@ -109,31 +107,31 @@ namespace SaubPanelOnlineSender
return new DataSaubBaseDto
{
Date = DateTime.Now,
AxialLoad = rnd.NextDouble()*100d,
AxialLoadLimitMax = rnd.NextDouble()*100d,
AxialLoadSp = rnd.NextDouble()*100d,
BitDepth = rnd.NextDouble()*100d,
BlockHeight = rnd.NextDouble()*100d,
BlockSpeed = rnd.NextDouble()*100d,
WellDepth = rnd.NextDouble()*100d,
BlockSpeedSp = rnd.NextDouble()*100d,
Flow = rnd.NextDouble()*100d,
FlowDeltaLimitMax = rnd.NextDouble()*100d,
FlowIdle = rnd.NextDouble()*100d,
HookWeight = rnd.NextDouble()*100d,
HookWeightIdle = rnd.NextDouble()*100d,
HookWeightLimitMax = rnd.NextDouble()*100d,
HookWeightLimitMin= rnd.NextDouble() * 100d,
Mode= 1,
Pressure= rnd.NextDouble() * 100d,
PressureDeltaLimitMax= rnd.NextDouble() * 100d,
PressureIdle= rnd.NextDouble() * 100d,
PressureSp= rnd.NextDouble() * 100d,
RotorSpeed= rnd.NextDouble() * 100d,
RotorTorque= rnd.NextDouble() * 100d,
RotorTorqueIdle= rnd.NextDouble() * 100d,
RotorTorqueLimitMax= rnd.NextDouble() * 100d,
RotorTorqueSp= rnd.NextDouble() * 100d,
AxialLoad = rnd.NextDouble() * 100d,
AxialLoadLimitMax = rnd.NextDouble() * 100d,
AxialLoadSp = rnd.NextDouble() * 100d,
BitDepth = rnd.NextDouble() * 100d,
BlockPosition = rnd.NextDouble() * 100d,
BlockSpeed = rnd.NextDouble() * 100d,
WellDepth = rnd.NextDouble() * 100d,
BlockSpeedSp = rnd.NextDouble() * 100d,
Flow = rnd.NextDouble() * 100d,
FlowDeltaLimitMax = rnd.NextDouble() * 100d,
FlowIdle = rnd.NextDouble() * 100d,
HookWeight = rnd.NextDouble() * 100d,
HookWeightIdle = rnd.NextDouble() * 100d,
HookWeightLimitMax = rnd.NextDouble() * 100d,
HookWeightLimitMin = rnd.NextDouble() * 100d,
Mode = 1,
Pressure = rnd.NextDouble() * 100d,
PressureDeltaLimitMax = rnd.NextDouble() * 100d,
PressureIdle = rnd.NextDouble() * 100d,
PressureSp = rnd.NextDouble() * 100d,
RotorSpeed = rnd.NextDouble() * 100d,
RotorTorque = rnd.NextDouble() * 100d,
RotorTorqueIdle = rnd.NextDouble() * 100d,
RotorTorqueLimitMax = rnd.NextDouble() * 100d,
RotorTorqueSp = rnd.NextDouble() * 100d,
};
}
}

112
SyncDicts/Program.cs Normal file
View File

@ -0,0 +1,112 @@
using AsbCloudApp.Data;
using AsbSaubDbModel.V3;
using System;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.Json;
namespace SyncDicts
{
class Program
{
/// <summary>
/// Описывает процесс синхронизации словарей БД
/// </summary>
/// <param name="args"></param>
static void Main(/*string[] args*/)
{
bool res;
var context = new ArchiveDbContext(@"c:\temp\default.sqlite3");
// sync Events
var events = context.EventsDictionary.ToList()
.Select(e => new EventDto
{
EventType = e.EventType,
Id = e.Id,
IdCategory = e.CategoryId,
IdSound = e.SoundId,
Message = e.MessageTemplate,
Tag = e.Tag,
});
var info = new TelemetryInfoDto
{
Caption = "скв 32",
Deposit = "мр 2",
Cluster = "куст 22",
TimeZoneId = TimeZoneInfo.Local.Id,
TimeZoneOffsetTotalHours = TimeZoneInfo.Local.BaseUtcOffset.TotalHours,
Date = DateTime.Now,
};
var users = context.Users.ToList()
.Select(u => new TelemetryUserDto
{
Id = u.Id,
Level = u.Level,
Name = u.Name,
Patronymic = u.Patronymic,
Surname = u.Surname,
});
var messages = context.Messages.Take(1024).ToList()
.Select(m => new TelemetryMessageDto
{
Id = m.Id,
Date = DateTime.UnixEpoch.AddSeconds(m.TimeStamp),
IdEvent = m.EventItemId,
IdTelemetryUser = m.UserId,
State = m.State,
Arg0 = m.Arg0,
Arg1 = m.Arg1,
Arg2 = m.Arg2,
Arg3 = m.Arg3,
});
//res = Send("http://127.0.0.1:5000/api/telemetry/asdasd/event", events);
//res = Send("http://127.0.0.1:5000/api/telemetry/asdasd/info", info);
//res = Send("http://127.0.0.1:5000/api/telemetry/asdasd/user", users);
res = Send("http://127.0.0.1:5000/api/telemetry/asdasd/message", messages);
}
private static bool Send<T>(string url, T obj)
{
// sending data
var requestBodyJson = JsonSerializer.Serialize(obj);
var data = Encoding.UTF8.GetBytes(requestBodyJson);
var request = MakeRequest(url);
using var streamWriter = request.GetRequestStream();
streamWriter.Write(data);
streamWriter.Close();
// getting response
if (request.GetResponse() is not HttpWebResponse response)
{//FAILED
return false;
}
if (response.StatusCode == HttpStatusCode.OK)
{// sent succesfilly
return true;
}
else
{//failed
return false;
}
}
private static HttpWebRequest MakeRequest(string url, string contentType = "application/json")
{
var request = WebRequest.CreateHttp(url);
request.Method = "POST";
request.Timeout = 4900;
request.ContentType = contentType;
request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
request.ServicePoint.Expect100Continue = false;
return request;
}
}
}

View File

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.5" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AsbCloudApp\AsbCloudApp.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="AsbSaubDbModel">
<HintPath>..\..\..\SAUB\asbsaub3\AsbSaubDbModel\bin\Release\netcoreapp3.1\AsbSaubDbModel.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

1022
swagger.json Normal file

File diff suppressed because it is too large Load Diff