diff options
Diffstat (limited to 'PagerHandler.cs')
| -rw-r--r-- | PagerHandler.cs | 125 |
1 files changed, 125 insertions, 0 deletions
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<RootPagerHandler> logger; + + public RootPagerHandler(IServiceProvider serviceProvider) { + handlers = typeof(RootPagerHandler).Assembly.GetTypes() + .Where(t => t.IsClass) + .Where(t => t.IsAssignableTo(typeof(IPagerHandler))) + .Where(t => t.GetCustomAttributes<PagerHandlerAttribute>().Any()) + .Select(t => Activator.CreateInstance(t)) + .Cast<IPagerHandler>() + .Select(h => new HandlerEntry(h)) + .ToArray(); + + var config = serviceProvider.GetRequiredService<IConfiguration>(); + + logger = serviceProvider.GetRequiredService<ILogger<RootPagerHandler>>(); + + 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 + } +} |
