Merge branch 'dev' into feature/daily_report

This commit is contained in:
Степанов Дмитрий 2023-11-14 11:02:29 +05:00
commit 4bd02ab348
37 changed files with 9608 additions and 122 deletions

View File

@ -57,5 +57,13 @@ namespace AsbCloudApp.Services
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<IEnumerable<ReportPropertiesDto>> GetAllReportsByWellAsync(int idWell, CancellationToken token); Task<IEnumerable<ReportPropertiesDto>> GetAllReportsByWellAsync(int idWell, CancellationToken token);
/// <summary>
/// Удаление отчетов, если превышен их период хранения
/// </summary>
/// <param name="lifetime">период хранения отчетов</param>
/// <param name="token"></param>
/// <returns></returns>
Task<int> DeleteAllOldReportsAsync(TimeSpan lifetime, CancellationToken token);
} }
} }

View File

@ -0,0 +1,224 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace AsbCloudDb.Migrations
{
public partial class UpdateTable_t_telemetry_data_Set_ImportantColumns_NotNull : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("DELETE FROM t_telemetry_data_saub WHERE " +
"well_depth IS NULL OR " +
"rotor_torque IS NULL OR " +
"rotor_speed IS NULL OR " +
"pressure IS NULL OR " +
"mode IS NULL OR " +
"hook_weight IS NULL OR " +
"block_position IS NULL OR " +
"bit_depth IS NULL OR " +
"axial_load IS NULL;");
migrationBuilder.AlterColumn<float>(
name: "well_depth",
table: "t_telemetry_data_saub",
type: "real",
nullable: false,
defaultValue: 0f,
comment: "Глубина забоя",
oldClrType: typeof(float),
oldType: "real",
oldNullable: true,
oldComment: "Глубина забоя");
migrationBuilder.AlterColumn<float>(
name: "rotor_torque",
table: "t_telemetry_data_saub",
type: "real",
nullable: false,
defaultValue: 0f,
comment: "Момент на роторе",
oldClrType: typeof(float),
oldType: "real",
oldNullable: true,
oldComment: "Момент на роторе");
migrationBuilder.AlterColumn<float>(
name: "rotor_speed",
table: "t_telemetry_data_saub",
type: "real",
nullable: false,
defaultValue: 0f,
comment: "Обороты ротора",
oldClrType: typeof(float),
oldType: "real",
oldNullable: true,
oldComment: "Обороты ротора");
migrationBuilder.AlterColumn<float>(
name: "pressure",
table: "t_telemetry_data_saub",
type: "real",
nullable: false,
defaultValue: 0f,
comment: "Давление",
oldClrType: typeof(float),
oldType: "real",
oldNullable: true,
oldComment: "Давление");
migrationBuilder.AlterColumn<short>(
name: "mode",
table: "t_telemetry_data_saub",
type: "smallint",
nullable: false,
defaultValue: (short)0,
comment: "Режим САУБ",
oldClrType: typeof(short),
oldType: "smallint",
oldNullable: true,
oldComment: "Режим САУБ");
migrationBuilder.AlterColumn<float>(
name: "hook_weight",
table: "t_telemetry_data_saub",
type: "real",
nullable: false,
defaultValue: 0f,
comment: "Вес на крюке",
oldClrType: typeof(float),
oldType: "real",
oldNullable: true,
oldComment: "Вес на крюке");
migrationBuilder.AlterColumn<float>(
name: "block_position",
table: "t_telemetry_data_saub",
type: "real",
nullable: false,
defaultValue: 0f,
comment: "Высота талевого блока",
oldClrType: typeof(float),
oldType: "real",
oldNullable: true,
oldComment: "Высота талевого блока");
migrationBuilder.AlterColumn<float>(
name: "bit_depth",
table: "t_telemetry_data_saub",
type: "real",
nullable: false,
defaultValue: 0f,
comment: "Положение инструмента",
oldClrType: typeof(float),
oldType: "real",
oldNullable: true,
oldComment: "Положение инструмента");
migrationBuilder.AlterColumn<float>(
name: "axial_load",
table: "t_telemetry_data_saub",
type: "real",
nullable: false,
defaultValue: 0f,
comment: "Осевая нагрузка",
oldClrType: typeof(float),
oldType: "real",
oldNullable: true,
oldComment: "Осевая нагрузка");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<float>(
name: "well_depth",
table: "t_telemetry_data_saub",
type: "real",
nullable: true,
comment: "Глубина забоя",
oldClrType: typeof(float),
oldType: "real",
oldComment: "Глубина забоя");
migrationBuilder.AlterColumn<float>(
name: "rotor_torque",
table: "t_telemetry_data_saub",
type: "real",
nullable: true,
comment: "Момент на роторе",
oldClrType: typeof(float),
oldType: "real",
oldComment: "Момент на роторе");
migrationBuilder.AlterColumn<float>(
name: "rotor_speed",
table: "t_telemetry_data_saub",
type: "real",
nullable: true,
comment: "Обороты ротора",
oldClrType: typeof(float),
oldType: "real",
oldComment: "Обороты ротора");
migrationBuilder.AlterColumn<float>(
name: "pressure",
table: "t_telemetry_data_saub",
type: "real",
nullable: true,
comment: "Давление",
oldClrType: typeof(float),
oldType: "real",
oldComment: "Давление");
migrationBuilder.AlterColumn<short>(
name: "mode",
table: "t_telemetry_data_saub",
type: "smallint",
nullable: true,
comment: "Режим САУБ",
oldClrType: typeof(short),
oldType: "smallint",
oldComment: "Режим САУБ");
migrationBuilder.AlterColumn<float>(
name: "hook_weight",
table: "t_telemetry_data_saub",
type: "real",
nullable: true,
comment: "Вес на крюке",
oldClrType: typeof(float),
oldType: "real",
oldComment: "Вес на крюке");
migrationBuilder.AlterColumn<float>(
name: "block_position",
table: "t_telemetry_data_saub",
type: "real",
nullable: true,
comment: "Высота талевого блока",
oldClrType: typeof(float),
oldType: "real",
oldComment: "Высота талевого блока");
migrationBuilder.AlterColumn<float>(
name: "bit_depth",
table: "t_telemetry_data_saub",
type: "real",
nullable: true,
comment: "Положение инструмента",
oldClrType: typeof(float),
oldType: "real",
oldComment: "Положение инструмента");
migrationBuilder.AlterColumn<float>(
name: "axial_load",
table: "t_telemetry_data_saub",
type: "real",
nullable: true,
comment: "Осевая нагрузка",
oldClrType: typeof(float),
oldType: "real",
oldComment: "Осевая нагрузка");
}
}
}

View File

