backend metrics implementation

This commit is contained in:
kkb 2024-01-11 10:26:08 +01:00
parent a4ed1a5956
commit 62c22d057b
69 changed files with 494 additions and 3834 deletions

View file

@ -27,8 +27,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Api", "Api", "{35BA5DCB-BEC
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Insight.Api", "src\Api\Insight.Api\Insight.Api.csproj", "{EF3188D7-338D-43DA-BF6B-D26E5BDAC3A6}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Insight.Api", "src\Api\Insight.Api\Insight.Api.csproj", "{EF3188D7-338D-43DA-BF6B-D26E5BDAC3A6}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Insight.Server", "src\Server\Insight.Server\Insight.Server.csproj", "{1E75F7E9-E6AA-44E7-A2F3-DB4CA85E0118}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Insight.Updater", "src\Updater\Insight.Updater\Insight.Updater.csproj", "{4875D70F-A96B-4EBA-99BE-218886D29BEB}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Insight.Updater", "src\Updater\Insight.Updater\Insight.Updater.csproj", "{4875D70F-A96B-4EBA-99BE-218886D29BEB}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Insight.Agent", "src\Agent\Insight.Agent\Insight.Agent.csproj", "{2A391CA2-F96B-4DB7-80AA-0668A5141640}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Insight.Agent", "src\Agent\Insight.Agent\Insight.Agent.csproj", "{2A391CA2-F96B-4DB7-80AA-0668A5141640}"
@ -41,7 +39,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Insight.Remote.Windows", "s
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Insight.Infrastructure.Web", "src\Core\Insight.Infrastructure.Web\Insight.Infrastructure.Web.csproj", "{39B81A0D-A88C-44D3-9624-1A19C78A4310}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Insight.Infrastructure.Web", "src\Core\Insight.Infrastructure.Web\Insight.Infrastructure.Web.csproj", "{39B81A0D-A88C-44D3-9624-1A19C78A4310}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Insight.Server2", "src\Server\Insight.Server2\Insight.Server2.csproj", "{9F7E88B2-7415-410C-9C31-7720596B0607}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Insight.Server", "src\Server\Insight.Server\Insight.Server.csproj", "{FCAE9C42-1DCE-4C2E-BAE0-251C147903B4}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -69,10 +67,6 @@ Global
{EF3188D7-338D-43DA-BF6B-D26E5BDAC3A6}.Debug|Any CPU.Build.0 = Debug|Any CPU {EF3188D7-338D-43DA-BF6B-D26E5BDAC3A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EF3188D7-338D-43DA-BF6B-D26E5BDAC3A6}.Release|Any CPU.ActiveCfg = Release|Any CPU {EF3188D7-338D-43DA-BF6B-D26E5BDAC3A6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EF3188D7-338D-43DA-BF6B-D26E5BDAC3A6}.Release|Any CPU.Build.0 = Release|Any CPU {EF3188D7-338D-43DA-BF6B-D26E5BDAC3A6}.Release|Any CPU.Build.0 = Release|Any CPU
{1E75F7E9-E6AA-44E7-A2F3-DB4CA85E0118}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1E75F7E9-E6AA-44E7-A2F3-DB4CA85E0118}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1E75F7E9-E6AA-44E7-A2F3-DB4CA85E0118}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1E75F7E9-E6AA-44E7-A2F3-DB4CA85E0118}.Release|Any CPU.Build.0 = Release|Any CPU
{4875D70F-A96B-4EBA-99BE-218886D29BEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4875D70F-A96B-4EBA-99BE-218886D29BEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4875D70F-A96B-4EBA-99BE-218886D29BEB}.Debug|Any CPU.Build.0 = Debug|Any CPU {4875D70F-A96B-4EBA-99BE-218886D29BEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4875D70F-A96B-4EBA-99BE-218886D29BEB}.Release|Any CPU.ActiveCfg = Release|Any CPU {4875D70F-A96B-4EBA-99BE-218886D29BEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -93,10 +87,10 @@ Global
{39B81A0D-A88C-44D3-9624-1A19C78A4310}.Debug|Any CPU.Build.0 = Debug|Any CPU {39B81A0D-A88C-44D3-9624-1A19C78A4310}.Debug|Any CPU.Build.0 = Debug|Any CPU
{39B81A0D-A88C-44D3-9624-1A19C78A4310}.Release|Any CPU.ActiveCfg = Release|Any CPU {39B81A0D-A88C-44D3-9624-1A19C78A4310}.Release|Any CPU.ActiveCfg = Release|Any CPU
{39B81A0D-A88C-44D3-9624-1A19C78A4310}.Release|Any CPU.Build.0 = Release|Any CPU {39B81A0D-A88C-44D3-9624-1A19C78A4310}.Release|Any CPU.Build.0 = Release|Any CPU
{9F7E88B2-7415-410C-9C31-7720596B0607}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FCAE9C42-1DCE-4C2E-BAE0-251C147903B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9F7E88B2-7415-410C-9C31-7720596B0607}.Debug|Any CPU.Build.0 = Debug|Any CPU {FCAE9C42-1DCE-4C2E-BAE0-251C147903B4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9F7E88B2-7415-410C-9C31-7720596B0607}.Release|Any CPU.ActiveCfg = Release|Any CPU {FCAE9C42-1DCE-4C2E-BAE0-251C147903B4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9F7E88B2-7415-410C-9C31-7720596B0607}.Release|Any CPU.Build.0 = Release|Any CPU {FCAE9C42-1DCE-4C2E-BAE0-251C147903B4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -107,13 +101,12 @@ Global
{CA99B8CF-520A-4B48-ACCE-0A301C35A7FE} = {15D04093-4974-4B2F-AE8A-F3721F31767A} {CA99B8CF-520A-4B48-ACCE-0A301C35A7FE} = {15D04093-4974-4B2F-AE8A-F3721F31767A}
{375EF474-512A-4410-86CF-46974E07C1F7} = {3F000016-069D-477E-ACA3-F643880B57E8} {375EF474-512A-4410-86CF-46974E07C1F7} = {3F000016-069D-477E-ACA3-F643880B57E8}
{EF3188D7-338D-43DA-BF6B-D26E5BDAC3A6} = {35BA5DCB-BECC-4F51-8DD0-694C555D205A} {EF3188D7-338D-43DA-BF6B-D26E5BDAC3A6} = {35BA5DCB-BECC-4F51-8DD0-694C555D205A}
{1E75F7E9-E6AA-44E7-A2F3-DB4CA85E0118} = {038C3821-E554-496D-B585-A3BC193B7913}
{4875D70F-A96B-4EBA-99BE-218886D29BEB} = {F2D241DB-7692-46DB-8A6A-958B365DAAF8} {4875D70F-A96B-4EBA-99BE-218886D29BEB} = {F2D241DB-7692-46DB-8A6A-958B365DAAF8}
{2A391CA2-F96B-4DB7-80AA-0668A5141640} = {140F73DD-29D3-4C44-809B-5B470880AA0D} {2A391CA2-F96B-4DB7-80AA-0668A5141640} = {140F73DD-29D3-4C44-809B-5B470880AA0D}
{5C4697BD-BC97-484F-9DB1-CA87E2BEAA4B} = {D4D7BF4A-B2E3-470A-A14C-FC658FF7461D} {5C4697BD-BC97-484F-9DB1-CA87E2BEAA4B} = {D4D7BF4A-B2E3-470A-A14C-FC658FF7461D}
{AF313B47-3079-407F-91D1-9989C1E1AF2A} = {D4D7BF4A-B2E3-470A-A14C-FC658FF7461D} {AF313B47-3079-407F-91D1-9989C1E1AF2A} = {D4D7BF4A-B2E3-470A-A14C-FC658FF7461D}
{39B81A0D-A88C-44D3-9624-1A19C78A4310} = {88B03853-2215-4E52-8986-0E76602E5F21} {39B81A0D-A88C-44D3-9624-1A19C78A4310} = {88B03853-2215-4E52-8986-0E76602E5F21}
{9F7E88B2-7415-410C-9C31-7720596B0607} = {038C3821-E554-496D-B585-A3BC193B7913} {FCAE9C42-1DCE-4C2E-BAE0-251C147903B4} = {038C3821-E554-496D-B585-A3BC193B7913}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F376A326-7590-4E7E-AB9B-76CED8527AB0} SolutionGuid = {F376A326-7590-4E7E-AB9B-76CED8527AB0}

View file

@ -0,0 +1,33 @@
using Insight.Agent.Network;
using Insight.Agent.Network.Handlers;
using Insight.Domain.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using System.Runtime.Versioning;
namespace Insight.Agent.Extensions;
internal static class ServiceExtensions
{
[SupportedOSPlatform("windows")]
internal static IServiceCollection InjectWindowsHandler(this IServiceCollection services)
{
services.AddSingleton<IMessageHandler<AgentSession>, DriveHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, InterfaceHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, MainboardHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, MemoryHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, OperationSystemHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, PrinterHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, ProcessorHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, ServiceHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, SessionHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, SoftwareHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, StoragePoolHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, SystemInfoHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, UpdateHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, UserHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, VideocardHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, VirtualMaschineHandler>();
return services;
}
}

View file

@ -11,6 +11,7 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<SatelliteResourceLanguages>none</SatelliteResourceLanguages> <SatelliteResourceLanguages>none</SatelliteResourceLanguages>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">

View file

@ -1,4 +1,5 @@
using Insight.Agent.Network; using Insight.Agent.Extensions;
using Insight.Agent.Network;
using Insight.Agent.Network.Handlers; using Insight.Agent.Network.Handlers;
using Insight.Agent.Services; using Insight.Agent.Services;
using Insight.Domain.Constants; using Insight.Domain.Constants;
@ -9,7 +10,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System.Runtime.Versioning; using System.Diagnostics;
using Vaitr.Network; using Vaitr.Network;
using Vaitr.Network.Hosting; using Vaitr.Network.Hosting;
@ -39,8 +40,7 @@ internal class Program
options.SingleLine = true; options.SingleLine = true;
options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff "; options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff ";
}); });
options.AddFile(Configuration.AppDirectory?.FullName + "/logs/" + Process.GetCurrentProcess().ProcessName + "_{Date}.log", LogLevel.Trace, fileSizeLimitBytes: 104857600, retainedFileCountLimit: 10, outputTemplate: "{Timestamp:o} [{Level:u3}] {Message} {NewLine}{Exception}");
options.AddFile($"{Configuration.AppDirectory?.FullName}/" + "logs/agent_{Date}.log", LogLevel.Trace, fileSizeLimitBytes: 104857600, retainedFileCountLimit: 10, outputTemplate: "{Timestamp:o} [{Level:u3}] {Message} {NewLine}{Exception}");
}); });
builder.ConfigureServices((host, services) => builder.ConfigureServices((host, services) =>
@ -70,7 +70,7 @@ internal class Program
services.AddSingleton<IMessageHandler<AgentSession>, ProxyHandler>(); services.AddSingleton<IMessageHandler<AgentSession>, ProxyHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, CustomHandler>(); services.AddSingleton<IMessageHandler<AgentSession>, CustomHandler>();
if (OperatingSystem.IsWindows()) ServiceCollectionExtensions.InjectWindowsHandler(services); if (OperatingSystem.IsWindows()) ServiceExtensions.InjectWindowsHandler(services);
// GLOBAL DEPENDENCIES // GLOBAL DEPENDENCIES
services.AddTransient(provider => new HttpClient(new HttpClientHandler services.AddTransient(provider => new HttpClient(new HttpClientHandler
@ -84,29 +84,3 @@ internal class Program
await host.RunAsync().ConfigureAwait(false); await host.RunAsync().ConfigureAwait(false);
} }
} }
internal static class ServiceCollectionExtensions
{
[SupportedOSPlatform("windows")]
internal static IServiceCollection InjectWindowsHandler(this IServiceCollection services)
{
services.AddSingleton<IMessageHandler<AgentSession>, DriveHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, InterfaceHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, MainboardHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, MemoryHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, OperationSystemHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, PrinterHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, ProcessorHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, ServiceHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, SessionHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, SoftwareHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, StoragePoolHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, SystemInfoHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, UpdateHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, UserHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, VideocardHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, VirtualMaschineHandler>();
return services;
}
}

View file

@ -1,15 +1,49 @@
using Microsoft.AspNetCore.Authentication.JwtBearer; using Insight.Infrastructure;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
using System.Reflection; using System.Reflection;
namespace Insight.Api.Extensions; namespace Insight.Api.Extensions;
public static class ServiceExtensions internal static class ServiceExtensions
{ {
internal static IServiceCollection AddSwaggerServices(this IServiceCollection services) internal static WebApplicationBuilder AddMetrics(this WebApplicationBuilder builder)
{ {
services.AddEndpointsApiExplorer(); builder.Services.AddOpenTelemetry()
services.AddSwaggerGen(options => .WithMetrics(provider =>
{
provider.ConfigureResource(configure =>
{
configure.Clear();
configure.AddService(builder.Configuration.GetValue<string?>(Appsettings.Influx.Service) ?? throw new Exception($"{Appsettings.Influx.Service} value not set (appsettings)"));
})
.AddRuntimeInstrumentation()
.AddProcessInstrumentation()
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
//.AddMeter("test")
.AddInfluxDBMetricsExporter(configure =>
{
configure.Endpoint = builder.Configuration.GetValue<Uri?>(Appsettings.Influx.Endpoint) ?? throw new Exception($"{Appsettings.Influx.Endpoint} value not set (appsettings)");
configure.Token = builder.Configuration.GetValue<string?>(Appsettings.Influx.Token) ?? throw new Exception($"{Appsettings.Influx.Token} value not set (appsettings)");
configure.Org = builder.Configuration.GetValue<string?>(Appsettings.Influx.Organization) ?? throw new Exception($"{Appsettings.Influx.Organization} value not set (appsettings)");
configure.Bucket = builder.Configuration.GetValue<string?>(Appsettings.Influx.Bucket) ?? throw new Exception($"{Appsettings.Influx.Bucket} value not set (appsettings)");
configure.MetricExportIntervalMilliseconds = 1000;
});
}
);
//builder.Services.AddSingleton<BasicMetrics>();
return builder;
}
internal static WebApplicationBuilder AddSwagger(this WebApplicationBuilder builder)
{
builder.Services.AddSwaggerGen(options =>
{ {
options.SwaggerDoc("v1", new OpenApiInfo options.SwaggerDoc("v1", new OpenApiInfo
{ {
@ -53,6 +87,23 @@ public static class ServiceExtensions
options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename)); options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
}); });
return services; return builder;
}
internal static WebApplication ConfigureSwagger(this WebApplication app)
{
app.UseSwagger(options =>
{
options.RouteTemplate = "api/swagger/{documentName}/swagger.json";
});
app.UseSwaggerUI(options =>
{
options.DefaultModelsExpandDepth(-1);
options.SwaggerEndpoint("/api/swagger/v1/swagger.json", "v1");
options.RoutePrefix = "api/swagger";
});
return app;
} }
} }

View file

@ -17,15 +17,21 @@
<GenerateDocumentationFile>True</GenerateDocumentationFile> <GenerateDocumentationFile>True</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591</NoWarn> <NoWarn>$(NoWarn);1591</NoWarn>
<SatelliteResourceLanguages>none</SatelliteResourceLanguages> <SatelliteResourceLanguages>none</SatelliteResourceLanguages>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.1" /> <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.1" />
<PackageReference Include="OpenTelemetry.Exporter.InfluxDB" Version="1.0.0-alpha.3" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Process" Version="0.5.0-beta.4" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.7.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0" /> <PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0" />
<!--Unix Serilog stuff-->
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -2,6 +2,7 @@ using Insight.Api.Extensions;
using Insight.Domain.Constants; using Insight.Domain.Constants;
using Insight.Infrastructure; using Insight.Infrastructure;
using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.FileProviders;
using System.Diagnostics;
namespace Insight.Api; namespace Insight.Api;
@ -13,47 +14,37 @@ internal class Program
builder.Host.UseWindowsService(); builder.Host.UseWindowsService();
builder.Host.UseSystemd(); builder.Host.UseSystemd();
// LOGGER // Configuration
builder.Configuration.Defaults();
// Logging
builder.Logging.ClearProviders(); builder.Logging.ClearProviders();
builder.Logging.SetMinimumLevel(LogLevel.Trace); builder.Logging.SetMinimumLevel(LogLevel.Trace);
builder.Logging.AddFilter("Microsoft.AspNetCore", LogLevel.Warning); builder.Logging.AddFilter("Microsoft.AspNetCore", LogLevel.Warning);
builder.Logging.AddSimpleConsole(options => builder.Logging.AddSimpleConsole(options =>
{ {
options.IncludeScopes = true; options.IncludeScopes = true;
options.SingleLine = true; options.SingleLine = true;
options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff "; options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff ";
}); });
builder.Logging.AddFile(Configuration.AppDirectory?.FullName + "/logs/" + Process.GetCurrentProcess().ProcessName + "_{Date}.log", LogLevel.Trace, fileSizeLimitBytes: 104857600, retainedFileCountLimit: 10, outputTemplate: "{Timestamp:o} [{Level:u3}] {Message} {NewLine}{Exception}");
builder.Logging.AddFile($"{Configuration.AppDirectory?.FullName}/" + "logs/api_{Date}.log", LogLevel.Trace, fileSizeLimitBytes: 104857600, retainedFileCountLimit: 10, outputTemplate: "{Timestamp:o} [{Level:u3}] {Message} {NewLine}{Exception}"); // Services
// INFRASTRUCTURE
builder.Services.AddDatabase(builder.Configuration); builder.Services.AddDatabase(builder.Configuration);
builder.Services.AddInfrastructureServices(); builder.Services.AddIdentity(builder.Configuration);
builder.Services.AddIdentityServices();
// IDENTITY
builder.Services.AddIdentityServices(builder.Configuration);
builder.Services.AddBearerAuthentication(builder.Configuration); builder.Services.AddBearerAuthentication(builder.Configuration);
builder.Services.AddTokenServices(builder.Configuration); builder.Services.AddTokenServices(builder.Configuration);
// SECURITY
builder.Services.AddAuthorization(); builder.Services.AddAuthorization();
// WEBSERVICES // Modules
builder.Services.AddProxyServices(); builder.AddDefaults();
builder.Services.AddRoutingServices(); builder.AddApiDefaults();
builder.Services.AddControllers(); builder.AddMetrics();
builder.AddSwagger();
// SWAGGER
builder.Services.AddSwaggerServices();
//builder.Services.AddControllers();
//builder.Services.AddEndpointsApiExplorer();
//builder.Services.AddSwaggerGen();
// HTTP Pipeline
var app = builder.Build(); var app = builder.Build();
// Configure the HTTP request pipeline.
app.UseForwardedHeaders(); app.UseForwardedHeaders();
if (app.Environment.IsDevelopment()) if (app.Environment.IsDevelopment())
@ -61,17 +52,7 @@ internal class Program
} }
app.UseSwagger(options => app.ConfigureSwagger();
{
options.RouteTemplate = "api/swagger/{documentName}/swagger.json";
});
app.UseSwaggerUI(options =>
{
options.DefaultModelsExpandDepth(-1);
options.SwaggerEndpoint("/api/swagger/v1/swagger.json", "v1");
options.RoutePrefix = "api/swagger";
});
app.UseCors(x => x app.UseCors(x => x
.AllowAnyOrigin() .AllowAnyOrigin()
@ -93,6 +74,6 @@ internal class Program
ServeUnknownFileTypes = true ServeUnknownFileTypes = true
}); });
await app.RunAsync(); await app.RunAsync().ConfigureAwait(false);
} }
} }

View file

