Files
ClubPenguinClient/MareSynchronos/Mediator/MareMediator.cs
2023-02-19 22:24:54 +01:00

99 lines
3.7 KiB
C#

using MareSynchronos.Utils;
using Microsoft.Extensions.Logging;
using System.Diagnostics;
using System.Text;
namespace MareSynchronos.Mediator;
public class MareMediator : IDisposable
{
private record MediatorSubscriber(IMediatorSubscriber Subscriber, Action<IMessage> Action);
private readonly Dictionary<Type, HashSet<MediatorSubscriber>> _subscriberDict = new();
private readonly ILogger<MareMediator> _logger;
private readonly PerformanceCollector _performanceCollector;
public MareMediator(ILogger<MareMediator> logger, PerformanceCollector performanceCollector)
{
_logger = logger;
_performanceCollector = performanceCollector;
}
public void Subscribe<T>(IMediatorSubscriber subscriber, Action<IMessage> action) where T : IMessage
{
_subscriberDict.TryAdd(typeof(T), new HashSet<MediatorSubscriber>());
if (!_subscriberDict[typeof(T)].Add(new(subscriber, action)))
{
throw new InvalidOperationException("Already subscribed");
}
}
public void Unsubscribe<T>(IMediatorSubscriber subscriber) where T : IMessage
{
if (_subscriberDict.TryGetValue(typeof(T), out var subscribers))
{
subscribers.RemoveWhere(p => p.Subscriber == subscriber);
}
}
public void Publish(IMessage message)
{
if (_subscriberDict.TryGetValue(message.GetType(), out var subscribers))
{
Stopwatch globalStopwatch = Stopwatch.StartNew();
_performanceCollector.LogPerformance(this, $"Publish>{message.GetType().Name}", () =>
{
foreach (var subscriber in subscribers.Where(s => s.Subscriber != null).ToList())
{
try
{
_performanceCollector.LogPerformance(this, $"Publish>{message.GetType().Name}+{subscriber.Subscriber.GetType().Name}", () => subscriber.Action.Invoke(message));
}
catch (Exception ex)
{
_logger.LogCritical(ex, "Error executing {type} for subscriber {subscriber}, removing from Mediator", message.GetType(), subscriber);
_subscriberDict[message.GetType()].RemoveWhere(s => s == subscriber);
}
}
});
}
}
internal void UnsubscribeAll(IMediatorSubscriber subscriber)
{
foreach (var kvp in _subscriberDict.ToList())
{
var unSubbed = _subscriberDict[kvp.Key].RemoveWhere(p => p.Subscriber == subscriber);
if (unSubbed > 0)
_logger.LogDebug("{sub} unsubscribed from {msg}", subscriber, kvp.Key.Name);
}
}
public void PrintSubscriberInfo()
{
foreach (var kvp in _subscriberDict.ToList().SelectMany(c => c.Value.Select(v => v))
.DistinctBy(p => p.Subscriber).OrderBy(p => p.Subscriber.GetType().FullName, StringComparer.Ordinal))
{
_logger.LogInformation("Subscriber {type}: {sub}", kvp.Subscriber.GetType().FullName, kvp);
StringBuilder sb = new();
sb.Append("=> ");
foreach (var item in _subscriberDict.ToList())
{
if (item.Value.Any(v => v.Subscriber == kvp.Subscriber))
{
sb.Append(item.Key.Name + ", ");
}
}
if (!string.Equals(sb.ToString(), "=> ", StringComparison.Ordinal))
_logger.LogInformation("{sb}", sb.ToString());
_logger.LogInformation("---");
}
}
public void Dispose()
{
_logger.LogTrace("Disposing {type}", GetType());
_subscriberDict.Clear();
}
}