Skip to content

Commit

Permalink
Added monitor rule service.
Browse files Browse the repository at this point in the history
  • Loading branch information
n.bitounis committed Jun 21, 2020
1 parent 5fa7d1a commit 116d1de
Show file tree
Hide file tree
Showing 21 changed files with 536 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Linq;
using System.Runtime.CompilerServices;
using Microsoft.AspNetCore.Mvc;
using SesNotifications.App.Factories;
using SesNotifications.App.Models;
Expand Down
23 changes: 23 additions & 0 deletions Projects/SesNotifications.App/Helpers/MatchingHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Text.RegularExpressions;
using Newtonsoft.Json.Linq;

namespace SesNotifications.App.Helpers
{
public static class MatchingHelpers
{
public static JToken TokenizeJson(this string json)
{
return JToken.Parse(json);
}

public static JToken FindToken(this JToken token, string jsonMatcher)
{
return token.SelectToken(jsonMatcher);
}

public static bool IsMatch(this string value, string regex)
{
return new Regex(regex).IsMatch(value);
}
}
}
13 changes: 13 additions & 0 deletions Projects/SesNotifications.App/Models/MonitorRuleType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace SesNotifications.App.Models
{
public enum MonitorRuleType
{
BounceEvent = 0,
ComplaintNotification,
ComplaintEvent,
DeliveryNotification,
DeliveryEvent,
OpenEvent,
SendEvent
}
}
10 changes: 10 additions & 0 deletions Projects/SesNotifications.App/Models/SqsConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace SesNotifications.App.Models
{
public class SqsConfiguration
{
public virtual string QueueUrl { get; set; }
public virtual string Region { get; set; }
public virtual string AccessKey { get; set; }
public virtual string SecretKey { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using SesNotifications.App.Models;

namespace SesNotifications.App.Services.Interfaces
{
public interface IRuleService
{
void ProcessMessage(string json, MonitorRuleType ruleType);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using SesNotifications.App.Models;

namespace SesNotifications.App.Services.Interfaces
{
public interface ISqsNotifier
{
void Notify(string header, string message, SqsConfiguration configuration);
}
}
24 changes: 21 additions & 3 deletions Projects/SesNotifications.App/Services/NotificationService.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using NLog;
using SesNotifications.App.Factories;
Expand Down Expand Up @@ -29,6 +28,7 @@ public class NotificationService : INotificationService
private readonly ISesDeliveryEventsRepository _sesDeliveryEventsRepository;
private readonly ISesBounceEventsRepository _sesBounceEventsRepository;
private readonly ISesComplaintEventsRepository _sesComplaintEventsRepository;
private readonly IRuleService _ruleService;

public NotificationService(INotificationsRepository notificationsRepository,
ISesBouncesRepository sesBouncesRepository,
Expand All @@ -38,8 +38,9 @@ public NotificationService(INotificationsRepository notificationsRepository,
ISesSendEventsRepository sesSendEventsRepository,
ISesDeliveryEventsRepository sesDeliveryEventsRepository,
ISesBounceEventsRepository sesBounceEventsRepository,
ISesComplaintEventsRepository sesComplaintEventsRepository
)
ISesComplaintEventsRepository sesComplaintEventsRepository,
IRuleService ruleService
)
{
_notificationsRepository = notificationsRepository;
_sesBouncesRepository = sesBouncesRepository;
Expand All @@ -51,6 +52,7 @@ ISesComplaintEventsRepository sesComplaintEventsRepository
_sesDeliveryEventsRepository = sesDeliveryEventsRepository;
_sesBounceEventsRepository = sesBounceEventsRepository;
_sesComplaintEventsRepository = sesComplaintEventsRepository;
_ruleService = ruleService;
}

public void HandleNotification(string content)
Expand Down Expand Up @@ -127,6 +129,8 @@ private void HandleComplaintEvent(string content)
var notification = SaveNotification(complaintEvent.Mail, content);

_sesComplaintEventsRepository.Save(complaintEvent.Create(notification.Id));

_ruleService.ProcessMessage(content, MonitorRuleType.ComplaintEvent);
}

private void HandleBounceEvent(string content)
Expand All @@ -136,6 +140,8 @@ private void HandleBounceEvent(string content)
var notification = SaveNotification(bounceEvent.Mail, content);

_sesBounceEventsRepository.Save(bounceEvent.Create(notification.Id));

_ruleService.ProcessMessage(content, MonitorRuleType.BounceEvent);
}

private void HandleDeliveryEvent(string content)
Expand All @@ -145,6 +151,8 @@ private void HandleDeliveryEvent(string content)
var notification = SaveNotification(delivery.Mail, content);

_sesDeliveryEventsRepository.Save(delivery.Create(notification.Id));

_ruleService.ProcessMessage(content, MonitorRuleType.DeliveryEvent);
}

private void HandleDelivery(string content)
Expand All @@ -154,6 +162,8 @@ private void HandleDelivery(string content)
var notification = SaveNotification(delivery.Mail, content);

_sesDeliveriesRepository.Save(delivery.Create(notification.Id));

_ruleService.ProcessMessage(content, MonitorRuleType.DeliveryNotification);
}

private void HandleComplaint(string content)
Expand All @@ -163,6 +173,8 @@ private void HandleComplaint(string content)
var notification = SaveNotification(complaint.Mail, content);

_sesComplaintsRepository.Save(complaint.Create(notification.Id));

_ruleService.ProcessMessage(content, MonitorRuleType.ComplaintNotification);
}

