forked from ddrilling/AsbCloudServer
настроил разделение по группас в signalR, отправку из веб апи. доработал кеш.
This commit is contained in:
parent
5e80746333
commit
24e0bed979
@ -6,6 +6,7 @@ namespace AsbCloudApp.Data
|
||||
{
|
||||
public class TelemetryInfoDto
|
||||
{
|
||||
public DateTime Date { get; set; }
|
||||
public string Caption { get; set; }
|
||||
public string Cluster { get; set; }
|
||||
public string Deposit { get; set; }
|
||||
|
@ -9,6 +9,7 @@ namespace AsbCloudApp.Services
|
||||
{
|
||||
public interface ITelemetryService
|
||||
{
|
||||
int? GetWellIdByUid(string uid);
|
||||
void UpdateData(string uid, TelemetryDataDto data);
|
||||
void UpdateInfo(string uid, TelemetryInfoDto info);
|
||||
}
|
||||
|
@ -136,12 +136,37 @@ namespace AsbCloudDb.Model
|
||||
.WithOne(p => p.Well)
|
||||
.HasForeignKey<Well>(d => d.IdTelemetry)
|
||||
.HasConstraintName("t_well_t_telemetry_id_fk");
|
||||
|
||||
|
||||
});
|
||||
|
||||
OnModelCreatingPartial(modelBuilder);
|
||||
FillData(modelBuilder);
|
||||
}
|
||||
|
||||
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
|
||||
private void FillData(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.Entity<Deposit>(entity =>
|
||||
{
|
||||
entity.HasData(new List<Deposit> {
|
||||
new Deposit{Id = 1, Caption = "месторождение" },
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Cluster>(entity =>
|
||||
{
|
||||
entity.HasData(new List<Cluster> {
|
||||
new Cluster{Id = 1, Caption = "месторождение", IdDeposit = 1 },
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Well>(entity =>
|
||||
{
|
||||
entity.HasData(new List<Well> {
|
||||
new Well{Id = 1, IdCluster = 1, IdCustomer = 1, Caption = "скв 1" },
|
||||
new Well{Id = 2, IdCluster = 1, IdCustomer = 1, Caption = "скв 2" },
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public IQueryable<Well> GetWellsByCustomer(int idCustomer)
|
||||
{
|
||||
|
@ -2,6 +2,7 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
#nullable disable
|
||||
|
||||
@ -68,6 +69,7 @@ namespace AsbCloudDb.Model
|
||||
[Column("flow_delta_limit_max"), Comment("Расход. Аварийный макс.")]
|
||||
public double? FlowDeltaLimitMax { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
[ForeignKey(nameof(IdTelemetry))]
|
||||
[InverseProperty(nameof(Model.Telemetry.DataSaubBases))]
|
||||
public virtual Telemetry Telemetry { get; set; }
|
||||
|
@ -29,18 +29,15 @@ namespace AsbCloudDb.Model
|
||||
[Column("info", TypeName = "jsonb"), Comment("Информация с панели о скважине")]
|
||||
public string Info { get; set; }
|
||||
|
||||
[Column("data", TypeName = "json"), Comment("последние пришедшие данные со скважины в сыром виде")]
|
||||
public string Data { get; set; }
|
||||
|
||||
[Column("last_data_saub", TypeName = "json"), Comment("последние пришедшие данные со скважины в виде json класса DataSaubBase")]
|
||||
public string LastDataSaub { get; set; }
|
||||
|
||||
[Column("version"), Comment("Версия ПО панели отправляющей телеметрию")]
|
||||
[StringLength(64)]
|
||||
public string Version { get; set; }
|
||||
|
||||
//[Column("time_zone", TypeName = "json"), Comment("Временная зона панели САУБ.")]
|
||||
//public TimeZoneInfo TimeZone { 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; }
|
||||
|
||||
[InverseProperty(nameof(Model.Well.Telemetry))]
|
||||
public virtual Well Well { get; set; }
|
||||
|
@ -2,6 +2,7 @@
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Text;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.Cache
|
||||
@ -9,17 +10,22 @@ namespace AsbCloudInfrastructure.Services.Cache
|
||||
|
||||
public class CacheDb
|
||||
{
|
||||
private Dictionary<Type, IEnumerable<object>> cache = new Dictionary<Type, IEnumerable<object>>();
|
||||
private ConcurrentDictionary<string, IEnumerable<object>> cache = new ConcurrentDictionary<string, IEnumerable<object>>();
|
||||
|
||||
public ICacheTable<TEntity> GetCachedTable<TEntity>(DbContext context)
|
||||
where TEntity : class
|
||||
{
|
||||
var entityType = typeof(TEntity);
|
||||
if (!cache.ContainsKey(entityType))
|
||||
cache[entityType] = new List<TEntity>(8);
|
||||
var entityTypeName = typeof(TEntity).FullName;
|
||||
|
||||
var tableCache = new CacheTable<TEntity>(context, (List<TEntity>)cache[entityType]);
|
||||
if (!cache.ContainsKey(entityTypeName))
|
||||
cache[entityTypeName] = new List<TEntity>(8);
|
||||
|
||||
var tableCache = new CacheTable<TEntity>(context, (List<TEntity>)cache[entityTypeName]);
|
||||
return tableCache;
|
||||
}
|
||||
|
||||
public void DropAll()=> cache.Clear();
|
||||
|
||||
public void Drop<TEntity>() => cache.Remove(typeof(TEntity).FullName, out _);
|
||||
}
|
||||
}
|
||||
|
@ -17,39 +17,46 @@ namespace AsbCloudInfrastructure.Services
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
private Telemetry GetOrCreateTelemetry(string uid)
|
||||
=> cacheTelemetry.FirstOrDefault(t => t.RemoteUid == uid, RefreshMode.IfResultEmpty)
|
||||
?? cacheTelemetry.Insert(new Telemetry{ RemoteUid = uid, });
|
||||
|
||||
public void UpdateData(string uid, TelemetryDataDto data)
|
||||
{
|
||||
var telemetry = cacheTelemetry.FirstOrDefault(t => t.RemoteUid == uid, RefreshMode.IfResultEmpty);
|
||||
var telemetry = GetOrCreateTelemetry(uid);
|
||||
|
||||
if(telemetry is null)
|
||||
{
|
||||
var newTelemetry = new Telemetry
|
||||
{
|
||||
RemoteUid = uid,
|
||||
Version = data.HmiVersion,
|
||||
Data = JsonSerializer.Serialize(data),
|
||||
LastDataSaub = JsonSerializer.Serialize(data.DataSaub),
|
||||
};
|
||||
telemetry = cacheTelemetry.Insert(newTelemetry);
|
||||
}
|
||||
|
||||
if (data.DataSaub != default)
|
||||
if ((data.DataSaub != default) && (data.DataSaub.Count() > 0))
|
||||
{
|
||||
DataSaubBase dataSaub = default;
|
||||
foreach (var item in data.DataSaub)
|
||||
{
|
||||
var dataSaub = mapper.Map<DataSaubBase>(item);
|
||||
dataSaub = mapper.Map<DataSaubBase>(item);
|
||||
dataSaub.IdTelemetry = telemetry.Id;
|
||||
db.DataSaubBases.Add(dataSaub);
|
||||
}
|
||||
|
||||
if(dataSaub != default)
|
||||
telemetry.LastDataSaub = dataSaub;
|
||||
|
||||
db.SaveChanges();
|
||||
}
|
||||
}
|
||||
@ -57,15 +64,21 @@ namespace AsbCloudInfrastructure.Services
|
||||
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 = JsonSerializer.Serialize(info),
|
||||
Info = infoJson,
|
||||
};
|
||||
telemetry = cacheTelemetry.Insert(newTelemetry);
|
||||
}
|
||||
else
|
||||
cacheTelemetry.Update(t => t.RemoteUid == uid, t => t.Info = infoJson);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,13 +34,8 @@ namespace AsbCloudInfrastructure.Services
|
||||
Deposit = well.Cluster.Deposit.Caption,
|
||||
};
|
||||
|
||||
var dataJson = well.Telemetry?.LastDataSaub;
|
||||
|
||||
if (string.IsNullOrEmpty(dataJson))
|
||||
return wellDto;
|
||||
|
||||
var data = System.Text.Json.JsonSerializer.Deserialize<DataSaubBase>(dataJson);
|
||||
wellDto.LastData = mapperConfiguration.CreateMapper().Map<DataSaubBaseDto>(data);
|
||||
if (well.Telemetry?.LastDataSaub != default)
|
||||
wellDto.LastData = mapperConfiguration.CreateMapper().Map<DataSaubBaseDto>(well.Telemetry.LastDataSaub);
|
||||
|
||||
return wellDto;
|
||||
}
|
||||
|
@ -25,7 +25,8 @@ namespace AsbCloudWebApi.Controllers
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Возвращает данные САУБ по скважине
|
||||
/// Возвращает данные САУБ по скважине.
|
||||
/// По умолчанию за последние 10 минут.
|
||||
/// </summary>
|
||||
/// <param name="wellId"></param>
|
||||
/// <param name=""></param>
|
||||
|
@ -1,6 +1,6 @@
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudWebApi.WebSocket;
|
||||
using AsbCloudWebApi.SignalR;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
@ -52,7 +52,12 @@ namespace AsbCloudWebApi.Controllers
|
||||
public IActionResult Data(string uid, [FromBody] TelemetryDataDto data)
|
||||
{
|
||||
telemetryService.UpdateData(uid, data);
|
||||
//telemetryHubContext.Clients.Group("").
|
||||
|
||||
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) );
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
|
@ -4,10 +4,10 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudWebApi.WebSocket
|
||||
namespace AsbCloudWebApi.SignalR
|
||||
{
|
||||
public interface ITelemetryHubClient
|
||||
{
|
||||
Task ReceiveDataSaub(DataSaubBaseDto data);
|
||||
Task ReceiveDataSaub(IEnumerable<DataSaubBaseDto> data);
|
||||
}
|
||||
}
|
@ -1,10 +1,13 @@
|
||||
using AsbCloudApp.Data;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudWebApi.WebSocket
|
||||
namespace AsbCloudWebApi.SignalR
|
||||
{
|
||||
// SignalR manual:
|
||||
// https://docs.microsoft.com/ru-ru/aspnet/core/signalr/introduction?view=aspnetcore-5.0
|
||||
|
||||
[Authorize]
|
||||
public class TelemetryHub : Hub<ITelemetryHubClient>
|
||||
@ -15,8 +18,8 @@ namespace AsbCloudWebApi.WebSocket
|
||||
public Task RemoveFromGroup(string groupName)
|
||||
=> Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
|
||||
|
||||
public Task SendDataSaub(int wellId, DataSaubBaseDto data)
|
||||
=> Clients.All.ReceiveDataSaub(data);
|
||||
public Task SendDataSaub(string groupName, IEnumerable<DataSaubBaseDto> data)
|
||||
=> Clients.Group(groupName).ReceiveDataSaub(data);
|
||||
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
using AsbCloudInfrastructure;
|
||||
using AsbCloudWebApi.WebSocket;
|
||||
using AsbCloudWebApi.SignalR;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
Loading…
Reference in New Issue
Block a user