Program.cs cleanup, HiveModel change, log level change

Clean up HiveMind Minimal API setup - move configuration to extenstion methods, same for CommunicationControl, move RequestSchema for Hive to HiveModel, make ComControl use it, set minimum log level for files to Information
This commit is contained in:
dsokolovrudakov 2025-02-19 23:02:15 +02:00
parent 744f9ea8e2
commit 21a6a22a9e
19 changed files with 207 additions and 109 deletions

View File

@ -141,8 +141,8 @@ namespace DevOpsProject.CommunicationControl.Logic.Services
Timestamp = DateTime.Now
};
var result = await _hiveHttpClient.SendHiveControlCommandAsync(_communicationControlConfiguration.CurrentValue.RequestScheme,
hive.HiveIP, hive.HivePort, _communicationControlConfiguration.CurrentValue.HiveMindPath, command);
var result = await _hiveHttpClient.SendHiveControlCommandAsync(hive.HiveSchema, hive.HiveIP, hive.HivePort,
_communicationControlConfiguration.CurrentValue.HiveMindPath, command);
isSuccessfullySent = true;
return result;
}

View File

@ -0,0 +1,29 @@
using DevOpsProject.HiveMind.Logic.Services.Interfaces;
using DevOpsProject.HiveMind.Logic.Services;
using Asp.Versioning;
namespace DevOpsProject.HiveMind.API.DI
{
public static class ApiVersioningConfiguration
{
public static IServiceCollection AddApiVersioningConfiguration(this IServiceCollection serviceCollection)
{
serviceCollection.AddApiVersioning(options =>
{
options.DefaultApiVersion = new ApiVersion(1, 0);
options.AssumeDefaultVersionWhenUnspecified = true;
options.ReportApiVersions = true;
options.ApiVersionReader = ApiVersionReader.Combine(
new UrlSegmentApiVersionReader(),
new HeaderApiVersionReader("X-Api-Version")
);
}).AddApiExplorer(options =>
{
options.GroupNameFormat = "'v'VVV";
options.SubstituteApiVersionInUrl = true;
});
return serviceCollection;
}
}
}

View File

@ -0,0 +1,21 @@
namespace DevOpsProject.HiveMind.API.DI
{
public static class CorsConfiguration
{
public static IServiceCollection AddCorsConfiguration(this IServiceCollection serviceCollection, string corsPolicyName)
{
serviceCollection.AddCors(options =>
{
options.AddPolicy(name: corsPolicyName,
policy =>
{
policy.AllowAnyOrigin() //SECURITY WARNING ! Never allow all origins
.AllowAnyMethod()
.AllowAnyHeader();
});
});
return serviceCollection;
}
}
}

View File

@ -0,0 +1,21 @@
using DevOpsProject.Shared.Clients;
using Polly.Extensions.Http;
using Polly;
namespace DevOpsProject.HiveMind.API.DI
{
public static class HttpClientsConfiguration
{
public static IServiceCollection AddHttpClientsConfiguration(this IServiceCollection serviceCollection)
{
var communicationControlTelemetryPolicy = HttpPolicyExtensions
.HandleTransientHttpError()
.WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
serviceCollection.AddHttpClient<HiveMindHttpClient>()
.AddPolicyHandler(communicationControlTelemetryPolicy);
serviceCollection.AddHttpClient("HiveConnectClient");
return serviceCollection;
}
}
}

View File

@ -0,0 +1,14 @@
using DevOpsProject.Shared.Configuration;
namespace DevOpsProject.HiveMind.API.DI
{
public static class OptionsConfiguration
{
public static IServiceCollection AddOptionsConfiguration(this IServiceCollection serviceCollection, IConfiguration configuration)
{
serviceCollection.Configure<HiveCommunicationConfig>(configuration.GetSection("CommunicationConfiguration"));
return serviceCollection;
}
}
}

View File