@ -4751,7 +4751,7 @@ namespace AsbCloudDb.Migrations
.HasColumnName("date") .HasColumnName("date")
.HasComment("'2021-10-19 18:23:54+05'"); .HasComment("'2021-10-19 18:23:54+05'");
b.Property<float?>("AxialLoad") b.Property<float>("AxialLoad")
.HasColumnType("real") .HasColumnType("real")
.HasColumnName("axial_load") .HasColumnName("axial_load")
.HasComment("Осевая нагрузка"); .HasComment("Осевая нагрузка");
@ -4766,12 +4766,12 @@ namespace AsbCloudDb.Migrations
.HasColumnName("axial_load_sp") .HasColumnName("axial_load_sp")
.HasComment("Осевая нагрузка. Задание"); .HasComment("Осевая нагрузка. Задание");
b.Property<float?>("BitDepth") b.Property<float>("BitDepth")
.HasColumnType("real") .HasColumnType("real")
.HasColumnName("bit_depth") .HasColumnName("bit_depth")
.HasComment("Положение инструмента"); .HasComment("Положение инструмента");
b.Property<float?>("BlockPosition") b.Property<float>("BlockPosition")
.HasColumnType("real") .HasColumnType("real")
.HasColumnName("block_position") .HasColumnName("block_position")
.HasComment("Высота талевого блока"); .HasComment("Высота талевого блока");
@ -4826,7 +4826,7 @@ namespace AsbCloudDb.Migrations
.HasColumnName("flow_idle") .HasColumnName("flow_idle")
.HasComment("Расход. Холостой ход"); .HasComment("Расход. Холостой ход");
b.Property<float?>("HookWeight") b.Property<float>("HookWeight")
.HasColumnType("real") .HasColumnType("real")
.HasColumnName("hook_weight") .HasColumnName("hook_weight")
.HasComment("Вес на крюке"); .HasComment("Вес на крюке");
@ -4856,7 +4856,7 @@ namespace AsbCloudDb.Migrations
.HasColumnName("id_user") .HasColumnName("id_user")
.HasComment("Пользователь САУБ"); .HasComment("Пользователь САУБ");
b.Property<short?>("Mode") b.Property<short>("Mode")
.HasColumnType("smallint") .HasColumnType("smallint")
.HasColumnName("mode") .HasColumnName("mode")
.HasComment("Режим САУБ"); .HasComment("Режим САУБ");
@ -4871,7 +4871,7 @@ namespace AsbCloudDb.Migrations
.HasColumnName("mse_state") .HasColumnName("mse_state")
.HasComment("Текущее состояние работы MSE"); .HasComment("Текущее состояние работы MSE");
b.Property<float?>("Pressure") b.Property<float>("Pressure")
.HasColumnType("real") .HasColumnType("real")
.HasColumnName("pressure") .HasColumnName("pressure")
.HasComment("Давление"); .HasComment("Давление");
@ -4921,12 +4921,12 @@ namespace AsbCloudDb.Migrations
.HasColumnName("pump2_flow") .HasColumnName("pump2_flow")
.HasComment("Расход. Буровой насос 3"); .HasComment("Расход. Буровой насос 3");
b.Property<float?>("RotorSpeed") b.Property<float>("RotorSpeed")
.HasColumnType("real") .HasColumnType("real")
.HasColumnName("rotor_speed") .HasColumnName("rotor_speed")
.HasComment("Обороты ротора"); .HasComment("Обороты ротора");
b.Property<float?>("RotorTorque") b.Property<float>("RotorTorque")
.HasColumnType("real") .HasColumnType("real")
.HasColumnName("rotor_torque") .HasColumnName("rotor_torque")
.HasComment("Момент на роторе"); .HasComment("Момент на роторе");
@ -4946,7 +4946,7 @@ namespace AsbCloudDb.Migrations
.HasColumnName("rotor_torque_sp") .HasColumnName("rotor_torque_sp")
.HasComment("Момент на роторе. Задание"); .HasComment("Момент на роторе. Задание");
b.Property<float?>("WellDepth") b.Property<float>("WellDepth")
.HasColumnType("real") .HasColumnType("real")
.HasColumnName("well_depth") .HasColumnName("well_depth")
.HasComment("Глубина забоя"); .HasComment("Глубина забоя");

View File

@ -18,7 +18,7 @@ namespace AsbCloudDb.Model
public DateTimeOffset DateTime { get; set; } public DateTimeOffset DateTime { get; set; }
[Column("mode"), Comment("Режим САУБ")] [Column("mode"), Comment("Режим САУБ")]
public short? Mode { get; set; } public short Mode { get; set; }
[Column("id_feed_regulator"), Comment("Текущий критерий бурения")] [Column("id_feed_regulator"), Comment("Текущий критерий бурения")]
public short? IdFeedRegulator { get; set; } public short? IdFeedRegulator { get; set; }
@ -27,13 +27,13 @@ namespace AsbCloudDb.Model
public short? MseState { get; set; } public short? MseState { get; set; }
[Column("well_depth"), Comment("Глубина забоя")] [Column("well_depth"), Comment("Глубина забоя")]
public float? WellDepth { get; set; } public float WellDepth { get; set; }
[Column("bit_depth"), Comment("Положение инструмента")] [Column("bit_depth"), Comment("Положение инструмента")]
public float? BitDepth { get; set; } public float BitDepth { get; set; }
[Column("block_position"), Comment("Высота талевого блока")] [Column("block_position"), Comment("Высота талевого блока")]
public float? BlockPosition { get; set; } public float BlockPosition { get; set; }
[Column("block_position_min"), Comment("Талевый блок. Мин положение")] [Column("block_position_min"), Comment("Талевый блок. Мин положение")]
public float? BlockPositionMin { get; set; } public float? BlockPositionMin { get; set; }
@ -57,7 +57,7 @@ namespace AsbCloudDb.Model
public float? BlockSpeedSpDevelop { get; set; } public float? BlockSpeedSpDevelop { get; set; }
[Column("pressure"), Comment("Давление")] [Column("pressure"), Comment("Давление")]
public float? Pressure { get; set; } public float Pressure { get; set; }
[Column("pressure_idle"), Comment("Давление. Холостой ход")] [Column("pressure_idle"), Comment("Давление. Холостой ход")]
public float? PressureIdle { get; set; } public float? PressureIdle { get; set; }
@ -78,7 +78,7 @@ namespace AsbCloudDb.Model
public float? PressureDeltaLimitMax { get; set; } public float? PressureDeltaLimitMax { get; set; }
[Column("axial_load"), Comment("Осевая нагрузка")] [Column("axial_load"), Comment("Осевая нагрузка")]
public float? AxialLoad { get; set; } public float AxialLoad { get; set; }
[Column("axial_load_sp"), Comment("Осевая нагрузка. Задание")] [Column("axial_load_sp"), Comment("Осевая нагрузка. Задание")]
public float? AxialLoadSp { get; set; } public float? AxialLoadSp { get; set; }
@ -87,7 +87,7 @@ namespace AsbCloudDb.Model
public float? AxialLoadLimitMax { get; set; } public float? AxialLoadLimitMax { get; set; }
[Column("hook_weight"), Comment("Вес на крюке")] [Column("hook_weight"), Comment("Вес на крюке")]
public float? HookWeight { get; set; } public float HookWeight { get; set; }
[Column("hook_weight_idle"), Comment("Вес на крюке. Холостой ход")] [Column("hook_weight_idle"), Comment("Вес на крюке. Холостой ход")]
public float? HookWeightIdle { get; set; } public float? HookWeightIdle { get; set; }
@ -99,7 +99,7 @@ namespace AsbCloudDb.Model
public float? HookWeightLimitMax { get; set; } public float? HookWeightLimitMax { get; set; }
[Column("rotor_torque"), Comment("Момент на роторе")] [Column("rotor_torque"), Comment("Момент на роторе")]
public float? RotorTorque { get; set; } public float RotorTorque { get; set; }
[Column("rotor_torque_idle"), Comment("Момент на роторе. Холостой ход")] [Column("rotor_torque_idle"), Comment("Момент на роторе. Холостой ход")]
public float? RotorTorqueIdle { get; set; } public float? RotorTorqueIdle { get; set; }
@ -111,7 +111,7 @@ namespace AsbCloudDb.Model
public float? RotorTorqueLimitMax { get; set; } public float? RotorTorqueLimitMax { get; set; }
[Column("rotor_speed"), Comment("Обороты ротора")] [Column("rotor_speed"), Comment("Обороты ротора")]
public float? RotorSpeed { get; set; } public float RotorSpeed { get; set; }
[Column("flow"), Comment("Расход")] [Column("flow"), Comment("Расход")]
public float? Flow { get; set; } public float? Flow { get; set; }

View File

@ -0,0 +1,34 @@
using AsbCloudApp.Services;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Background
{
/// <summary>
/// Задача по удалению загруженных отчетов
/// </summary>
public class WorkToDeleteOldReports : Work
{
public WorkToDeleteOldReports()
: base("work to delete reports older than 30 days")
{
Timeout = TimeSpan.FromMinutes(10);
}
/// <summary>
/// Удаление отчетов, загруженных ранее 30 дней от текущей даты
/// </summary>
/// <param name="id"></param>
/// <param name="services"></param>
/// <param name="onProgressCallback"></param>
/// <param name="token"></param>
/// <returns></returns>
protected override async Task Action(string id, IServiceProvider services, Action<string, double?> onProgressCallback, CancellationToken token)
{
var reportService = services.GetRequiredService<IReportService>();
await reportService.DeleteAllOldReportsAsync(TimeSpan.FromDays(30), token);
}
}
}

