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 class TelemetryInfoDto
|
||||||
{
|
{
|
||||||
|
public DateTime Date { get; set; }
|
||||||
public string Caption { get; set; }
|
public string Caption { get; set; }
|
||||||
public string Cluster { get; set; }
|
public string Cluster { get; set; }
|
||||||
public string Deposit { get; set; }
|
public string Deposit { get; set; }
|
||||||
|
@ -9,6 +9,7 @@ namespace AsbCloudApp.Services
|
|||||||
{
|
{
|
||||||
public interface ITelemetryService
|
public interface ITelemetryService
|
||||||
{
|
{
|
||||||
|
int? GetWellIdByUid(string uid);
|
||||||
void UpdateData(string uid, TelemetryDataDto data);
|
void UpdateData(string uid, TelemetryDataDto data);
|
||||||
void UpdateInfo(string uid, TelemetryInfoDto info);
|
void UpdateInfo(string uid, TelemetryInfoDto info);
|
||||||
}
|
}
|
||||||
|
@ -136,12 +136,37 @@ namespace AsbCloudDb.Model
|
|||||||
.WithOne(p => p.Well)
|
.WithOne(p => p.Well)
|
||||||
.HasForeignKey<Well>(d => d.IdTelemetry)
|
.HasForeignKey<Well>(d => d.IdTelemetry)
|
||||||
.HasConstraintName("t_well_t_telemetry_id_fk");
|
.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)
|
public IQueryable<Well> GetWellsByCustomer(int idCustomer)
|
||||||
{
|
{
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
@ -68,6 +69,7 @@ namespace AsbCloudDb.Model
|
|||||||
[Column("flow_delta_limit_max"), Comment("Расход. Аварийный макс.")]
|
[Column("flow_delta_limit_max"), Comment("Расход. Аварийный макс.")]
|
||||||
public double? FlowDeltaLimitMax { get; set; }
|
public double? FlowDeltaLimitMax { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
[ForeignKey(nameof(IdTelemetry))]
|
[ForeignKey(nameof(IdTelemetry))]
|
||||||
[InverseProperty(nameof(Model.Telemetry.DataSaubBases))]
|
[InverseProperty(nameof(Model.Telemetry.DataSaubBases))]
|
||||||
public virtual Telemetry Telemetry { get; set; }
|
public virtual Telemetry Telemetry { get; set; }
|
||||||
|
@ -29,18 +29,15 @@ namespace AsbCloudDb.Model
|
|||||||
[Column("info", TypeName = "jsonb"), Comment("Информация с панели о скважине")]
|
[Column("info", TypeName = "jsonb"), Comment("Информация с панели о скважине")]
|
||||||
public string Info { get; set; }
|
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("Версия ПО панели отправляющей телеметрию")]
|
[Column("version"), Comment("Версия ПО панели отправляющей телеметрию")]
|
||||||
[StringLength(64)]
|
[StringLength(64)]
|
||||||
public string Version { get; set; }
|
public string Version { get; set; }
|
||||||
|
|
||||||
//[Column("time_zone", TypeName = "json"), Comment("Временная зона панели САУБ.")]
|
[Column("last_data_saub", TypeName = "jsonb"), Comment("Информация с панели о скважине")]
|
||||||
//public TimeZoneInfo TimeZone { get; set; }
|
public DataSaubBase LastDataSaub { get; set; }
|
||||||
|
|
||||||
|
[Column("time_zone", TypeName = "json"), Comment("Временная зона панели САУБ.")]
|
||||||
|
public TimeZoneInfo TimeZone { get; set; }
|
||||||
|
|
||||||
[InverseProperty(nameof(Model.Well.Telemetry))]
|
[InverseProperty(nameof(Model.Well.Telemetry))]
|
||||||
public virtual Well Well { get; set; }
|
public virtual Well Well { get; set; }
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Internal;
|
using Microsoft.EntityFrameworkCore.Internal;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.Cache
|
namespace AsbCloudInfrastructure.Services.Cache
|
||||||
@ -9,17 +10,22 @@ namespace AsbCloudInfrastructure.Services.Cache
|
|||||||
|
|
||||||
public class CacheDb
|
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)
|
public ICacheTable<TEntity> GetCachedTable<TEntity>(DbContext context)
|
||||||
where TEntity : class
|
where TEntity : class
|
||||||
{
|
{
|
||||||
var entityType = typeof(TEntity);
|
var entityTypeName = typeof(TEntity).FullName;
|
||||||
if (!cache.ContainsKey(entityType))
|
|
||||||
cache[entityType] = new List<TEntity>(8);
|
|
||||||
|
|
||||||
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;
|
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 IAsbCloudDbContext db;
|
||||||
private readonly IMapper mapper;
|
private readonly IMapper mapper;
|
||||||
private readonly ICacheTable<Telemetry> cacheTelemetry;
|
private readonly ICacheTable<Telemetry> cacheTelemetry;
|
||||||
|
private readonly ICacheTable<Well> cacheWell;
|
||||||
|
|
||||||
public TelemetryService(IAsbCloudDbContext db, CacheDb cacheDb, MapperConfiguration mapperConfiguration)
|
public TelemetryService(IAsbCloudDbContext db, CacheDb cacheDb, MapperConfiguration mapperConfiguration)
|
||||||
{
|
{
|
||||||
this.db = db;
|
this.db = db;
|
||||||
mapper = mapperConfiguration.CreateMapper();
|
mapper = mapperConfiguration.CreateMapper();
|
||||||
cacheTelemetry = cacheDb.GetCachedTable<Telemetry>((AsbCloudDbContext)db);
|
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)
|
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)
|
if ((data.DataSaub != default) && (data.DataSaub.Count() > 0))
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
|
DataSaubBase dataSaub = default;
|
||||||
foreach (var item in data.DataSaub)
|
foreach (var item in data.DataSaub)
|
||||||
{
|
{
|
||||||
var dataSaub = mapper.Map<DataSaubBase>(item);
|
dataSaub = mapper.Map<DataSaubBase>(item);
|
||||||
dataSaub.IdTelemetry = telemetry.Id;
|
dataSaub.IdTelemetry = telemetry.Id;
|
||||||
db.DataSaubBases.Add(dataSaub);
|
db.DataSaubBases.Add(dataSaub);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(dataSaub != default)
|
||||||
|
telemetry.LastDataSaub = dataSaub;
|
||||||
|
|
||||||
db.SaveChanges();
|
db.SaveChanges();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -57,15 +64,21 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
public void UpdateInfo(string uid, TelemetryInfoDto info)
|
public void UpdateInfo(string uid, TelemetryInfoDto info)
|
||||||
{
|
{
|
||||||
var telemetry = cacheTelemetry.FirstOrDefault(t => t.RemoteUid == uid);
|
var telemetry = cacheTelemetry.FirstOrDefault(t => t.RemoteUid == uid);
|
||||||
|
var infoJson = JsonSerializer.Serialize(info);
|
||||||
|
|
||||||
|
//TODO: update telemetry timezone
|
||||||
|
|
||||||
if (telemetry is null)
|
if (telemetry is null)
|
||||||
{
|
{
|
||||||
var newTelemetry = new Telemetry
|
var newTelemetry = new Telemetry
|
||||||
{
|
{
|
||||||
RemoteUid = uid,
|
RemoteUid = uid,
|
||||||
Info = JsonSerializer.Serialize(info),
|
Info = infoJson,
|
||||||
};
|
};
|
||||||
telemetry = cacheTelemetry.Insert(newTelemetry);
|
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,
|
Deposit = well.Cluster.Deposit.Caption,
|
||||||
};
|
};
|
||||||
|
|
||||||
var dataJson = well.Telemetry?.LastDataSaub;
|
if (well.Telemetry?.LastDataSaub != default)
|
||||||
|
wellDto.LastData = mapperConfiguration.CreateMapper().Map<DataSaubBaseDto>(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);
|
|
||||||
|
|
||||||
return wellDto;
|
return wellDto;
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,8 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Возвращает данные САУБ по скважине
|
/// Возвращает данные САУБ по скважине.
|
||||||
|
/// По умолчанию за последние 10 минут.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="wellId"></param>
|
/// <param name="wellId"></param>
|
||||||
/// <param name=""></param>
|
/// <param name=""></param>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudWebApi.WebSocket;
|
using AsbCloudWebApi.SignalR;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
@ -52,7 +52,12 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
public IActionResult Data(string uid, [FromBody] TelemetryDataDto data)
|
public IActionResult Data(string uid, [FromBody] TelemetryDataDto data)
|
||||||
{
|
{
|
||||||
telemetryService.UpdateData(uid, 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();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,10 +4,10 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace AsbCloudWebApi.WebSocket
|
namespace AsbCloudWebApi.SignalR
|
||||||
{
|
{
|
||||||
public interface ITelemetryHubClient
|
public interface ITelemetryHubClient
|
||||||
{
|
{
|
||||||
Task ReceiveDataSaub(DataSaubBaseDto data);
|
Task ReceiveDataSaub(IEnumerable<DataSaubBaseDto> data);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,10 +1,13 @@
|
|||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
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]
|
[Authorize]
|
||||||
public class TelemetryHub : Hub<ITelemetryHubClient>
|
public class TelemetryHub : Hub<ITelemetryHubClient>
|
||||||
@ -15,8 +18,8 @@ namespace AsbCloudWebApi.WebSocket
|
|||||||
public Task RemoveFromGroup(string groupName)
|
public Task RemoveFromGroup(string groupName)
|
||||||
=> Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
|
=> Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
|
||||||
|
|
||||||
public Task SendDataSaub(int wellId, DataSaubBaseDto data)
|
public Task SendDataSaub(string groupName, IEnumerable<DataSaubBaseDto> data)
|
||||||
=> Clients.All.ReceiveDataSaub(data);
|
=> Clients.Group(groupName).ReceiveDataSaub(data);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
using AsbCloudInfrastructure;
|
using AsbCloudInfrastructure;
|
||||||
using AsbCloudWebApi.WebSocket;
|
using AsbCloudWebApi.SignalR;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
Loading…
Reference in New Issue
Block a user