@ -3,13 +3,10 @@ using Asp.Versioning.Builder;
using DevOpsProject.HiveMind.API.DI;
using DevOpsProject.HiveMind.API.Middleware;
using DevOpsProject.HiveMind.Logic.Services.Interfaces;
using DevOpsProject.Shared.Clients;
using DevOpsProject.Shared.Configuration;
using DevOpsProject.Shared.Models;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using Polly;
using Polly.Extensions.Http;
using Serilog;
var builder = WebApplication.CreateBuilder(args);
@ -19,52 +16,23 @@ builder.Host.UseSerilog((context, services, loggerConfig) =>
.ReadFrom.Services(services)
.Enrich.FromLogContext());
builder.Services.AddApiVersioning(options =>
{
options.DefaultApiVersion = new ApiVersion(1, 0);
options.AssumeDefaultVersionWhenUnspecified = true;
options.ReportApiVersions = true;
options.ApiVersionReader = ApiVersionReader.Combine(
new UrlSegmentApiVersionReader(),
new HeaderApiVersionReader("X-Api-Version")
);
}).AddApiExplorer(options =>
{
options.GroupNameFormat = "'v'VVV";
options.SubstituteApiVersionInUrl = true;
});
builder.Services.AddApiVersioningConfiguration();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddAuthorization();
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "HiveMind - V1", Version = "v1.0" });
});
builder.Services.AddOptionsConfiguration(builder.Configuration);
builder.Services.AddHiveMindLogic();
builder.Services.Configure<HiveCommunicationConfig>(builder.Configuration.GetSection("CommunicationConfiguration"));
var communicationControlTelemetryPolicy = HttpPolicyExtensions
.HandleTransientHttpError()
.WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
builder.Services.AddHttpClient<HiveMindHttpClient>()
.AddPolicyHandler(communicationControlTelemetryPolicy);
// register NAMED client for connect request
builder.Services.AddHttpClient("HiveConnectClient");
builder.Services.AddHttpClientsConfiguration();
string corsPolicyName = "HiveMindCorsPolicy";
builder.Services.AddCors(options =>
{
options.AddPolicy(name: corsPolicyName,
policy =>
{
policy.AllowAnyOrigin() //SECURITY WARNING ! Never allow all origins
.AllowAnyMethod()
.AllowAnyHeader();
});
});
builder.Services.AddCorsConfiguration(corsPolicyName);
builder.Services.AddExceptionHandler<ExceptionHandlingMiddleware>();
builder.Services.AddProblemDetails();
@ -82,7 +50,7 @@ using (var scope = app.Services.CreateScope())
catch (Exception ex)
{
logger.LogError($"Error occured while connecting Hive to Communication Control. \nException text: {ex.Message}");
System.Diagnostics.Process.GetCurrentProcess().Kill();
Environment.Exit(1);
}
}
@ -105,7 +73,6 @@ ApiVersionSet apiVersionSet = app.NewApiVersionSet()
.HasApiVersion(new ApiVersion(1))
.ReportApiVersions()
.Build();
RouteGroupBuilder groupBuilder = app.MapGroup("api/v{apiVersion:apiVersion}").WithApiVersionSet(apiVersionSet);
groupBuilder.MapGet("ping", (IOptionsSnapshot<HiveCommunicationConfig> config) =>

View File

@ -38,7 +38,7 @@
"rollingInterval": "Day",
"rollOnFileSizeLimit": true,
"formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact",
"restrictedToMinimumLevel": "Warning"
"restrictedToMinimumLevel": "Information"
}
}
],

View File

@ -31,6 +31,7 @@ namespace DevOpsProject.HiveMind.Logic.Services
{
var request = new HiveConnectRequest
{
HiveSchema = _communicationConfigurationOptions.RequestSchema,
HiveIP = _communicationConfigurationOptions.HiveIP,
HivePort = _communicationConfigurationOptions.HivePort,
HiveID = _communicationConfigurationOptions.HiveID
@ -68,7 +69,6 @@ namespace DevOpsProject.HiveMind.Logic.Services
HiveInMemoryState.OperationalArea = hiveConnectResponse.OperationalArea;
HiveInMemoryState.CurrentLocation = _communicationConfigurationOptions.InitialLocation;
// HERE - we are starting to send telemetry
StartTelemetry();
}
else
@ -80,7 +80,7 @@ namespace DevOpsProject.HiveMind.Logic.Services
else
{
_logger.LogError($"Failed to connect hive, terminating process");
System.Diagnostics.Process.GetCurrentProcess().Kill();
Environment.Exit(1);
}
}