@ -1,7 +1,16 @@
{ {
"AllowedHosts": "*", "AllowedHosts": "*",
"Urls": "http://127.0.0.1:5000", "Urls": "http://127.0.0.1:5000",
// set in env vars
//"influx.endpoint": "http://127.0.0.1:8086",
//"influx.token": "",
"influx.org": "insight",
"influx.bucket": "insight",
"influx.service": "api",
"mongo.connection": "mongodb://db.insight.local:27017", "mongo.connection": "mongodb://db.insight.local:27017",
"jwt.key": "x5dcaE8fiBmHfgsNrwIEtSWzZkz6gpouzKOIgEiVjxJnW28V1aUnYXF19IcnF5x", "jwt.key": "x5dcaE8fiBmHfgsNrwIEtSWzZkz6gpouzKOIgEiVjxJnW28V1aUnYXF19IcnF5x",
"jwt.exp": 3600, "jwt.exp": 3600,
"jwt.audience": "http://127.0.0.1:5000", "jwt.audience": "http://127.0.0.1:5000",

View file

@ -1,7 +1,16 @@
{ {
"AllowedHosts": "*", "AllowedHosts": "*",
"Urls": "http://127.0.0.1:5000", "Urls": "http://127.0.0.1:5000",
// set in env vars
//"influx.endpoint": "http://127.0.0.1:8086",
//"influx.token": "",
"influx.org": "insight",
"influx.bucket": "insight",
"influx.service": "api",
"mongo.connection": "mongodb://127.0.0.1:27017", "mongo.connection": "mongodb://127.0.0.1:27017",
"jwt.key": "x5dcaE8fiBmHfgsNrwIEtSWzZkz6gpouzKOIgEiVjxJnW28V1aUnYXF19IcnF5x", "jwt.key": "x5dcaE8fiBmHfgsNrwIEtSWzZkz6gpouzKOIgEiVjxJnW28V1aUnYXF19IcnF5x",
"jwt.exp": 3600, "jwt.exp": 3600,
"jwt.audience": "https://insight.webmatic.de/api", "jwt.audience": "https://insight.webmatic.de/api",

View file

@ -8,6 +8,9 @@ public static class ConfigurationExtensions
{ {
configuration.Sources.Clear(); configuration.Sources.Clear();
configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true); configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
return configuration.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true, reloadOnChange: true); configuration.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true, reloadOnChange: true);
configuration.AddEnvironmentVariables();
return configuration;
} }
} }

View file

@ -17,6 +17,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
<PackageReference Include="Vaitr.Network" Version="2024.1.8" /> <PackageReference Include="Vaitr.Network" Version="2024.1.8" />
</ItemGroup> </ItemGroup>

View file

@ -16,43 +16,29 @@ namespace Insight.Infrastructure;
public static partial class ServiceExtensions public static partial class ServiceExtensions
{ {
public static IServiceCollection AddTokenServices(this IServiceCollection services, IConfiguration configuration) public static WebApplicationBuilder AddDefaults(this WebApplicationBuilder builder)
{ {
var options = new Models.TokenOptions( builder.Services.Configure<ForwardedHeadersOptions>(options =>
key: configuration.GetValue<string?>(Appsettings.Jwt.Key) ?? throw new Exception($"{Appsettings.Jwt.Key} value not set (appsettings)"),
expires: configuration.GetValue<int?>(Appsettings.Jwt.Exp) ?? throw new Exception($"{Appsettings.Jwt.Exp} value not set (appsettings)"),
audience: configuration.GetValue<Uri?>(Appsettings.Jwt.Audience) ?? throw new Exception($"{Appsettings.Jwt.Audience} value not set (appsettings)"),
issuer: configuration.GetValue<Uri?>(Appsettings.Jwt.Issuer) ?? throw new Exception($"{Appsettings.Jwt.Issuer} value not set (appsettings)"));
services.AddSingleton(options);
services.AddTransient<TokenService>();
return services;
}
public static IServiceCollection AddProxyServices(this IServiceCollection services)
{
// add before routing
services.Configure<ForwardedHeadersOptions>(options =>
{ {
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
}); });
builder.Services.AddRouting(options =>
return services;
}
public static IServiceCollection AddRoutingServices(this IServiceCollection services)
{
// add after proxy
services.AddRouting(options =>
{ {
options.LowercaseUrls = true; options.LowercaseUrls = true;
}); });
return services; return builder;
} }
public static IServiceCollection AddIdentityServices(this IServiceCollection services, IConfiguration configuration) public static WebApplicationBuilder AddApiDefaults(this WebApplicationBuilder builder)
{
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
return builder;
}
public static IServiceCollection AddIdentity(this IServiceCollection services, IConfiguration configuration)
{ {
var connectionString = configuration.GetValue<string?>(Appsettings.Mongo.ConnectionString) ?? throw new Exception($"{Appsettings.Mongo.ConnectionString} value not set (appsettings)"); var connectionString = configuration.GetValue<string?>(Appsettings.Mongo.ConnectionString) ?? throw new Exception($"{Appsettings.Mongo.ConnectionString} value not set (appsettings)");
@ -67,6 +53,20 @@ public static partial class ServiceExtensions
return services; return services;
} }
public static IServiceCollection AddTokenServices(this IServiceCollection services, IConfiguration configuration)
{
var options = new Models.TokenOptions(
key: configuration.GetValue<string?>(Appsettings.Jwt.Key) ?? throw new Exception($"{Appsettings.Jwt.Key} value not set (appsettings)"),
expires: configuration.GetValue<int?>(Appsettings.Jwt.Exp) ?? throw new Exception($"{Appsettings.Jwt.Exp} value not set (appsettings)"),
audience: configuration.GetValue<Uri?>(Appsettings.Jwt.Audience) ?? throw new Exception($"{Appsettings.Jwt.Audience} value not set (appsettings)"),
issuer: configuration.GetValue<Uri?>(Appsettings.Jwt.Issuer) ?? throw new Exception($"{Appsettings.Jwt.Issuer} value not set (appsettings)"));
services.AddSingleton(options);
services.AddTransient<TokenService>();
return services;
}
public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration) public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration)
{ {
// REWRITE TO COOKIE ONLY FOR WEB // REWRITE TO COOKIE ONLY FOR WEB

View file

@ -13,7 +13,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.1" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.1" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.1.2" /> <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.2.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -8,6 +8,9 @@ public static class ConfigurationExtensions
{ {
configuration.Sources.Clear(); configuration.Sources.Clear();
configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true); configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
return configuration.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true, reloadOnChange: true); configuration.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true, reloadOnChange: true);
configuration.AddEnvironmentVariables();
return configuration;
} }
} }

View file

@ -27,7 +27,7 @@ public static partial class ServiceExtensions
return services.AddSingleton(provider => provider.GetRequiredService<MongoClient>().GetDatabase(Settings.Database)); return services.AddSingleton(provider => provider.GetRequiredService<MongoClient>().GetDatabase(Settings.Database));
} }
public static IServiceCollection AddInfrastructureServices(this IServiceCollection services) public static IServiceCollection AddIdentityServices(this IServiceCollection services)
{ {
services.AddTransient<IdentityService>(); services.AddTransient<IdentityService>();
services.AddTransient<AuthenticatorService>(); services.AddTransient<AuthenticatorService>();

View file

@ -13,6 +13,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="AspNetCore.Identity.MongoDbCore" Version="3.1.2" /> <PackageReference Include="AspNetCore.Identity.MongoDbCore" Version="3.1.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
<PackageReference Include="MongoDB.Driver" Version="2.23.1" /> <PackageReference Include="MongoDB.Driver" Version="2.23.1" />
<PackageReference Include="Vaitr.Scheduler" Version="2023.12.15.1" /> <PackageReference Include="Vaitr.Scheduler" Version="2023.12.15.1" />

View file

@ -14,6 +14,7 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks> <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<SatelliteResourceLanguages>none</SatelliteResourceLanguages> <SatelliteResourceLanguages>none</SatelliteResourceLanguages>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View file

@ -0,0 +1,17 @@
using Microsoft.AspNetCore.Mvc;
namespace Insight.Server.Controllers
{
[ApiController]
[Route("[controller]")]
public class BlankController(ILogger<BlankController> logger) : ControllerBase
{
private readonly ILogger<BlankController> _logger = logger;
[HttpGet(Name = "Test")]
public async Task<IActionResult> Get()
{
return Ok();
}
}
}

View file

@ -1,52 +0,0 @@
using System.Threading.Tasks.Dataflow;
namespace Insight.Server.Extensions;
public static class Async
{
public static async Task ParallelForEach<T>(
this IAsyncEnumerable<T> source,
Func<T, Task> body,
int maxDegreeOfParallelism = DataflowBlockOptions.Unbounded,
TaskScheduler? scheduler = null)
{
var options = new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = maxDegreeOfParallelism
};
if (scheduler != null)
options.TaskScheduler = scheduler;
var block = new ActionBlock<T>(body, options);
await foreach (var item in source)
block.Post(item);
block.Complete();
await block.Completion;
}
public static async Task ParallelForEach<T>(
this IEnumerable<T> source,
Func<T, Task> body,
int maxDegreeOfParallelism = DataflowBlockOptions.Unbounded,
TaskScheduler? scheduler = null)
{
var options = new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = maxDegreeOfParallelism
};
if (scheduler != null)
options.TaskScheduler = scheduler;
var block = new ActionBlock<T>(body, options);
foreach (var item in source)
block.Post(item);
block.Complete();
await block.Completion;
}
}

View file