private void HandleBounce(string content)
Expand All @@ -172,6 +184,8 @@ private void HandleBounce(string content)
var notification = SaveNotification(bounce.Mail, content);

_sesBouncesRepository.Save(bounce.Create(notification.Id));

_ruleService.ProcessMessage(content, MonitorRuleType.BounceEvent);
}

private void HandleOpenEvent(string content)
Expand All @@ -181,6 +195,8 @@ private void HandleOpenEvent(string content)
var notification = SaveNotification(open.Mail, content);

_sesOpensEventsRepository.Save(open.Create(notification.Id));

_ruleService.ProcessMessage(content, MonitorRuleType.OpenEvent);
}

private void HandleSendEvent(string content)
Expand All @@ -190,6 +206,8 @@ private void HandleSendEvent(string content)
var notification = SaveNotification(send.Mail, content);

_sesSendEventsRepository.Save(send.Create(notification.Id));

_ruleService.ProcessMessage(content, MonitorRuleType.SendEvent);
}

private SesNotification SaveNotification(SesMail mail, string content)
Expand Down
79 changes: 79 additions & 0 deletions Projects/SesNotifications.App/Services/RuleService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using System;
using System.Linq;
using Newtonsoft.Json;
using NLog;
using SesNotifications.App.Helpers;
using SesNotifications.App.Models;
using SesNotifications.App.Services.Interfaces;
using SesNotifications.DataAccess.Repositories.Interfaces;

namespace SesNotifications.App.Services
{
public class RuleService : IRuleService
{
private static readonly ILogger Logger = LogManager.GetCurrentClassLogger();

private readonly IMonitorRuleRepository _monitorRuleRepository;
private readonly ISqsNotifier _sqsNotifier;
private readonly SqsConfiguration _sqsConfiguration;

public RuleService(IConfigurationRepository configurationRepository,
IMonitorRuleRepository monitorRuleRepository,
ISqsNotifier sqsNotifier)
{
_monitorRuleRepository = monitorRuleRepository;
_sqsNotifier = sqsNotifier;

var sqsConfig = configurationRepository.GetByKey("sqs_notification_config");
if (sqsConfig == null)
{
Logger.Debug("No SQS notification configuration found");
return;
}

try
{
_sqsConfiguration = JsonConvert.DeserializeObject<SqsConfiguration>(sqsConfig.Value);
}
catch (Exception e)
{
Logger.Error(e, "SQS notification configuration is invalid");
_sqsConfiguration = null;
}
}

public void ProcessMessage(string json, MonitorRuleType ruleType)
{
if (_sqsConfiguration == null)
{
return;
}

var rules = _monitorRuleRepository.GetAll();
var typeRules = rules.Where(x => x.SesMessage.ToLower() == ruleType.ToString().ToLower()).ToList();

if (typeRules.Count == 0)
{
return;
}

var o = json.TokenizeJson();

foreach (var rule in typeRules)
{
var extracted = o.FindToken(rule.JsonMatcher);
if (extracted == null)
{
break;
}

var isMatch = extracted.ToString().IsMatch(rule.Regex);

if (isMatch)
{
_sqsNotifier.Notify($"Rule {rule.Name} match", extracted.ToString(), _sqsConfiguration);
}
}
}
}
}
69 changes: 69 additions & 0 deletions Projects/SesNotifications.App/Services/SqsNotifier.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading;
using Amazon;
using Amazon.Runtime;
using Amazon.SQS;
using Amazon.SQS.Model;
using NLog;
using SesNotifications.App.Models;
using SesNotifications.App.Services.Interfaces;