View File

@ -2,7 +2,6 @@
{
public class ComControlCommunicationConfiguration
{
public string RequestScheme { get; set; }
public string HiveMindPath { get; set; }
}
}

View File

@ -1,13 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DevOpsProject.Shared.Models
namespace DevOpsProject.Shared.Models
{
public class HiveConnectRequest
{
public string HiveSchema { get; set; }
public string HiveIP { get; set; }
public int HivePort { get; set; }
public string HiveID { get; set; }

View File

@ -5,6 +5,7 @@
public string HiveID { get; set; }
public string HiveIP { get; set; }
public int HivePort { get; set; }
public string HiveSchema { get; set; }
public HiveTelemetryModel Telemetry { get; set; }
}
}

View File

@ -25,6 +25,7 @@ namespace DevOpsProject.CommunicationControl.API.Controllers
HiveID = request.HiveID,
HiveIP = request.HiveIP,
HivePort = request.HivePort,
HiveSchema = request.HiveSchema
};
var hiveOperationalArea = await _communicationControlService.ConnectHive(hiveModel);

View File

@ -0,0 +1,27 @@
using Asp.Versioning;
namespace DevOpsProject.CommunicationControl.API.DI
{
public static class ApiVersioningConfiguration
{
public static IServiceCollection AddApiVersioningConfiguration(this IServiceCollection serviceCollection)
{
serviceCollection.AddApiVersioning(options =>
{
options.DefaultApiVersion = new ApiVersion(1, 0);
options.AssumeDefaultVersionWhenUnspecified = true;
options.ReportApiVersions = true;
options.ApiVersionReader = ApiVersionReader.Combine(
new UrlSegmentApiVersionReader(),
new HeaderApiVersionReader("X-Api-Version")
);
}).AddApiExplorer(options =>
{
options.GroupNameFormat = "'v'VVV";
options.SubstituteApiVersionInUrl = true;
});
return serviceCollection;
}
}
}

View File

@ -0,0 +1,21 @@
namespace DevOpsProject.CommunicationControl.API.DI
{
public static class CorsConfiguration
{
public static IServiceCollection AddCorsConfiguration(this IServiceCollection serviceCollection, string corsPolicyName)
{
serviceCollection.AddCors(options =>
{
options.AddPolicy(name: corsPolicyName,
policy =>
{
policy.AllowAnyOrigin() //SECURITY WARNING ! Never allow all origins
.AllowAnyMethod()
.AllowAnyHeader();
});
});
return serviceCollection;
}
}
}

View File

@ -0,0 +1,20 @@
using DevOpsProject.Shared.Clients;
using Polly;
using Polly.Extensions.Http;
namespace DevOpsProject.CommunicationControl.API.DI
{
public static class HttpClientsConfiguration
{
public static IServiceCollection AddHttpClientsConfiguration(this IServiceCollection serviceCollection)
{
var hiveRetryPolicy = HttpPolicyExtensions
.HandleTransientHttpError()
.WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
serviceCollection.AddHttpClient<CommunicationControlHttpClient>()
.AddPolicyHandler(hiveRetryPolicy);
return serviceCollection;
}
}
}

View File

@ -0,0 +1,15 @@
namespace DevOpsProject.CommunicationControl.API.DI
{
public static class JsonControllerOptionsConfiguration
{
public static IServiceCollection AddJsonControllerOptionsConfiguration(this IServiceCollection serviceCollection)
{
serviceCollection.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNamingPolicy = null;
});
return serviceCollection;
}
}
}

View File