@ -1,74 +1,21 @@
using Insight.Domain.Constants; using Insight.Domain.Interfaces;
using Insight.Domain.Interfaces;
using Insight.Domain.Network; using Insight.Domain.Network;
using Insight.Infrastructure; using Insight.Infrastructure;
using Insight.Server.Network.Agent; using Insight.Server.Network.Agent;
using Insight.Server.Network.Agent.Handlers; using Insight.Server.Network.Agent.Handlers;
using Insight.Server.Network.Globals; using Insight.Server.Network.Globals;
using Insight.Server.Network.Web; using Insight.Server.Network.Web;
using Microsoft.OpenApi.Models;
using OpenTelemetry.Metrics; using OpenTelemetry.Metrics;
using OpenTelemetry.Resources; using OpenTelemetry.Resources;
using System.Net; using System.Net;
using Vaitr.Network; using Vaitr.Network;
using Vaitr.Network.Hosting; using Vaitr.Network.Hosting;
namespace Insight.Server; namespace Insight.Server.Extensions;
internal class Program
{
public static async Task Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseWindowsService();
builder.Host.UseSystemd();
// Configuration
builder.Configuration.Defaults();
// Logging
builder.Logging.ClearProviders();
builder.Logging.SetMinimumLevel(LogLevel.Trace);
builder.Logging.AddSimpleConsole(options =>
{
options.IncludeScopes = true;
options.SingleLine = true;
options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff ";
});
builder.Logging.AddFile($"{Configuration.AppDirectory?.FullName}/" + "logs/server_{Date}.log", LogLevel.Trace, fileSizeLimitBytes: 104857600, retainedFileCountLimit: 10, outputTemplate: "{Timestamp:o} [{Level:u3}] {Message} {NewLine}{Exception}");
// Modules
builder.AddDefaults();
builder.AddMetrics();
builder.AddAgentServices();
builder.AddWebServices();
// HTTP Pipeline
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseAuthorization();
app.MapControllers();
await app.RunAsync();
}
}
internal static class ServiceExtensions internal static class ServiceExtensions
{ {
internal static WebApplicationBuilder AddDefaults(this WebApplicationBuilder builder)
{
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
return builder;
}
internal static WebApplicationBuilder AddMetrics(this WebApplicationBuilder builder) internal static WebApplicationBuilder AddMetrics(this WebApplicationBuilder builder)
{ {
builder.Services.AddOpenTelemetry() builder.Services.AddOpenTelemetry()
@ -82,6 +29,7 @@ internal static class ServiceExtensions
.AddRuntimeInstrumentation() .AddRuntimeInstrumentation()
.AddProcessInstrumentation() .AddProcessInstrumentation()
.AddAspNetCoreInstrumentation() .AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
//.AddMeter("test") //.AddMeter("test")
.AddInfluxDBMetricsExporter(configure => .AddInfluxDBMetricsExporter(configure =>
{ {
@ -100,7 +48,21 @@ internal static class ServiceExtensions
return builder; return builder;
} }
internal static WebApplicationBuilder AddAgentServices(this WebApplicationBuilder builder) internal static WebApplicationBuilder AddSwagger(this WebApplicationBuilder builder)
{
builder.Services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo
{
Title = "Insight Server",
Version = "v1"
});
});
return builder;
}
internal static WebApplicationBuilder AddAgentBackend(this WebApplicationBuilder builder)
{ {
// SERVER // SERVER
builder.Services.UseHostedServer<AgentSession, IMessage>(options => builder.Services.UseHostedServer<AgentSession, IMessage>(options =>
@ -144,7 +106,7 @@ internal static class ServiceExtensions
return builder; return builder;
} }
internal static WebApplicationBuilder AddWebServices(this WebApplicationBuilder builder) internal static WebApplicationBuilder AddWebBackend(this WebApplicationBuilder builder)
{ {
// SERVER // SERVER
builder.Services.UseHostedServer<WebSession, IMessage>(options => builder.Services.UseHostedServer<WebSession, IMessage>(options =>
@ -168,4 +130,21 @@ internal static class ServiceExtensions
return builder; return builder;
} }
internal static WebApplication ConfigureSwagger(this WebApplication app)
{
app.UseSwagger(options =>
{
options.RouteTemplate = "api/swagger/{documentName}/swagger.json";
});
app.UseSwaggerUI(options =>
{
options.DefaultModelsExpandDepth(-1);
options.SwaggerEndpoint("/api/swagger/v1/swagger.json", "v1");
options.RoutePrefix = "api/swagger";
});
return app;
}
} }

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
@ -6,54 +6,31 @@
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<Product>Insight</Product> <Product>Insight</Product>
<AssemblyName>server</AssemblyName> <AssemblyName>server</AssemblyName>
<AssemblyVersion>2023.12.14.0</AssemblyVersion> <AssemblyVersion>2024.1.10.0</AssemblyVersion>
<RootNamespace>Insight.Server</RootNamespace> <RootNamespace>Insight.Server</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<SatelliteResourceLanguages>none</SatelliteResourceLanguages> <SatelliteResourceLanguages>none</SatelliteResourceLanguages>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>none</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DebugType>none</DebugType>
</PropertyGroup>
<ItemGroup>
<None Remove="appsettings.Development.json" />
<None Remove="appsettings.json" />
</ItemGroup>
<ItemGroup>
<Content Include="appsettings.Development.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0" />
<PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0" />
<PackageReference Include="Vaitr.Bus" Version="2023.12.15.1" />
<PackageReference Include="OpenTelemetry.Exporter.InfluxDB" Version="1.0.0-alpha.3" /> <PackageReference Include="OpenTelemetry.Exporter.InfluxDB" Version="1.0.0-alpha.3" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.7.0" /> <PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.7.0" /> <PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Process" Version="0.5.0-beta.4" /> <PackageReference Include="OpenTelemetry.Instrumentation.Process" Version="0.5.0-beta.4" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.7.0" /> <PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.7.0" />
<!--Unix Serilog stuff--> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0" />
<PackageReference Include="Vaitr.Bus" Version="2023.12.15.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\Core\Insight.Domain\Insight.Domain.csproj" /> <ProjectReference Include="..\..\Core\Insight.Domain\Insight.Domain.csproj" />
<ProjectReference Include="..\..\Core\Insight.Infrastructure.Web\Insight.Infrastructure.Web.csproj" />
<ProjectReference Include="..\..\Core\Insight.Infrastructure\Insight.Infrastructure.csproj" /> <ProjectReference Include="..\..\Core\Insight.Infrastructure\Insight.Infrastructure.csproj" />
</ItemGroup> </ItemGroup>
@ -61,10 +38,6 @@
<None Update="localhost.pfx"> <None Update="localhost.pfx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
<None Update="Properties\launchSettings.json">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -3,7 +3,6 @@ using Insight.Domain.Interfaces;
using Insight.Domain.Network; using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages; using Insight.Domain.Network.Agent.Messages;
using Insight.Infrastructure.Entities; using Insight.Infrastructure.Entities;
using Microsoft.Extensions.Logging;
using MongoDB.Driver; using MongoDB.Driver;
using Vaitr.Network; using Vaitr.Network;
@ -184,15 +183,13 @@ public class AgentSession(
{ {
while (cancellationToken.IsCancellationRequested is false) while (cancellationToken.IsCancellationRequested is false)
{ {
_logger.LogWarning("try get inventory");
// find assigned host // find assigned host
var host = await _database.Host() var hostCount = await _database.Host()
.CountDocumentsAsync(Builders<HostEntity>.Filter.Eq(p => p.Agent, Id), cancellationToken: cancellationToken) .CountDocumentsAsync(Builders<HostEntity>.Filter.Eq(p => p.Agent, Id), cancellationToken: cancellationToken)
.ConfigureAwait(false); .ConfigureAwait(false);
// if not assigned => short delay // if not assigned => short delay
if (host == 0) if (hostCount == 0)
{ {
await Task.Delay(TimeSpan.FromMinutes(1), cancellationToken); await Task.Delay(TimeSpan.FromMinutes(1), cancellationToken);
continue; continue;

View file

@ -1,20 +1,8 @@
using Insight.Domain.Constants; using Insight.Domain.Constants;
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Infrastructure; using Insight.Infrastructure;
using Insight.Server.Network.Agent; using Insight.Server.Extensions;
using Insight.Server.Network.Agent.Handlers; using System.Collections;
using Insight.Server.Network.Globals; using System.Diagnostics;
using Insight.Server.Network.Web;
using Insight.Server.Services;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System.Net;
using Vaitr.Bus;
using Vaitr.Network;
using Vaitr.Network.Hosting;
namespace Insight.Server; namespace Insight.Server;
@ -22,126 +10,54 @@ internal class Program
{ {
public static async Task Main(string[] args) public static async Task Main(string[] args)
{ {
var builder = Host.CreateDefaultBuilder(args); var builder = WebApplication.CreateBuilder(args);
builder.UseWindowsService(); builder.Host.UseWindowsService();
builder.UseSystemd(); builder.Host.UseSystemd();
builder.ConfigureAppConfiguration(options => // Configuration
{ builder.Configuration.Defaults();
options.Defaults();
});
builder.ConfigureLogging(options => // Logging
{ builder.Logging.ClearProviders();
options.ClearProviders(); builder.Logging.SetMinimumLevel(LogLevel.Trace);
options.SetMinimumLevel(LogLevel.Trace); builder.Logging.AddFilter("Microsoft.AspNetCore", LogLevel.Warning);
builder.Logging.AddSimpleConsole(options =>
options.AddSimpleConsole(options =>
{ {
options.IncludeScopes = true; options.IncludeScopes = true;
options.SingleLine = true; options.SingleLine = true;
options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff "; options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff ";
}); });
builder.Logging.AddFile(Configuration.AppDirectory?.FullName + "/logs/" + Process.GetCurrentProcess().ProcessName + "_{Date}.log", LogLevel.Trace, fileSizeLimitBytes: 104857600, retainedFileCountLimit: 10, outputTemplate: "{Timestamp:o} [{Level:u3}] {Message} {NewLine}{Exception}");
options.AddFile($"{Configuration.AppDirectory?.FullName}/" + "logs/server_{Date}.log", LogLevel.Trace, fileSizeLimitBytes: 104857600, retainedFileCountLimit: 10, outputTemplate: "{Timestamp:o} [{Level:u3}] {Message} {NewLine}{Exception}"); // Services
}); builder.Services.AddDatabase(builder.Configuration);
builder.ConfigureServices((host, services) => // Modules
builder.AddDefaults();
builder.AddApiDefaults();
builder.AddMetrics();
builder.AddSwagger();
builder.AddAgentBackend();
builder.AddWebBackend();
// HTTP Pipeline
var app = builder.Build();
if (app.Environment.IsDevelopment())
{ {
// AGENT
services.AddAgentServices(host.Configuration);
// WEB
services.AddWebServices(host.Configuration);
// INFRASTRUCTURE
services.AddDatabase(host.Configuration);
// BACKGROUND SERVICES
services.AddHostedService<DispatchService>();
// GLOBAL DEPENDENCIES
services.AddSingleton<Bus>();
services.AddTransient(provider => new HttpClient(new HttpClientHandler
{
ClientCertificateOptions = ClientCertificateOption.Manual,
ServerCertificateCustomValidationCallback = (httpRequestMessage, cert, cetChain, policyErrors) => true
}));
});
var host = builder.Build();
await host.RunAsync().ConfigureAwait(false);
}
} }
internal static class ServiceExtensions app.ConfigureSwagger();
{
internal static IServiceCollection AddAgentServices(this IServiceCollection services, IConfiguration configuration)
{
// AGENT SERVER
services.UseHostedServer<AgentSession, IMessage>(options =>
{
options.Address = IPAddress.Any;
options.Port = configuration.GetValue<int?>(Appsettings.Agent.Port) ?? throw new Exception($"{Appsettings.Agent.Port} value not set (appsettings)");
options.Keepalive = 10000;
options.Timeout = 30000;
options.Backlog = 128;
options.Compression = true; app.UseCors(x => x
options.Encryption = Encryption.Tls12; .AllowAnyOrigin()
options.Certificate = configuration.GetValue<string?>(Appsettings.Agent.Certificate) ?? throw new Exception($"{Appsettings.Agent.Certificate} value not set (appsettings)"); .AllowAnyMethod()
options.CertificatePassword = configuration.GetValue<string?>(Appsettings.Agent.CertificatePassword) ?? throw new Exception($"{Appsettings.Agent.CertificatePassword} value not set (appsettings)"); .AllowAnyHeader());
options.UseSerializer<AgentSession, IMessage, MemPackSerializer<IMessage>>(); app.UseAuthorization();
}); app.MapControllers();
// HANDLER await app.RunAsync();
services.AddSingleton<IMessageHandler<AgentSession>, CustomHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, ProxyHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, DriveHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, Network.Agent.Handlers.EventHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, InterfaceHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, MainboardHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, MemoryHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, OperationSystemHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, PrinterHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, ProcessorHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, ServiceHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, SessionHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, SoftwareHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, StoragePoolHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, SystemInfoHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, TrapHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, UpdateHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, UserHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, VideocardHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, VirtualMaschineHandler>();
return services;
}
internal static IServiceCollection AddWebServices(this IServiceCollection services, IConfiguration configuration)
{
// SERVER
services.UseHostedServer<WebSession, IMessage>(options =>
{
options.Address = IPAddress.Any;
options.Port = configuration.GetValue<int?>(Appsettings.Web.Port) ?? throw new Exception($"{Appsettings.Web.Port} value not set (appsettings)");
options.Keepalive = 10000;
options.Timeout = 30000;
options.Backlog = 128;
options.Encryption = Encryption.Tls12;
options.Compression = true;
options.Certificate = configuration.GetValue<string?>(Appsettings.Web.Certificate) ?? throw new Exception($"{Appsettings.Web.Certificate} value not set (appsettings)");
options.CertificatePassword = configuration.GetValue<string?>(Appsettings.Web.CertificatePassword) ?? throw new Exception($"{Appsettings.Web.CertificatePassword} value not set (appsettings)");
options.UseSerializer<WebSession, IMessage, MemPackSerializer<IMessage>>();
});
// HANDLER
services.AddSingleton<IMessageHandler<WebSession>, ProxyHandler>();
return services;
} }
} }

View file

@ -1,14 +1,19 @@
{ {
"$schema": "https://json.schemastore.org/launchsettings.json", "$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": { "profiles": {
"Development": { "Development": {
"commandName": "Project", "commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5001",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
} }
}, },
"Production": { "Production": {
"commandName": "Project" "commandName": "Project",
"applicationUrl": "http://localhost:5001"
} }
} }
} }

View file

@ -1,4 +1,20 @@
{ {
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"Urls": "http://127.0.0.1:5005",
// set in env vars
//"influx.endpoint": "http://127.0.0.1:8086",
//"influx.token": "",
"influx.org": "insight",
"influx.bucket": "insight",
"influx.service": "server",
"mongo.connection": "mongodb://db.insight.local:27017", "mongo.connection": "mongodb://db.insight.local:27017",
"agent.port": 3002, "agent.port": 3002,

View file

@ -1,4 +1,20 @@
{ {
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"Urls": "http://127.0.0.1:5005",
// set in env vars
//"influx.endpoint": "http://127.0.0.1:8086",
//"influx.token": "",
"influx.org": "insight",
"influx.bucket": "insight",
"influx.service": "server",
"mongo.connection": "mongodb://127.0.0.1:27017", "mongo.connection": "mongodb://127.0.0.1:27017",
"agent.port": 3002, "agent.port": 3002,
@ -9,5 +25,5 @@
"web.certificate": "localhost.pfx", "web.certificate": "localhost.pfx",
"web.certificate.password": "Webmatic12", "web.certificate.password": "Webmatic12",
"dispatch.webmatic": false "dispatch.webmatic": true
} }

View file

@ -0,0 +1,5 @@
{
"version": "1.0",
"defaultProvider": "cdnjs",
"libraries": []
}

View file

@ -1,33 +0,0 @@
using Microsoft.AspNetCore.Mvc;
namespace Insight.Server2.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
}

View file

@ -1,52 +0,0 @@
using System.Threading.Tasks.Dataflow;
namespace Insight.Server.Extensions;
public static class Async
{
public static async Task ParallelForEach<T>(
this IAsyncEnumerable<T> source,
Func<T, Task> body,
int maxDegreeOfParallelism = DataflowBlockOptions.Unbounded,
TaskScheduler? scheduler = null)
{
var options = new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = maxDegreeOfParallelism
};
if (scheduler != null)
options.TaskScheduler = scheduler;
var block = new ActionBlock<T>(body, options);
await foreach (var item in source)
block.Post(item);
block.Complete();
await block.Completion;
}
public static async Task ParallelForEach<T>(
this IEnumerable<T> source,
Func<T, Task> body,
int maxDegreeOfParallelism = DataflowBlockOptions.Unbounded,
TaskScheduler? scheduler = null)
{
var options = new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = maxDegreeOfParallelism
};
if (scheduler != null)
options.TaskScheduler = scheduler;
var block = new ActionBlock<T>(body, options);
foreach (var item in source)
block.Post(item);
block.Complete();
await block.Completion;
}
}

View file

@ -1,41 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<LangVersion>latest</LangVersion>
<Product>Insight</Product>
<AssemblyName>server</AssemblyName>
<AssemblyVersion>2024.1.10.0</AssemblyVersion>
<RootNamespace>Insight.Server</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<SatelliteResourceLanguages>none</SatelliteResourceLanguages>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
<PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0" />
<PackageReference Include="Vaitr.Bus" Version="2023.12.15.1" />
<PackageReference Include="OpenTelemetry.Exporter.InfluxDB" Version="1.0.0-alpha.3" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Process" Version="0.5.0-beta.4" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.7.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Core\Insight.Domain\Insight.Domain.csproj" />
<ProjectReference Include="..\..\Core\Insight.Infrastructure\Insight.Infrastructure.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="localhost.pfx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View file

@ -1,26 +0,0 @@
using Insight.Domain.Enums;
namespace Insight.Server.Models;
internal class MonitorMessage
{
public DateTime? Timestamp { get; set; }
public string? Community { get; set; }
public ApplicationEnum? Application { get; set; }
public CategoryEnum? Category { get; set; }
public StatusEnum? Status { get; set; }
public string? Endpoint { get; set; }
public string? Hostname { get; set; }
public string? Subject { get; set; }
public string? Message { get; set; }
public enum ApplicationEnum
{
Unknown = 0,
Insight = 1,
Acronis = 2,
Veeam = 3,
QNAP = 4,
FreeNas = 5
}
}

View file

@ -1,206 +0,0 @@
using Insight.Domain.Enums;
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages;
using Insight.Infrastructure.Entities;
using Microsoft.Extensions.Logging;
using MongoDB.Driver;
using Vaitr.Network;
namespace Insight.Server.Network.Agent;
public class AgentSession(
IMongoDatabase database,
IEnumerable<IMessageHandler<AgentSession>> handlers,
ISerializer<IMessage> serializer,
ILogger<AgentSession> logger) : TcpSession<IMessage>(serializer, logger)
{
public string? Id { get; set; }
private readonly IMongoDatabase _database = database;
private readonly IEnumerable<IMessageHandler<AgentSession>> _handlers = handlers;
protected override async ValueTask OnConnectedAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Agent ({ep?}) connected", RemoteEndPoint);
// auth request
await SendAsync(new AuthenticationRequest(), cancellationToken);
// wait for ack
for (int i = 0; i < 200; i++)
{
if (Id is not null)
break;
await Task.Delay(50, cancellationToken).ConfigureAwait(false);
}
// if ack not received
if (Id is null)
{
_logger.LogError("Agent ({ep?}) authentication timeout", RemoteEndPoint);
Disconnect();
return;
}
_logger.LogInformation("Agent ({ep?} / {id}) authenticated", RemoteEndPoint, Id);
// insert log
await WriteLogAsync(CategoryEnum.Network, StatusEnum.Information, $"Connected ({RemoteEndPoint})", default);
// update entity
await UpdateAsync(default);
// init inventory task
_ = InitInventoryAsync(cancellationToken);
}
protected override async ValueTask OnDisconnectedAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Agent ({ep?}) disconnected", RemoteEndPoint);
// insert log
await WriteLogAsync(CategoryEnum.Network, StatusEnum.Information, $"Disconnected ({RemoteEndPoint})", default);
// update entity
await UpdateAsync(default);
}
protected override async ValueTask OnSentAsync(IPacketContext<IMessage> context, CancellationToken cancellationToken)
{
await base.OnSentAsync(context, cancellationToken);
// update entity
await UpdateAsync(cancellationToken);
}
protected override async ValueTask OnReceivedAsync(IPacketContext<IMessage> context, CancellationToken cancellationToken)
{
await base.OnReceivedAsync(context, cancellationToken);
// only accept auth response if not authenticated
if (Id is null)
{
if (context.Packet is not AuthenticationResponse authentication) return;
await OnAuthenticationAsync(authentication, cancellationToken);
}
// update entity
await UpdateAsync(cancellationToken);
// pass message to handlers
foreach (var handler in _handlers)
{
try
{
await handler.HandleAsync(this, context.Packet, cancellationToken);
}
catch (Exception ex)
{
_logger.LogWarning("Agent ({ep?}) {ex}", RemoteEndPoint, ex.ToString());
}
}
}
protected override async ValueTask OnHeartbeatAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Agent ({ep?}) Heartbeat", RemoteEndPoint);
// update entity
await UpdateAsync(cancellationToken);
}
private async ValueTask OnAuthenticationAsync(AuthenticationResponse authentication, CancellationToken cancellationToken)
{
// check serial
if (authentication.Serial == default)
throw new InvalidDataException($"authentication failed ({nameof(authentication.Serial)})");
// check version
//if (authentication.Version == default || authentication.Version < Domain.Constants.Configuration.Version)
// throw new InvalidDataException($"authentication failed ({nameof(authentication.Version)})");
// upsert agent
await _database.Agent()
.UpdateOneAsync(Builders<AgentEntity>
.Filter
.Eq(p => p.Serial, authentication.Serial.ToString()), Builders<AgentEntity>.Update
.SetOnInsert(p => p.Insert, DateTime.Now)
.SetOnInsert(p => p.Serial, authentication.Serial.ToString())
.Set(p => p.Update, DateTime.Now)
.Set(p => p.Connected, DateTime.Now)
.Set(p => p.Version, authentication.Version)
.Set(p => p.Endpoint, RemoteEndPoint?.ToString())
.Set(p => p.Hostname, authentication.Hostname), new UpdateOptions
{
IsUpsert = true
}, cancellationToken)
.ConfigureAwait(false);
// get agent
var agentEntity = await _database.Agent()
.Find(Builders<AgentEntity>
.Filter
.Eq(p => p.Serial, authentication.Serial.ToString()))
.FirstOrDefaultAsync(cancellationToken)
.ConfigureAwait(false);
// set session id
Id = agentEntity.Id;
}
private async ValueTask WriteLogAsync(CategoryEnum category, StatusEnum status, string message, CancellationToken cancellationToken)
{
await _database.AgentLog()
.InsertOneAsync(new AgentLogEntity
{
Insert = DateTime.Now,
Agent = Id,
Category = category.ToString(),
Status = status.ToString(),
Message = message,
Timestamp = DateTime.Now
}, cancellationToken: cancellationToken)
.ConfigureAwait(false);
}
private async ValueTask UpdateAsync(CancellationToken cancellationToken)
{
await _database.Agent().UpdateOneAsync(Builders<AgentEntity>
.Filter
.Eq(p => p.Id, Id), Builders<AgentEntity>
.Update
.Set(p => p.Update, DateTime.Now)
.Set(p => p.Activity, Activity)
.Set(p => p.SentBytes, SentBytes)
.Set(p => p.SentPackets, SentPackets)
.Set(p => p.ReceivedBytes, ReceivedBytes)
.Set(p => p.ReceivedPackets, ReceivedPackets), null, cancellationToken)
.ConfigureAwait(false);
}
private async Task InitInventoryAsync(CancellationToken cancellationToken)
{
while (cancellationToken.IsCancellationRequested is false)
{
_logger.LogWarning("try get inventory");
// find assigned host
var host = await _database.Host()
.CountDocumentsAsync(Builders<HostEntity>.Filter.Eq(p => p.Agent, Id), cancellationToken: cancellationToken)
.ConfigureAwait(false);
// if not assigned => short delay
if (host == 0)
{
await Task.Delay(TimeSpan.FromMinutes(1), cancellationToken);
continue;
}
// send request
await SendAsync(new InventoryRequest(), cancellationToken);
await Task.Delay(TimeSpan.FromHours(1), cancellationToken);
}
}
}

View file

@ -1,27 +0,0 @@
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages;
using Microsoft.Extensions.Logging;
namespace Insight.Server.Network.Agent.Handlers;
public class CustomHandler(ILogger<CustomHandler> logger) : IMessageHandler<AgentSession>
{
private readonly ILogger<CustomHandler> _logger = logger;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
switch (message)
{
case Response response:
await OnResponseAsync(sender, response, cancellationToken);
break;
}
}
private ValueTask OnResponseAsync(AgentSession sender, Response response, CancellationToken cancellationToken)
{
_logger.LogWarning("Response: {response}", response.ResponseData);
return default;
}
}

View file

@ -1,141 +0,0 @@
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages;
using Insight.Infrastructure.Entities;
using MongoDB.Bson;
using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers;
public class DriveHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
switch (message)
{
case Collection<Drive> drives:
await OnDrivesAsync(sender, drives, cancellationToken);
break;
}
}
private async ValueTask OnDrivesAsync(AgentSession session, List<Drive> drives, CancellationToken cancellationToken)
{
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
if (agentEntity is null) return;
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
if (hostEntity is null) return;
var batch = ObjectId.GenerateNewId().ToString();
var date = DateTime.Now;
var driveBulk = new List<WriteModel<HostDriveEntity>>();
if (drives is not null && drives.Count != 0)
{
foreach (var drive in drives)
{
var driveFilter = Builders<HostDriveEntity>.Filter.And(new List<FilterDefinition<HostDriveEntity>>
{
Builders<HostDriveEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostDriveEntity>.Filter.Eq(x => x.Index, drive.Index)
});
var driveUpdate = Builders<HostDriveEntity>.Update
.SetOnInsert(p => p.Insert, date)
.SetOnInsert(p => p.Host, hostEntity.Id)
.SetOnInsert(p => p.Index, drive.Index)
.Set(p => p.Update, date)
.Set(p => p.Batch, batch)
.Set(p => p.Company, drive.Manufacturer)
.Set(p => p.Name, drive.Name)
.Set(p => p.Size, drive.Size)
.Set(p => p.Type, drive.InterfaceType)
.Set(p => p.Serial, drive.SerialNumber)
.Set(p => p.Firmware, drive.FirmwareRevision)
.Set(p => p.Status, drive.Status)
.Set(p => p.Pnp, drive.PNPDeviceID);
driveBulk.Add(new UpdateOneModel<HostDriveEntity>(driveFilter, driveUpdate)
{
IsUpsert = true
});
}
}
driveBulk.Add(new DeleteManyModel<HostDriveEntity>(Builders<HostDriveEntity>.Filter.And(new List<FilterDefinition<HostDriveEntity>>
{
Builders<HostDriveEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostDriveEntity>.Filter.Ne(x => x.Batch, batch)
})));
var driveResult = await _database.HostDrive().BulkWriteAsync(driveBulk, cancellationToken: cancellationToken);
// volumes
var volumeBulk = new List<WriteModel<HostVolumeEntity>>();
if (drives is not null && drives.Count != 0)
{
foreach (var drive in drives)
{
var driveId = await _database.HostDrive()
.Find(p => p.Host == hostEntity.Id && p.Index == drive.Index)
.Project(p => p.Id)
.FirstOrDefaultAsync(cancellationToken: default);
if (drive.Volumes is not null && drive.Volumes.Count != 0)
{
foreach (var volume in drive.Volumes)
{
var volumeFilter = Builders<HostVolumeEntity>.Filter.And(new List<FilterDefinition<HostVolumeEntity>>
{
Builders<HostVolumeEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostVolumeEntity>.Filter.Eq(x => x.Drive, driveId),
Builders<HostVolumeEntity>.Filter.Eq(x => x.Index, volume.Index)
});
var volumeUpdate = Builders<HostVolumeEntity>.Update
.SetOnInsert(p => p.Insert, date)
.SetOnInsert(p => p.Host, hostEntity.Id)
.SetOnInsert(p => p.Drive, driveId)
.SetOnInsert(p => p.Index, volume.Index)
.Set(p => p.Update, date)
.Set(p => p.Batch, batch)
.Set(p => p.Name, volume.Name)
.Set(p => p.Label, volume.Id)
.Set(p => p.Serial, volume.SerialNumber)
.Set(p => p.Size, volume.Size)
.Set(p => p.FreeSpace, volume.FreeSpace)
.Set(p => p.Type, volume.Type)
.Set(p => p.FileSystem, volume.FileSystem)
.Set(p => p.Compressed, volume.Compressed)
.Set(p => p.Bootable, volume.Bootable)
.Set(p => p.Primary, volume.PrimaryPartition)
.Set(p => p.Boot, volume.Bootable)
.Set(p => p.BlockSize, volume.BlockSize)
.Set(p => p.Blocks, volume.NumberOfBlocks)
.Set(p => p.StartingOffset, volume.StartingOffset)
.Set(p => p.Provider, volume.ProviderName);
volumeBulk.Add(new UpdateOneModel<HostVolumeEntity>(volumeFilter, volumeUpdate)
{
IsUpsert = true
});
}
}
}
}
volumeBulk.Add(new DeleteManyModel<HostVolumeEntity>(Builders<HostVolumeEntity>.Filter.And(new List<FilterDefinition<HostVolumeEntity>>
{
Builders<HostVolumeEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostVolumeEntity>.Filter.Ne(x => x.Batch, batch)
})));
var volumeResult = await _database.HostVolume().BulkWriteAsync(volumeBulk, cancellationToken: cancellationToken);
}
}

View file

@ -1,261 +0,0 @@
using Insight.Domain.Enums;
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages;
using Insight.Infrastructure.Entities;
using MongoDB.Driver;
using static Insight.Domain.Network.Agent.Messages.Event;
namespace Insight.Server.Network.Agent.Handlers;
public class EventHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
switch (message)
{
case Event @event:
await OnEventAsync(sender, @event, cancellationToken);
break;
}
}
private async ValueTask OnEventAsync(AgentSession session, Event @event, CancellationToken cancellationToken)
{
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
if (agentEntity is null) return;
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
if (hostEntity is null) return;
if (FilterEventId(@event)) return;
var hostLog = await InsertHostLogAsync(hostEntity, @event, cancellationToken);
if (hostLog is null || FilterMonitoringHostLog(hostLog)) return;
await _database.HostLogMonitoring()
.InsertOneAsync(new HostLogMonitoringEntity
{
Host = hostEntity.Id,
Insert = hostLog.Insert,
Timestamp = hostLog.Timestamp,
Category = hostLog.Category,
Status = hostLog.Status,
Message = hostLog.Message,
Dispatch = DispatchEnum.Pending.ToString()
}, cancellationToken: cancellationToken);
}
private async ValueTask<AgentLogEntity?> InsertAgentLogAsync(AgentSession session, Event @event, CancellationToken cancellationToken)
{
var agentEntity = await _database.Agent()
.Aggregate()
.Match(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id))
.Lookup<AgentEntity, HostEntity, AgentEntity>(_database.Host(), p => p.Serial, p => p.Agent, p => p.Hosts)
.FirstOrDefaultAsync(cancellationToken);
if (agentEntity is null) return null;
StatusEnum? status = @event.Status switch
{
StatusType.Information => StatusEnum.Information,
StatusType.Warning => StatusEnum.Warning,
StatusType.Error => StatusEnum.Error,
_ => null
};
CategoryEnum? category = @event.Category?.ToLower() switch
{
"network" => CategoryEnum.Network,
"application" => CategoryEnum.Application,
"security" => CategoryEnum.Security,
"system" => CategoryEnum.System,
_ => CategoryEnum.None
};
var date = DateTime.Now;
var log = new AgentLogEntity
{
Insert = date,
Agent = agentEntity.Id,
Timestamp = @event.Timestamp,
EventId = @event.EventId.ToString(),
Source = @event.Source,
Status = status.ToString(),
Category = category.ToString(),
Message = @event.Message
};
await _database.AgentLog().InsertOneAsync(log, cancellationToken: cancellationToken);
return log;
}
private async ValueTask<HostLogEntity?> InsertHostLogAsync(HostEntity hostEntity, Event @event, CancellationToken cancellationToken)
{
StatusEnum? status = @event.Status switch
{
StatusType.Information => StatusEnum.Information,
StatusType.Warning => StatusEnum.Warning,
StatusType.Error => StatusEnum.Error,
StatusType.Critical => StatusEnum.Error,
StatusType.Unknown => null,
_ => null
};
var category = CategoryEnum.None;
if (@event.Category is not null)
{
switch (@event.Category)
{
case var _ when @event.Category.Contains("network", StringComparison.InvariantCultureIgnoreCase):
category = CategoryEnum.Network;
break;
case var _ when @event.Category.Contains("application", StringComparison.InvariantCultureIgnoreCase):
category = CategoryEnum.Application;
break;
case var _ when @event.Category.Contains("security", StringComparison.InvariantCultureIgnoreCase):
category = CategoryEnum.Security;
break;
case var _ when @event.Category.Contains("system", StringComparison.InvariantCultureIgnoreCase):
category = CategoryEnum.System;
break;
case var _ when @event.Category.Contains("printservice", StringComparison.InvariantCultureIgnoreCase):
category = CategoryEnum.Printer;
break;
case var _ when @event.Category.Contains("taskscheduler", StringComparison.InvariantCultureIgnoreCase):
category = CategoryEnum.Task;
break;
case var _ when @event.Category.Contains("terminalservices", StringComparison.InvariantCultureIgnoreCase):
category = CategoryEnum.RDP;
break;
case var _ when @event.Category.Contains("smbclient", StringComparison.InvariantCultureIgnoreCase):
category = CategoryEnum.Network;
break;
case var _ when @event.Category.Contains("smbserver", StringComparison.InvariantCultureIgnoreCase):
category = CategoryEnum.Network;
break;
case var _ when @event.Category.Contains("storagespaces", StringComparison.InvariantCultureIgnoreCase):
category = CategoryEnum.System;
break;
case var _ when @event.Category.Contains("diagnostics", StringComparison.InvariantCultureIgnoreCase):
category = CategoryEnum.System;
break;
default:
break;
}
}
var date = DateTime.Now;
var log = new HostLogEntity
{
Insert = date,
Host = hostEntity.Id,
Timestamp = @event.Timestamp,
EventId = @event.EventId.ToString(),
Status = status.ToString(),
Source = @event.Source,
Category = category.ToString(),
Message = @event.Message
};
await _database.HostLog().InsertOneAsync(log, cancellationToken: cancellationToken);
return log;
}
private static bool FilterEventId(Event @event)
{
var filter = new List<int>
{
0,
3,
4,
16,
37,
900,
902,
903,
1001,
1003,
1008,
1023,
1066,
4624,
4625,
4634,
4648,
4672,
4776,
4798,
4799,
5058,
5059,
5061,
5379,
5612,
5781,
//7036,
8014,
8016,
8019,
8194,
8224,
9009,
9027,
10001,
10016,
16384,
16394,
36874,
36888,
};
if (filter.Any(p => p == @event.EventId)) return true;
return false;
}
private static bool FilterMonitoringHostLog(HostLogEntity hostLog)
{
if (Enum.TryParse(hostLog.Status, out StatusType status) is false) return true;
if (hostLog.Category == CategoryEnum.System.ToString())
{
if (hostLog.Source == "Service Control Manager" && status < StatusType.Warning) return true;
}
if (hostLog.Category == CategoryEnum.Task.ToString())
{
if (status < StatusType.Error) return true;
}
// skip rdp infos
if (hostLog.Category == CategoryEnum.RDP.ToString())
{
if (hostLog.EventId == "261") return true;
}
// skip smbclient (veeam errors)
if (hostLog.Category == CategoryEnum.Security.ToString())
{
if (hostLog.Source == "Microsoft-Windows-SMBClient") return true;
}
return false;
}
}