View File

@ -147,17 +147,17 @@ namespace AsbCloudInfrastructure.Repository
public async Task<IEnumerable<FileInfoDto>> DeleteAsync(IEnumerable<int> ids, CancellationToken token) public async Task<IEnumerable<FileInfoDto>> DeleteAsync(IEnumerable<int> ids, CancellationToken token)
{ {
var query = dbSetConfigured var query = dbSetConfigured
.Where(f => ids.Contains(f.Id) && f.IsDeleted); .Where(f => ids.Contains(f.Id));
var files = await query.ToListAsync(token); var files = await query.ToListAsync(token);
var filesDtos = files.Select(x => Convert(x)); var filesDtos = files.Select(x => Convert(x));
db.Files.RemoveRange(query); db.Files.RemoveRange(query);
await db.SaveChangesAsync(token).ConfigureAwait(false); await db.SaveChangesAsync(token).ConfigureAwait(false);
return filesDtos; return filesDtos;
} }
public async Task<FileInfoDto> GetByMarkId(int idMark, CancellationToken token) public async Task<FileInfoDto> GetByMarkId(int idMark, CancellationToken token)
{ {

View File

@ -95,12 +95,12 @@ public class WorkOperationDetection: Work
{ {
DateTime = d.DateTime, DateTime = d.DateTime,
IdUser = d.IdUser, IdUser = d.IdUser,
WellDepth = d.WellDepth ?? float.NaN, WellDepth = d.WellDepth,
Pressure = d.Pressure ?? float.NaN, Pressure = d.Pressure,
HookWeight = d.HookWeight ?? float.NaN, HookWeight = d.HookWeight,
BlockPosition = d.BlockPosition ?? float.NaN, BlockPosition = d.BlockPosition,
BitDepth = d.BitDepth ?? float.NaN, BitDepth = d.BitDepth,
RotorSpeed = d.RotorSpeed ?? float.NaN, RotorSpeed = d.RotorSpeed,
}) })
.OrderBy(d => d.DateTime); .OrderBy(d => d.DateTime);

View File

@ -20,20 +20,23 @@ namespace AsbCloudInfrastructure.Services
{ {
private readonly IAsbCloudDbContext db; private readonly IAsbCloudDbContext db;
private readonly ITelemetryService telemetryService; private readonly ITelemetryService telemetryService;
private readonly FileService fileService;
private readonly IWellService wellService; private readonly IWellService wellService;
private readonly BackgroundWorker backgroundWorkerService; private readonly BackgroundWorker backgroundWorkerService;
public int ReportCategoryId { get; private set; } public int ReportCategoryId { get; private set; }
public ReportService(IAsbCloudDbContext db, public ReportService(IAsbCloudDbContext db,
ITelemetryService telemetryService, ITelemetryService telemetryService,
IWellService wellService, IWellService wellService,
FileService fileService,
BackgroundWorker backgroundWorkerService) BackgroundWorker backgroundWorkerService)
{ {
this.db = db; this.db = db;
this.wellService = wellService; this.wellService = wellService;
this.backgroundWorkerService = backgroundWorkerService; this.backgroundWorkerService = backgroundWorkerService;
this.telemetryService = telemetryService; this.telemetryService = telemetryService;
this.fileService = fileService;
ReportCategoryId = db.FileCategories ReportCategoryId = db.FileCategories
.AsNoTracking() .AsNoTracking()
.First(c => c.Name.Equals("Рапорт")) .First(c => c.Name.Equals("Рапорт"))
@ -69,7 +72,7 @@ namespace AsbCloudInfrastructure.Services
progressHandler.Invoke(arg, id); progressHandler.Invoke(arg, id);
}; };
generator.Make(reportFileName); generator.Make(reportFileName);
var fileInfo = (await fileService.MoveAsync(idWell, idUser, ReportCategoryId, reportFileName, reportFileName, token))!; var fileInfo = (await fileService.MoveAsync(idWell, idUser, ReportCategoryId, reportFileName, reportFileName, token))!;
progressHandler.Invoke(new progressHandler.Invoke(new
@ -186,6 +189,16 @@ namespace AsbCloudInfrastructure.Services
return generator; return generator;
} }
}
public async Task<int> DeleteAllOldReportsAsync(TimeSpan lifetime, CancellationToken token)
{
var lifeTimeStartDate = DateTime.UtcNow.Date - lifetime;
var fileIds = await db.ReportProperties
.Where(r => r.File.UploadDate.Date < lifeTimeStartDate)
.Select(r => r.IdFile)
.ToArrayAsync(token);
return await fileService.DeleteAsync(fileIds, token);
}
}
} }

View File

