- Implement RedisCounterService for rate limiting - Implement RuleLoader with timer refresh - Implement RiskEvaluator for local rule evaluation - Implement SamplingService for CAP events - Implement CapEventPublisher for async event publishing - Implement FailoverStrategy for Redis failure handling - Add configuration classes and DI extensions - Add unit tests (9 tests) - Add NuGet publishing script
99 lines
3.4 KiB
C#
99 lines
3.4 KiB
C#
using Fengling.RiskControl;
|
|
using Fengling.RiskControl.Configuration;
|
|
using Fengling.RiskControl.Counter;
|
|
using Fengling.RiskControl.Evaluation;
|
|
using Fengling.RiskControl.Events;
|
|
using Fengling.RiskControl.Failover;
|
|
using Fengling.RiskControl.Rules;
|
|
using Fengling.RiskControl.Sampling;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.Options;
|
|
using DotNetCore.CAP;
|
|
using StackExchange.Redis;
|
|
|
|
namespace Microsoft.Extensions.DependencyInjection;
|
|
|
|
public static class RiskControlClientServiceExtensions
|
|
{
|
|
public static IServiceCollection AddRiskControlClientCore(
|
|
this IServiceCollection services,
|
|
Action<RiskControlClientOptions>? configureOptions = null)
|
|
{
|
|
if (configureOptions != null)
|
|
{
|
|
services.Configure(configureOptions);
|
|
}
|
|
|
|
services.TryAddSingleton<RiskControlClientOptions>(sp =>
|
|
{
|
|
var options = sp.GetRequiredService<IOptions<RiskControlClientOptions>>().Value;
|
|
return options;
|
|
});
|
|
|
|
services.TryAddSingleton<IConnectionMultiplexer>(sp =>
|
|
{
|
|
var options = sp.GetRequiredService<RiskControlClientOptions>();
|
|
var connectionString = options.Redis.ConnectionString;
|
|
var connection = ConnectionMultiplexer.Connect(connectionString);
|
|
return connection;
|
|
});
|
|
|
|
services.TryAddSingleton<IRuleLoader, RedisRuleLoader>();
|
|
services.TryAddSingleton<IRiskCounterService, RedisCounterService>();
|
|
services.TryAddSingleton<IRiskEvaluator, RiskEvaluator>();
|
|
services.TryAddSingleton<ISamplingService, SamplingService>();
|
|
services.TryAddSingleton<IFailoverStrategy, FailoverStrategy>();
|
|
|
|
if (services.Any(s => s.ServiceType == typeof(ICapPublisher)))
|
|
{
|
|
services.TryAddSingleton<IRiskEventPublisher, CapEventPublisher>();
|
|
}
|
|
else
|
|
{
|
|
services.TryAddSingleton<IRiskEventPublisher, NoOpEventPublisher>();
|
|
}
|
|
|
|
services.TryAddSingleton<IRiskControlClient, RiskControlClient>();
|
|
services.TryAddSingleton<RiskControlClientHostedService>();
|
|
|
|
services.TryAddSingleton<IHostedService>(sp => sp.GetRequiredService<RiskControlClientHostedService>());
|
|
|
|
return services;
|
|
}
|
|
|
|
public static IServiceCollection AddRiskControlClient(
|
|
this IServiceCollection services,
|
|
Action<RiskControlClientOptions> configureOptions)
|
|
{
|
|
services.Configure(configureOptions);
|
|
services.AddRiskControlClientCore();
|
|
return services;
|
|
}
|
|
}
|
|
|
|
internal class NoOpEventPublisher : IRiskEventPublisher
|
|
{
|
|
private readonly ILogger<NoOpEventPublisher> _logger;
|
|
|
|
public NoOpEventPublisher(ILogger<NoOpEventPublisher> logger)
|
|
{
|
|
_logger = logger;
|
|
}
|
|
|
|
public Task PublishRiskAssessmentAsync(RiskEvaluationRequest request, RiskEvaluationResult result)
|
|
{
|
|
_logger.LogDebug("CAP publisher not configured, skipping RiskAssessmentEvent");
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public Task PublishRiskAlertAsync(RiskEvaluationRequest request, RiskEvaluationResult result)
|
|
{
|
|
_logger.LogDebug("CAP publisher not configured, skipping RiskAlertEvent");
|
|
return Task.CompletedTask;
|
|
}
|
|
}
|