View file

@ -1,295 +0,0 @@
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages;
using Insight.Infrastructure.Entities;
using MongoDB.Bson;
using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers;
public class InterfaceHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
switch (message)
{
case Collection<Interface> interfaces:
await OnInterfacesAsync(sender, interfaces, cancellationToken);
break;
}
}
private async ValueTask OnInterfacesAsync(AgentSession session, List<Interface> interfaces, CancellationToken cancellationToken)
{
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
if (agentEntity is null) return;
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
if (hostEntity is null) return;
var batch = ObjectId.GenerateNewId().ToString();
var date = DateTime.Now;
// interfaces
if (interfaces is not null && interfaces.Count != 0)
{
var interfaceBulk = new List<WriteModel<HostInterfaceEntity>>();
foreach (var @interface in interfaces)
{
var interfaceFilter = Builders<HostInterfaceEntity>.Filter.And(new List<FilterDefinition<HostInterfaceEntity>>
{
Builders<HostInterfaceEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostInterfaceEntity>.Filter.Eq(x => x.Index, @interface.Index)
});
var interfaceUpdate = Builders<HostInterfaceEntity>.Update
.SetOnInsert(p => p.Insert, date)
.SetOnInsert(p => p.Host, hostEntity.Id)
.SetOnInsert(p => p.Index, @interface.Index)
.Set(p => p.Update, date)
.Set(p => p.Batch, batch)
.Set(p => p.Mac, @interface?.Mac)
.Set(p => p.Name, @interface?.Name)
.Set(p => p.Description, @interface?.Description)
.Set(p => p.Physical, @interface?.Physical)
.Set(p => p.Status, @interface?.Status?.ToString())
.Set(p => p.Suffix, @interface?.Suffix)
.Set(p => p.Speed, @interface?.Speed)
.Set(p => p.Ipv4Mtu, @interface?.Ipv4Mtu)
.Set(p => p.Ipv4Dhcp, @interface?.Ipv4Dhcp)
.Set(p => p.Ipv4Forwarding, @interface?.Ipv4Forwarding)
.Set(p => p.Ipv6Mtu, @interface?.Ipv6Mtu)
.Set(p => p.Sent, @interface?.Sent)
.Set(p => p.Received, @interface?.Received)
.Set(p => p.IncomingPacketsDiscarded, @interface?.IncomingPacketsDiscarded)
.Set(p => p.IncomingPacketsWithErrors, @interface?.IncomingPacketsWithErrors)
.Set(p => p.IncomingUnknownProtocolPackets, @interface?.IncomingUnknownProtocolPackets)
.Set(p => p.OutgoingPacketsDiscarded, @interface?.OutgoingPacketsDiscarded)
.Set(p => p.OutgoingPacketsWithErrors, @interface?.OutgoingPacketsWithErrors);
interfaceBulk.Add(new UpdateOneModel<HostInterfaceEntity>(interfaceFilter, interfaceUpdate)
{
IsUpsert = true
});
}
interfaceBulk.Add(new DeleteManyModel<HostInterfaceEntity>(Builders<HostInterfaceEntity>.Filter.And(new List<FilterDefinition<HostInterfaceEntity>>
{
Builders<HostInterfaceEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostInterfaceEntity>.Filter.Ne(x => x.Batch, batch)
})));
var interfaceResult = await _database.HostInterface().BulkWriteAsync(interfaceBulk, cancellationToken: cancellationToken);
}
// addresses
if (interfaces is not null && interfaces.Count != 0)
{
var addressBulk = new List<WriteModel<HostInterfaceAddressEntity>>();
foreach (var @interface in interfaces)
{
var interfaceId = await _database.HostInterface()
.Find(p => p.Host == hostEntity.Id && p.Index == @interface.Index)
.Project(p => p.Id)
.FirstOrDefaultAsync(cancellationToken: default);
if (@interface.Addresses is not null && @interface.Addresses.Count != 0)
{
foreach (var address in @interface.Addresses)
{
var addressFilter = Builders<HostInterfaceAddressEntity>.Filter.And(new List<FilterDefinition<HostInterfaceAddressEntity>>
{
Builders<HostInterfaceAddressEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostInterfaceAddressEntity>.Filter.Eq(x => x.Interface, interfaceId),
Builders<HostInterfaceAddressEntity>.Filter.Eq(x => x.Address, address?.IpAddress?.Address),
Builders<HostInterfaceAddressEntity>.Filter.Eq(x => x.Mask, address?.Ipv4Mask?.Address)
});
var addressUpdate = Builders<HostInterfaceAddressEntity>.Update
.SetOnInsert(p => p.Insert, date)
.SetOnInsert(p => p.Host, hostEntity.Id)
.SetOnInsert(p => p.Interface, interfaceId)
.SetOnInsert(p => p.Address, address?.IpAddress?.Address)
.SetOnInsert(p => p.Mask, address?.Ipv4Mask?.Address)
.Set(p => p.Update, date)
.Set(p => p.Batch, batch);
addressBulk.Add(new UpdateOneModel<HostInterfaceAddressEntity>(addressFilter, addressUpdate)
{
IsUpsert = true
});
}
}
}
addressBulk.Add(new DeleteManyModel<HostInterfaceAddressEntity>(Builders<HostInterfaceAddressEntity>.Filter.And(new List<FilterDefinition<HostInterfaceAddressEntity>>
{
Builders<HostInterfaceAddressEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostInterfaceAddressEntity>.Filter.Ne(x => x.Batch, batch)
})));
var addressResult = await _database.HostInterfaceAddress().BulkWriteAsync(addressBulk, cancellationToken: cancellationToken);
}
// gateways
if (interfaces is not null && interfaces.Count != 0)
{
var gatewayBulk = new List<WriteModel<HostInterfaceGatewayEntity>>();
foreach (var @interface in interfaces)
{
var interfaceId = await _database.HostInterface()
.Find(p => p.Host == hostEntity.Id && p.Index == @interface.Index)
.Project(p => p.Id)
.FirstOrDefaultAsync(cancellationToken: default);
if (@interface.Gateways is not null && @interface.Gateways.Count != 0)
{
foreach (var gateway in @interface.Gateways)
{
var gatewayFilter = Builders<HostInterfaceGatewayEntity>.Filter.And(new List<FilterDefinition<HostInterfaceGatewayEntity>>
{
Builders<HostInterfaceGatewayEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostInterfaceGatewayEntity>.Filter.Eq(x => x.Interface, interfaceId),
Builders<HostInterfaceGatewayEntity>.Filter.Eq(x => x.Address, gateway?.Address)
});
var gatewayUpdate = Builders<HostInterfaceGatewayEntity>.Update
.SetOnInsert(p => p.Insert, date)
.SetOnInsert(p => p.Host, hostEntity.Id)
.SetOnInsert(p => p.Interface, interfaceId)
.SetOnInsert(p => p.Address, gateway?.Address)
.Set(p => p.Update, date)
.Set(p => p.Batch, batch);
gatewayBulk.Add(new UpdateOneModel<HostInterfaceGatewayEntity>(gatewayFilter, gatewayUpdate)
{
IsUpsert = true
});
}
}
}
gatewayBulk.Add(new DeleteManyModel<HostInterfaceGatewayEntity>(Builders<HostInterfaceGatewayEntity>.Filter.And(new List<FilterDefinition<HostInterfaceGatewayEntity>>
{
Builders<HostInterfaceGatewayEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostInterfaceGatewayEntity>.Filter.Ne(x => x.Batch, batch)
})));
var gatewayResult = await _database.HostInterfaceGateway().BulkWriteAsync(gatewayBulk, cancellationToken: cancellationToken);
}
// nameservers
if (interfaces is not null && interfaces.Count != 0)
{
var nameserverBulk = new List<WriteModel<HostInterfaceNameserverEntity>>();
foreach (var @interface in interfaces)
{
var interfaceId = await _database.HostInterface()
.Find(p => p.Host == hostEntity.Id && p.Index == @interface.Index)
.Project(p => p.Id)
.FirstOrDefaultAsync(cancellationToken: default);
if (@interface.Dns is not null && @interface.Dns.Count != 0)
{
foreach (var nameserver in @interface.Dns)
{
var nameserverFilter = Builders<HostInterfaceNameserverEntity>.Filter.And(new List<FilterDefinition<HostInterfaceNameserverEntity>>
{
Builders<HostInterfaceNameserverEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostInterfaceNameserverEntity>.Filter.Eq(x => x.Interface, interfaceId),
Builders<HostInterfaceNameserverEntity>.Filter.Eq(x => x.Address, nameserver?.Address)
});
var nameserverUpdate = Builders<HostInterfaceNameserverEntity>.Update
.SetOnInsert(p => p.Insert, date)
.SetOnInsert(p => p.Host, hostEntity.Id)
.SetOnInsert(p => p.Interface, interfaceId)
.SetOnInsert(p => p.Address, nameserver?.Address)
.Set(p => p.Update, date)
.Set(p => p.Batch, batch);
nameserverBulk.Add(new UpdateOneModel<HostInterfaceNameserverEntity>(nameserverFilter, nameserverUpdate)
{
IsUpsert = true
});
}
}
}
nameserverBulk.Add(new DeleteManyModel<HostInterfaceNameserverEntity>(Builders<HostInterfaceNameserverEntity>.Filter.And(new List<FilterDefinition<HostInterfaceNameserverEntity>>
{
Builders<HostInterfaceNameserverEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostInterfaceNameserverEntity>.Filter.Ne(x => x.Batch, batch)
})));
var nameserverResult = await _database.HostInterfaceNameserver().BulkWriteAsync(nameserverBulk, cancellationToken: cancellationToken);
}
// routes
if (interfaces is not null && interfaces.Count != 0)
{
var routeBulk = new List<WriteModel<HostInterfaceRouteEntity>>();
foreach (var @interface in interfaces)
{
var interfaceId = await _database.HostInterface()
.Find(p => p.Host == hostEntity.Id && p.Index == @interface.Index)
.Project(p => p.Id)
.FirstOrDefaultAsync(cancellationToken: default);
if (@interface.Routes is not null && @interface.Routes.Count != 0)
{
foreach (var route in @interface.Routes)
{
var routeFilter = Builders<HostInterfaceRouteEntity>.Filter.And(new List<FilterDefinition<HostInterfaceRouteEntity>>
{
Builders<HostInterfaceRouteEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostInterfaceRouteEntity>.Filter.Eq(x => x.Interface, interfaceId),
Builders<HostInterfaceRouteEntity>.Filter.Eq(x => x.Destination, route?.Destination?.Address),
Builders<HostInterfaceRouteEntity>.Filter.Eq(x => x.Gateway, route?.Gateway?.Address),
Builders<HostInterfaceRouteEntity>.Filter.Eq(x => x.Mask, route?.Mask),
});
var routeUpdate = Builders<HostInterfaceRouteEntity>.Update
.SetOnInsert(p => p.Insert, date)
.SetOnInsert(p => p.Host, hostEntity.Id)
.SetOnInsert(p => p.Interface, interfaceId)
.SetOnInsert(p => p.Destination, route?.Destination?.Address)
.SetOnInsert(p => p.Gateway, route?.Gateway?.Address)
.SetOnInsert(p => p.Mask, route?.Mask)
.Set(p => p.Update, date)
.Set(p => p.Batch, batch)
.Set(p => p.Metric, route?.Metric);
routeBulk.Add(new UpdateOneModel<HostInterfaceRouteEntity>(routeFilter, routeUpdate)
{
IsUpsert = true
});
}
}
}
routeBulk.Add(new DeleteManyModel<HostInterfaceRouteEntity>(Builders<HostInterfaceRouteEntity>.Filter.And(new List<FilterDefinition<HostInterfaceRouteEntity>>
{
Builders<HostInterfaceRouteEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostInterfaceRouteEntity>.Filter.Ne(x => x.Batch, batch)
})));
var routeResult = await _database.HostInterfaceRoute().BulkWriteAsync(routeBulk, cancellationToken: cancellationToken);
}
}
}

View file

@ -1,48 +0,0 @@
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages;
using Insight.Infrastructure.Entities;
using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers
{
public class MainboardHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
switch (message)
{
case Mainboard mainboard:
await OnMainboardAsync(sender, mainboard, cancellationToken);
break;
}
}
private async ValueTask OnMainboardAsync(AgentSession session, Mainboard mainboard, CancellationToken cancellationToken)
{
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
if (agentEntity is null) return;
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
if (hostEntity is null) return;
var date = DateTime.Now;
await _database.HostMainboard().UpdateOneAsync(p => p.Host == hostEntity.Id, Builders<HostMainboardEntity>.Update
.SetOnInsert(p => p.Insert, date)
.SetOnInsert(p => p.Host, hostEntity.Id)
.Set(p => p.Update, date)
.Set(p => p.Name, mainboard?.Manufacturer)
.Set(p => p.Name, mainboard?.Model)
.Set(p => p.Serial, mainboard?.Serial)
.Set(p => p.Bios, mainboard?.BiosManufacturer)
.Set(p => p.Version, mainboard?.BiosVersion)
.Set(p => p.Date, mainboard?.BiosDate), new UpdateOptions
{
IsUpsert = true
}, cancellationToken);
}
}
}

View file

@ -1,79 +0,0 @@
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages;
using Insight.Infrastructure.Entities;
using MongoDB.Bson;
using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers;
public class MemoryHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
switch (message)
{
case Collection<Memory> memory:
await OnMemoryAsync(sender, memory, cancellationToken);
break;
}
}
private async ValueTask OnMemoryAsync(AgentSession session, List<Memory> memory, CancellationToken cancellationToken)
{
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
if (agentEntity is null) return;
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
if (hostEntity is null) return;
var batch = ObjectId.GenerateNewId().ToString();
var date = DateTime.Now;
var bulk = new List<WriteModel<HostMemoryEntity>>();
if (memory is not null && memory.Count != 0)
{
foreach (var mem in memory)
{
var filterDefinition = Builders<HostMemoryEntity>.Filter.And(new List<FilterDefinition<HostMemoryEntity>>
{
Builders<HostMemoryEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostMemoryEntity>.Filter.Eq(x => x.Index, mem.Index)
});
var updateDefinition = Builders<HostMemoryEntity>.Update
.SetOnInsert(p => p.Insert, date)
.SetOnInsert(p => p.Host, hostEntity.Id)
.SetOnInsert(p => p.Index, mem.Index)
.Set(p => p.Update, date)
.Set(p => p.Batch, batch)
.Set(p => p.Company, mem.Manufacturer)
.Set(p => p.Name, mem.Model)
.Set(p => p.Tag, mem.Tag)
.Set(p => p.Location, mem.Location)
.Set(p => p.Serial, mem.Serial)
.Set(p => p.Capacity, mem.Capacity)
.Set(p => p.Clock, mem.Speed)
.Set(p => p.CurrentClock, mem.ConfiguredSpeed)
.Set(p => p.Voltage, mem.Voltage)
.Set(p => p.CurrentVoltage, mem.ConfiguredVoltage);
bulk.Add(new UpdateOneModel<HostMemoryEntity>(filterDefinition, updateDefinition)
{
IsUpsert = true
});
}
}
bulk.Add(new DeleteManyModel<HostMemoryEntity>(Builders<HostMemoryEntity>.Filter.And(new List<FilterDefinition<HostMemoryEntity>>
{
Builders<HostMemoryEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostMemoryEntity>.Filter.Ne(x => x.Batch, batch)
})));
var result = await _database.HostMemory().BulkWriteAsync(bulk, cancellationToken: cancellationToken);
}
}

View file

@ -1,47 +0,0 @@
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages;
using Insight.Infrastructure.Entities;
using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers;
public class OperationSystemHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
switch (message)
{
case OperationSystem os:
await OnOperationSystemAsync(sender, os, cancellationToken);
break;
}
}
private async ValueTask OnOperationSystemAsync(AgentSession session, OperationSystem operatingSystem, CancellationToken cancellationToken)
{
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
if (agentEntity is null) return;
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
if (hostEntity is null) return;
var date = DateTime.Now;
await _database.HostOs().UpdateOneAsync(p => p.Host == hostEntity.Id, Builders<HostOsEntity>.Update
.SetOnInsert(p => p.Insert, date)
.SetOnInsert(p => p.Host, hostEntity.Id)
.Set(p => p.Update, date)
.Set(p => p.Name, operatingSystem.Name)
.Set(p => p.Version, operatingSystem.Version)
.Set(p => p.Architecture, operatingSystem.Architecture.ToString())
.Set(p => p.SerialNumber, operatingSystem.SerialNumber)
.Set(p => p.Virtual, operatingSystem.Virtual)
.Set(p => p.Installed, operatingSystem.InstallDate), new UpdateOptions
{
IsUpsert = true
}, cancellationToken);
}
}

View file