@ -44,37 +44,37 @@ namespace AsbCloudInfrastructure.Services.SAUB
.Where(t => t.BlockPosition > 0.0001) .Where(t => t.BlockPosition > 0.0001)
.Where(t => t.WellDepth > 0.0001) .Where(t => t.WellDepth > 0.0001)
.Where(t => t.Mode != null) .Where(t => t.Mode != null)
.Where(t => modes.Contains(t.Mode!.Value)) .Where(t => modes.Contains(t.Mode))
.Where(t => t.WellDepth - t.BitDepth < 0.01) .Where(t => t.WellDepth - t.BitDepth < 0.01)
.GroupBy(t => new { .GroupBy(t => new {
t.DateTime.Hour, t.DateTime.Hour,
WellDepthX10 = Math.Truncate(t.WellDepth!.Value * 10), WellDepthX10 = Math.Truncate(t.WellDepth * 10),
t.Mode, t.Mode,
t.IdFeedRegulator}) t.IdFeedRegulator})
.Select(g => new TelemetryDataSaubStatDto .Select(g => new TelemetryDataSaubStatDto
{ {
Count = g.Count(), Count = g.Count(),
IdMode = g.Key.Mode??0, IdMode = g.Key.Mode,
IdFeedRegulator = g.Key.IdFeedRegulator, IdFeedRegulator = g.Key.IdFeedRegulator,
DateMin = DateTime.SpecifyKind(g.Min(t => t.DateTime.UtcDateTime) + timezoneOffset, DateTimeKind.Unspecified), DateMin = DateTime.SpecifyKind(g.Min(t => t.DateTime.UtcDateTime) + timezoneOffset, DateTimeKind.Unspecified),
DateMax = DateTime.SpecifyKind(g.Max(t => t.DateTime.UtcDateTime) + timezoneOffset, DateTimeKind.Unspecified), DateMax = DateTime.SpecifyKind(g.Max(t => t.DateTime.UtcDateTime) + timezoneOffset, DateTimeKind.Unspecified),
WellDepthMin = g.Min(t => t.WellDepth!.Value), WellDepthMin = g.Min(t => t.WellDepth),
WellDepthMax = g.Max(t => t.WellDepth!.Value), WellDepthMax = g.Max(t => t.WellDepth),
Pressure = g.Average(t => t.Pressure!.Value), Pressure = g.Average(t => t.Pressure),
PressureSp = g.Average(t => t.PressureSp!.Value), PressureSp = g.Average(t => t.PressureSp!.Value),
PressureIdle = g.Average(t => t.PressureIdle!.Value), PressureIdle = g.Average(t => t.PressureIdle!.Value),
PressureDeltaLimitMax = g.Average(t => t.PressureDeltaLimitMax!.Value), PressureDeltaLimitMax = g.Average(t => t.PressureDeltaLimitMax!.Value),
PressureDelta = g.Average(t => t.Pressure!.Value - t.PressureIdle!.Value), PressureDelta = g.Average(t => t.Pressure - t.PressureIdle!.Value),
PressureSpDelta = g.Average(t => t.PressureSp!.Value - t.PressureIdle!.Value), PressureSpDelta = g.Average(t => t.PressureSp!.Value - t.PressureIdle!.Value),
AxialLoad = g.Average(t => t.AxialLoad!.Value), AxialLoad = g.Average(t => t.AxialLoad),
AxialLoadSp = g.Average(t => t.AxialLoadSp!.Value), AxialLoadSp = g.Average(t => t.AxialLoadSp!.Value),
AxialLoadLimitMax = g.Average(t => t.AxialLoadLimitMax!.Value), AxialLoadLimitMax = g.Average(t => t.AxialLoadLimitMax!.Value),
RotorTorque = g.Average(t => t.RotorTorque!.Value), RotorTorque = g.Average(t => t.RotorTorque),
RotorTorqueSp = g.Average(t => t.RotorTorqueSp!.Value), RotorTorqueSp = g.Average(t => t.RotorTorqueSp!.Value),
RotorTorqueLimitMax = g.Average(t => t.RotorTorqueLimitMax!.Value), RotorTorqueLimitMax = g.Average(t => t.RotorTorqueLimitMax!.Value),

View File

@ -279,11 +279,11 @@ public class WorkSubsystemOperationTimeCalc : Work
.Where(d => d.DateTime <= dateEnd) .Where(d => d.DateTime <= dateEnd)
.Where(d => d.WellDepth != null) .Where(d => d.WellDepth != null)
.Where(d => d.WellDepth > 0) .Where(d => d.WellDepth > 0)
.GroupBy(d => Math.Ceiling(d.WellDepth ?? 0 * 10)) .GroupBy(d => Math.Ceiling(d.WellDepth * 10))
.Select(g => new .Select(g => new
{ {
DateMin = g.Min(d => d.DateTime), DateMin = g.Min(d => d.DateTime),
DepthMin = g.Min(d => d.WellDepth) ?? 0, DepthMin = g.Min(d => d.WellDepth),
}) })
.OrderBy(i => i.DateMin) .OrderBy(i => i.DateMin)
.ToArrayAsync(token); .ToArrayAsync(token);

View File

@ -29,6 +29,7 @@ namespace AsbCloudInfrastructure
_ = provider.GetRequiredService<ITelemetryDataCache<TelemetryDataSpinDto>>(); _ = provider.GetRequiredService<ITelemetryDataCache<TelemetryDataSpinDto>>();
var backgroundWorker = provider.GetRequiredService<PeriodicBackgroundWorker>(); var backgroundWorker = provider.GetRequiredService<PeriodicBackgroundWorker>();
backgroundWorker.Add<WorkToDeleteOldReports>(TimeSpan.FromDays(1));
backgroundWorker.Add<WellInfoService.WorkWellInfoUpdate>(TimeSpan.FromMinutes(30)); backgroundWorker.Add<WellInfoService.WorkWellInfoUpdate>(TimeSpan.FromMinutes(30));
backgroundWorker.Add<WorkOperationDetection>(TimeSpan.FromMinutes(15)); backgroundWorker.Add<WorkOperationDetection>(TimeSpan.FromMinutes(15));
backgroundWorker.Add<WorkSubsystemOperationTimeCalc>(TimeSpan.FromMinutes(30)); backgroundWorker.Add<WorkSubsystemOperationTimeCalc>(TimeSpan.FromMinutes(30));

View File

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<ServerGarbageCollection>true</ServerGarbageCollection> <ServerGarbageCollection>true</ServerGarbageCollection>
<NoWarn>$(NoWarn);1591</NoWarn> <NoWarn>$(NoWarn);1591</NoWarn>
<UserSecretsId>80899ceb-210f-4f19-ac56-aa90a5d666d4</UserSecretsId> <UserSecretsId>80899ceb-210f-4f19-ac56-aa90a5d666d4</UserSecretsId>
@ -14,6 +14,7 @@
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="6.0.8" /> <PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="6.0.8" />
<PackageReference Include="protobuf-net" Version="3.1.17" /> <PackageReference Include="protobuf-net" Version="3.1.17" />
<PackageReference Include="protobuf-net.AspNetCore" Version="3.1.17" /> <PackageReference Include="protobuf-net.AspNetCore" Version="3.1.17" />
<PackageReference Include="SignalRSwaggerGen" Version="4.4.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.4.0" /> <PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.4.0" />
</ItemGroup> </ItemGroup>

View File

@ -5,6 +5,7 @@ using AsbCloudApp.Repositories;
using AsbCloudApp.Requests; using AsbCloudApp.Requests;
using AsbCloudApp.Services; using AsbCloudApp.Services;
using AsbCloudWebApi.SignalR; using AsbCloudWebApi.SignalR;
using AsbCloudWebApi.SignalR.Clients;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@ -28,16 +29,15 @@ public class DrillTestController : ControllerBase
private readonly IDrillTestRepository drillTestRepository; private readonly IDrillTestRepository drillTestRepository;
private readonly IWellService wellService; private readonly IWellService wellService;
private readonly ITelemetryService telemetryService; private readonly ITelemetryService telemetryService;
private readonly IHubContext<TelemetryHub> telemetryHubContext; private readonly IHubContext<TelemetryHub, ITelemetryHubClient> telemetryHubContext;
public string SignalRMethodGetDataName { get; protected set; } = "ReceiveDrilltestData";
public DrillTestController( public DrillTestController(
IDrillTestReportService drillTestReportService, IDrillTestReportService drillTestReportService,
IDrillTestRepository drillTestRepository, IDrillTestRepository drillTestRepository,
IWellService wellService, IWellService wellService,
ITelemetryService telemetryService, ITelemetryService telemetryService,
IHubContext<TelemetryHub> telemetryHubContext) IHubContext<TelemetryHub, ITelemetryHubClient> telemetryHubContext)
{ {
this.drillTestReportService = drillTestReportService; this.drillTestReportService = drillTestReportService;
this.drillTestRepository = drillTestRepository; this.drillTestRepository = drillTestRepository;
@ -71,7 +71,7 @@ public class DrillTestController : ControllerBase
_ = Task.Run(async () => _ = Task.Run(async () =>
{ {
var clients = telemetryHubContext.Clients.Group($"well_{idWell}"); var clients = telemetryHubContext.Clients.Group($"well_{idWell}");
await clients.SendAsync(SignalRMethodGetDataName, dto); await clients.ReceiveDrilltestData(dto, token);
}, CancellationToken.None); }, CancellationToken.None);
return Ok(); return Ok();

View File

@ -9,6 +9,7 @@ using AsbCloudApp.Repositories;
using AsbCloudApp.Requests; using AsbCloudApp.Requests;
using AsbCloudApp.Services; using AsbCloudApp.Services;
using AsbCloudWebApi.SignalR; using AsbCloudWebApi.SignalR;
using AsbCloudWebApi.SignalR.Clients;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@ -25,7 +26,7 @@ namespace AsbCloudWebApi.Controllers.ProcessMaps;
public abstract class ProcessMapBaseController<T> : ControllerBase public abstract class ProcessMapBaseController<T> : ControllerBase
where T : ProcessMapPlanBaseDto where T : ProcessMapPlanBaseDto
{ {
private readonly IHubContext<TelemetryHub> telemetryHubContext; private readonly IHubContext<TelemetryHub, ITelemetryHubClient> telemetryHubContext;
private readonly ITelemetryService telemetryService; private readonly ITelemetryService telemetryService;
private readonly IWellService wellService; private readonly IWellService wellService;
private readonly IUserRepository userRepository; private readonly IUserRepository userRepository;
@ -36,7 +37,7 @@ public abstract class ProcessMapBaseController<T> : ControllerBase
IProcessMapPlanRepository<T> repository, IProcessMapPlanRepository<T> repository,
IUserRepository userRepository, IUserRepository userRepository,
ICrudRepository<WellSectionTypeDto> wellSectionRepository, ICrudRepository<WellSectionTypeDto> wellSectionRepository,
IHubContext<TelemetryHub> telemetryHubContext, IHubContext<TelemetryHub, ITelemetryHubClient> telemetryHubContext,
ITelemetryService telemetryService) ITelemetryService telemetryService)
{ {
this.wellService = wellService; this.wellService = wellService;
@ -204,7 +205,7 @@ public abstract class ProcessMapBaseController<T> : ControllerBase
await telemetryHubContext.Clients await telemetryHubContext.Clients
.Group($"{SignalRMethod}_{idWell}") .Group($"{SignalRMethod}_{idWell}")
.SendAsync("UpdateProcessMap", dtos, cancellationToken); .UpdateProcessMap(dtos, cancellationToken);
} }
private async Task CheckIsExistsWellSectionTypeAsync(int idWellSectionType, CancellationToken cancellationToken) private async Task CheckIsExistsWellSectionTypeAsync(int idWellSectionType, CancellationToken cancellationToken)

View File

@ -10,6 +10,7 @@ using AsbCloudApp.Services;
using AsbCloudApp.Services.ProcessMaps; using AsbCloudApp.Services.ProcessMaps;
using AsbCloudApp.Services.ProcessMaps.WellDrilling; using AsbCloudApp.Services.ProcessMaps.WellDrilling;
using AsbCloudWebApi.SignalR; using AsbCloudWebApi.SignalR;
using AsbCloudWebApi.SignalR.Clients;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR; using Microsoft.AspNetCore.SignalR;
@ -34,7 +35,7 @@ public class ProcessMapWellDrillingController : ProcessMapBaseController<Process
IProcessMapPlanImportService processMapPlanImportService, IProcessMapPlanImportService processMapPlanImportService,
IProcessMapReportWellDrillingService processMapReportWellDrillingService, IProcessMapReportWellDrillingService processMapReportWellDrillingService,
ICrudRepository<WellSectionTypeDto> wellSectionRepository, ICrudRepository<WellSectionTypeDto> wellSectionRepository,
IHubContext<TelemetryHub> telemetryHubContext, IHubContext<TelemetryHub, ITelemetryHubClient> telemetryHubContext,
ITelemetryService telemetryService) ITelemetryService telemetryService)
: base(wellService, repository, userRepository, wellSectionRepository, telemetryHubContext, telemetryService) : base(wellService, repository, userRepository, wellSectionRepository, telemetryHubContext, telemetryService)
{ {

View File

@ -3,6 +3,7 @@ using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Repositories; using AsbCloudApp.Repositories;
using AsbCloudApp.Services; using AsbCloudApp.Services;
using AsbCloudWebApi.SignalR; using AsbCloudWebApi.SignalR;
using AsbCloudWebApi.SignalR.Clients;
using Microsoft.AspNetCore.SignalR; using Microsoft.AspNetCore.SignalR;
namespace AsbCloudWebApi.Controllers.ProcessMaps; namespace AsbCloudWebApi.Controllers.ProcessMaps;
@ -16,7 +17,7 @@ public class ProcessMapWellReamController : ProcessMapBaseController<ProcessMapP
IProcessMapPlanRepository<ProcessMapPlanWellReamDto> repository, IProcessMapPlanRepository<ProcessMapPlanWellReamDto> repository,
IUserRepository userRepository, IUserRepository userRepository,
ICrudRepository<WellSectionTypeDto> wellSectionRepository, ICrudRepository<WellSectionTypeDto> wellSectionRepository,
IHubContext<TelemetryHub> telemetryHubContext, IHubContext<TelemetryHub, ITelemetryHubClient> telemetryHubContext,
ITelemetryService telemetryService) ITelemetryService telemetryService)
: base(wellService, repository, userRepository, wellSectionRepository, telemetryHubContext, telemetryService) : base(wellService, repository, userRepository, wellSectionRepository, telemetryHubContext, telemetryService)
{ {

View File

@ -8,6 +8,7 @@ using System.ComponentModel.DataAnnotations;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Requests; using AsbCloudApp.Requests;
using AsbCloudWebApi.SignalR.Clients;
namespace AsbCloudWebApi.Controllers namespace AsbCloudWebApi.Controllers
{ {
@ -21,10 +22,10 @@ namespace AsbCloudWebApi.Controllers
private readonly IReportService reportService; private readonly IReportService reportService;
private readonly FileService fileService; private readonly FileService fileService;
private readonly IWellService wellService; private readonly IWellService wellService;
private readonly IHubContext<ReportsHub> reportsHubContext; private readonly IHubContext<ReportsHub, IReportHubClient> reportsHubContext;
public ReportController(IReportService reportService, IWellService wellService, public ReportController(IReportService reportService, IWellService wellService,
FileService fileService, IHubContext<ReportsHub> reportsHubContext) FileService fileService, IHubContext<ReportsHub, IReportHubClient> reportsHubContext)
{ {
this.reportService = reportService; this.reportService = reportService;
this.fileService = fileService; this.fileService = fileService;
@ -57,13 +58,10 @@ namespace AsbCloudWebApi.Controllers
return Forbid(); return Forbid();
void HandleReportProgressAsync(object progress, string id) => void HandleReportProgressAsync(object progress, string id) =>
Task.Run(() => Task.Run(async() =>
{ {
reportsHubContext.Clients.Group($"Report_{id}").SendAsync( await reportsHubContext.Clients.Group($"Report_{id}")
nameof(IReportHubClient.GetReportProgress), .GetReportProgress(progress, token);
progress,
token
).ConfigureAwait(false);
}, token); }, token);
var id = reportService.EnqueueCreateReportWork(idWell, (int)idUser, var id = reportService.EnqueueCreateReportWork(idWell, (int)idUser,

View File

@ -2,6 +2,7 @@
using AsbCloudApp.Requests; using AsbCloudApp.Requests;
using AsbCloudApp.Services; using AsbCloudApp.Services;
using AsbCloudWebApi.SignalR; using AsbCloudWebApi.SignalR;
using AsbCloudWebApi.SignalR.Clients;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR; using Microsoft.AspNetCore.SignalR;
@ -23,22 +24,23 @@ namespace AsbCloudWebApi.Controllers.SAUB
protected readonly IWellService wellService; protected readonly IWellService wellService;
private readonly ITelemetryService telemetryService; private readonly ITelemetryService telemetryService;
private readonly ITelemetryDataService<TDto> telemetryDataService; private readonly ITelemetryDataService<TDto> telemetryDataService;
private readonly IHubContext<TelemetryHub> telemetryHubContext; protected readonly IHubContext<TelemetryHub, ITelemetryHubClient> telemetryHubContext;
public string SignalRMethodGetDataName { get; protected set; } = "ReceiveData";
public TelemetryDataBaseController( public TelemetryDataBaseController(
ITelemetryService telemetryService, ITelemetryService telemetryService,
ITelemetryDataService<TDto> telemetryDataService, ITelemetryDataService<TDto> telemetryDataService,
IWellService wellService, IWellService wellService,
IHubContext<TelemetryHub> telemetryHubContext) IHubContext<TelemetryHub, ITelemetryHubClient> telemetryHubContext)
{ {
this.telemetryService = telemetryService; this.telemetryService = telemetryService;
this.telemetryDataService = telemetryDataService; this.telemetryDataService = telemetryDataService;
this.wellService = wellService; this.wellService = wellService;
this.telemetryHubContext = telemetryHubContext; this.telemetryHubContext = telemetryHubContext;
} }
protected abstract Task SignalRNotifyAsync(int idWell, IEnumerable<TDto> dtos, CancellationToken token);
/// <summary> /// <summary>
/// Принимает данные от разных систем по скважине /// Принимает данные от разных систем по скважине
/// </summary> /// </summary>
@ -55,8 +57,7 @@ namespace AsbCloudWebApi.Controllers.SAUB
var idWell = telemetryService.GetIdWellByTelemetryUid(uid); var idWell = telemetryService.GetIdWellByTelemetryUid(uid);
if (idWell is not null && dtos.Any()) if (idWell is not null && dtos.Any())
_ = Task.Run(() => telemetryHubContext.Clients.Group($"well_{idWell}") _ = Task.Run(() => SignalRNotifyAsync(idWell.Value, dtos, CancellationToken.None));
.SendAsync(SignalRMethodGetDataName, dtos), CancellationToken.None);
return Ok(); return Ok();
} }
@ -75,7 +76,7 @@ namespace AsbCloudWebApi.Controllers.SAUB
[Permission] [Permission]
public virtual async Task<ActionResult<IEnumerable<TDto>>> GetDataAsync(int idWell, public virtual async Task<ActionResult<IEnumerable<TDto>>> GetDataAsync(int idWell,
DateTime begin = default, DateTime begin = default,
int intervalSec = 600, int intervalSec = 600,
int approxPointsCount = 1024, int approxPointsCount = 1024,
//TODO: сделать cancellationToken обязательным //TODO: сделать cancellationToken обязательным
CancellationToken token = default) CancellationToken token = default)

View File

@ -1,12 +1,14 @@
using AsbCloudApp.Data.SAUB; using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Services; using AsbCloudApp.Services;
using AsbCloudWebApi.SignalR; using AsbCloudWebApi.SignalR;
using AsbCloudWebApi.SignalR.Clients;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR; using Microsoft.AspNetCore.SignalR;
using System.Threading.Tasks;
using System.Threading;
using System; using System;
using Microsoft.AspNetCore.Http; using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudWebApi.Controllers.SAUB namespace AsbCloudWebApi.Controllers.SAUB
{ {
@ -23,14 +25,13 @@ namespace AsbCloudWebApi.Controllers.SAUB
ITelemetryService telemetryService, ITelemetryService telemetryService,
ITelemetryDataSaubService telemetryDataService, ITelemetryDataSaubService telemetryDataService,
IWellService wellService, IWellService wellService,
IHubContext<TelemetryHub> telemetryHubContext) IHubContext<TelemetryHub, ITelemetryHubClient> telemetryHubContext)
: base( : base(
telemetryService, telemetryService,
telemetryDataService, telemetryDataService,
wellService, wellService,
telemetryHubContext) telemetryHubContext)
{ {
SignalRMethodGetDataName = "ReceiveDataSaub";
telemetryDataSaubService = telemetryDataService; telemetryDataSaubService = telemetryDataService;
} }
@ -62,5 +63,10 @@ namespace AsbCloudWebApi.Controllers.SAUB
var fileName = $"DataSaub idWell{idWell} {beginDate:yyyy-MM-DDTHH-mm} - {endDate:yyyy-MM-DDTHH-mm}.zip"; var fileName = $"DataSaub idWell{idWell} {beginDate:yyyy-MM-DDTHH-mm} - {endDate:yyyy-MM-DDTHH-mm}.zip";
return File(stream, "application/octet-stream", fileName); return File(stream, "application/octet-stream", fileName);
} }
protected override Task SignalRNotifyAsync(int idWell, IEnumerable<TelemetryDataSaubDto> dtos, CancellationToken token)
{
return telemetryHubContext.Clients.Group($"well_{idWell}").ReceiveDataSaub(dtos, token);
}
} }
} }

View File

@ -1,8 +1,12 @@
using AsbCloudApp.Data.SAUB; using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Services; using AsbCloudApp.Services;
using AsbCloudWebApi.SignalR; using AsbCloudWebApi.SignalR;
using AsbCloudWebApi.SignalR.Clients;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR; using Microsoft.AspNetCore.SignalR;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudWebApi.Controllers.SAUB namespace AsbCloudWebApi.Controllers.SAUB
{ {
@ -17,14 +21,17 @@ namespace AsbCloudWebApi.Controllers.SAUB
ITelemetryService telemetryService, ITelemetryService telemetryService,
ITelemetryDataService<TelemetryDataSpinDto> telemetryDataService, ITelemetryDataService<TelemetryDataSpinDto> telemetryDataService,
IWellService wellService, IWellService wellService,
IHubContext<TelemetryHub> telemetryHubContext) IHubContext<TelemetryHub, ITelemetryHubClient> telemetryHubContext)
: base( : base(
telemetryService, telemetryService,
telemetryDataService, telemetryDataService,
wellService, wellService,
telemetryHubContext) telemetryHubContext)
{}
protected override Task SignalRNotifyAsync(int idWell, IEnumerable<TelemetryDataSpinDto> dtos, CancellationToken token)
{ {
SignalRMethodGetDataName = "ReceiveDataSpin"; return telemetryHubContext.Clients.Group($"well_{idWell}").ReceiveDataSpin(dtos, token);
} }
} }
} }

