From cc5608f1647c103c5f90fb283771209b9f4c99a9 Mon Sep 17 00:00:00 2001 From: "pa.pecherskij" Date: Tue, 30 Sep 2025 22:06:26 +0300 Subject: [PATCH] feat: use MessagePipe as event dispatcher --- .../GitHubApi/GithubRetryHandlerTests.cs | 8 +-- .../DiscourseApi/DummyDiscourseClient.cs | 4 +- SS14.Labeller/Endpoints/GithubWebhook.cs | 5 +- SS14.Labeller/GenericPublisher.cs | 35 ++++++++++++ SS14.Labeller/GitHubApi/GithubRetryHandler.cs | 2 +- .../Handlers/GitHubWebhookHandlerService.cs | 12 ---- SS14.Labeller/Handlers/LabelIssueHandler.cs | 15 ++--- .../Handlers/LabelPullRequestHandler.cs | 54 +++++++++--------- .../Handlers/LabelPullRequestReviewHandler.cs | 27 ++++----- SS14.Labeller/Handlers/RequestHandlerBase.cs | 31 ---------- ...onServicesInitializingBackgroundService.cs | 56 +++++++++++++++++++ .../IOnApplicationStartInitializable.cs | 22 ++++++++ .../MessagePipeSubscriptionManager.cs | 43 ++++++++++++++ SS14.Labeller/Registry.cs | 29 ++++++---- SS14.Labeller/SS14.Labeller.csproj | 6 +- 15 files changed, 240 insertions(+), 109 deletions(-) create mode 100644 SS14.Labeller/GenericPublisher.cs delete mode 100644 SS14.Labeller/Handlers/GitHubWebhookHandlerService.cs delete mode 100644 SS14.Labeller/Handlers/RequestHandlerBase.cs create mode 100644 SS14.Labeller/Initialization/ApplicationServicesInitializingBackgroundService.cs create mode 100644 SS14.Labeller/Initialization/IOnApplicationStartInitializable.cs create mode 100644 SS14.Labeller/Initialization/MessagePipeSubscriptionManager.cs diff --git a/SS14.Labeller.Tests/GitHubApi/GithubRetryHandlerTests.cs b/SS14.Labeller.Tests/GitHubApi/GithubRetryHandlerTests.cs index 9ee15ab..898cca9 100644 --- a/SS14.Labeller.Tests/GitHubApi/GithubRetryHandlerTests.cs +++ b/SS14.Labeller.Tests/GitHubApi/GithubRetryHandlerTests.cs @@ -39,7 +39,7 @@ public void SendAsync_SuccessfulRequest() _mockInnerHandler.Send(Arg.Any(), Arg.Any()) .Returns(Task.FromResult(new HttpResponseMessage { StatusCode = HttpStatusCode.OK })); - var handler = new GithubRetryHandler(_mockInnerHandler, _config, _logger); + var handler = new GithubRetryHandler(_config, _logger) { InnerHandler = _mockInnerHandler }; var httpClient = new HttpClient(handler); // Act @@ -59,7 +59,7 @@ public void SendAsync_NetworkErrorRetries() _=> Task.FromResult(new HttpResponseMessage { StatusCode = HttpStatusCode.OK }) ); - var handler = new GithubRetryHandler(_mockInnerHandler, _config, _logger); + var handler = new GithubRetryHandler(_config, _logger) { InnerHandler = _mockInnerHandler }; var httpClient = new HttpClient(handler); // Act @@ -87,7 +87,7 @@ public void SendAsync_CalculateNextRequestTimeWithRateLimits() _mockInnerHandler.Send(Arg.Any(), Arg.Any()) .Returns(response1, response2); - var handler = new GithubRetryHandler(_mockInnerHandler, _config, _logger); + var handler = new GithubRetryHandler(_config, _logger) { InnerHandler = _mockInnerHandler }; var httpClient = new HttpClient(handler); // Act @@ -108,7 +108,7 @@ public void SendAsync_MaxRetryExceeded() _gitHubConfig.MaxRetryAttempt = 2; - var handler = new GithubRetryHandler(_mockInnerHandler, _config, _logger); + var handler = new GithubRetryHandler(_config, _logger) { InnerHandler = _mockInnerHandler }; var httpClient = new HttpClient(handler); // Act & Assert diff --git a/SS14.Labeller/DiscourseApi/DummyDiscourseClient.cs b/SS14.Labeller/DiscourseApi/DummyDiscourseClient.cs index 5ce1ff4..98babff 100644 --- a/SS14.Labeller/DiscourseApi/DummyDiscourseClient.cs +++ b/SS14.Labeller/DiscourseApi/DummyDiscourseClient.cs @@ -2,7 +2,9 @@ namespace SS14.Labeller.DiscourseApi; -public class DummyDiscourseClient : IDiscourseClient +#pragma warning disable CS9113 // Parameter is unread. +public class DummyDiscourseClient(HttpClient _) : IDiscourseClient +#pragma warning restore CS9113 // Parameter is unread. { public Task CreateTopic(int category, string body, string title, CancellationToken ct) => Task.FromResult(new DiscourseCreatedPost() diff --git a/SS14.Labeller/Endpoints/GithubWebhook.cs b/SS14.Labeller/Endpoints/GithubWebhook.cs index 2142429..e05957e 100644 --- a/SS14.Labeller/Endpoints/GithubWebhook.cs +++ b/SS14.Labeller/Endpoints/GithubWebhook.cs @@ -1,6 +1,5 @@ using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Mvc; -using SS14.Labeller.Handlers; using SS14.Labeller.Middlewares; using SS14.Labeller.Models; @@ -24,10 +23,10 @@ public static void MapGithubWebhook(this WebApplication app) private static async Task HandleWebhook( EventBase @event, - [FromServices] GitHubWebhookHandlerService handler, + [FromServices] GenericPublisher publisher, CancellationToken ct) { - await handler.Handle(@event, ct); + await publisher.PublishByType(@event, ct); return TypedResults.NoContent(); } } \ No newline at end of file diff --git a/SS14.Labeller/GenericPublisher.cs b/SS14.Labeller/GenericPublisher.cs new file mode 100644 index 0000000..f948cc0 --- /dev/null +++ b/SS14.Labeller/GenericPublisher.cs @@ -0,0 +1,35 @@ +using System.Collections.Concurrent; +using MessagePipe; + +namespace SS14.Labeller; + +public class GenericPublisher(IServiceProvider sp) +{ + private static readonly ConcurrentDictionary> HandlingDelegates = new(); + + public ValueTask PublishByType(object message, CancellationToken ct) + { + var type = message.GetType(); + + var handlingDelegate = HandlingDelegates.GetOrAdd(type, (t, state) => + { + var methodInfo = state.GetType().GetMethod(nameof(Publish)); + var targetMethod = methodInfo?.MakeGenericMethod(t); + return (object msg, CancellationToken tkn) => + { + var result = targetMethod?.Invoke(this, [msg, tkn]); + return result == null + ? ValueTask.CompletedTask + : (ValueTask)result; + }; + }, this); + + return handlingDelegate.Invoke(message, ct); + } + + public ValueTask Publish(T message, CancellationToken ct) + { + var publisher = sp.GetRequiredService>(); + return publisher.PublishAsync(message, cancellationToken: ct); + } +} \ No newline at end of file diff --git a/SS14.Labeller/GitHubApi/GithubRetryHandler.cs b/SS14.Labeller/GitHubApi/GithubRetryHandler.cs index 0f9b248..d85db53 100644 --- a/SS14.Labeller/GitHubApi/GithubRetryHandler.cs +++ b/SS14.Labeller/GitHubApi/GithubRetryHandler.cs @@ -15,7 +15,7 @@ namespace SS14.Labeller.GitHubApi; ///
Rate limit information /// /// This was designed for the 2022-11-28 version of the API. -public sealed class GithubRetryHandler(HttpMessageHandler innerHandler, IOptionsMonitor githubConfig, ILogger logger) : DelegatingHandler(innerHandler) +public sealed class GithubRetryHandler(IOptionsMonitor githubConfig, ILogger logger) : DelegatingHandler { private const int MaxWaitSeconds = 32; diff --git a/SS14.Labeller/Handlers/GitHubWebhookHandlerService.cs b/SS14.Labeller/Handlers/GitHubWebhookHandlerService.cs deleted file mode 100644 index aed4a37..0000000 --- a/SS14.Labeller/Handlers/GitHubWebhookHandlerService.cs +++ /dev/null @@ -1,12 +0,0 @@ -using SS14.Labeller.Models; - -namespace SS14.Labeller.Handlers; - -public sealed class GitHubWebhookHandlerService(IReadOnlyDictionary handlers) -{ - public async Task Handle(EventBase @event, CancellationToken ct) - { - if (handlers.TryGetValue(@event.GetType(), out var handler)) - await handler.Handle(@event, ct); - } -} \ No newline at end of file diff --git a/SS14.Labeller/Handlers/LabelIssueHandler.cs b/SS14.Labeller/Handlers/LabelIssueHandler.cs index a57f773..d30056d 100644 --- a/SS14.Labeller/Handlers/LabelIssueHandler.cs +++ b/SS14.Labeller/Handlers/LabelIssueHandler.cs @@ -1,22 +1,23 @@ -using SS14.Labeller.GitHubApi; +using MessagePipe; +using SS14.Labeller.GitHubApi; using SS14.Labeller.Labelling.Labels; using SS14.Labeller.Models; namespace SS14.Labeller.Handlers; -public class LabelIssueHandler(IGitHubApiClient client) : RequestHandlerBase +public class LabelIssueHandler(IGitHubApiClient client) : IAsyncMessageHandler { /// - protected override async Task HandleInternal(IssuesEvent request, CancellationToken ct) + public async ValueTask HandleAsync(IssuesEvent message, CancellationToken ct) { - var action = request.Action; + var action = message.Action; if (action == "opened") { - var number = request.Issue.Number; - var labels = request.Issue.Labels; + var number = message.Issue.Number; + var labels = message.Issue.Labels; if (labels.Length == 0) - await client.AddLabel(request.Repository, number, StatusLabel.Untriaged, ct); + await client.AddLabel(message.Repository, number, StatusLabel.Untriaged, ct); } } } \ No newline at end of file diff --git a/SS14.Labeller/Handlers/LabelPullRequestHandler.cs b/SS14.Labeller/Handlers/LabelPullRequestHandler.cs index a70cbec..375cd1d 100644 --- a/SS14.Labeller/Handlers/LabelPullRequestHandler.cs +++ b/SS14.Labeller/Handlers/LabelPullRequestHandler.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.FileSystemGlobbing; +using MessagePipe; +using Microsoft.Extensions.FileSystemGlobbing; using Microsoft.Extensions.Options; using SS14.Labeller.Configuration; using SS14.Labeller.DiscourseApi; @@ -17,54 +18,55 @@ public class LabelPullRequestHandler( IDiscourseTopicsRepository topicsRepository, ILabelManager labelManager, IOptions config -) : RequestHandlerBase +) : IAsyncMessageHandler { private readonly DiscourseConfig _discourseConfig = config.Value; /// - protected override async Task HandleInternal(PullRequestEvent request, CancellationToken ct) + public async ValueTask HandleAsync(PullRequestEvent message, CancellationToken ct) + { - var pr = request.PullRequest; + var pr = message.PullRequest; var prNumber = pr.Number; - var repoOwner = request.Repository.Owner.Login; - var repoName = request.Repository.Name; + var repoOwner = message.Repository.Owner.Login; + var repoName = message.Repository.Name; var labels = pr.Labels .Select(x => x.Name) .ToArray(); // basic labels - var repository = request.Repository; + var repository = message.Repository; - await (request.EventType switch + await (message.EventType switch { - PullRequestEventType.Labelled => OnLabelAdd(request, ct, repoOwner, repoName, prNumber, repository), - PullRequestEventType.ClosedRejected => OnClosed(ct, repoOwner, repoName, prNumber), - PullRequestEventType.ClosedMerged => OnMerged(ct, repoOwner, repoName, prNumber, labels, repository), - PullRequestEventType.Opened => OnOpened(request, ct, labels, pr, repository), - PullRequestEventType.ReviewRequested => OnReviewRequested(request, ct, repository), + PullRequestEventType.Labelled => OnLabelAdd(message, repoOwner, repoName, prNumber, repository, ct), + PullRequestEventType.ClosedRejected => OnClosed(repoOwner, repoName, prNumber, ct), + PullRequestEventType.ClosedMerged => OnMerged(repoOwner, repoName, prNumber, labels, repository, ct), + PullRequestEventType.Opened => OnOpened(message, labels, pr, repository, ct), + PullRequestEventType.ReviewRequested => OnReviewRequested(message, repository, ct), _ => Task.CompletedTask }); var totalDiff = pr.Additions + pr.Deletions; if (SizeLabel.TryGetLabelFor(totalDiff, out var sizeLabel)) { - await labelManager.EnsureLabeled(request, sizeLabel, ct); + await labelManager.EnsureLabeled(message, sizeLabel, ct); } if(!ContainsLabelsStartingWith(labels, "A:", "T:", "P:")) - await labelManager.EnsureLabeled(request, StatusLabel.Untriaged, ct); + await labelManager.EnsureLabeled(message, StatusLabel.Untriaged, ct); var changedFiles = await client.GetChangedFiles(repository, prNumber, ct); - await EnsureChangesLabels(ChangesLabel.Sprites, ["**/*.rsi/*.png"], request, changedFiles, ct: ct); - await EnsureChangesLabels(ChangesLabel.Map, ["Resources/Maps/**/*.yml", "Resources/Prototypes/Maps/**/*.yml"], request, changedFiles, ct: ct); - await EnsureChangesLabels(ChangesLabel.Ui, ["**/*.xaml*"], request, changedFiles, ct:ct); - await EnsureChangesLabels(ChangesLabel.Shaders, ["**/*.sws"], request, changedFiles, ct: ct); - await EnsureChangesLabels(ChangesLabel.Audio, ["**/*.ogg"], request, changedFiles, ct: ct); - await EnsureChangesLabels(ChangesLabel.NoCSharp, ["**/*.cs"], request, changedFiles, isInverted: true, ct: ct); + await EnsureChangesLabels(ChangesLabel.Sprites, ["**/*.rsi/*.png"], message, changedFiles, ct: ct); + await EnsureChangesLabels(ChangesLabel.Map, ["Resources/Maps/**/*.yml", "Resources/Prototypes/Maps/**/*.yml"], message, changedFiles, ct: ct); + await EnsureChangesLabels(ChangesLabel.Ui, ["**/*.xaml*"], message, changedFiles, ct: ct); + await EnsureChangesLabels(ChangesLabel.Shaders, ["**/*.sws"], message, changedFiles, ct: ct); + await EnsureChangesLabels(ChangesLabel.Audio, ["**/*.ogg"], message, changedFiles, ct: ct); + await EnsureChangesLabels(ChangesLabel.NoCSharp, ["**/*.cs"], message, changedFiles, isInverted: true, ct: ct); } private async Task EnsureChangesLabels( @@ -89,7 +91,7 @@ private async Task EnsureChangesLabels( await labelManager.EnsureNotLabeled(request, label, ct); } - private async Task OnClosed(CancellationToken ct, string repoOwner, string repoName, int prNumber) + private async Task OnClosed(string repoOwner, string repoName, int prNumber, CancellationToken ct) { // pr was just closed, not merged. var discussion = await topicsRepository.FindTopicIdForDiscussion(repoOwner, repoName, prNumber, ct); @@ -100,7 +102,7 @@ private async Task OnClosed(CancellationToken ct, string repoOwner, string repoN } } - private async Task OnMerged(CancellationToken ct, string repoOwner, string repoName, int prNumber, string?[] labels, GithubRepo repository) + private async Task OnMerged(string repoOwner, string repoName, int prNumber, string?[] labels, GithubRepo repository, CancellationToken ct) { // PR got merged var discussion = await topicsRepository.FindTopicIdForDiscussion(repoOwner, repoName, prNumber, ct); @@ -117,7 +119,7 @@ private async Task OnMerged(CancellationToken ct, string repoOwner, string repoN } } - private async Task OnReviewRequested(PullRequestEvent request, CancellationToken ct, GithubRepo repository) + private async Task OnReviewRequested(PullRequestEvent request, GithubRepo repository, CancellationToken ct) { if (await client.IsMaintainer(request.RequestedReviewer!.Login, repository, ct)) { @@ -125,7 +127,7 @@ private async Task OnReviewRequested(PullRequestEvent request, CancellationToken } } - private async Task OnLabelAdd(PullRequestEvent request, CancellationToken ct, string repoOwner, string repoName, int prNumber, GithubRepo repository) + private async Task OnLabelAdd(PullRequestEvent request, string repoOwner, string repoName, int prNumber, GithubRepo repository, CancellationToken ct) { if(!_discourseConfig.Enable) return; @@ -155,7 +157,7 @@ private async Task OnLabelAdd(PullRequestEvent request, CancellationToken ct, st } } - private async Task OnOpened(PullRequestEvent request, CancellationToken ct, string?[] labels, PullRequest pr, GithubRepo repository) + private async Task OnOpened(PullRequestEvent request, string?[] labels, PullRequest pr, GithubRepo repository, CancellationToken ct) { var targetBranch = pr.Base.Ref; if (targetBranch == "stable") diff --git a/SS14.Labeller/Handlers/LabelPullRequestReviewHandler.cs b/SS14.Labeller/Handlers/LabelPullRequestReviewHandler.cs index 4d7618a..e0d7bdb 100644 --- a/SS14.Labeller/Handlers/LabelPullRequestReviewHandler.cs +++ b/SS14.Labeller/Handlers/LabelPullRequestReviewHandler.cs @@ -1,4 +1,5 @@ -using SS14.Labeller.GitHubApi; +using MessagePipe; +using SS14.Labeller.GitHubApi; using SS14.Labeller.Labelling; using SS14.Labeller.Labelling.Labels; using SS14.Labeller.Models; @@ -6,23 +7,23 @@ namespace SS14.Labeller.Handlers; public class LabelPullRequestReviewHandler(IGitHubApiClient client, ILabelManager labelManager) - : RequestHandlerBase + : IAsyncMessageHandler { /// - protected override async Task HandleInternal(PullRequestReviewEvent request, CancellationToken ct) + public async ValueTask HandleAsync(PullRequestReviewEvent message, CancellationToken ct) { - var pr = request.PullRequest; - var repo = request.Repository; - var user = request.Review.User.Login; + var pr = message.PullRequest; + var repo = message.Repository; + var user = message.Review.User.Login; - // only process if the review state is "approved" or "changes_requested" (ignore comments and other states) - var state = request.Review.State; - if (state != "approved" && state != "changes_requested") + // only process if the review state is "approved" or "changes_messageed" (ignore comments and other states) + var state = message.Review.State; + if (state != "approved" && state != "changes_messageed") return; // Ignore reviews if PR is closed or merged // "closed" means closed or merged, but let's also check for merged explicitly if available - var isClosed = request.Review.State == "closed"; + var isClosed = message.Review.State == "closed"; var isMerged = pr.MergedAt != null; if (isClosed || isMerged) return; @@ -34,9 +35,9 @@ protected override async Task HandleInternal(PullRequestReviewEvent request, Can await (state switch { "approved" - => labelManager.EnsureLabeled(request, StatusLabel.Approved, ct), - "changes_requested" - => labelManager.EnsureLabeled(request, StageOfWorkLabel.AwaitingChanges, ct) + => labelManager.EnsureLabeled(message, StatusLabel.Approved, ct), + "changes_messageed" + => labelManager.EnsureLabeled(message, StageOfWorkLabel.AwaitingChanges, ct) }); #pragma warning restore CS8509 // The switch expression does not handle all possible values of its input type (it is not exhaustive). } diff --git a/SS14.Labeller/Handlers/RequestHandlerBase.cs b/SS14.Labeller/Handlers/RequestHandlerBase.cs deleted file mode 100644 index 921c1e7..0000000 --- a/SS14.Labeller/Handlers/RequestHandlerBase.cs +++ /dev/null @@ -1,31 +0,0 @@ -using SS14.Labeller.Models; - -namespace SS14.Labeller.Handlers; - -public abstract class RequestHandlerBase -{ - /// - /// Github-declared type of event this handler should process. - /// - public abstract Type CanHandleType { get; } - - /// Process event. - /// bytes of request body. - /// Operation cancellation token. - public abstract Task Handle(EventBase eventFromRequest, CancellationToken ct); -} - -public abstract class RequestHandlerBase : RequestHandlerBase where T : EventBase -{ - /// - public override Task Handle(EventBase eventFromRequest, CancellationToken ct) - { - return HandleInternal((T)eventFromRequest, ct); - } - - /// Process provided event. - protected abstract Task HandleInternal(T request, CancellationToken ct); - - /// - public override Type CanHandleType => typeof(T); -} \ No newline at end of file diff --git a/SS14.Labeller/Initialization/ApplicationServicesInitializingBackgroundService.cs b/SS14.Labeller/Initialization/ApplicationServicesInitializingBackgroundService.cs new file mode 100644 index 0000000..77eaa51 --- /dev/null +++ b/SS14.Labeller/Initialization/ApplicationServicesInitializingBackgroundService.cs @@ -0,0 +1,56 @@ +namespace SS14.Labeller.Initialization; + +/// +/// Background service for application initialization. +/// Starts initialization for classes marked with interface. +/// +public class ApplicationServicesInitializingBackgroundService : BackgroundService +{ + private readonly IReadOnlyCollection _services; + private readonly ILogger _logger; + + /// c-tor. + public ApplicationServicesInitializingBackgroundService( + IEnumerable initializableServiceCollection, + ILogger logger + ) + { + _services = ( + initializableServiceCollection ?? throw new ArgumentNullException(nameof(initializableServiceCollection)) + ).ToArray(); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + } + + /// + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + await ProcessInitializables(stoppingToken); + + _logger.LogInformation("Application initialization is finished."); + } + + private async Task ProcessInitializables(CancellationToken ct) + { + if (_services.Count == 0) + { + const string noInitMessage = "There is no initializable classes found, app initialization is not required. "; + _logger.LogInformation(noInitMessage); + return; + } + + _logger.LogInformation( + "Starting application initialization. Found {serviceCount} initializable services" + + $"(that implement {nameof(IOnApplicationStartInitializable)}).", + _services.Count + ); + foreach (var initializable in _services) + { + ct.ThrowIfCancellationRequested(); + + var args = $"{initializable.GetType().FullName}.{nameof(IOnApplicationStartInitializable.Initialize)}"; + _logger.LogDebug("Starting {called}.", args); + await initializable.Initialize(ct); + _logger.LogTrace("Finished {called}.", args); + } + } +} \ No newline at end of file diff --git a/SS14.Labeller/Initialization/IOnApplicationStartInitializable.cs b/SS14.Labeller/Initialization/IOnApplicationStartInitializable.cs new file mode 100644 index 0000000..25ef80b --- /dev/null +++ b/SS14.Labeller/Initialization/IOnApplicationStartInitializable.cs @@ -0,0 +1,22 @@ +namespace SS14.Labeller.Initialization; + +/// +/// Initializable object in system. Can be singleton service, job or something else. +/// will be called by background service, but +/// should be set to True manually during this call. +/// +public interface IOnApplicationStartInitializable +{ + /// + /// Initializes component of system. + /// + public Task Initialize(CancellationToken ct); + + /// + /// Is component initialized already? + /// + /// + /// This is used in health-check and will be regularly requested using background service. + /// + public bool Initialized { get; } +} \ No newline at end of file diff --git a/SS14.Labeller/Initialization/MessagePipeSubscriptionManager.cs b/SS14.Labeller/Initialization/MessagePipeSubscriptionManager.cs new file mode 100644 index 0000000..a13700c --- /dev/null +++ b/SS14.Labeller/Initialization/MessagePipeSubscriptionManager.cs @@ -0,0 +1,43 @@ +using MessagePipe; +using SS14.Labeller.Models; + +namespace SS14.Labeller.Initialization; + +public class MessagePipeSubscriptionManager(IServiceProvider sp, IHostApplicationLifetime lifetime) : IOnApplicationStartInitializable +{ + /// + public Task Initialize(CancellationToken ct) + + { + List subscriptions = + [ + Sub(sp), + Sub(sp), + Sub(sp), + ]; + + lifetime.ApplicationStopping.Register(x => + { + if(x is not List disposables) + return; + + foreach (var subscription in disposables) + { + subscription.Dispose(); + } + }, subscriptions); + + Initialized = true; + return Task.CompletedTask; + } + + private static IDisposable Sub(IServiceProvider sp) + { + var handler = sp.GetRequiredService>(); + var sub = sp.GetRequiredService>(); + return sub.Subscribe(handler); + } + + /// + public bool Initialized { get; private set; } +} \ No newline at end of file diff --git a/SS14.Labeller/Registry.cs b/SS14.Labeller/Registry.cs index 7757d5d..028ab93 100644 --- a/SS14.Labeller/Registry.cs +++ b/SS14.Labeller/Registry.cs @@ -3,12 +3,15 @@ using SS14.Labeller.Database; using SS14.Labeller.DiscourseApi; using SS14.Labeller.GitHubApi; -using SS14.Labeller.Handlers; using SS14.Labeller.Labelling; using SS14.Labeller.Repository; using System.Net.Http.Headers; using Polly; using Polly.Extensions.Http; +using SS14.Labeller.Initialization; +using MessagePipe; +using SS14.Labeller.Handlers; +using SS14.Labeller.Models; namespace SS14.Labeller; @@ -43,6 +46,7 @@ public static void RegisterDependencies(this IServiceCollection service, IConfig client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", githubConfig.Token); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/vnd.github+json")); }).AddHttpMessageHandler(); + service.AddTransient(); var discourseStartupConfig = new DiscourseConfig(); configuration.Bind(DiscourseConfig.Name, discourseStartupConfig); @@ -66,20 +70,25 @@ public static void RegisterDependencies(this IServiceCollection service, IConfig } service.AddSingleton(); - - service.AddSingleton(); - service.AddSingleton(); - service.AddSingleton(); - service.AddSingleton(); - + + service.AddSingleton(); + + service.AddHostedService(); + + service.AddSingleton(); service.AddHostedService(); - service.AddSingleton>( - sp => sp.GetServices() - .ToDictionary(x => x.CanHandleType) + service.AddSingleton, LabelIssueHandler>(); + service.AddSingleton, LabelPullRequestHandler>(); + service.AddSingleton, LabelPullRequestReviewHandler>(); + + service.AddMessagePipe( + x => x.SetAutoRegistrationSearchAssemblies(typeof(Registry).Assembly) ); + + service.AddSingleton(); } private static IAsyncPolicy GetDiscourseRetryPolicy(IServiceProvider sp) diff --git a/SS14.Labeller/SS14.Labeller.csproj b/SS14.Labeller/SS14.Labeller.csproj index 932e3b2..6d196d4 100644 --- a/SS14.Labeller/SS14.Labeller.csproj +++ b/SS14.Labeller/SS14.Labeller.csproj @@ -4,7 +4,6 @@ enable enable true - true true $(InterceptorsPreviewNamespaces);Dapper.AOT true @@ -16,6 +15,11 @@ + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive +