Merge branch 'Cleanup' into 'main'

Program.cs cleanup, HiveModel change, log level change

See merge request kzotkin/hiveemulator!3
This commit is contained in:
Kirill 2025-02-20 14:41:51 +00:00
commit 08f30fc7fc
24 changed files with 294 additions and 186 deletions

View File

@ -37,7 +37,7 @@ namespace DevOpsProject.CommunicationControl.Logic.Services
bool isSuccessfullyDisconnected = false;
try
{
var result = await _redisService.DeleteAsync(hiveId);
var result = await _redisService.DeleteAsync(GetHiveKey(hiveId));
isSuccessfullyDisconnected = result;
return result;
}
@ -65,9 +65,11 @@ namespace DevOpsProject.CommunicationControl.Logic.Services
public async Task<HiveOperationalArea> ConnectHive(HiveModel model)
{
_logger.LogInformation("Trying to connect Hive: {@model}", model);
bool result = await _redisService.SetAsync(GetHiveKey(model.HiveID), model);
if (result)
{
_logger.LogInformation("Successfully connected Hive: {@model}", model);
var operationalArea = _spatialService.GetHiveOperationalArea(model);
await _messageBus.Publish(new HiveConnectedMessage
{
@ -80,46 +82,41 @@ namespace DevOpsProject.CommunicationControl.Logic.Services
}
else
{
await _messageBus.Publish(new HiveConnectedMessage
{
HiveID = model.HiveID,
Hive = model,
IsSuccessfullyConnected = result
});
_logger.LogError("Failed to connect Hive: {@model}", model);
throw new HiveConnectionException($"Failed to connect hive for HiveId: {model.HiveID}");
}
}
public async Task<bool> IsHiveConnected(string hiveId)
{
string hiveKey = GetHiveKey(hiveId);
return await _redisService.CheckIfKeyExists(hiveKey);
}
public async Task<DateTime> AddTelemetry(HiveTelemetryModel model)
{
string hiveKey = GetHiveKey(model.HiveID);
bool hiveExists = await _redisService.CheckIfKeyExists(hiveKey);
if (hiveExists)
bool result = await _redisService.UpdateAsync(hiveKey, (HiveModel hive) =>
{
bool result = await _redisService.UpdateAsync(hiveKey, (HiveModel hive) =>
{
hive.Telemetry = model;
});
hive.Telemetry = model;
});
await _messageBus.Publish(new TelemetrySentMessage
{
HiveID = model.HiveID,
Telemetry = model,
IsSuccessfullySent = result
});
return model.Timestamp;
if (result)
{
_logger.LogInformation("Telemetry updated for HiveID: {hiveId}. Updated telemetry timestamp: {timestamp}", model.HiveID, model.Timestamp);
}
else
{
await _messageBus.Publish(new TelemetrySentMessage
{
HiveID = model.HiveID,
Telemetry = model,
IsSuccessfullySent = false
});
throw new HiveNotFoundException($"Hive not found for id: {model.HiveID}");
_logger.LogError("Failed to update Telemetry - Redis update issue. HiveID: {hiveId}, Telemetry model: {@telemetry}", model.HiveID, model);
}
await _messageBus.Publish(new TelemetrySentMessage
{
HiveID = model.HiveID,
Telemetry = model,
IsSuccessfullySent = result
});
return model.Timestamp;
}
public async Task<string> SendHiveControlSignal(string hiveId, Location destination)
@ -127,33 +124,40 @@ namespace DevOpsProject.CommunicationControl.Logic.Services
var hive = await GetHiveModel(hiveId);
if (hive == null)
{
throw new Exception($"Hive control signal error: cannot find hive with id: {hiveId}");
_logger.LogError("Sending Hive Control signal: Hive not found for HiveID: {hiveId}", hiveId);
return null;
}
bool isSuccessfullySent = false;
string hiveMindPath = _communicationControlConfiguration.CurrentValue.HiveMindPath;
var command = new MoveHiveMindCommand
{
CommandType = State.Move,
Location = destination,
Timestamp = DateTime.Now
};
try
{
var command = new MoveHiveMindCommand
{
CommandType = State.Move,
Location = destination,
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, hiveMindPath, command);
isSuccessfullySent = true;
return result;
}
finally
{
await _messageBus.Publish(new MoveHiveMessage
if (isSuccessfullySent)
{
IsSuccessfullySent = isSuccessfullySent,
Destination = destination,
HiveID = hiveId
});
await _messageBus.Publish(new MoveHiveMessage
{
IsSuccessfullySent = isSuccessfullySent,
Destination = destination,
HiveID = hiveId
});
}
else
{
_logger.LogError("Failed to send control command for Hive: {@hive}, path: {path}, \n Command: {@command}", hive, hiveMindPath, command);
}
}
}