View File

@ -0,0 +1,13 @@
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using System.Linq;
namespace AsbCloudWebApi.Conventions
{
public class ApiExplorerGroupPerVersionConvention : IControllerModelConvention
{
public void Apply(ControllerModel controller)
{
controller.ApiExplorer.GroupName = "v1";
}
}
}

View File

@ -19,6 +19,7 @@ using AsbCloudWebApi.SignalR;
using AsbCloudWebApi.SignalR.Services; using AsbCloudWebApi.SignalR.Services;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Any;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace AsbCloudWebApi namespace AsbCloudWebApi
{ {
@ -46,6 +47,7 @@ namespace AsbCloudWebApi
}); });
c.SwaggerDoc("v1", new OpenApiInfo { Title = "ASB cloud web api", Version = "v1" }); c.SwaggerDoc("v1", new OpenApiInfo { Title = "ASB cloud web api", Version = "v1" });
c.SwaggerDoc("signalr", new OpenApiInfo { Title = "SignalR client methods", Version = "signalr" });
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme 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'", Description = @"JWT Authorization header using the Bearer scheme. Enter 'Bearer' [space] and then your token in the text input below. Example: 'Bearer 12345abcdef'",
@ -78,6 +80,13 @@ namespace AsbCloudWebApi
var includeControllerXmlComment = true; var includeControllerXmlComment = true;
c.IncludeXmlComments(xmlPath, includeControllerXmlComment); c.IncludeXmlComments(xmlPath, includeControllerXmlComment);
c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "AsbCloudApp.xml"), includeControllerXmlComment); c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "AsbCloudApp.xml"), includeControllerXmlComment);
c.AddSignalRSwaggerGen(options => {
options.DisplayInDocument("signalr");
options.UseHubXmlCommentsSummaryAsTagDescription = true;
options.UseHubXmlCommentsSummaryAsTag = true;
options.UseXmlComments(xmlPath);
});
}); });
} }