@ -1,72 +0,0 @@
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages;
using Insight.Infrastructure.Entities;
using MongoDB.Bson;
using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers;
public class PrinterHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
switch (message)
{
case Collection<Printer> printers:
await OnPrintersAsync(sender, printers, cancellationToken);
break;
}
}
private async ValueTask OnPrintersAsync(AgentSession session, List<Printer> printers, CancellationToken cancellationToken)
{
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
if (agentEntity is null) return;
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
if (hostEntity is null) return;
var batch = ObjectId.GenerateNewId().ToString();
var date = DateTime.Now;
var bulk = new List<WriteModel<HostPrinterEntity>>();
if (printers is not null && printers.Count != 0)
{
foreach (var printer in printers)
{
var filterDefinition = Builders<HostPrinterEntity>.Filter.And(new List<FilterDefinition<HostPrinterEntity>>
{
Builders<HostPrinterEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostPrinterEntity>.Filter.Eq(x => x.Name, printer.Name)
});
var updateDefinition = Builders<HostPrinterEntity>.Update
.SetOnInsert(p => p.Insert, date)
.SetOnInsert(p => p.Host, hostEntity.Id)
.SetOnInsert(p => p.Name, printer.Name)
.Set(p => p.Update, date)
.Set(p => p.Batch, batch)
.Set(p => p.Port, printer.Port)
.Set(p => p.Location, printer.Location)
.Set(p => p.Comment, printer.Comment);
bulk.Add(new UpdateOneModel<HostPrinterEntity>(filterDefinition, updateDefinition)
{
IsUpsert = true
});
}
}
bulk.Add(new DeleteManyModel<HostPrinterEntity>(Builders<HostPrinterEntity>.Filter.And(new List<FilterDefinition<HostPrinterEntity>>
{
Builders<HostPrinterEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostPrinterEntity>.Filter.Ne(x => x.Batch, batch)
})));
var result = await _database.HostPrinter().BulkWriteAsync(bulk, cancellationToken: cancellationToken);
}
}

View file

@ -1,83 +0,0 @@
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages;
using Insight.Infrastructure.Entities;
using MongoDB.Bson;
using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers;
public class ProcessorHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
switch (message)
{
case Collection<Processor> processors:
await OnProcessorsAsync(sender, processors, cancellationToken);
break;
}
}
private async ValueTask OnProcessorsAsync(AgentSession session, List<Processor> processors, CancellationToken cancellationToken)
{
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
if (agentEntity is null) return;
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
if (hostEntity is null) return;
var batch = ObjectId.GenerateNewId().ToString();
var date = DateTime.Now;
var bulk = new List<WriteModel<HostProcessorEntity>>();
if (processors is not null && processors.Count != 0)
{
foreach (var processor in processors)
{
var filterDefinition = Builders<HostProcessorEntity>.Filter.And(new List<FilterDefinition<HostProcessorEntity>>
{
Builders<HostProcessorEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostProcessorEntity>.Filter.Eq(x => x.Index, processor.Index)
});
var updateDefinition = Builders<HostProcessorEntity>.Update
.SetOnInsert(p => p.Insert, date)
.SetOnInsert(p => p.Host, hostEntity.Id)
.SetOnInsert(p => p.Index, processor.Index)
.Set(p => p.Update, date)
.Set(p => p.Batch, batch)
.Set(p => p.Company, processor.Manufacturer)
.Set(p => p.Name, processor.Name)
.Set(p => p.Socket, processor.Socket)
.Set(p => p.Serial, processor.SerialNumber)
.Set(p => p.Version, processor.Version)
.Set(p => p.Cores, processor.Cores)
.Set(p => p.LogicalCores, processor.LogicalCores)
.Set(p => p.Clock, processor.MaxSpeed)
.Set(p => p.CurrentClock, processor.CurrentSpeed)
.Set(p => p.L1Size, processor.L1Size)
.Set(p => p.L2Size, processor.L2Size)
.Set(p => p.L3Size, processor.L3Size)
.Set(p => p.Virtualization, processor.Virtualization)
.Set(p => p.PNP, processor.DeviceId);
bulk.Add(new UpdateOneModel<HostProcessorEntity>(filterDefinition, updateDefinition)
{
IsUpsert = true
});
}
}
bulk.Add(new DeleteManyModel<HostProcessorEntity>(Builders<HostProcessorEntity>.Filter.And(new List<FilterDefinition<HostProcessorEntity>>
{
Builders<HostProcessorEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostProcessorEntity>.Filter.Ne(x => x.Batch, batch)
})));
var result = await _database.HostProcessor().BulkWriteAsync(bulk, cancellationToken: cancellationToken);
}
}

View file

@ -1,77 +0,0 @@
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages;
using Insight.Infrastructure.Entities;
using MongoDB.Bson;
using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers;
public class ServiceHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
switch (message)
{
case Collection<Service> services:
await OnServicesAsync(sender, services, cancellationToken);
break;
}
}
private async ValueTask OnServicesAsync(AgentSession session, List<Service> services, CancellationToken cancellationToken)
{
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
if (agentEntity is null) return;
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
if (hostEntity is null) return;
var batch = ObjectId.GenerateNewId().ToString();
var date = DateTime.Now;
var bulk = new List<WriteModel<HostServiceEntity>>();
if (services is not null && services.Count != 0)
{
foreach (var service in services)
{
var filterDefinition = Builders<HostServiceEntity>.Filter.And(new List<FilterDefinition<HostServiceEntity>>
{
Builders<HostServiceEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostServiceEntity>.Filter.Eq(x => x.Name, service.Name)
});
var updateDefinition = Builders<HostServiceEntity>.Update
.SetOnInsert(p => p.Insert, date)
.SetOnInsert(p => p.Host, hostEntity.Id)
.SetOnInsert(p => p.Name, service.Name)
.Set(p => p.Update, date)
.Set(p => p.Batch, batch)
.Set(p => p.DisplayName, service.Display)
.Set(p => p.Description, service.Description)
.Set(p => p.StartMode, service.StartMode.ToString())
.Set(p => p.State, service.Status.ToString())
.Set(p => p.ProcessId, service.ProcessId)
.Set(p => p.Delay, service.Delay)
.Set(p => p.Path, service.PathName)
.Set(p => p.Account, service.Account);
bulk.Add(new UpdateOneModel<HostServiceEntity>(filterDefinition, updateDefinition)
{
IsUpsert = true
});
}
}
bulk.Add(new DeleteManyModel<HostServiceEntity>(Builders<HostServiceEntity>.Filter.And(new List<FilterDefinition<HostServiceEntity>>
{
Builders<HostServiceEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostServiceEntity>.Filter.Ne(x => x.Batch, batch)
})));
var result = await _database.HostService().BulkWriteAsync(bulk, cancellationToken: cancellationToken);
}
}

View file

@ -1,73 +0,0 @@
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages;
using Insight.Infrastructure.Entities;
using MongoDB.Bson;
using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers;
public class SessionHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
switch (message)
{
case Collection<Session> sessions:
await OnSessionsAsync(sender, sessions, cancellationToken);
break;
}
}
private async ValueTask OnSessionsAsync(AgentSession session, List<Session> sessions, CancellationToken cancellationToken)
{
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
if (agentEntity is null) return;
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
if (hostEntity is null) return;
var batch = ObjectId.GenerateNewId().ToString();
var date = DateTime.Now;
var bulk = new List<WriteModel<HostSessionEntity>>();
if (sessions is not null && sessions.Count != 0)
{
foreach (var sess in sessions)
{
var filterDefinition = Builders<HostSessionEntity>.Filter.And(new List<FilterDefinition<HostSessionEntity>>
{
Builders<HostSessionEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostSessionEntity>.Filter.Eq(x => x.Sid, sess.Sid)
});
var updateDefinition = Builders<HostSessionEntity>.Update
.SetOnInsert(p => p.Insert, date)
.SetOnInsert(p => p.Host, hostEntity.Id)
.SetOnInsert(p => p.Sid, sess.Sid)
.Set(p => p.Update, date)
.Set(p => p.Batch, batch)
.Set(p => p.User, sess.User)
.Set(p => p.Remote, sess.Remote)
.Set(p => p.Type, sess.Type)
.Set(p => p.State, sess.Status);
bulk.Add(new UpdateOneModel<HostSessionEntity>(filterDefinition, updateDefinition)
{
IsUpsert = true
});
}
}
bulk.Add(new DeleteManyModel<HostSessionEntity>(Builders<HostSessionEntity>.Filter.And(new List<FilterDefinition<HostSessionEntity>>
{
Builders<HostSessionEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostSessionEntity>.Filter.Ne(x => x.Batch, batch)
})));
var result = await _database.HostSession().BulkWriteAsync(bulk, cancellationToken: cancellationToken);
}
}

View file

@ -1,74 +0,0 @@
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages;
using Insight.Infrastructure.Entities;
using MongoDB.Bson;
using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers;
public class SoftwareHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
switch (message)
{
case Collection<Application> applications:
await OnApplicationsAsync(sender, applications, cancellationToken);
break;
}
}
private async ValueTask OnApplicationsAsync(AgentSession session, List<Application> applications, CancellationToken cancellationToken)
{
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
if (agentEntity is null) return;
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
if (hostEntity is null) return;
var batch = ObjectId.GenerateNewId().ToString();
var date = DateTime.Now;
var bulk = new List<WriteModel<HostApplicationEntity>>();
if (applications is not null && applications.Count != 0)
{
foreach (var app in applications)
{
var filterDefinition = Builders<HostApplicationEntity>.Filter.And(new List<FilterDefinition<HostApplicationEntity>>
{
Builders<HostApplicationEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostApplicationEntity>.Filter.Eq(x => x.Name, app.Name),
Builders<HostApplicationEntity>.Filter.Eq(x => x.Architecture, app.Architecture?.ToString())
});
var updateDefinition = Builders<HostApplicationEntity>.Update
.SetOnInsert(p => p.Insert, date)
.SetOnInsert(p => p.Host, hostEntity.Id)
.SetOnInsert(p => p.Name, app.Name)
.SetOnInsert(p => p.Architecture, app.Architecture?.ToString())
.Set(p => p.Update, date)
.Set(p => p.Batch, batch)
.Set(p => p.Company, app.Publisher)
.Set(p => p.Version, app.Version)
.Set(p => p.InstallDate, app.InstallDate);
bulk.Add(new UpdateOneModel<HostApplicationEntity>(filterDefinition, updateDefinition)
{
IsUpsert = true
});
}
}
bulk.Add(new DeleteManyModel<HostApplicationEntity>(Builders<HostApplicationEntity>.Filter.And(new List<FilterDefinition<HostApplicationEntity>>
{
Builders<HostApplicationEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostApplicationEntity>.Filter.Ne(x => x.Batch, batch)
})));
var result = await _database.HostApplication().BulkWriteAsync(bulk, cancellationToken: cancellationToken);
}
}

View file

@ -1,243 +0,0 @@
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages;
using Insight.Infrastructure.Entities;
using MongoDB.Bson;
using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers;
public class StoragePoolHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
switch (message)
{
case Collection<StoragePool> storagePools:
await OnStoragePoolsAsync(sender, storagePools, cancellationToken);
break;
}
}
private async ValueTask OnStoragePoolsAsync(AgentSession session, List<StoragePool>? storagePools, CancellationToken cancellationToken)
{
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
if (agentEntity is null) return;
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
if (hostEntity is null) return;
var batch = ObjectId.GenerateNewId().ToString();
var date = DateTime.Now;
// storagepools
if (storagePools is not null && storagePools.Count != 0)
{
var storagepoolBulk = new List<WriteModel<HostStoragePoolEntity>>();
foreach (var storagePool in storagePools)
{
var storagePoolFilter = Builders<HostStoragePoolEntity>.Filter.And(new List<FilterDefinition<HostStoragePoolEntity>>
{
Builders<HostStoragePoolEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostStoragePoolEntity>.Filter.Eq(x => x.UniqueId, storagePool.UniqueId)
});
List<string>? states = null;
if (storagePool.States is not null)
{
states = [];
foreach (var state in storagePool.States)
states.Add(state.ToString());
}
var storagePoolUpdate = Builders<HostStoragePoolEntity>.Update
.SetOnInsert(p => p.Insert, date)
.SetOnInsert(p => p.Host, hostEntity.Id)
.SetOnInsert(p => p.UniqueId, storagePool.UniqueId)
.Set(p => p.Update, date)
.Set(p => p.Batch, batch)
.Set(p => p.Name, storagePool.FriendlyName)
.Set(p => p.Health, storagePool.Health?.ToString())
.Set(p => p.Resiliency, storagePool.Resiliency)
.Set(p => p.Primordial, storagePool.IsPrimordial)
.Set(p => p.ReadOnly, storagePool.IsReadOnly)
.Set(p => p.Clustered, storagePool.IsClustered)
.Set(p => p.Size, storagePool.Size)
.Set(p => p.AllocatedSize, storagePool.AllocatedSize)
.Set(p => p.SectorSize, storagePool.SectorSize)
.Set(p => p.States, states);
storagepoolBulk.Add(new UpdateOneModel<HostStoragePoolEntity>(storagePoolFilter, storagePoolUpdate)
{
IsUpsert = true
});
}
storagepoolBulk.Add(new DeleteManyModel<HostStoragePoolEntity>(Builders<HostStoragePoolEntity>.Filter.And(new List<FilterDefinition<HostStoragePoolEntity>>
{
Builders<HostStoragePoolEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostStoragePoolEntity>.Filter.Ne(x => x.Batch, batch)
})));
var storagePoolResult = await _database.HostStoragePool().BulkWriteAsync(storagepoolBulk, cancellationToken: cancellationToken);
}
// physicaldisks
if (storagePools is not null && storagePools.Count != 0)
{
var physicalDiskBulk = new List<WriteModel<HostStoragePoolPhysicalDiskEntity>>();
foreach (var storagePool in storagePools)
{
var storagePoolId = await _database.HostStoragePool()
.Find(p => p.Host == hostEntity.Id && p.UniqueId == storagePool.UniqueId)
.Project(p => p.Id)
.FirstOrDefaultAsync(cancellationToken: default);
if (storagePool.PhysicalDisks is not null && storagePool.PhysicalDisks.Count != 0)
{
foreach (var physicalDisk in storagePool.PhysicalDisks)
{
var physicalDiskFilter = Builders<HostStoragePoolPhysicalDiskEntity>.Filter.And(new List<FilterDefinition<HostStoragePoolPhysicalDiskEntity>>
{
Builders<HostStoragePoolPhysicalDiskEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostStoragePoolPhysicalDiskEntity>.Filter.Eq(x => x.StoragePool, storagePoolId),
Builders<HostStoragePoolPhysicalDiskEntity>.Filter.Eq(x => x.UniqueId, physicalDisk.UniqueId)
});
List<string>? states = null;
if (physicalDisk.States is not null)
{
states = [];
foreach (var state in physicalDisk.States)
states.Add(state.ToString());
}
var physicalDiskUpdate = Builders<HostStoragePoolPhysicalDiskEntity>.Update
.SetOnInsert(p => p.Insert, date)
.SetOnInsert(p => p.Host, hostEntity.Id)
.SetOnInsert(p => p.StoragePool, storagePoolId)
.SetOnInsert(p => p.UniqueId, physicalDisk.UniqueId)
.Set(p => p.Update, date)
.Set(p => p.Batch, batch)
.Set(p => p.DeviceId, physicalDisk.DeviceId)
.Set(p => p.Name, physicalDisk.FriendlyName)
.Set(p => p.Manufacturer, physicalDisk.Manufacturer)
.Set(p => p.Model, physicalDisk.Model)
.Set(p => p.Media, physicalDisk.MediaType.ToString())
.Set(p => p.Bus, physicalDisk.BusType.ToString())
.Set(p => p.Health, physicalDisk.Health.ToString())
.Set(p => p.Usage, physicalDisk.Usage)
.Set(p => p.Location, physicalDisk.PhysicalLocation)
.Set(p => p.Serial, physicalDisk.SerialNumber)
.Set(p => p.Firmware, physicalDisk.FirmwareVersion)
.Set(p => p.Size, physicalDisk.Size)
.Set(p => p.AllocatedSize, physicalDisk.AllocatedSize)
.Set(p => p.Footprint, physicalDisk.VirtualDiskFootprint)
.Set(p => p.LogicalSectorSize, physicalDisk.LogicalSectorSize)
.Set(p => p.PhysicalSectorSize, physicalDisk.PhysicalSectorSize)
.Set(p => p.States, states);
physicalDiskBulk.Add(new UpdateOneModel<HostStoragePoolPhysicalDiskEntity>(physicalDiskFilter, physicalDiskUpdate)
{
IsUpsert = true
});
}
}
}
physicalDiskBulk.Add(new DeleteManyModel<HostStoragePoolPhysicalDiskEntity>(Builders<HostStoragePoolPhysicalDiskEntity>.Filter.And(new List<FilterDefinition<HostStoragePoolPhysicalDiskEntity>>
{
Builders<HostStoragePoolPhysicalDiskEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostStoragePoolPhysicalDiskEntity>.Filter.Ne(x => x.Batch, batch)
})));
var physicalDiskResult = await _database.HostStoragePoolPhysicalDisk().BulkWriteAsync(physicalDiskBulk, cancellationToken: cancellationToken);
}
// virtual disks
if (storagePools is not null && storagePools.Count != 0)
{
var virtualDiskBulk = new List<WriteModel<HostStoragePoolVirtualDiskEntity>>();
foreach (var storagePool in storagePools)
{
if (storagePool.VirtualDisks is not null && storagePool.VirtualDisks.Count != 0)
{
foreach (var virtualDisk in storagePool.VirtualDisks)
{
var storagePoolId = await _database.HostStoragePool()
.Find(p => p.Host == hostEntity.Id && p.UniqueId == storagePool.UniqueId)
.Project(p => p.Id)
.FirstOrDefaultAsync(cancellationToken: default);
var virtualDiskFilter = Builders<HostStoragePoolVirtualDiskEntity>.Filter.And(new List<FilterDefinition<HostStoragePoolVirtualDiskEntity>>
{
Builders<HostStoragePoolVirtualDiskEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostStoragePoolVirtualDiskEntity>.Filter.Eq(x => x.StoragePool, storagePoolId),
Builders<HostStoragePoolVirtualDiskEntity>.Filter.Eq(x => x.UniqueId, virtualDisk.UniqueId)
});
List<string>? states = null;
if (virtualDisk.States is not null)
{
states = [];
foreach (var state in virtualDisk.States)
states.Add(state.ToString());
}
var virtualDiskUpdate = Builders<HostStoragePoolVirtualDiskEntity>.Update
.SetOnInsert(p => p.Insert, date)
.SetOnInsert(p => p.Host, hostEntity.Id)
.SetOnInsert(p => p.StoragePool, storagePoolId)
.SetOnInsert(p => p.UniqueId, virtualDisk.UniqueId)
.Set(p => p.Update, date)
.Set(p => p.Batch, batch)
.Set(p => p.Name, virtualDisk.FriendlyName)
.Set(p => p.Health, virtualDisk.Health.ToString())
.Set(p => p.Access, virtualDisk.AccessType.ToString())
.Set(p => p.Provisioning, virtualDisk.ProvisioningType.ToString())
.Set(p => p.PhysicalRedundancy, virtualDisk.PhysicalDiskRedundancy)
.Set(p => p.Resiliency, virtualDisk.ResiliencySettingName)
.Set(p => p.Deduplication, virtualDisk.Deduplication)
.Set(p => p.Snapshot, virtualDisk.IsSnapshot)
.Set(p => p.Size, virtualDisk.Size)
.Set(p => p.AllocatedSize, virtualDisk.AllocatedSize)
.Set(p => p.Footprint, virtualDisk.FootprintOnPool)
.Set(p => p.ReadCacheSize, virtualDisk.ReadCacheSize)
.Set(p => p.WriteCacheSize, virtualDisk.WriteCacheSize)
.Set(p => p.States, states);
virtualDiskBulk.Add(new UpdateOneModel<HostStoragePoolVirtualDiskEntity>(virtualDiskFilter, virtualDiskUpdate)
{
IsUpsert = true
});
}
}
}
virtualDiskBulk.Add(new DeleteManyModel<HostStoragePoolVirtualDiskEntity>(Builders<HostStoragePoolVirtualDiskEntity>.Filter.And(new List<FilterDefinition<HostStoragePoolVirtualDiskEntity>>
{
Builders<HostStoragePoolVirtualDiskEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostStoragePoolVirtualDiskEntity>.Filter.Ne(x => x.Batch, batch)
})));
var virtualDiskResult = await _database.HostStoragePoolVirtualDisk().BulkWriteAsync(virtualDiskBulk, cancellationToken: cancellationToken);
}
}
}

View file

@ -1,47 +0,0 @@
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages;
using Insight.Infrastructure.Entities;
using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers;
public class SystemInfoHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
switch (message)
{
case SystemInfo systemInfo:
await OnSystemInfoAsync(sender, systemInfo, cancellationToken);
break;
}
}
private async ValueTask OnSystemInfoAsync(AgentSession session, SystemInfo? system, CancellationToken cancellationToken)
{
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session?.Id)).FirstOrDefaultAsync(cancellationToken);
if (agentEntity is null) return;
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity?.Id)).FirstOrDefaultAsync(cancellationToken);
if (hostEntity is null) return;
var date = DateTime.Now;
if (hostEntity.Id is null) return;
await _database.HostSystem().UpdateOneAsync(p => p.Host == hostEntity.Id, Builders<HostSystemEntity>.Update
.SetOnInsert(p => p.Insert, date)
.SetOnInsert(p => p.Host, hostEntity.Id)
.Set(p => p.Update, date)
.Set(p => p.BootUpTime, system?.LastBootUpTime)
.Set(p => p.LocalTime, system?.LocalDateTime)
.Set(p => p.Processes, system?.Processes)
.Set(p => p.License, system?.License), new UpdateOptions
{
IsUpsert = true
}, cancellationToken);
}
}