View File

@ -8,6 +8,7 @@ namespace DevOpsProject.CommunicationControl.Logic.Services.Interfaces
Task<HiveModel> GetHiveModel(string hiveId);
Task<List<HiveModel>> GetAllHives();
Task<HiveOperationalArea> ConnectHive(HiveModel model);
Task<bool> IsHiveConnected(string hiveId);
Task<DateTime> AddTelemetry(HiveTelemetryModel model);
Task<string> SendHiveControlSignal(string hiveId, Location destination);
}

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

@ -27,6 +27,7 @@ namespace DevOpsProject.HiveMind.Logic.Services
// If already moving - stop movement
if (HiveInMemoryState.IsMoving)
{
_logger.LogWarning("Previous movement command terminated. Previous destination: {@destination}, Current Location: {@current}, new destination: {@destination}", HiveInMemoryState.Destination, HiveInMemoryState.CurrentLocation, destination);
StopMovement();
}
@ -39,8 +40,9 @@ namespace DevOpsProject.HiveMind.Logic.Services
if (_movementTimer == null)
{
// TODO: Recalculating position each N seconds
_movementTimer = new Timer(UpdateMovement, null, TimeSpan.Zero, TimeSpan.FromSeconds(3));
_logger.LogInformation("Movement timer started.");
int intervalFromSeconds = 3;
_movementTimer = new Timer(UpdateMovement, null, TimeSpan.Zero, TimeSpan.FromSeconds(intervalFromSeconds));
_logger.LogInformation("Movement timer started. Destination: {@destination}, recalculation interval: {interval}", destination, intervalFromSeconds);
}
}
}
@ -60,14 +62,13 @@ namespace DevOpsProject.HiveMind.Logic.Services
if (AreLocationsEqual(currentLocation.Value, destination.Value))
{
_logger.LogInformation("Reached destination. Current location: {@currentLocation}, Destination: {@destination}", currentLocation, destination);
StopMovement();
return;
}
Location newLocation = CalculateNextPosition(currentLocation.Value, destination.Value, 0.1f);
HiveInMemoryState.CurrentLocation = newLocation;
_logger.LogInformation($"Moved closer: {newLocation}");
}
}
@ -77,7 +78,6 @@ namespace DevOpsProject.HiveMind.Logic.Services
_movementTimer = null;
HiveInMemoryState.IsMoving = false;
HiveInMemoryState.Destination = null;
_logger.LogInformation("Movement stopped: Reached destination.");
}
private static bool AreLocationsEqual(Location loc1, Location loc2)

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
@ -47,6 +48,8 @@ namespace DevOpsProject.HiveMind.Logic.Services
};
var jsonContent = new StringContent(JsonSerializer.Serialize(request), Encoding.UTF8, "application/json");
_logger.LogInformation("Attempting to connect Hive. Request: {@request}, URI: {uri}", request, uriBuilder.Uri);
var retryPolicy = Policy.HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
.WaitAndRetryAsync(
10,
@ -68,7 +71,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 +82,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,19 +0,0 @@
namespace DevOpsProject.Shared.Exceptions
{
public class HiveNotFoundException : Exception
{
public HiveNotFoundException()
{
}
public HiveNotFoundException(string message)
: base(message)
{
}
public HiveNotFoundException(string message, Exception inner)
: base(message, inner)
{
}
}
}

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

@ -32,17 +32,21 @@ namespace DevOpsProject.CommunicationControl.API.Controllers
[HttpGet("hive/{hiveId}")]
public async Task<IActionResult> GetHive(string hiveId)
{
var hiveModel = await _communicationControlService.GetHiveModel(hiveId);
var hiveExists = await _communicationControlService.IsHiveConnected(hiveId);
if (!hiveExists)
{
_logger.LogWarning("Failed to get Hive for HiveID: {hiveId}", hiveId);
return NotFound($"Hive with HiveID: {hiveId} is not found");
}
var hiveModel = await _communicationControlService.GetHiveModel(hiveId);
return Ok(hiveModel);
}
[HttpGet("hive")]
public async Task<IActionResult> GetHives()
{
var hives = await _communicationControlService.GetAllHives();
return Ok(hives);
}
@ -59,6 +63,7 @@ namespace DevOpsProject.CommunicationControl.API.Controllers
if (request?.Hives == null || !request.Hives.Any())
return BadRequest("No hive IDs provided.");
_logger.LogInformation("Hive moving request accepted by enpdoint. Request: {@request}", request);
foreach (var id in request.Hives)
{
_ = Task.Run(async () =>
@ -69,7 +74,7 @@ namespace DevOpsProject.CommunicationControl.API.Controllers
}
catch (Exception ex)
{
_logger.LogError(ex, $"Failed to send control signal for HiveID: {id}");
_logger.LogError(ex, "Failed to send control signal for HiveID: {id} \n Request: {@request}", id, request);
}
});
}