namespace SesNotifications.App.Services
{
public class SqsNotifier : ISqsNotifier, IDisposable
{
private static readonly ILogger Logger = LogManager.GetCurrentClassLogger();

private AmazonSQSClient _sqsClient;

public void Notify(string header, string message, SqsConfiguration configuration)
{
var client = CreateClient(configuration);

try
{
var response = client.SendMessageAsync(new SendMessageRequest
{
QueueUrl = configuration.QueueUrl,
MessageBody = message,
MessageAttributes = new Dictionary<string, MessageAttributeValue>
{
["Title"] = new MessageAttributeValue { DataType = "String", StringValue = header }
}
}, CancellationToken.None).Result;

if (response.HttpStatusCode != HttpStatusCode.OK)
{
Logger.Error($"Error while sending SNS notification, status code {response.HttpStatusCode}");
}
}
catch (Exception e)
{
Logger.Error(e, "Unexpected error while sending SQS notification");
}
}

private AmazonSQSClient CreateClient(SqsConfiguration configuration)
{
if (_sqsClient == null)
{
_sqsClient = string.IsNullOrEmpty(configuration.AccessKey)
? new AmazonSQSClient(new AmazonSQSConfig
{
RegionEndpoint = RegionEndpoint.GetBySystemName(configuration.Region)
})
: new AmazonSQSClient(new BasicAWSCredentials(configuration.AccessKey, configuration.SecretKey),
RegionEndpoint.GetBySystemName(configuration.Region));
}

return _sqsClient;
}

public void Dispose()
{
_sqsClient?.Dispose();
}
}
}
1 change: 1 addition & 0 deletions Projects/SesNotifications.App/SesNotifications.App.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="AWSSDK.SQS" Version="3.3.102.128" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="3.1.5" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="NLog.Web.AspNetCore" Version="4.9.2" />
Expand Down
2 changes: 2 additions & 0 deletions Projects/SesNotifications.App/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ public void ConfigureScopedRepositories(IServiceCollection services)
{
services.AddScoped<INotificationService, NotificationService>();
services.AddScoped<ISearchService, SearchService>();
services.AddScoped<ISqsNotifier, SqsNotifier>();
services.AddScoped<IRuleService, RuleService>();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace SesNotifications.DataAccess.Entities
{
public class ConfigurationItem
{
public virtual int Id { get; set; }
public virtual string Key { get; set; }
public virtual string Value { get; set; }
}
}
17 changes: 17 additions & 0 deletions Projects/SesNotifications.DataAccess/Mappings/ConfigurationMap.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using FluentNHibernate.Mapping;
using SesNotifications.DataAccess.Entities;

namespace SesNotifications.DataAccess.Mappings
{
public class ConfigurationMap : ClassMap<ConfigurationItem>
{
public ConfigurationMap()
{
Table("ses_notifications.configuration");
Id(x => x.Id).Column("id").GeneratedBy.Identity();
Map(x => x.Key).Column("key");
Map(x => x.Value).Column("value");
Cache.ReadOnly();
}
}
}
Loading

0 comments on commit 116d1de

Please sign in to comment.