using DotNetCore.CAP; using Fengling.RiskControl.Configuration; using Fengling.RiskControl.Evaluation; using Microsoft.Extensions.Logging; namespace Fengling.RiskControl.Events; public interface IRiskEventPublisher { Task PublishRiskAssessmentAsync(RiskEvaluationRequest request, RiskEvaluationResult result); Task PublishRiskAlertAsync(RiskEvaluationRequest request, RiskEvaluationResult result); } public class CapEventPublisher : IRiskEventPublisher { private readonly ICapPublisher _capPublisher; private readonly RiskControlClientOptions _options; private readonly ILogger _logger; public CapEventPublisher( ICapPublisher capPublisher, RiskControlClientOptions options, ILogger logger) { _capPublisher = capPublisher; _options = options; _logger = logger; } public async Task PublishRiskAssessmentAsync(RiskEvaluationRequest request, RiskEvaluationResult result) { if (!_options.Cap.PublisherEnabled) { _logger.LogDebug("CAP publisher is disabled, skipping event publish"); return; } try { var @event = new RiskAssessmentEvent { MemberId = request.MemberId, EventType = request.EventType, Amount = request.Amount, DeviceFingerprint = request.DeviceFingerprint, IpAddress = request.IpAddress, TotalScore = result.TotalScore, RiskLevel = result.RiskLevel.ToString(), Blocked = result.Blocked, Factors = result.Factors, EvaluatedAt = result.EvaluatedAt }; await _capPublisher.PublishAsync("fengling.risk.assessed", @event); _logger.LogDebug("Published RiskAssessmentEvent for member {MemberId}", request.MemberId); } catch (Exception ex) { _logger.LogError(ex, "Failed to publish RiskAssessmentEvent for member {MemberId}", request.MemberId); } } public async Task PublishRiskAlertAsync(RiskEvaluationRequest request, RiskEvaluationResult result) { if (!_options.Cap.PublisherEnabled) return; try { var @event = new RiskAlertEvent { MemberId = request.MemberId, EventType = request.EventType, RiskLevel = result.RiskLevel.ToString(), TotalScore = result.TotalScore, Blocked = result.Blocked, AlertTime = DateTime.UtcNow, Priority = result.RiskLevel switch { Evaluation.RiskLevel.High => "P0", Evaluation.RiskLevel.Medium => "P1", _ => "P2" } }; await _capPublisher.PublishAsync("fengling.risk.alert", @event); _logger.LogWarning("Published RiskAlertEvent for member {MemberId}, level={Level}", request.MemberId, result.RiskLevel); } catch (Exception ex) { _logger.LogError(ex, "Failed to publish RiskAlertEvent for member {MemberId}", request.MemberId); } } } public class RiskAssessmentEvent { public string MemberId { get; set; } = string.Empty; public string EventType { get; set; } = string.Empty; public int? Amount { get; set; } public string? DeviceFingerprint { get; set; } public string? IpAddress { get; set; } public int TotalScore { get; set; } public string RiskLevel { get; set; } = string.Empty; public bool Blocked { get; set; } public List Factors { get; set; } = new(); public DateTime EvaluatedAt { get; set; } } public class RiskAlertEvent { public string MemberId { get; set; } = string.Empty; public string EventType { get; set; } = string.Empty; public string RiskLevel { get; set; } = string.Empty; public int TotalScore { get; set; } public bool Blocked { get; set; } public DateTime AlertTime { get; set; } public string Priority { get; set; } = string.Empty; }