View File

@ -11,10 +11,12 @@ namespace DevOpsProject.CommunicationControl.API.Controllers
public class HiveController : Controller
{
private readonly ICommunicationControlService _communicationControlService;
private readonly ILogger<HiveController> _logger;
public HiveController(ICommunicationControlService communicationControlService)
public HiveController(ICommunicationControlService communicationControlService, ILogger<HiveController> logger)
{
_communicationControlService = communicationControlService;
_logger = logger;
}
[HttpPost("connect")]
@ -25,8 +27,16 @@ namespace DevOpsProject.CommunicationControl.API.Controllers
HiveID = request.HiveID,
HiveIP = request.HiveIP,
HivePort = request.HivePort,
HiveSchema = request.HiveSchema
};
bool isConnected = await _communicationControlService.IsHiveConnected(request.HiveID);
if (isConnected)
{
_logger.LogError("Hive with HiveID: {hiveId} already connected. Request: {@request}", request.HiveID, request);
return BadRequest($"Hive with HiveID: {request.HiveID} already connected");
}
var hiveOperationalArea = await _communicationControlService.ConnectHive(hiveModel);
var connectResponse = new HiveConnectResponse
{
@ -35,6 +45,7 @@ namespace DevOpsProject.CommunicationControl.API.Controllers
};
return Ok(connectResponse);
}
[HttpPost("telemetry")]
@ -50,13 +61,22 @@ namespace DevOpsProject.CommunicationControl.API.Controllers
Timestamp = DateTime.Now
};
var telemetryUpdateTimestamp = await _communicationControlService.AddTelemetry(hiveTelemetryModel);
var telemetryResponse = new HiveTelemetryResponse
bool isHiveConnected = await _communicationControlService.IsHiveConnected(request.HiveID);
if (isHiveConnected)
{
Timestamp = telemetryUpdateTimestamp
};
var telemetryUpdateTimestamp = await _communicationControlService.AddTelemetry(hiveTelemetryModel);
var telemetryResponse = new HiveTelemetryResponse
{
Timestamp = telemetryUpdateTimestamp
};
return Ok(telemetryResponse);
return Ok(telemetryResponse);
}
else
{
_logger.LogWarning("Failed to write telemetry. Hive with HiveID: {hiveId} is not connected. Request: {@request}", request.HiveID, request);
return NotFound($"Failed to write telemetry. Hive with HiveID: {request.HiveID} is not connected");
}
}
}

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

@ -12,7 +12,5 @@ namespace DevOpsProject.CommunicationControl.API.DI
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"
}
}
],