View file

@ -1,264 +0,0 @@
using Insight.Domain.Enums;
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages;
using Insight.Infrastructure.Entities;
using Insight.Server.Models;
using MongoDB.Driver;
using System.Text;
using System.Text.RegularExpressions;
using static Insight.Server.Models.MonitorMessage;
namespace Insight.Server.Network.Agent.Handlers;
public partial class TrapHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
switch (message)
{
case Trap trap:
await OnTrapAsync(sender, trap, cancellationToken);
break;
}
}
private async ValueTask OnTrapAsync(AgentSession session, Trap? trap, CancellationToken cancellationToken)
{
if (trap is null) return;
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
if (agentEntity is null) return;
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
if (hostEntity is null) return;
if (TryParse(trap, out var monitoring) is false)
{
//_logger.LogWarning($"Failed to parse");
}
// insert monitoring log
var monitoringLog = new HostLogMonitoringEntity
{
Host = hostEntity.Id,
Insert = DateTime.Now,
Timestamp = monitoring?.Timestamp,
Category = monitoring?.Category?.ToString(),
Status = monitoring?.Status?.ToString(),
Hostname = monitoring?.Hostname,
Task = monitoring?.Subject,
Message = monitoring?.Message,
Dispatch = DispatchEnum.Pending.ToString()
};
await _database.HostLogMonitoring()
.InsertOneAsync(monitoringLog, cancellationToken: cancellationToken);
// insert host log
var log = new HostLogEntity
{
Insert = monitoringLog.Insert,
Host = monitoringLog.Host,
Category = monitoringLog.Category,
Status = monitoringLog.Status,
Source = "Trap",
Message = monitoringLog?.Task,
Timestamp = monitoringLog?.Insert
};
if (monitoringLog?.Message is not null) log.Message += $"\n{monitoringLog.Message}";
await _database.HostLog()
.InsertOneAsync(log, cancellationToken: cancellationToken)
.ConfigureAwait(false);
}
private static bool TryParse(Trap packet, out MonitorMessage? monitoring)
{
monitoring = null;
if (packet is null || packet.Data is null || packet.Data.Count == 0)
return false;
monitoring = new MonitorMessage
{
Community = packet.Community,
Category = CategoryEnum.Monitoring,
Endpoint = packet.Endpoint,
Timestamp = packet.Timestamp
};
if (Enum.TryParse<ApplicationEnum>(packet.Community, true, out var application))
monitoring.Application = application;
StatusEnum? status;
string? task;
string? message;
switch (application)
{
case ApplicationEnum.Acronis:
monitoring.Application = ApplicationEnum.Acronis;
if (ParseAcronis(packet.Data, out status, out task, out message) is false) return false;
break;
case ApplicationEnum.Veeam:
monitoring.Application = ApplicationEnum.Veeam;
if (ParseVeeam(packet.Data, out status, out task, out message) is false) return false;
break;
case ApplicationEnum.QNAP:
monitoring.Application = ApplicationEnum.QNAP;
monitoring.Category = CategoryEnum.System;
monitoring.Hostname = packet.Hostname;
if (ParseQnap(packet.Data, out status, out task, out message) is false) return false;
break;
default:
return false;
}
monitoring.Status = status;
monitoring.Subject = task;
monitoring.Message = message;
return true;
}
[GeneratedRegex(@"\s+")]
private static partial Regex AcronisRegex();
private static bool ParseAcronis(List<KeyValuePair<string, string?>> data, out StatusEnum? status, out string? task, out string? message)
{
status = data[0].Value?.ToLower() switch
{
"erfolgreich" => StatusEnum.Information,
"success" => StatusEnum.Information,
"information" => StatusEnum.Information,
"warnung" => StatusEnum.Warning,
"warning" => StatusEnum.Warning,
"fehler" => StatusEnum.Error,
"failed" => StatusEnum.Error,
"error" => StatusEnum.Error,
_ => null,
};
task = null;
message = null;
var trim = data[1].Value?.Split(':', StringSplitOptions.None);
if (trim is null || trim.Length == 0) return false;
task = trim[1].Split("'", StringSplitOptions.None)[1].Split("'")[0].Trim();
message = trim[1].Split("' ", StringSplitOptions.None)[1].Trim();
if (message is not null) return true;
if (data[1].Value is not string val) return false;
var content = AcronisRegex().Replace(val, "");
var bytes = Enumerable.Range(0, content.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(content.Substring(x, 2), 16))
.ToArray();
content = Encoding.UTF8.GetString(bytes);
trim = content.Split(':', StringSplitOptions.None);
if (trim is null || trim.Length == 0) return false;
task = trim[1].Split("'", StringSplitOptions.None)[1].Split("'")[0].Trim();
message = trim[1].Split("' ", StringSplitOptions.None)[1].Trim();
return message is not null;
}
private static bool ParseVeeam(List<KeyValuePair<string, string?>> data, out StatusEnum? status, out string? task, out string? message)
{
status = null;
task = null;
message = null;
var parsed = false;
try
{
var summary = false;
if (Guid.TryParse(data[0].Value, out _))
summary = true;
if (data[1].Value?.ToLower() == "backup configuration job")
return false;
status = (summary ? data[2].Value?.ToLower() : data[3].Value?.ToLower()) switch
{
"success" => StatusEnum.Information,
"warning" => StatusEnum.Warning,
"failed" => StatusEnum.Error,
"error" => StatusEnum.Error,
_ => null,
};
task = data[1].Value;
parsed = true;
}
catch (Exception)
{
}
if (parsed) return true;
return false;
}
private static bool ParseQnap(List<KeyValuePair<string, string?>> data, out StatusEnum? status, out string? task, out string? message)
{
status = StatusEnum.Information;
task = null;
message = string.Empty;
var parsed = false;
try
{
var keywords = new Dictionary<string, StatusEnum>
{
{ "power", StatusEnum.Information },
{ "rights", StatusEnum.Information },
{ "added", StatusEnum.Information },
{ "changed", StatusEnum.Information },
{ "password", StatusEnum.Information },
{ "firmware", StatusEnum.Information },
{ "restarting", StatusEnum.Information },
{ "detected", StatusEnum.Warning },
{ "external", StatusEnum.Warning },
{ "threshold", StatusEnum.Warning },
{ "file system", StatusEnum.Warning },
{ "raid", StatusEnum.Warning },
{ "full", StatusEnum.Error },
{ "failure", StatusEnum.Error },
{ "failed", StatusEnum.Error },
{ "resyncing", StatusEnum.Error },
{ "degraded", StatusEnum.Error },
{ "error", StatusEnum.Error },
{ "without error", StatusEnum.Information },
{ "ncsi", StatusEnum.Information }
};
foreach (var key in keywords)
if (Regex.IsMatch(string.Concat(data).ToLowerInvariant(), $@"\b{key.Key}\b"))
status = key.Value;
foreach (var kv in data)
message += kv.Value;
parsed = true;
}
catch (Exception)
{
//_logger.LogError("{ex}", ex);
}
if (parsed) return true;
return false;
}
}

View file

@ -1,117 +0,0 @@
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages;
using Insight.Infrastructure.Entities;
using MongoDB.Bson;
using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers;
public class UpdateHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
switch (message)
{
case UpdateCollection updates:
await OnUpdatesAsync(sender, updates, cancellationToken);
break;
}
}
private async ValueTask OnUpdatesAsync(AgentSession session, UpdateCollection updates, CancellationToken cancellationToken)
{
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
if (agentEntity is null) return;
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
if (hostEntity is null) return;
var batch = ObjectId.GenerateNewId().ToString();
var date = DateTime.Now;
var bulk = new List<WriteModel<HostUpdateEntity>>();
if (updates is not null)
{
if (updates.Installed is not null && updates.Installed.Count != 0)
{
foreach (var update in updates.Installed)
{
var filterDefinition = Builders<HostUpdateEntity>.Filter.And(new List<FilterDefinition<HostUpdateEntity>>
{
Builders<HostUpdateEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostUpdateEntity>.Filter.Eq(x => x.Serial, update.Id)
});
var updateDefinition = Builders<HostUpdateEntity>.Update
.SetOnInsert(p => p.Insert, date)
.SetOnInsert(p => p.Host, hostEntity.Id)
.SetOnInsert(p => p.Serial, update.Id)
.Set(p => p.Update, date)
.Set(p => p.Batch, batch)
.Set(p => p.Pending, false)
.Set(p => p.Name, update.Name)
.Set(p => p.Description, update.Description)
.Set(p => p.SupportUrl, update.SupportUrl)
.Set(p => p.Result, update.Result.ToString())
.Set(p => p.Date, update.Date);
bulk.Add(new UpdateOneModel<HostUpdateEntity>(filterDefinition, updateDefinition)
{
IsUpsert = true
});
}
}
if (updates.Pending is not null && updates.Pending.Count != 0)
{
foreach (var update in updates.Pending)
{
var filterDefinition = Builders<HostUpdateEntity>.Filter.And(new List<FilterDefinition<HostUpdateEntity>>
{
Builders<HostUpdateEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostUpdateEntity>.Filter.Eq(x => x.Serial, update.Id)
});
var updateDefinition = Builders<HostUpdateEntity>.Update
.SetOnInsert(p => p.Insert, date)
.SetOnInsert(p => p.Host, hostEntity.Id)
.SetOnInsert(p => p.Serial, update.Id)
.Set(p => p.Update, date)
.Set(p => p.Batch, batch)
.Set(p => p.Pending, true)
.Set(p => p.Name, update.Name)
.Set(p => p.Description, update.Description)
.Set(p => p.SupportUrl, update.SupportUrl)
.Set(p => p.Result, update.Result?.ToString())
.Set(p => p.Type, update.Type.ToString())
.Set(p => p.Size, update.Size)
.Set(p => p.IsDownloaded, update.IsDownloaded)
.Set(p => p.CanRequestUserInput, update.CanRequestUserInput)
.Set(p => p.RebootBehavior, update.RebootBehavior?.ToString())
.Set(p => p.Date, update.Date);
bulk.Add(new UpdateOneModel<HostUpdateEntity>(filterDefinition, updateDefinition)
{
IsUpsert = true
});
}
}
}
bulk.Add(new DeleteManyModel<HostUpdateEntity>(Builders<HostUpdateEntity>.Filter.And(new List<FilterDefinition<HostUpdateEntity>>
{
Builders<HostUpdateEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostUpdateEntity>.Filter.Ne(x => x.Batch, batch)
})));
var result = await _database.HostUpdate().BulkWriteAsync(bulk, cancellationToken: cancellationToken);
}
}

View file

@ -1,183 +0,0 @@
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages;
using Insight.Infrastructure.Entities;
using MongoDB.Bson;
using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers;
public class UserHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
switch (message)
{
case Collection<User> users:
await OnUsersAsync(sender, users, cancellationToken);
break;
}
}
private async ValueTask OnUsersAsync(AgentSession session, List<User>? users, CancellationToken cancellationToken)
{
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
if (agentEntity is null) return;
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
if (hostEntity is null) return;
var batch = ObjectId.GenerateNewId().ToString();
var date = DateTime.Now;
// users
if (users is not null && users.Count != 0)
{
var userBulk = new List<WriteModel<HostSysUserEntity>>();
foreach (var user in users)
{
var userFilter = Builders<HostSysUserEntity>.Filter.And(new List<FilterDefinition<HostSysUserEntity>>
{
Builders<HostSysUserEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostSysUserEntity>.Filter.Eq(x => x.Domain, user?.Domain),
Builders<HostSysUserEntity>.Filter.Eq(x => x.Name, user?.Name)
});
var userUpdate = Builders<HostSysUserEntity>.Update
.SetOnInsert(p => p.Insert, date)
.SetOnInsert(p => p.Host, hostEntity.Id)
.SetOnInsert(p => p.Domain, user?.Domain)
.SetOnInsert(p => p.Name, user?.Name)
.Set(p => p.Update, date)
.Set(p => p.Batch, batch)
.Set(p => p.Sid, user?.Sid)
.Set(p => p.FullName, user?.FullName)
.Set(p => p.Description, user?.Description)
.Set(p => p.Status, user?.Status)
.Set(p => p.LocalAccount, user?.LocalAccount)
.Set(p => p.Disabled, user?.Disabled)
.Set(p => p.Lockout, user?.Lockout)
.Set(p => p.PasswordChangeable, user?.PasswordChangeable)
.Set(p => p.PasswordExpires, user?.PasswordExpires)
.Set(p => p.PasswordRequired, user?.PasswordRequired);
userBulk.Add(new UpdateOneModel<HostSysUserEntity>(userFilter, userUpdate)
{
IsUpsert = true
});
}
userBulk.Add(new DeleteManyModel<HostSysUserEntity>(Builders<HostSysUserEntity>.Filter.And(new List<FilterDefinition<HostSysUserEntity>>
{
Builders<HostSysUserEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostSysUserEntity>.Filter.Ne(x => x.Batch, batch)
})));
var userResult = await _database.HostSystemUser().BulkWriteAsync(userBulk, cancellationToken: cancellationToken);
}
// groups
if (users is not null && users.Count != 0)
{
var groupBulk = new List<WriteModel<HostSysGroupEntity>>();
var distinctGroups = users.SelectMany(p => p.Groups ?? [])
.GroupBy(p => new { p?.Domain, p?.Name })
.Select(p => p.First());
foreach (var group in distinctGroups)
{
var groupFilter = Builders<HostSysGroupEntity>.Filter.And(new List<FilterDefinition<HostSysGroupEntity>>
{
Builders<HostSysGroupEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostSysGroupEntity>.Filter.Eq(x => x.Domain, group?.Domain),
Builders<HostSysGroupEntity>.Filter.Eq(x => x.Name, group?.Name)
});
var groupUpdate = Builders<HostSysGroupEntity>.Update
.SetOnInsert(p => p.Insert, date)
.SetOnInsert(p => p.Host, hostEntity.Id)
.SetOnInsert(p => p.Domain, group?.Domain)
.SetOnInsert(p => p.Name, group?.Name)
.Set(p => p.Update, date)
.Set(p => p.Batch, batch)
.Set(p => p.Sid, group?.Sid)
.Set(p => p.Description, group?.Description)
.Set(p => p.LocalAccount, group?.LocalAccount);
groupBulk.Add(new UpdateOneModel<HostSysGroupEntity>(groupFilter, groupUpdate)
{
IsUpsert = true
});
}
groupBulk.Add(new DeleteManyModel<HostSysGroupEntity>(Builders<HostSysGroupEntity>.Filter.And(new List<FilterDefinition<HostSysGroupEntity>>
{
Builders<HostSysGroupEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostSysGroupEntity>.Filter.Ne(x => x.Batch, batch)
})));
var groupResult = await _database.HostSystemGroup().BulkWriteAsync(groupBulk, cancellationToken: cancellationToken);
}
// relations
if (users is not null && users.Count != 0)
{
var relationBulk = new List<WriteModel<HostSysUserSysGroupEntity>>();
foreach (var user in users)
{
var userId = await _database.HostSystemUser()
.Find(p => p.Host == hostEntity.Id && p.Domain == user.Domain && p.Name == user.Name)
.Project(p => p.Id)
.FirstOrDefaultAsync(cancellationToken: default);
if (user.Groups is not null && user.Groups.Count != 0)
{
foreach (var group in user.Groups)
{
var groupId = await _database.HostSystemGroup()
.Find(p => p.Host == hostEntity.Id && p.Domain == group.Domain && p.Name == group.Name)
.Project(p => p.Id)
.FirstOrDefaultAsync(cancellationToken: default);
var relationFilter = Builders<HostSysUserSysGroupEntity>.Filter.And(new List<FilterDefinition<HostSysUserSysGroupEntity>>
{
Builders<HostSysUserSysGroupEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostSysUserSysGroupEntity>.Filter.Eq(x => x.User, userId),
Builders<HostSysUserSysGroupEntity>.Filter.Eq(x => x.Group, groupId)
});
var relationUpdate = Builders<HostSysUserSysGroupEntity>.Update
.SetOnInsert(p => p.Insert, date)
.SetOnInsert(p => p.Host, hostEntity.Id)
.SetOnInsert(p => p.User, userId)
.SetOnInsert(p => p.Group, groupId)
.Set(p => p.Update, date)
.Set(p => p.Batch, batch);
relationBulk.Add(new UpdateOneModel<HostSysUserSysGroupEntity>(relationFilter, relationUpdate)
{
IsUpsert = true
});
}
}
}
relationBulk.Add(new DeleteManyModel<HostSysUserSysGroupEntity>(Builders<HostSysUserSysGroupEntity>.Filter.And(new List<FilterDefinition<HostSysUserSysGroupEntity>>
{
Builders<HostSysUserSysGroupEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostSysUserSysGroupEntity>.Filter.Ne(x => x.Batch, batch)
})));
var relationResult = await _database.HostSystemUserSystemGroup().BulkWriteAsync(relationBulk, cancellationToken: cancellationToken);
}
}
}

View file

@ -1,73 +0,0 @@
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages;
using Insight.Infrastructure.Entities;
using MongoDB.Bson;
using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers;
public class VideocardHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
switch (message)
{
case Collection<Videocard> videocards:
await OnVideocardsAsync(sender, videocards, cancellationToken);
break;
}
}
private async ValueTask OnVideocardsAsync(AgentSession session, List<Videocard>? videocards, CancellationToken cancellationToken)
{
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
if (agentEntity is null) return;
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
if (hostEntity is null) return;
var batch = ObjectId.GenerateNewId().ToString();
var date = DateTime.Now;
var bulk = new List<WriteModel<HostVideocardEntity>>();
if (videocards is not null && videocards.Count != 0)
{
foreach (var videocard in videocards)
{
var filterDefinition = Builders<HostVideocardEntity>.Filter.And(new List<FilterDefinition<HostVideocardEntity>>
{
Builders<HostVideocardEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostVideocardEntity>.Filter.Eq(x => x.Name, videocard.Model)
});
var updateDefinition = Builders<HostVideocardEntity>.Update
.SetOnInsert(p => p.Insert, date)
.SetOnInsert(p => p.Host, hostEntity.Id)
.SetOnInsert(p => p.Name, videocard.Model)
.Set(p => p.Update, date)
.Set(p => p.Batch, batch)
.Set(p => p.Company, null)
.Set(p => p.Memory, videocard.Memory)
.Set(p => p.Driver, videocard.DriverVersion)
.Set(p => p.Date, videocard.DriverDate);
bulk.Add(new UpdateOneModel<HostVideocardEntity>(filterDefinition, updateDefinition)
{
IsUpsert = true
});
}
bulk.Add(new DeleteManyModel<HostVideocardEntity>(Builders<HostVideocardEntity>.Filter.And(new List<FilterDefinition<HostVideocardEntity>>
{
Builders<HostVideocardEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostVideocardEntity>.Filter.Ne(x => x.Batch, batch)
})));
var result = await _database.HostVideocard().BulkWriteAsync(bulk, cancellationToken: cancellationToken);
}
}
}

View file