View File

@ -0,0 +1,161 @@
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
# multi_accept on;
}
http {
proxy_cache_path /home/asb/web-content/cache keys_zone=map-cache:1024m;
server{
listen 5085;
charset UTF-8;
location / {
root /home/asb/public_files;
autoindex on;
autoindex_exact_size off;
autoindex_format html;
autoindex_localtime on;
}
}
server {
listen 5090;
proxy_buffering on;
proxy_buffer_size 1M;
proxy_buffers 48 1M;
proxy_cache_lock on;
proxy_cache_lock_age 5s;
proxy_http_version 1.1;
proxy_cache_valid 200 61d;
proxy_cache_use_stale error timeout;
#путь до папки с ui-проектом в файловой системе
root /home/asb/AsbCloudUI;
index index.html;
location / {
try_files $uri /index.html;
}
#запрос, начинающийся с /api или /auth или /hubs
location ~ ^/(api|auth|hubs)/ {
#адрес, на который будут пересылаться запросы от клиентов
proxy_pass http://127.0.0.1:5000;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /swagger/ {
proxy_pass http://127.0.0.1:5000/swagger/;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /favicon.ico {
alias /home/asb/web-content/images/favicon.ico;
add_header Cache-Control "public";
expires 4h;
}
location /config.json {
alias /home/asb/web-content/config.json;
add_header Cache-Control "public";
expires 4h;
}
location /images/ {
root /home/asb/web-content;
add_header Cache-Control "public";
expires 4h;
}
location /map/a/ {
proxy_pass https://a.tile.openstreetmap.org/;
proxy_cache map-cache;
proxy_cache_key $request_uri;
}
location /map/b/ {
proxy_pass https://b.tile.openstreetmap.org/;
proxy_cache map-cache;
proxy_cache_key $request_uri;
}
location /map/c/ {
proxy_pass https://c.tile.openstreetmap.org/;
proxy_cache map-cache;
proxy_cache_key $request_uri;
}
location /map/ {
proxy_pass https://b.tile.openstreetmap.org/;
proxy_cache map-cache;
proxy_cache_key $request_uri;
}
}
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# SSL Settings
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
# gzip_vary on;
# gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}

View File

@ -1,6 +1,6 @@
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Org.BouncyCastle.Asn1.Ocsp; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace AsbCloudWebApi.Middlewares namespace AsbCloudWebApi.Middlewares
@ -18,10 +18,11 @@ namespace AsbCloudWebApi.Middlewares
public async Task InvokeAsync(HttpContext context) public async Task InvokeAsync(HttpContext context)
{ {
var service = context.RequestServices.GetRequiredService<AsbCloudApp.Services.IRequerstTrackerService>(); var service = context.RequestServices.GetRequiredService<AsbCloudApp.Services.IRequerstTrackerService>();
var clientIp = context.Request.Headers["X-Real-IP"].FirstOrDefault();
var requestLog = new AsbCloudApp.Data.RequestLogDto var requestLog = new AsbCloudApp.Data.RequestLogDto
{ {
UserLogin = context.User.Identity?.Name ?? string.Empty, UserLogin = context.User.Identity?.Name ?? string.Empty,
UserIp = context.Connection?.RemoteIpAddress?.ToString(), UserIp = clientIp ?? context.Connection?.RemoteIpAddress?.ToString(),
RequestMethod = context.Request.Method, RequestMethod = context.Request.Method,
RequestPath = context.Request.Path.Value, RequestPath = context.Request.Path.Value,
RequestContentLength = context.Request.ContentLength, RequestContentLength = context.Request.ContentLength,

View File

@ -1,9 +1,10 @@
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR; using Microsoft.AspNetCore.SignalR;
namespace AsbCloudWebApi.SignalR; namespace AsbCloudWebApi.SignalR;
public abstract class BaseHub : Hub public abstract class BaseHub<T> : Hub<T> where T : class
{ {
public virtual Task AddToGroup(string groupName) => public virtual Task AddToGroup(string groupName) =>
Groups.AddToGroupAsync(Context.ConnectionId, groupName); Groups.AddToGroupAsync(Context.ConnectionId, groupName);
@ -11,9 +12,3 @@ public abstract class BaseHub : Hub
public virtual Task RemoveFromGroup(string groupName) => public virtual Task RemoveFromGroup(string groupName) =>
Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName); Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
} }
public abstract class BaseHub<T> : BaseHub
where T : class
{
}

View File

@ -0,0 +1,23 @@
using AsbCloudWebApi.SignalR.Messages;
using SignalRSwaggerGen.Attributes;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudWebApi.SignalR.Clients
{
/// <summary>
/// Hub по работе с уведомлениями
/// </summary>
[SignalRHub]
public interface INotificationHubClient
{
/// <summary>
/// Отправка клиенту сообщения с уведомлением.
/// Для подписки на метод необходимо отправить connectionId
/// </summary>
/// <param name="message">сообщение с уведомлением</param>
/// <param name="token"></param>
/// <returns></returns>
Task ReceiveNotifications(NotificationMessage message, CancellationToken token);
}
}

View File

@ -0,0 +1,22 @@
using SignalRSwaggerGen.Attributes;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudWebApi.SignalR.Clients
{
/// <summary>
/// Hub по работе с отчетами
/// </summary>
[SignalRHub]
public interface IReportHubClient
{
/// <summary>
/// Отправка клиенту сообщения о статусе формирования отчета.
/// Для подписки на метод необходимо отправить сообщение в формате $"Report_{id}"
/// </summary>
/// <param name="progress">статус формирования отчета</param>
/// <param name="token"></param>
/// <returns></returns>
Task GetReportProgress(object progress, CancellationToken token);
}
}

View File

@ -0,0 +1,52 @@
using AsbCloudApp.Data.SAUB;
using SignalRSwaggerGen.Attributes;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudWebApi.SignalR.Clients
{
/// <summary>
/// Hub по работе с телеметрией
/// </summary>
[SignalRHub]
public interface ITelemetryHubClient
{
/// <summary>
/// Отправка клиенту уведомления о доставке с панели drill test данных.
/// Для подписки на метод необходимо отправить сообщение в формате $"well_{idWell}"
/// </summary>
/// <param name="dto"></param>
/// <param name="token"></param>
/// <returns></returns>
Task ReceiveDrilltestData(DrillTestDto dto, CancellationToken token);
/// <summary>
///
/// </summary>
/// <param name="dtos"></param>
/// <param name="token"></param>
/// <returns></returns>
Task UpdateProcessMap(IEnumerable dtos, CancellationToken token);
/// <summary>
/// Отправка сауб-данных клиенту.
/// Для подписки на метод необходимо отправить сообщение в формате $"well_{idWell}"
/// </summary>
/// <param name="dtos"></param>
/// <param name="token"></param>
/// <returns></returns>
Task ReceiveDataSaub(IEnumerable<TelemetryDataSaubDto> dtos, CancellationToken token);
/// <summary>
/// Отправка спин-данных клиенту.
/// Для подписки на метод необходимо отправить сообщение в формате $"well_{idWell}"
/// </summary>
/// <param name="dtos"></param>
/// <param name="token"></param>
/// <returns></returns>
Task ReceiveDataSpin(IEnumerable<TelemetryDataSpinDto> dtos, CancellationToken token);
}
}

View File

@ -0,0 +1,23 @@
using AsbCloudApp.Data;
using SignalRSwaggerGen.Attributes;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudWebApi.SignalR.Clients
{
/// <summary>
/// Hub по работе с информацией о скважине
/// </summary>
[SignalRHub]
public interface IWellInfoHubClient
{
/// <summary>
/// Отправка клиенту сообщения об обновлении информации о скважине
/// Для подписки на метод необходимо отправить сообщение в формате $"well_info_{idWell}"
/// </summary>
/// <param name="wellInfo">информация о скважине</param>
/// <param name="token"></param>
/// <returns></returns>
Task UpdateWellInfo(object wellInfo, CancellationToken token);
}
}

View File

@ -1,7 +0,0 @@
namespace AsbCloudWebApi.SignalR
{
public interface IReportHubClient
{
float GetReportProgress(float progress);
}
}

View File

@ -2,6 +2,7 @@ using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Services.Notifications; using AsbCloudApp.Services.Notifications;
using AsbCloudWebApi.SignalR.Clients;
using AsbCloudWebApi.SignalR.Services; using AsbCloudWebApi.SignalR.Services;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@ -9,7 +10,7 @@ using Microsoft.AspNetCore.Mvc;
namespace AsbCloudWebApi.SignalR; namespace AsbCloudWebApi.SignalR;
[Authorize] [Authorize]
public class NotificationHub : BaseHub public class NotificationHub : BaseHub<INotificationHubClient>
{ {
private readonly ConnectionManagerService connectionManagerService; private readonly ConnectionManagerService connectionManagerService;
private readonly NotificationService notificationService; private readonly NotificationService notificationService;

View File

@ -1,7 +1,7 @@
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudInfrastructure.Background; using AsbCloudInfrastructure.Background;
using AsbCloudWebApi.SignalR.Clients;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -10,7 +10,10 @@ namespace AsbCloudWebApi.SignalR
{ {
// SignalR manual: // SignalR manual:
// https://docs.microsoft.com/ru-ru/aspnet/core/signalr/introduction?view=aspnetcore-5.0 // https://docs.microsoft.com/ru-ru/aspnet/core/signalr/introduction?view=aspnetcore-5.0
//[SignalRHub]
/// <summary>
/// ReportsHub
/// </summary>
[Authorize] [Authorize]
public class ReportsHub : BaseHub<IReportHubClient> public class ReportsHub : BaseHub<IReportHubClient>
{ {
@ -21,6 +24,11 @@ namespace AsbCloudWebApi.SignalR
this.backgroundWorker = backgroundWorker; this.backgroundWorker = backgroundWorker;
} }
/// <summary>
/// Добавление в группу, отправка данных о формировании отчета
/// </summary>
/// <param name="groupName"></param>
/// <returns></returns>
public override async Task AddToGroup(string groupName) public override async Task AddToGroup(string groupName)
{ {
await base.AddToGroup(groupName); await base.AddToGroup(groupName);
@ -34,19 +42,14 @@ namespace AsbCloudWebApi.SignalR
Progress = 0f, Progress = 0f,
}; };
var state = work?.CurrentState; var state = work?.CurrentState;
if (state is not null) if (state is not null)
{ {
progress.Operation = state.State; progress.Operation = state.State;
progress.Progress = (float)state.Progress; progress.Progress = (float)state.Progress;
} }
await Clients.Group(groupName).SendAsync( await Clients.Group(groupName).GetReportProgress(progress, CancellationToken.None);
nameof(IReportHubClient.GetReportProgress),
progress,
CancellationToken.None
);
} }
} }
} }

View File

@ -4,6 +4,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudApp.Repositories; using AsbCloudApp.Repositories;
using AsbCloudWebApi.SignalR.Clients;
using AsbCloudWebApi.SignalR.Messages; using AsbCloudWebApi.SignalR.Messages;
using Microsoft.AspNetCore.SignalR; using Microsoft.AspNetCore.SignalR;
@ -12,11 +13,11 @@ namespace AsbCloudWebApi.SignalR.Services;
public class NotificationPublisher public class NotificationPublisher
{ {
private readonly ConnectionManagerService connectionManagerService; private readonly ConnectionManagerService connectionManagerService;
private readonly IHubContext<NotificationHub> notificationHubContext; private readonly IHubContext<NotificationHub, INotificationHubClient> notificationHubContext;
private readonly INotificationRepository notificationRepository; private readonly INotificationRepository notificationRepository;
public NotificationPublisher(ConnectionManagerService connectionManagerService, public NotificationPublisher(ConnectionManagerService connectionManagerService,
IHubContext<NotificationHub> notificationHubContext, IHubContext<NotificationHub, INotificationHubClient> notificationHubContext,
INotificationRepository notificationRepository) INotificationRepository notificationRepository)
{ {
this.connectionManagerService = connectionManagerService; this.connectionManagerService = connectionManagerService;
@ -70,8 +71,6 @@ public class NotificationPublisher
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
await notificationHubContext.Clients.Client(connectionId) await notificationHubContext.Clients.Client(connectionId)
.SendAsync("receiveNotifications", .ReceiveNotifications(message, cancellationToken);
message,
cancellationToken);
} }
} }

View File

@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Authorization; using AsbCloudWebApi.SignalR.Clients;
using Microsoft.AspNetCore.Authorization;
namespace AsbCloudWebApi.SignalR namespace AsbCloudWebApi.SignalR
{ {
@ -6,7 +7,7 @@ namespace AsbCloudWebApi.SignalR
// https://docs.microsoft.com/ru-ru/aspnet/core/signalr/introduction?view=aspnetcore-5.0 // https://docs.microsoft.com/ru-ru/aspnet/core/signalr/introduction?view=aspnetcore-5.0
[Authorize] [Authorize]
public class TelemetryHub : BaseHub public class TelemetryHub : BaseHub<ITelemetryHubClient>
{ {
} }

View File

@ -4,17 +4,18 @@ using AsbCloudApp.IntegrationEvents;
using AsbCloudApp.IntegrationEvents.Interfaces; using AsbCloudApp.IntegrationEvents.Interfaces;
using AsbCloudApp.Services; using AsbCloudApp.Services;
using AsbCloudInfrastructure.Services; using AsbCloudInfrastructure.Services;
using AsbCloudWebApi.SignalR.Clients;
using Microsoft.AspNetCore.SignalR; using Microsoft.AspNetCore.SignalR;
namespace AsbCloudWebApi.SignalR; namespace AsbCloudWebApi.SignalR;
public class WellInfoHub : BaseHub, IIntegrationEventHandler<UpdateWellInfoEvent> public class WellInfoHub : BaseHub<IWellInfoHubClient>, IIntegrationEventHandler<UpdateWellInfoEvent>
{ {
private readonly IHubContext<WellInfoHub> hubContext; private readonly IHubContext<WellInfoHub, IWellInfoHubClient> hubContext;
private readonly IWellService wellService; private readonly IWellService wellService;
private readonly WellInfoService wellInfoService; private readonly WellInfoService wellInfoService;
public WellInfoHub(IHubContext<WellInfoHub> hubContext, public WellInfoHub(IHubContext<WellInfoHub, IWellInfoHubClient> hubContext,
IWellService wellService, IWellService wellService,
WellInfoService wellInfoService) WellInfoService wellInfoService)
{ {
@ -34,8 +35,6 @@ public class WellInfoHub : BaseHub, IIntegrationEventHandler<UpdateWellInfoEvent
public async Task HandleAsync(UpdateWellInfoEvent integrationEvent, CancellationToken cancellationToken) public async Task HandleAsync(UpdateWellInfoEvent integrationEvent, CancellationToken cancellationToken)
{ {
const string method = "update_well_info";
var well = await wellService.GetOrDefaultAsync(integrationEvent.IdWell, cancellationToken); var well = await wellService.GetOrDefaultAsync(integrationEvent.IdWell, cancellationToken);
if(well is null) if(well is null)
@ -44,7 +43,7 @@ public class WellInfoHub : BaseHub, IIntegrationEventHandler<UpdateWellInfoEvent
var wellInfo = wellInfoService.FirstOrDefault(w => w.Id == well.Id); var wellInfo = wellInfoService.FirstOrDefault(w => w.Id == well.Id);
await hubContext.Clients.Group($"well_info_{integrationEvent.IdWell}") await hubContext.Clients.Group($"well_info_{integrationEvent.IdWell}")
.SendAsync(method, new .UpdateWellInfo(new
{ {
Well = well, Well = well,
WellInfo = wellInfo WellInfo = wellInfo

View File

@ -10,6 +10,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.ResponseCompression; using Microsoft.AspNetCore.ResponseCompression;
using AsbCloudWebApi.Conventions;
namespace AsbCloudWebApi namespace AsbCloudWebApi
{ {
@ -108,6 +109,10 @@ namespace AsbCloudWebApi
options.EnableForHttps = true; options.EnableForHttps = true;
options.Providers.Add<GzipCompressionProvider>(); options.Providers.Add<GzipCompressionProvider>();
}); });
services.AddMvc(c =>
c.Conventions.Add(new ApiExplorerGroupPerVersionConvention())
);
} }
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
@ -116,6 +121,7 @@ namespace AsbCloudWebApi
app.UseSwaggerUI(c => app.UseSwaggerUI(c =>
{ {
c.SwaggerEndpoint("/swagger/v1/swagger.json", "V1"); c.SwaggerEndpoint("/swagger/v1/swagger.json", "V1");
c.SwaggerEndpoint("/swagger/signalr/swagger.json", "signalr");
c.EnablePersistAuthorization(); c.EnablePersistAuthorization();
c.EnableFilter(); c.EnableFilter();
c.DisplayOperationId(); c.DisplayOperationId();
@ -158,11 +164,6 @@ namespace AsbCloudWebApi
endpoints.MapHub<TelemetryHub>("/hubs/telemetry"); endpoints.MapHub<TelemetryHub>("/hubs/telemetry");
endpoints.MapHub<ReportsHub>("/hubs/reports"); endpoints.MapHub<ReportsHub>("/hubs/reports");
}); });
app.UseSpa(spa =>
{
spa.Options.SourcePath = "wwwroot";
});
} }
} }
} }