From e8e3c4cba8ffa0056e984c113cfbb75319e00022 Mon Sep 17 00:00:00 2001 From: Jake Mannens Date: Fri, 20 Sep 2024 16:21:09 +1000 Subject: v0.4-rc1 --- PagerHandler.cs | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 PagerHandler.cs (limited to 'PagerHandler.cs') diff --git a/PagerHandler.cs b/PagerHandler.cs new file mode 100644 index 0000000..8520064 --- /dev/null +++ b/PagerHandler.cs @@ -0,0 +1,125 @@ +using System.Reflection; + +namespace PagerParser; + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)] +public class PagerHandlerAttribute : Attribute {} + +public interface IPagerHandler { + public void OnConfiguring( + ILogger logger, + IConfiguration config, + IServiceProvider serviceProvider); + + public Task StartAsync(CancellationToken ct); + public Task StopAsync(CancellationToken ct); + + public Task HandleMessageAsync( + PagerMessage message, + ParsedPagerMessage? parsedMessage); +} + +public interface IRootPagerHandler { + public Task HandleMessageAsync( + PagerMessage message, + ParsedPagerMessage? parsedMessage); +} + +public class RootPagerHandler : IRootPagerHandler, IHostedService { + private readonly HandlerEntry[] handlers; + + private readonly ILogger logger; + + public RootPagerHandler(IServiceProvider serviceProvider) { + handlers = typeof(RootPagerHandler).Assembly.GetTypes() + .Where(t => t.IsClass) + .Where(t => t.IsAssignableTo(typeof(IPagerHandler))) + .Where(t => t.GetCustomAttributes().Any()) + .Select(t => Activator.CreateInstance(t)) + .Cast() + .Select(h => new HandlerEntry(h)) + .ToArray(); + + var config = serviceProvider.GetRequiredService(); + + logger = serviceProvider.GetRequiredService>(); + + foreach(var entry in handlers) { + var name = entry.Handler.GetType().Name; + var loggerType = typeof(ILogger<>).MakeGenericType(entry.GetType()); + var logger = serviceProvider.GetRequiredService(loggerType); + try { + this.logger.LogDebug($"Configuring page handler: {name}"); + entry.Handler.OnConfiguring((ILogger) logger, config, serviceProvider); + } catch { + // TODO: include exceptions in log on failure + this.logger.LogWarning($"Failed to configure page handler: {name}"); + entry.State = HandlerState.Failed; + } + } + } + + public async Task StartAsync(CancellationToken ct) { + logger.LogInformation("Root pager handler service starting..."); + await Task.WhenAll( + handlers.Select(async e => { + var name = e.Handler.GetType().Name; + if(e.State != HandlerState.Stopped) + return; + logger.LogDebug($"Starting page handler: {name}"); + try { + await e.Handler.StartAsync(ct); + e.State = HandlerState.Started; + } catch { + logger.LogWarning($"Failed to start page handler: {name}"); + e.State = HandlerState.Failed; + } + }).ToArray()); + } + + public async Task StopAsync(CancellationToken ct) { + logger.LogInformation("Root pager handler service stopping..."); + await Task.WhenAll( + handlers.Select(async e => { + var name = e.Handler.GetType().Name; + if(e.State != HandlerState.Started) + return; + logger.LogDebug($"Stopping page handler: {name}"); + try { + await e.Handler.StopAsync(ct); + e.State = HandlerState.Stopped; + } catch { + logger.LogWarning($"Failed to stop page handler: {name}"); + e.State = HandlerState.Failed; + } + }).ToArray()); + } + + public async Task HandleMessageAsync(PagerMessage m, ParsedPagerMessage? pm) { + await Task.WhenAll( + handlers + .Where(e => e.State == HandlerState.Started) + .Select(async e => { + var name = e.Handler.GetType().Name; + try { + await e.Handler.HandleMessageAsync(m, pm); + } catch { + logger.LogWarning($"Page handler {name} failed to handle pager message"); + } + }).ToArray()); + } + + private record HandlerEntry { + public IPagerHandler Handler { get; set; } + public HandlerState State { get; set; } = HandlerState.Stopped; + + public HandlerEntry(IPagerHandler handler) => + Handler = handler; + } + + private enum HandlerState { + Stopped, + Started, + Failed + } +} -- cgit v1.3