@ -1,173 +0,0 @@
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages;
using Insight.Infrastructure.Entities;
using MongoDB.Bson;
using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers;
public class VirtualMaschineHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
switch (message)
{
case Collection<VirtualMaschine> virtualMaschines:
await OnVirtualMaschinesAsync(sender, virtualMaschines, cancellationToken);
break;
}
}
private async ValueTask OnVirtualMaschinesAsync(AgentSession session, List<VirtualMaschine>? virtualMaschines, CancellationToken cancellationToken)
{
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
if (agentEntity is null) return;
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
if (hostEntity is null) return;
var batch = ObjectId.GenerateNewId().ToString();
var date = DateTime.Now;
// virtual maschines
if (virtualMaschines is not null && virtualMaschines.Count != 0)
{
var virtualMaschineBulk = new List<WriteModel<HostHypervisorVirtualMaschineEntity>>();
foreach (var virtualMaschine in virtualMaschines)
{
var virtualMaschineFilter = Builders<HostHypervisorVirtualMaschineEntity>.Filter.And(new List<FilterDefinition<HostHypervisorVirtualMaschineEntity>>
{
Builders<HostHypervisorVirtualMaschineEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostHypervisorVirtualMaschineEntity>.Filter.Eq(x => x.UniqueId, virtualMaschine.Id.ToString())
});
var virtualMaschineUpdate = Builders<HostHypervisorVirtualMaschineEntity>.Update
.SetOnInsert(p => p.Insert, date)
.SetOnInsert(p => p.Host, hostEntity.Id)
.SetOnInsert(p => p.UniqueId, virtualMaschine.Id.ToString())
.Set(p => p.Update, date)
.Set(p => p.Batch, batch)
.Set(p => p.Name, virtualMaschine?.Name)
.Set(p => p.Notes, virtualMaschine?.Notes)
.Set(p => p.Enabled, virtualMaschine?.Enabled?.ToString())
.Set(p => p.EnabledDefault, virtualMaschine?.EnabledDefault?.ToString())
.Set(p => p.Health, virtualMaschine?.HealthState?.ToString())
.Set(p => p.Status, virtualMaschine?.Status)
.Set(p => p.OnTime, virtualMaschine?.OnTime)
.Set(p => p.ReplicationState, virtualMaschine?.ReplicationState?.ToString())
.Set(p => p.ReplicationHealth, virtualMaschine?.ReplicationHealth?.ToString())
.Set(p => p.ConfigurationVersion, virtualMaschine?.ConfigurationVersion)
.Set(p => p.IntegrationServicesVersionState, virtualMaschine?.IntegrationServicesVersionState?.ToString())
.Set(p => p.ProcessId, virtualMaschine?.ProcessId)
.Set(p => p.NumberOfProcessors, virtualMaschine?.NumberOfProcessors)
.Set(p => p.ProcessorLoad, virtualMaschine?.ProcessorLoad)
.Set(p => p.MemoryAvailable, virtualMaschine?.MemoryAvailable)
.Set(p => p.MemoryUsage, virtualMaschine?.MemoryUsage)
.Set(p => p.InstallDate, virtualMaschine?.InstallDate)
.Set(p => p.ConfigurationVersion, virtualMaschine?.ConfigurationVersion)
.Set(p => p.TimeOfLastStateChange, virtualMaschine?.TimeOfLastStateChange)
.Set(p => p.LastReplicationTime, virtualMaschine?.LastReplicationTime)
.Set(p => p.Os, virtualMaschine?.GuestOperatingSystem);
virtualMaschineBulk.Add(new UpdateOneModel<HostHypervisorVirtualMaschineEntity>(virtualMaschineFilter, virtualMaschineUpdate)
{
IsUpsert = true
});
}
virtualMaschineBulk.Add(new DeleteManyModel<HostHypervisorVirtualMaschineEntity>(Builders<HostHypervisorVirtualMaschineEntity>.Filter.And(new List<FilterDefinition<HostHypervisorVirtualMaschineEntity>>
{
Builders<HostHypervisorVirtualMaschineEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostHypervisorVirtualMaschineEntity>.Filter.Ne(x => x.Batch, batch)
})));
var virtualMaschineResult = await _database.HostHypervisorVirtualMaschine().BulkWriteAsync(virtualMaschineBulk, cancellationToken: cancellationToken);
}
// virtual maschine configurations
if (virtualMaschines is not null && virtualMaschines.Count != 0)
{
var configurationBulk = new List<WriteModel<HostHypervisorVirtualMaschineConfigEntity>>();
foreach (var virtualmaschine in virtualMaschines)
{
var virtualMaschineId = await _database.HostHypervisorVirtualMaschine()
.Find(p => p.Host == hostEntity.Id && p.UniqueId == virtualmaschine.Id.ToString())
.Project(p => p.Id)
.FirstOrDefaultAsync(cancellationToken: default);
if (virtualmaschine.Configurations is not null && virtualmaschine.Configurations.Count != 0)
{
foreach (var config in virtualmaschine.Configurations)
{
var configFilter = Builders<HostHypervisorVirtualMaschineConfigEntity>.Filter.And(new List<FilterDefinition<HostHypervisorVirtualMaschineConfigEntity>>
{
Builders<HostHypervisorVirtualMaschineConfigEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostHypervisorVirtualMaschineConfigEntity>.Filter.Eq(x => x.VirtualMaschine, virtualMaschineId),
Builders<HostHypervisorVirtualMaschineConfigEntity>.Filter.Eq(x => x.UniqueId, config.Id)
});
// custom "notes" concat
string notes = string.Empty;
if (config?.Notes is not null)
foreach (var n in config.Notes) notes += n;
if (config?.Id is null) continue;
var configUpdate = Builders<HostHypervisorVirtualMaschineConfigEntity>.Update
.SetOnInsert(p => p.Insert, date)
.SetOnInsert(p => p.Host, hostEntity.Id)
.SetOnInsert(p => p.VirtualMaschine, virtualMaschineId)
.SetOnInsert(p => p.UniqueId, config.Id)
.Set(p => p.Update, date)
.Set(p => p.Batch, batch)
.Set(p => p.ParentId, config.ParentId)
.Set(p => p.Type, config.Type)
.Set(p => p.Name, config.Name)
.Set(p => p.Notes, notes)
.Set(p => p.CreationTime, config.CreationTime)
.Set(p => p.Generation, config.Generation)
.Set(p => p.Architecture, config.Architecture)
.Set(p => p.SecureBootEnabled, config.SecureBootEnabled)
.Set(p => p.IsAutomaticSnapshot, config.IsAutomaticSnapshot)
.Set(p => p.AutomaticStartupAction, config.AutomaticStartupAction?.ToString())
.Set(p => p.AutomaticShutdownAction, config.AutomaticShutdownAction?.ToString())
.Set(p => p.AutomaticRecoveryAction, config.AutomaticRecoveryAction?.ToString())
.Set(p => p.AutomaticSnapshotsEnabled, config.AutomaticSnapshotsEnabled)
.Set(p => p.BaseBoardSerialNumber, config.BaseBoardSerialNumber)
.Set(p => p.BIOSSerialNumber, config.BIOSSerialNumber)
.Set(p => p.BIOSGUID, config.BIOSGUID)
.Set(p => p.ConfigurationDataRoot, config.ConfigurationDataRoot)
.Set(p => p.ConfigurationFile, config.ConfigurationFile)
.Set(p => p.GuestStateDataRoot, config.GuestStateDataRoot)
.Set(p => p.GuestStateFile, config.GuestStateFile)
.Set(p => p.SnapshotDataRoot, config.SnapshotDataRoot)
.Set(p => p.SuspendDataRoot, config.SuspendDataRoot)
.Set(p => p.SwapFileDataRoot, config.SwapFileDataRoot);
configurationBulk.Add(new UpdateOneModel<HostHypervisorVirtualMaschineConfigEntity>(configFilter, configUpdate)
{
IsUpsert = true
});
}
}
}
configurationBulk.Add(new DeleteManyModel<HostHypervisorVirtualMaschineConfigEntity>(Builders<HostHypervisorVirtualMaschineConfigEntity>.Filter.And(new List<FilterDefinition<HostHypervisorVirtualMaschineConfigEntity>>
{
Builders<HostHypervisorVirtualMaschineConfigEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
Builders<HostHypervisorVirtualMaschineConfigEntity>.Filter.Ne(x => x.Batch, batch)
})));
var configurationResult = await _database.HostVirtualMaschineConfig().BulkWriteAsync(configurationBulk, cancellationToken: cancellationToken);
}
}
}

View file

@ -1,104 +0,0 @@
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Remote.Messages;
using Microsoft.Extensions.Logging;
using Vaitr.Bus;
using Vaitr.Network;
namespace Insight.Server.Network.Remote.Handlers;
public class RemoteHandler(Bus bus, ISessionPool<RemoteSession, IMessage> remotePool, ILogger<RemoteHandler> logger) : IMessageHandler<RemoteSession>
{
private readonly Bus _bus = bus;
private readonly ISessionPool<RemoteSession, IMessage> _remotePool = remotePool;
private readonly ILogger<RemoteHandler> _logger = logger;
public async ValueTask HandleAsync<TMessage>(RemoteSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
if (message is RemoteSessionRequest sessionRequest)
{
await OnSessionRequest(sender, sessionRequest, cancellationToken);
}
else if (message is CastRequestResponse castRequestResponse)
{
await OnCastRequestResponse(sender, castRequestResponse, cancellationToken);
}
else if (message is CastMetric metricData)
{
await OnMetricData(sender, metricData, cancellationToken);
}
else if (message is CastScreen screenData)
{
await OnScreenData(sender, screenData, cancellationToken);
}
else if (message is CastCursor cursorData)
{
await OnCursorData(sender, cursorData, cancellationToken);
}
else if (message is CastClipboardReceived clipboardData)
{
await OnClipboardData(sender, clipboardData, cancellationToken);
}
else if (message is CastAudio audioData)
{
await OnAudioData(sender, audioData, cancellationToken);
}
}
private async Task OnSessionRequest(RemoteSession session, RemoteSessionRequest sessionRequest, CancellationToken cancellationToken)
{
_logger.LogInformation("Remote {session} => SessionRequest", session.Id);
session.Mode = sessionRequest.Mode;
await session.SendAsync(new RemoteSessionResponse
{
SessionId = session.Id
}, cancellationToken);
}
private async Task OnCastRequestResponse(RemoteSession session, CastRequestResponse castRequestResponse, CancellationToken cancellationToken)
{
await _bus.PublishAsync(castRequestResponse, cancellationToken);
}
private async Task OnMetricData(RemoteSession session, CastMetric streamMetrics, CancellationToken cancellationToken)
{
//_logger.LogInformation($"Remote {session.Id} => MetricData");
await _bus.PublishAsync(streamMetrics, cancellationToken);
}
private async Task OnScreenData(RemoteSession session, CastScreen screenData, CancellationToken cancellationToken)
{
//_logger.LogInformation($"Remote {session.Id} => ScreenData");
await _bus.PublishAsync(screenData, cancellationToken);
await session.SendAsync(new CastScreenReceived
{
Timestamp = screenData.Timestamp
}, cancellationToken);
}
private async Task OnCursorData(RemoteSession session, CastCursor cursorChanged, CancellationToken cancellationToken)
{
//_logger.LogInformation($"Remote {session.Id} => CursorData");
await _bus.PublishAsync(cursorChanged, cancellationToken);
}
private async Task OnClipboardData(RemoteSession session, CastClipboardReceived clipboardChanged, CancellationToken cancellationToken)
{
_logger.LogInformation("Remote {session} => ClipboardData", session.Id);
await _bus.PublishAsync(clipboardChanged, cancellationToken);
}
private async Task OnAudioData(RemoteSession session, CastAudio audioSample, CancellationToken cancellationToken)
{
_logger.LogInformation("Remote {session} => AudioData", session.Id);
await _bus.PublishAsync(audioSample, cancellationToken);
}
}

View file

@ -1,83 +0,0 @@
using Insight.Domain.Enums;
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Server.Network.Web;
using Microsoft.Extensions.Logging;
using Vaitr.Network;
namespace Insight.Server.Network.Remote;
public class RemoteSession(
ISessionPool<WebSession, IMessage> webPool,
IEnumerable<IMessageHandler<RemoteSession>> handlers,
ISerializer<IMessage> serializer,
ILogger<RemoteSession> logger) : TcpSession<IMessage>(serializer, logger)
{
public string Id { get; } = GenerateRandomId();
public RemoteControlMode Mode { get; set; }
private readonly ISessionPool<WebSession, IMessage> _webPool = webPool;
private readonly IEnumerable<IMessageHandler<RemoteSession>> _handlers = handlers;
public async ValueTask ProxyAsync<TMessage>(TMessage message, CancellationToken cancellationToken)
where TMessage : IMessage
{
// check if web online
if (_webPool.FirstOrDefault().Value is not WebSession web) return;
// proxy-send request packet to web
await web.SendAsync(new Proxy<TMessage>
{
Message = message
}, cancellationToken);
}
protected override ValueTask OnConnectedAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Remote ({ep?}) connected", RemoteEndPoint);
return default;
}
protected override ValueTask OnDisconnectedAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Remote ({ep?}) disconnected", RemoteEndPoint);
return default;
}
protected override async ValueTask OnSentAsync(IPacketContext<IMessage> context, CancellationToken cancellationToken)
{
await base.OnSentAsync(context, cancellationToken);
}
protected override async ValueTask OnReceivedAsync(IPacketContext<IMessage> context, CancellationToken cancellationToken)
{
await base.OnReceivedAsync(context, cancellationToken);
foreach (var handler in _handlers)
{
try
{
await handler.HandleAsync(this, context.Packet, cancellationToken);
}
catch (Exception ex)
{
_logger.LogWarning("Remote ({ep?}) {ex}", RemoteEndPoint, ex.ToString());
}
}
}
protected override ValueTask OnHeartbeatAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Remote ({ep?}) Heartbeat", RemoteEndPoint);
return default;
}
private static string GenerateRandomId()
{
var random = new Random();
string? sessionId = string.Empty;
for (var i = 0; i < 3; i++) sessionId += random.Next(0, 999).ToString().PadLeft(3, '0');
return sessionId;
}
}

View file

@ -1,86 +0,0 @@
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages;
using Insight.Infrastructure.Entities;
using Insight.Server.Network.Agent;
using Insight.Server.Network.Web;
using Microsoft.Extensions.Logging;
using MongoDB.Driver;
using Vaitr.Network;
namespace Insight.Server.Network.Globals;
public class ProxyHandler(
ISessionPool<AgentSession, IMessage> agentPool,
ISessionPool<WebSession, IMessage> webPool,
IMongoDatabase database,
ILogger<ProxyHandler> logger) : IMessageHandler<AgentSession>, IMessageHandler<WebSession>
{
private readonly ISessionPool<AgentSession, IMessage> _agentPool = agentPool;
private readonly ISessionPool<WebSession, IMessage> _webPool = webPool;
private readonly IMongoDatabase _database = database;
private readonly ILogger<ProxyHandler> _logger = logger;
public async ValueTask HandleAsync<TMessage>(WebSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
switch (message)
{
case Proxy<Request> proxyRequest:
await OnProxyRequestAsync(sender, proxyRequest, cancellationToken);
break;
}
}
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
switch (message)
{
case Proxy<Response> proxyResponse:
await OnProxyResponseAsync(sender, proxyResponse, cancellationToken);
break;
}
}
private async ValueTask OnProxyRequestAsync(WebSession session, Proxy<Request> request, CancellationToken cancellationToken)
{
// get host
var hostEntity = await _database.Host()
.Find(Builders<HostEntity>
.Filter
.Eq(p => p.Id, request.ProxyId))
.FirstOrDefaultAsync(cancellationToken);
if (hostEntity is null)
{
_logger.LogWarning("hostEntity is null");
return;
}
// get agent
var agentEntity = await _database.Agent()
.Find(Builders<AgentEntity>
.Filter
.Eq(p => p.Id, hostEntity.Agent))
.FirstOrDefaultAsync(cancellationToken);
if (agentEntity is null)
{
_logger.LogWarning("agentEntity is null");
return;
}
// check if agent online
if (_agentPool.FirstOrDefault(p => p.Value.Id == agentEntity.Id).Value is not AgentSession agent) return;
// proxy-send request packet to agent
await agent.SendAsync(request, cancellationToken);
}
private async ValueTask OnProxyResponseAsync(AgentSession session, Proxy<Response> response, CancellationToken cancellationToken)
{
// check if web online
if (_webPool.FirstOrDefault().Value is not WebSession web) return;
await web.SendAsync(response, cancellationToken);
}
}

View file

@ -1,53 +0,0 @@
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Microsoft.Extensions.Logging;
using Vaitr.Network;
namespace Insight.Server.Network.Web;
public class WebSession(IEnumerable<IMessageHandler<WebSession>> handlers, ISerializer<IMessage> serializer, ILogger<WebSession> logger) : TcpSession<IMessage>(serializer, logger)
{
public string? Id { get; set; }
private readonly IEnumerable<IMessageHandler<WebSession>> _handlers = handlers;
protected override ValueTask OnConnectedAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Web ({ep?}) connected", RemoteEndPoint);
return default;
}
protected override ValueTask OnDisconnectedAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Web ({ep?}) disconnected", RemoteEndPoint);
return default;
}
protected override async ValueTask OnSentAsync(IPacketContext<IMessage> context, CancellationToken cancellationToken)
{
await base.OnSentAsync(context, cancellationToken);
}
protected override async ValueTask OnReceivedAsync(IPacketContext<IMessage> context, CancellationToken cancellationToken)
{
await base.OnReceivedAsync(context, cancellationToken);
foreach (var handler in _handlers)
{
try
{
await handler.HandleAsync(this, context.Packet, cancellationToken);
}
catch (Exception ex)
{
_logger.LogWarning("Web ({ep?}) {ex}", RemoteEndPoint, ex.ToString());
}
}
}
protected override ValueTask OnHeartbeatAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Web ({ep?}) Heartbeat", RemoteEndPoint);
return default;
}
}

View file

@ -1,19 +0,0 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"Development": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5001",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Production": {
"commandName": "Project",
"applicationUrl": "http://localhost:5001"
}
}
}

View file

@ -1,148 +0,0 @@
using Insight.Domain.Enums;
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using MongoDB.Driver;
namespace Insight.Server.Services;
internal class DispatchService(HttpClient httpClient, IMongoDatabase database, IConfiguration configuration, ILogger<DispatchService> logger) : BackgroundService
{
private readonly HttpClient _httpClient = httpClient;
private readonly IMongoDatabase _database = database;
private readonly IConfiguration _configuration = configuration;
private readonly ILogger<DispatchService> _logger = logger;
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
{
_logger.LogTrace("ExecuteAsync");
var enabled = _configuration.GetValue<bool?>(Appsettings.Dispatch.Webmatic) ?? throw new Exception($"{Appsettings.Dispatch.Webmatic} value not set (appsettings)");
if (enabled is false) return;
try
{
while (cancellationToken.IsCancellationRequested is false)
{
await DispatchAsync(cancellationToken);
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
}
}
catch (OperationCanceledException) { }
catch (Exception) { }
}
private async ValueTask DispatchAsync(CancellationToken cancellationToken)
{
_logger.LogTrace($"DispatchAsync");
var pendings = await _database.HostLogMonitoring()
.Find(Builders<HostLogMonitoringEntity>
.Filter.Eq(p => p.Dispatch, DispatchEnum.Pending.ToString()))
.Limit(10)
.ToListAsync(cancellationToken);
if (pendings is null || pendings.Count == 0) return;
foreach (var entity in pendings)
{
try
{
var result = await SendAsync(entity, default);
await _database.HostLogMonitoring()
.UpdateOneAsync(Builders<HostLogMonitoringEntity>.Filter
.Eq(p => p.Id, entity.Id), Builders<HostLogMonitoringEntity>
.Update
.Set(p => p.Dispatch, result.ToString()), cancellationToken: default);
}
catch (Exception ex)
{
_logger.LogError("{exception}", ex.Message);
}
finally
{
// webmatic safety offset
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken: default);
}
}
}
private async ValueTask<DispatchEnum> SendAsync(HostLogMonitoringEntity monitoring, CancellationToken cancellationToken)
{
_logger.LogTrace("SendAsync ({monitoring})", monitoring);
var monitoringApi = Monitoring.LogUri;
var monitoringContent = new List<KeyValuePair<string, string>>();
var monitoringResult = new List<KeyValuePair<string, string>>();
// adjust by category
if (Enum.TryParse<CategoryEnum>(monitoring.Category, true, out var monitoringCategory) is false) return DispatchEnum.Failure;
if (monitoringCategory == CategoryEnum.Monitoring) monitoringApi = Monitoring.StatusUri;
// set category (if log)
if (monitoringApi == Monitoring.LogUri) monitoringContent.Add(new KeyValuePair<string, string>("category", monitoringCategory.ToString()));
// host resolve
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Id, monitoring.Host?.ToString())).FirstOrDefaultAsync(cancellationToken);
if (hostEntity is null) return DispatchEnum.Failure;
// customer resolve
var customerEntity = await _database.Customer().Find(Builders<CustomerEntity>.Filter.Eq(p => p.Id, hostEntity.Customer)).FirstOrDefaultAsync(cancellationToken);
if (hostEntity is null) return DispatchEnum.Failure;
// set host name if no remote host set
if (string.IsNullOrEmpty(monitoring.Hostname)) monitoring.Hostname = hostEntity.Name;
// remove any domain from hostname
if (monitoring.Hostname is not null && monitoring.Hostname.Contains('.')) monitoring.Hostname = monitoring.Hostname.Split(".")[0];
// add customer tag to hostname
monitoring.Hostname += $".{customerEntity.Tag}";
// if task null, set hostname
if (string.IsNullOrEmpty(monitoring.Task)) monitoring.Task = monitoring.Hostname;
// insert hostname as computer-name (lowercase)
monitoringContent.Add(new KeyValuePair<string, string>("computer_name", monitoring.Hostname.ToLower()));
// insert converted status (api styled)
if (Enum.TryParse<StatusEnum>(monitoring.Status, true, out var monitoringStatus) is false) return DispatchEnum.Failure;
monitoringContent.Add(monitoringStatus switch
{
StatusEnum.Information => new KeyValuePair<string, string>("status", monitoringApi == Monitoring.StatusUri ? "erfolgreich" : "info"),
StatusEnum.Warning => new KeyValuePair<string, string>("status", monitoringApi == Monitoring.StatusUri ? "Interaktion" : "warning"),
StatusEnum.Error => new KeyValuePair<string, string>("status", monitoringApi == Monitoring.StatusUri ? "fehlgeschlagen" : "error"),
_ => throw new NotImplementedException(nameof(monitoringStatus))
});
// insert task, timestamp, message,
monitoringContent.Add(new KeyValuePair<string, string>("task", monitoring.Task));
if (monitoring.Timestamp is not null)
{
monitoringContent.Add(new KeyValuePair<string, string>("timestamp", monitoring.Timestamp.Value.ToLocalTime().ToString()));
}
if (string.IsNullOrWhiteSpace(monitoring.Message) is false)
{
monitoringContent.Add(new KeyValuePair<string, string>("message", monitoring.Message));
}
// send message
var result = await _httpClient.PostAsync(monitoringApi, new FormUrlEncodedContent(monitoringContent), default);
monitoringResult.Add(new KeyValuePair<string, string>("HttpStatusCode", result.StatusCode.ToString()));
monitoringResult.Add(new KeyValuePair<string, string>("HttpResponseMessage", await result.Content.ReadAsStringAsync(default)));
// if content != "OK"
if (result is null || result.IsSuccessStatusCode == false) return DispatchEnum.Failure;
// success
return DispatchEnum.Success;
}
}