@ -0,0 +1,16 @@
using DevOpsProject.Shared.Configuration;
using DevOpsProject.Shared.Models;
namespace DevOpsProject.CommunicationControl.API.DI
{
public static class OptionsConfiguration
{
public static IServiceCollection AddOptionsConfiguration(this IServiceCollection serviceCollection, IConfiguration configuration)
{
serviceCollection.Configure<OperationalAreaConfig>(configuration.GetSection("OperationalArea"));
serviceCollection.Configure<ComControlCommunicationConfiguration>(configuration.GetSection("CommunicationConfiguration"));
return serviceCollection;
}
}
}

View File

@ -1,13 +1,6 @@
using Asp.Versioning;
using DevOpsProject.CommunicationControl.API.DI;
using DevOpsProject.CommunicationControl.API.Middleware;
using DevOpsProject.Shared.Clients;
using DevOpsProject.Shared.Configuration;
using DevOpsProject.Shared.Models;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using Polly;
using Polly.Extensions.Http;
using Serilog;
internal class Program
@ -21,26 +14,11 @@ internal class Program
.ReadFrom.Services(services)
.Enrich.FromLogContext());
builder.Services.AddApiVersioning(options =>
{
options.DefaultApiVersion = new ApiVersion(1, 0);
options.AssumeDefaultVersionWhenUnspecified = true;
options.ReportApiVersions = true;
options.ApiVersionReader = ApiVersionReader.Combine(
new UrlSegmentApiVersionReader(),
new HeaderApiVersionReader("X-Api-Version")
);
}).AddApiExplorer(options =>
{
options.GroupNameFormat = "'v'VVV";
options.SubstituteApiVersionInUrl = true;
});
builder.Services.AddApiVersioningConfiguration();
// TODO: consider this approach
builder.Services.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNamingPolicy = null;
}); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddJsonControllerOptionsConfiguration();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
@ -52,36 +30,12 @@ internal class Program
builder.Services.AddRedis(builder.Configuration);
builder.Services.AddCommunicationControlLogic();
builder.Services.Configure<OperationalAreaConfig>(builder.Configuration.GetSection("OperationalArea"));
builder.Services.Configure<ComControlCommunicationConfiguration>(builder.Configuration.GetSection("CommunicationConfiguration"));
var hiveRetryPolicy = HttpPolicyExtensions
.HandleTransientHttpError()
.WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
builder.Services.AddHttpClient<CommunicationControlHttpClient>()
.AddPolicyHandler(hiveRetryPolicy);
builder.Services.AddOptionsConfiguration(builder.Configuration);
builder.Services.AddHttpClientsConfiguration();
var corsPolicyName = "AllowReactApp";
var localCorsPolicyName = "AllowLocalHtml";
builder.Services.AddCors(options =>
{
options.AddPolicy(name: corsPolicyName,
policy =>
{
policy.AllowAnyOrigin() //SECURITY WARNING ! Never allow all origins
.AllowAnyMethod()
.AllowAnyHeader();
});
options.AddPolicy(name: localCorsPolicyName,
policy =>
{
policy.AllowAnyOrigin() //SECURITY WARNING ! Never allow all origins
.AllowAnyMethod()
.AllowAnyHeader();
});
});
builder.Services.AddCorsConfiguration(corsPolicyName);
builder.Services.AddExceptionHandler<ExceptionHandlingMiddleware>();
builder.Services.AddProblemDetails();
@ -97,7 +51,6 @@ internal class Program
}
app.UseCors(corsPolicyName);
//app.UseCors(localCorsPolicyName);
app.UseAuthorization();

View File

@ -14,10 +14,8 @@
"InitialSpeed_KM": 5,
"TelemetryInterval_MS": 30000,
"PingInterval_MS": 15000
},
"CommunicationConfiguration": {
"RequestScheme": "http",
"HiveMindPath": "api/v1"
},
"AllowedHosts": "*",
@ -45,7 +43,7 @@
"rollingInterval": "Day",
"rollOnFileSizeLimit": true,
"formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact",
"restrictedToMinimumLevel": "Warning"
"restrictedToMinimumLevel": "Information"
}
}
],