View file

@ -1,13 +0,0 @@
namespace Insight.Server2
{
public class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string? Summary { get; set; }
}
}

View file

@ -1,30 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"Urls": "http://127.0.0.1:5001",
"influx.endpoint": "http://10.22.70.40:8086",
"influx.endpoint0": "http://192.168.1.10:8086",
"influx.token": "253pd3prqWfwhyLH3eirJkgCE5n6tzPVZcRwRrDcla9z1fIPVLB6tGqJ641e4yI5LY8lxb1VfJX_HrrIXMEv5A==",
"influx.token0": "x7ldV7EYb8ocnNAVbtpfpX0nS2HMyPxq3WyBPrVWBRT3C3tCjU8L8h5WPeESFnUqVvYubOM48GBydz5b3n69YA==",
"influx.org": "insight",
"influx.bucket": "insight",
"influx.service": "server",
"mongo.connection": "mongodb://db.insight.local:27017",
"agent.port": 3002,
"agent.certificate": "localhost.pfx",
"agent.certificate.password": "Webmatic12",
"web.port": 3001,
"web.certificate": "localhost.pfx",
"web.certificate.password": "Webmatic12",
"dispatch.webmatic": false
}

View file

@ -1,30 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"Urls": "http://127.0.0.1:5001",
"influx.endpoint": "http://10.22.70.40:8086",
"influx.endpoint0": "http://192.168.1.10:8086",
"influx.token": "253pd3prqWfwhyLH3eirJkgCE5n6tzPVZcRwRrDcla9z1fIPVLB6tGqJ641e4yI5LY8lxb1VfJX_HrrIXMEv5A==",
"influx.token0": "x7ldV7EYb8ocnNAVbtpfpX0nS2HMyPxq3WyBPrVWBRT3C3tCjU8L8h5WPeESFnUqVvYubOM48GBydz5b3n69YA==",
"influx.org": "insight",
"influx.bucket": "insight",
"influx.service": "server",
"mongo.connection": "mongodb://127.0.0.1:27017",
"agent.port": 3002,
"agent.certificate": "localhost.pfx",
"agent.certificate.password": "Webmatic12",
"web.port": 3001,
"web.certificate": "localhost.pfx",
"web.certificate.password": "Webmatic12",
"dispatch.webmatic": true
}

View file

@ -11,6 +11,7 @@
<Product>Insight</Product> <Product>Insight</Product>
<AssemblyVersion>2023.12.14.0</AssemblyVersion> <AssemblyVersion>2023.12.14.0</AssemblyVersion>
<SatelliteResourceLanguages>none</SatelliteResourceLanguages> <SatelliteResourceLanguages>none</SatelliteResourceLanguages>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">

View file

@ -11,6 +11,7 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<SatelliteResourceLanguages>none</SatelliteResourceLanguages> <SatelliteResourceLanguages>none</SatelliteResourceLanguages>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">

View file

@ -4,6 +4,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System.Diagnostics;
namespace Insight.Updater.Windows; namespace Insight.Updater.Windows;
@ -33,8 +34,7 @@ internal class Program
options.SingleLine = true; options.SingleLine = true;
options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff "; options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff ";
}); });
options.AddFile(Configuration.AppDirectory?.FullName + "/logs/" + Process.GetCurrentProcess().ProcessName + "_{Date}.log", LogLevel.Trace, fileSizeLimitBytes: 104857600, retainedFileCountLimit: 10, outputTemplate: "{Timestamp:o} [{Level:u3}] {Message} {NewLine}{Exception}");
options.AddFile($"{Configuration.AppDirectory?.FullName}/" + "logs/updater_{Date}.log", LogLevel.Trace, fileSizeLimitBytes: 104857600, retainedFileCountLimit: 10, outputTemplate: "{Timestamp:o} [{Level:u3}] {Message} {NewLine}{Exception}");
}); });
builder.ConfigureServices((host, services) => builder.ConfigureServices((host, services) =>

View file

@ -1,13 +1,57 @@
using Blazored.LocalStorage; using Blazored.LocalStorage;
using Blazored.SessionStorage; using Blazored.SessionStorage;
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Infrastructure;
using Insight.Web.Network.Broker;
using Insight.Web.Network.Broker.Handlers;
using Insight.Web.Network.Remote;
using Insight.Web.Network.Remote.Handlers;
using Insight.Web.Services; using Insight.Web.Services;
using Microsoft.AspNetCore.Components.Server.Circuits; using Microsoft.AspNetCore.Components.Server.Circuits;
using MudBlazor.Services; using MudBlazor.Services;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
using System.Net;
using Vaitr.Network;
using Vaitr.Network.Hosting;
namespace Insight.Web.Extensions; namespace Insight.Web.Extensions;
public static class ServiceExtensions public static class ServiceExtensions
{ {
internal static WebApplicationBuilder AddMetrics(this WebApplicationBuilder builder)
{
builder.Services.AddOpenTelemetry()
.WithMetrics(provider =>
{
provider.ConfigureResource(configure =>
{
configure.Clear();
configure.AddService(builder.Configuration.GetValue<string?>(Appsettings.Influx.Service) ?? throw new Exception($"{Appsettings.Influx.Service} value not set (appsettings)"));
})
.AddRuntimeInstrumentation()
.AddProcessInstrumentation()
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
//.AddMeter("test")
.AddInfluxDBMetricsExporter(configure =>
{
configure.Endpoint = builder.Configuration.GetValue<Uri?>(Appsettings.Influx.Endpoint) ?? throw new Exception($"{Appsettings.Influx.Endpoint} value not set (appsettings)");
configure.Token = builder.Configuration.GetValue<string?>(Appsettings.Influx.Token) ?? throw new Exception($"{Appsettings.Influx.Token} value not set (appsettings)");
configure.Org = builder.Configuration.GetValue<string?>(Appsettings.Influx.Organization) ?? throw new Exception($"{Appsettings.Influx.Organization} value not set (appsettings)");
configure.Bucket = builder.Configuration.GetValue<string?>(Appsettings.Influx.Bucket) ?? throw new Exception($"{Appsettings.Influx.Bucket} value not set (appsettings)");
configure.MetricExportIntervalMilliseconds = 1000;
});
}
);
//builder.Services.AddSingleton<BasicMetrics>();
return builder;
}
internal static IServiceCollection AddWebServices(this IServiceCollection services) internal static IServiceCollection AddWebServices(this IServiceCollection services)
{ {
// HOSTS // HOSTS
@ -42,4 +86,46 @@ public static class ServiceExtensions
return services; return services;
} }
internal static IServiceCollection AddBrokerServices(this IServiceCollection services, IConfiguration configuration)
{
services.UseHostedClient<WebSession, IMessage>(options =>
{
options.Host = configuration.GetValue<string?>(Appsettings.Backend.Host) ?? throw new Exception($"{Appsettings.Backend.Host} value not set (appsettings)");
options.Port = configuration.GetValue<int?>(Appsettings.Backend.Port) ?? throw new Exception($"{Appsettings.Backend.Port} value not set (appsettings)");
options.Keepalive = 10000;
options.Timeout = 30000;
options.Encryption = Encryption.Tls12;
options.Compression = true;
options.UseSerializer<WebSession, IMessage, MemPackSerializer<IMessage>>();
});
services.AddSingleton<IMessageHandler<WebSession>, AgentHandler>();
return services;
}
internal static IServiceCollection AddRemoteServices(this IServiceCollection services, IConfiguration configuration)
{
services.UseHostedServer<RemoteSession, IMessage>(options =>
{
options.Address = IPAddress.Any;
options.Port = configuration.GetValue<int?>(Appsettings.Remote.Port) ?? throw new Exception($"{Appsettings.Remote.Port} value not set (appsettings)");
options.Keepalive = 10000;
options.Timeout = 30000;
options.Backlog = 128;
options.Compression = true;
options.Encryption = Encryption.Tls12;
options.Certificate = configuration.GetValue<string?>(Appsettings.Remote.Certificate) ?? throw new Exception($"{Appsettings.Remote.Certificate} value not set (appsettings)");
options.CertificatePassword = configuration.GetValue<string?>(Appsettings.Remote.CertificatePassword) ?? throw new Exception($"{Appsettings.Remote.CertificatePassword} value not set (appsettings)");
options.UseSerializer<RemoteSession, IMessage, MemPackSerializer<IMessage>>();
});
services.AddSingleton<IMessageHandler<RemoteSession>, RemoteHandler>();
return services;
}
} }

View file

@ -12,6 +12,7 @@
<PublishAot>false</PublishAot> <PublishAot>false</PublishAot>
<PublishTrimmed>false</PublishTrimmed> <PublishTrimmed>false</PublishTrimmed>
<SatelliteResourceLanguages>none</SatelliteResourceLanguages> <SatelliteResourceLanguages>none</SatelliteResourceLanguages>
<InvariantGlobalization>true</InvariantGlobalization>
<!--<ServerGarbageCollection>false</ServerGarbageCollection> <!--<ServerGarbageCollection>false</ServerGarbageCollection>
<ConcurrentGarbageCollection>false</ConcurrentGarbageCollection>--> <ConcurrentGarbageCollection>false</ConcurrentGarbageCollection>-->
</PropertyGroup> </PropertyGroup>
@ -29,13 +30,18 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="8.0.1" />
<PackageReference Include="OpenTelemetry.Exporter.InfluxDB" Version="1.0.0-alpha.3" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Process" Version="0.5.0-beta.4" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.7.0" />
<PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0" /> <PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0" />
<PackageReference Include="Blazored.LocalStorage" Version="4.4.0" /> <PackageReference Include="Blazored.LocalStorage" Version="4.4.0" />
<PackageReference Include="Blazored.SessionStorage" Version="2.4.0" /> <PackageReference Include="Blazored.SessionStorage" Version="2.4.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="8.0.1" />
<PackageReference Include="MudBlazor" Version="6.12.0" /> <PackageReference Include="MudBlazor" Version="6.12.0" />
<PackageReference Include="Vaitr.Bus" Version="2023.12.15.1" /> <PackageReference Include="Vaitr.Bus" Version="2023.12.15.1" />
<!--Unix Serilog stuff-->
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -1,17 +1,9 @@
using Insight.Domain.Constants; using Insight.Domain.Constants;
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Infrastructure; using Insight.Infrastructure;
using Insight.Web.Extensions; using Insight.Web.Extensions;
using Insight.Web.Middleware; using Insight.Web.Middleware;
using Insight.Web.Network.Broker; using System.Diagnostics;
using Insight.Web.Network.Broker.Handlers;
using Insight.Web.Network.Remote;
using Insight.Web.Network.Remote.Handlers;
using System.Net;
using Vaitr.Bus; using Vaitr.Bus;
using Vaitr.Network;
using Vaitr.Network.Hosting;
namespace Insight.Web; namespace Insight.Web;
@ -22,43 +14,26 @@ internal class Program
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
builder.Host.UseWindowsService(options => options.ServiceName = "insight_web"); builder.Host.UseWindowsService(options => options.ServiceName = "insight_web");
builder.Host.UseSystemd(); builder.Host.UseSystemd();
builder.WebHost.UseStaticWebAssets();
// LOGGING // Configuration
builder.Configuration.Defaults();
// Logging
builder.Logging.ClearProviders(); builder.Logging.ClearProviders();
builder.Logging.SetMinimumLevel(LogLevel.Trace); builder.Logging.SetMinimumLevel(LogLevel.Trace);
builder.Logging.AddFilter("Microsoft.AspNetCore", LogLevel.Error); builder.Logging.AddFilter("Microsoft.AspNetCore", LogLevel.Error);
builder.Logging.AddFilter("MudBlazor", LogLevel.Warning); builder.Logging.AddFilter("MudBlazor", LogLevel.Warning);
builder.Logging.AddSimpleConsole(options => builder.Logging.AddSimpleConsole(options =>
{ {
options.IncludeScopes = false; options.IncludeScopes = false;
options.SingleLine = true; options.SingleLine = true;
options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff "; options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff ";
}); });
builder.Logging.AddFile(Configuration.AppDirectory?.FullName + "/logs/" + Process.GetCurrentProcess().ProcessName + "_{Date}.log", LogLevel.Trace, fileSizeLimitBytes: 104857600, retainedFileCountLimit: 10, outputTemplate: "{Timestamp:o} [{Level:u3}] {Message} {NewLine}{Exception}");
builder.Logging.AddFile($"{Configuration.AppDirectory?.FullName}/" + "logs/web_{Date}.log", LogLevel.Trace, fileSizeLimitBytes: 104857600, retainedFileCountLimit: 10, outputTemplate: "{Timestamp:o} [{Level:u3}] {Message} {NewLine}{Exception}"); // Services
// BROKER
builder.Services.AddBrokerServices(builder.Configuration);
// REMOTE
builder.Services.AddRemoteServices(builder.Configuration);
// ASSETS
builder.WebHost.UseStaticWebAssets();
// IDENTITY
builder.Services.AddIdentityServices(builder.Configuration);
builder.Services.AddCustomAuthentication(builder.Configuration);
builder.Services.AddSingleton<Bus>();
// SECURITY
builder.Services.AddAuthorization();
// WEBSERVICES
builder.Services.AddWebServices(); builder.Services.AddWebServices();
builder.Services.AddProxyServices();
builder.Services.AddRoutingServices();
builder.Services.AddSignalR(options => builder.Services.AddSignalR(options =>
{ {
options.EnableDetailedErrors = true; options.EnableDetailedErrors = true;
@ -66,19 +41,23 @@ internal class Program
//options.StreamBufferCapacity = 1024; //options.StreamBufferCapacity = 1024;
options.EnableDetailedErrors = true; options.EnableDetailedErrors = true;
}); });
// INFRASTRUCTURE
builder.Services.AddDatabase(builder.Configuration); builder.Services.AddDatabase(builder.Configuration);
builder.Services.AddInfrastructureServices(); builder.Services.AddIdentity(builder.Configuration);
builder.Services.AddIdentityServices();
builder.Services.AddCustomAuthentication(builder.Configuration);
builder.Services.AddAuthorization();
builder.Services.AddBrokerServices(builder.Configuration);
builder.Services.AddRemoteServices(builder.Configuration);
builder.Services.AddSingleton<Bus>();
// WEB:APP // Modules
builder.AddDefaults();
builder.AddMetrics();
// HTTP Pipeline
var app = builder.Build(); var app = builder.Build();
// BASICS
app.UseForwardedHeaders(); app.UseForwardedHeaders();
//app.UseHttpsRedirection();
// DEV-PROD SETTINGS
if (app.Environment.IsDevelopment()) if (app.Environment.IsDevelopment())
{ {
app.UseDeveloperExceptionPage(); app.UseDeveloperExceptionPage();
@ -89,77 +68,14 @@ internal class Program
//app.UseHsts(); //app.UseHsts();
} }
// CORS
//app.UseCors(x => x
// .AllowAnyOrigin()
// .AllowAnyMethod()
// .AllowAnyHeader());
// ROUTING
app.UseRouting(); app.UseRouting();
// SECURITY
//app.UseAuthentication(); //app.UseAuthentication();
app.UseAuthorization(); app.UseAuthorization();
// MIDDLEWARE
app.UseMiddleware<IdentityMiddleware>(); app.UseMiddleware<IdentityMiddleware>();
// BLAZOR HUBS (SIGNALR)
app.MapBlazorHub(); app.MapBlazorHub();
// FALLBACK
app.MapFallbackToPage("/_Host"); app.MapFallbackToPage("/_Host");
// STATIC FILES
app.UseStaticFiles(); app.UseStaticFiles();
// HOST START
await app.RunAsync().ConfigureAwait(false); await app.RunAsync().ConfigureAwait(false);
} }
} }
internal static class ServiceExtensions
{
internal static IServiceCollection AddBrokerServices(this IServiceCollection services, IConfiguration configuration)
{
services.UseHostedClient<WebSession, IMessage>(options =>
{
options.Host = configuration.GetValue<string?>(Appsettings.Backend.Host) ?? throw new Exception($"{Appsettings.Backend.Host} value not set (appsettings)");
options.Port = configuration.GetValue<int?>(Appsettings.Backend.Port) ?? throw new Exception($"{Appsettings.Backend.Port} value not set (appsettings)");
options.Keepalive = 10000;
options.Timeout = 30000;
options.Encryption = Encryption.Tls12;
options.Compression = true;
options.UseSerializer<WebSession, IMessage, MemPackSerializer<IMessage>>();
});
services.AddSingleton<IMessageHandler<WebSession>, AgentHandler>();
return services;
}
internal static IServiceCollection AddRemoteServices(this IServiceCollection services, IConfiguration configuration)
{
services.UseHostedServer<RemoteSession, IMessage>(options =>
{
options.Address = IPAddress.Any;
options.Port = configuration.GetValue<int?>(Appsettings.Remote.Port) ?? throw new Exception($"{Appsettings.Remote.Port} value not set (appsettings)");
options.Keepalive = 10000;
options.Timeout = 30000;
options.Backlog = 128;
options.Compression = true;
options.Encryption = Encryption.Tls12;
options.Certificate = configuration.GetValue<string?>(Appsettings.Remote.Certificate) ?? throw new Exception($"{Appsettings.Remote.Certificate} value not set (appsettings)");
options.CertificatePassword = configuration.GetValue<string?>(Appsettings.Remote.CertificatePassword) ?? throw new Exception($"{Appsettings.Remote.CertificatePassword} value not set (appsettings)");
options.UseSerializer<RemoteSession, IMessage, MemPackSerializer<IMessage>>();
});
services.AddSingleton<IMessageHandler<RemoteSession>, RemoteHandler>();
return services;
}
}

View file

@ -2,8 +2,14 @@
"AllowedHosts": "*", "AllowedHosts": "*",
"Urls": "http://127.0.0.1:5001", "Urls": "http://127.0.0.1:5001",
// set in env vars
//"influx.endpoint": "http://127.0.0.1:8086",
//"influx.token": "",
"influx.org": "insight",
"influx.bucket": "insight",
"influx.service": "web",
"mongo.connection": "mongodb://db.insight.local:27017", "mongo.connection": "mongodb://db.insight.local:27017",
"mongo.connection0": "mongodb://insight.webmatic.de:27017",
"server.host": "insight.local", "server.host": "insight.local",
"server.port": 3001, "server.port": 3001,

View file

@ -2,6 +2,13 @@
"AllowedHosts": "*", "AllowedHosts": "*",
"Urls": "http://127.0.0.1:5001", "Urls": "http://127.0.0.1:5001",
// set in env vars
//"influx.endpoint": "http://127.0.0.1:8086",
//"influx.token": "",
"influx.org": "insight",
"influx.bucket": "insight",
"influx.service": "web",
"mongo.connection": "mongodb://127.0.0.1:27017", "mongo.connection": "mongodb://127.0.0.1:27017",
"server.host": "127.0.0.1", "server.host": "127.0.0.1",