mirror of
https://github.com/bitwarden/server
synced 2026-01-12 21:44:13 +00:00
570 lines
30 KiB
C#
570 lines
30 KiB
C#
using Azure.Messaging.ServiceBus;
|
|
using Bit.Core.AdminConsole.Repositories;
|
|
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrationConfigurations;
|
|
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrationConfigurations.Interfaces;
|
|
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrations;
|
|
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrations.Interfaces;
|
|
using Bit.Core.Dirt.Models.Data.EventIntegrations;
|
|
using Bit.Core.Dirt.Models.Data.Teams;
|
|
using Bit.Core.Dirt.Repositories;
|
|
using Bit.Core.Dirt.Services;
|
|
using Bit.Core.Dirt.Services.Implementations;
|
|
using Bit.Core.Dirt.Services.NoopImplementations;
|
|
using Bit.Core.Repositories;
|
|
using Bit.Core.Services;
|
|
using Bit.Core.Settings;
|
|
using Bit.Core.Utilities;
|
|
using Microsoft.Bot.Builder;
|
|
using Microsoft.Bot.Builder.Integration.AspNet.Core;
|
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.Logging;
|
|
using ZiggyCreatures.Caching.Fusion;
|
|
using TableStorageRepos = Bit.Core.Repositories.TableStorage;
|
|
|
|
namespace Microsoft.Extensions.DependencyInjection;
|
|
|
|
public static class EventIntegrationsServiceCollectionExtensions
|
|
{
|
|
/// <summary>
|
|
/// Adds all event integrations commands, queries, and required cache infrastructure.
|
|
/// This method is idempotent and can be called multiple times safely.
|
|
/// </summary>
|
|
public static IServiceCollection AddEventIntegrationsCommandsQueries(
|
|
this IServiceCollection services,
|
|
GlobalSettings globalSettings)
|
|
{
|
|
// Ensure cache is registered first - commands depend on this keyed cache.
|
|
// This is idempotent for the same named cache, so it's safe to call.
|
|
services.AddExtendedCache(EventIntegrationsCacheConstants.CacheName, globalSettings);
|
|
|
|
// Add Validator
|
|
services.TryAddSingleton<IOrganizationIntegrationConfigurationValidator, OrganizationIntegrationConfigurationValidator>();
|
|
|
|
// Add all commands/queries
|
|
services.AddOrganizationIntegrationCommandsQueries();
|
|
services.AddOrganizationIntegrationConfigurationCommandsQueries();
|
|
|
|
return services;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Registers event write services based on available configuration.
|
|
/// </summary>
|
|
/// <param name="services">The service collection to add services to.</param>
|
|
/// <param name="globalSettings">The global settings containing event logging configuration.</param>
|
|
/// <returns>The service collection for chaining.</returns>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// This method registers the appropriate IEventWriteService implementation based on the available
|
|
/// configuration, checking in the following priority order:
|
|
/// </para>
|
|
/// <para>
|
|
/// 1. Azure Service Bus - If all Azure Service Bus settings are present, registers
|
|
/// EventIntegrationEventWriteService with AzureServiceBusService as the publisher
|
|
/// </para>
|
|
/// <para>
|
|
/// 2. RabbitMQ - If all RabbitMQ settings are present, registers EventIntegrationEventWriteService with
|
|
/// RabbitMqService as the publisher
|
|
/// </para>
|
|
/// <para>
|
|
/// 3. Azure Queue Storage - If Events.ConnectionString is present, registers AzureQueueEventWriteService
|
|
/// </para>
|
|
/// <para>
|
|
/// 4. Repository (Self-Hosted) - If SelfHosted is true, registers RepositoryEventWriteService
|
|
/// </para>
|
|
/// <para>
|
|
/// 5. Noop - If none of the above are configured, registers NoopEventWriteService (no-op implementation)
|
|
/// </para>
|
|
/// </remarks>
|
|
public static IServiceCollection AddEventWriteServices(this IServiceCollection services, GlobalSettings globalSettings)
|
|
{
|
|
if (IsAzureServiceBusEnabled(globalSettings))
|
|
{
|
|
services.TryAddSingleton<IEventIntegrationPublisher, AzureServiceBusService>();
|
|
services.TryAddSingleton<IEventWriteService, EventIntegrationEventWriteService>();
|
|
return services;
|
|
}
|
|
|
|
if (IsRabbitMqEnabled(globalSettings))
|
|
{
|
|
services.TryAddSingleton<IEventIntegrationPublisher, RabbitMqService>();
|
|
services.TryAddSingleton<IEventWriteService, EventIntegrationEventWriteService>();
|
|
return services;
|
|
}
|
|
|
|
if (CoreHelpers.SettingHasValue(globalSettings.Events.ConnectionString) &&
|
|
CoreHelpers.SettingHasValue(globalSettings.Events.QueueName))
|
|
{
|
|
services.TryAddSingleton<IEventWriteService, AzureQueueEventWriteService>();
|
|
return services;
|
|
}
|
|
|
|
if (globalSettings.SelfHosted)
|
|
{
|
|
services.TryAddSingleton<IEventWriteService, RepositoryEventWriteService>();
|
|
return services;
|
|
}
|
|
|
|
services.TryAddSingleton<IEventWriteService, NoopEventWriteService>();
|
|
return services;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Registers Azure Service Bus-based event integration listeners and supporting infrastructure.
|
|
/// </summary>
|
|
/// <param name="services">The service collection to add services to.</param>
|
|
/// <param name="globalSettings">The global settings containing Azure Service Bus configuration.</param>
|
|
/// <returns>The service collection for chaining.</returns>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// If Azure Service Bus is not enabled (missing required settings), this method returns immediately
|
|
/// without registering any services.
|
|
/// </para>
|
|
/// <para>
|
|
/// When Azure Service Bus is enabled, this method registers:
|
|
/// - IAzureServiceBusService and IEventIntegrationPublisher implementations
|
|
/// - Table Storage event repository
|
|
/// - Azure Table Storage event handler
|
|
/// - All event integration services via AddEventIntegrationServices
|
|
/// </para>
|
|
/// <para>
|
|
/// PREREQUISITE: Callers must ensure AddDistributedCache has been called before this method,
|
|
/// as it is required to create the event integrations extended cache.
|
|
/// </para>
|
|
/// </remarks>
|
|
public static IServiceCollection AddAzureServiceBusListeners(this IServiceCollection services, GlobalSettings globalSettings)
|
|
{
|
|
if (!IsAzureServiceBusEnabled(globalSettings))
|
|
{
|
|
return services;
|
|
}
|
|
|
|
services.TryAddSingleton<IAzureServiceBusService, AzureServiceBusService>();
|
|
services.TryAddSingleton<IEventIntegrationPublisher, AzureServiceBusService>();
|
|
services.TryAddSingleton<IEventRepository, TableStorageRepos.EventRepository>();
|
|
services.TryAddKeyedSingleton<IEventWriteService, RepositoryEventWriteService>("persistent");
|
|
services.TryAddSingleton<AzureTableStorageEventHandler>();
|
|
|
|
services.AddEventIntegrationServices(globalSettings);
|
|
|
|
return services;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Registers RabbitMQ-based event integration listeners and supporting infrastructure.
|
|
/// </summary>
|
|
/// <param name="services">The service collection to add services to.</param>
|
|
/// <param name="globalSettings">The global settings containing RabbitMQ configuration.</param>
|
|
/// <returns>The service collection for chaining.</returns>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// If RabbitMQ is not enabled (missing required settings), this method returns immediately
|
|
/// without registering any services.
|
|
/// </para>
|
|
/// <para>
|
|
/// When RabbitMQ is enabled, this method registers:
|
|
/// - IRabbitMqService and IEventIntegrationPublisher implementations
|
|
/// - Event repository handler
|
|
/// - All event integration services via AddEventIntegrationServices
|
|
/// </para>
|
|
/// <para>
|
|
/// PREREQUISITE: Callers must ensure AddDistributedCache has been called before this method,
|
|
/// as it is required to create the event integrations extended cache.
|
|
/// </para>
|
|
/// </remarks>
|
|
public static IServiceCollection AddRabbitMqListeners(this IServiceCollection services, GlobalSettings globalSettings)
|
|
{
|
|
if (!IsRabbitMqEnabled(globalSettings))
|
|
{
|
|
return services;
|
|
}
|
|
|
|
services.TryAddSingleton<IRabbitMqService, RabbitMqService>();
|
|
services.TryAddSingleton<IEventIntegrationPublisher, RabbitMqService>();
|
|
services.TryAddSingleton<EventRepositoryHandler>();
|
|
|
|
services.AddEventIntegrationServices(globalSettings);
|
|
|
|
return services;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Registers Slack integration services based on configuration settings.
|
|
/// </summary>
|
|
/// <param name="services">The service collection to add services to.</param>
|
|
/// <param name="globalSettings">The global settings containing Slack configuration.</param>
|
|
/// <returns>The service collection for chaining.</returns>
|
|
/// <remarks>
|
|
/// If all required Slack settings are configured (ClientId, ClientSecret, Scopes), registers the full SlackService,
|
|
/// including an HttpClient for Slack API calls. Otherwise, registers a NoopSlackService that performs no operations.
|
|
/// </remarks>
|
|
public static IServiceCollection AddSlackService(this IServiceCollection services, GlobalSettings globalSettings)
|
|
{
|
|
if (CoreHelpers.SettingHasValue(globalSettings.Slack.ClientId) &&
|
|
CoreHelpers.SettingHasValue(globalSettings.Slack.ClientSecret) &&
|
|
CoreHelpers.SettingHasValue(globalSettings.Slack.Scopes))
|
|
{
|
|
services.AddHttpClient(SlackService.HttpClientName);
|
|
services.TryAddSingleton<ISlackService, SlackService>();
|
|
}
|
|
else
|
|
{
|
|
services.TryAddSingleton<ISlackService, NoopSlackService>();
|
|
}
|
|
|
|
return services;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Registers Microsoft Teams integration services based on configuration settings.
|
|
/// </summary>
|
|
/// <param name="services">The service collection to add services to.</param>
|
|
/// <param name="globalSettings">The global settings containing Teams configuration.</param>
|
|
/// <returns>The service collection for chaining.</returns>
|
|
/// <remarks>
|
|
/// If all required Teams settings are configured (ClientId, ClientSecret, Scopes), registers:
|
|
/// - TeamsService and its interfaces (IBot, ITeamsService)
|
|
/// - IBotFrameworkHttpAdapter with Teams credentials
|
|
/// - HttpClient for Teams API calls
|
|
/// Otherwise, registers a NoopTeamsService that performs no operations.
|
|
/// </remarks>
|
|
public static IServiceCollection AddTeamsService(this IServiceCollection services, GlobalSettings globalSettings)
|
|
{
|
|
if (CoreHelpers.SettingHasValue(globalSettings.Teams.ClientId) &&
|
|
CoreHelpers.SettingHasValue(globalSettings.Teams.ClientSecret) &&
|
|
CoreHelpers.SettingHasValue(globalSettings.Teams.Scopes))
|
|
{
|
|
services.AddHttpClient(TeamsService.HttpClientName);
|
|
services.TryAddSingleton<TeamsService>();
|
|
services.TryAddSingleton<IBot>(sp => sp.GetRequiredService<TeamsService>());
|
|
services.TryAddSingleton<ITeamsService>(sp => sp.GetRequiredService<TeamsService>());
|
|
services.TryAddSingleton<IBotFrameworkHttpAdapter>(_ =>
|
|
new BotFrameworkHttpAdapter(
|
|
new TeamsBotCredentialProvider(
|
|
clientId: globalSettings.Teams.ClientId,
|
|
clientSecret: globalSettings.Teams.ClientSecret
|
|
)
|
|
)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
services.TryAddSingleton<ITeamsService, NoopTeamsService>();
|
|
}
|
|
|
|
return services;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Registers event integration services including handlers, listeners, and supporting infrastructure.
|
|
/// </summary>
|
|
/// <param name="services">The service collection to add services to.</param>
|
|
/// <param name="globalSettings">The global settings containing integration configuration.</param>
|
|
/// <returns>The service collection for chaining.</returns>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// This method orchestrates the registration of all event integration components based on the enabled
|
|
/// message broker (Azure Service Bus or RabbitMQ). It is an internal method called by the public
|
|
/// entry points AddAzureServiceBusListeners and AddRabbitMqListeners.
|
|
/// </para>
|
|
/// <para>
|
|
/// NOTE: If both Azure Service Bus and RabbitMQ are configured, Azure Service Bus takes precedence. This means that
|
|
/// Azure Service Bus listeners will be registered (and RabbitMQ listeners will NOT) even if this event is called
|
|
/// from AddRabbitMqListeners when Azure Service Bus settings are configured.
|
|
/// </para>
|
|
/// <para>
|
|
/// PREREQUISITE: Callers must ensure AddDistributedCache has been called before invoking this method.
|
|
/// This method depends on distributed cache infrastructure being available for the keyed extended
|
|
/// cache registration.
|
|
/// </para>
|
|
/// <para>
|
|
/// Registered Services:
|
|
/// - Keyed ExtendedCache for event integrations
|
|
/// - Integration filter service
|
|
/// - Integration handlers for Slack, Webhook, Hec, Datadog, and Teams
|
|
/// - Hosted services for event and integration listeners (based on enabled message broker)
|
|
/// </para>
|
|
/// </remarks>
|
|
internal static IServiceCollection AddEventIntegrationServices(this IServiceCollection services,
|
|
GlobalSettings globalSettings)
|
|
{
|
|
// Add common services
|
|
// NOTE: AddDistributedCache must be called by the caller before this method
|
|
services.AddExtendedCache(EventIntegrationsCacheConstants.CacheName, globalSettings);
|
|
services.TryAddSingleton<IIntegrationFilterService, IntegrationFilterService>();
|
|
services.TryAddKeyedSingleton<IEventWriteService, RepositoryEventWriteService>("persistent");
|
|
|
|
// Add services in support of handlers
|
|
services.AddSlackService(globalSettings);
|
|
services.AddTeamsService(globalSettings);
|
|
services.TryAddSingleton(TimeProvider.System);
|
|
services.AddHttpClient(WebhookIntegrationHandler.HttpClientName);
|
|
services.AddHttpClient(DatadogIntegrationHandler.HttpClientName);
|
|
|
|
// Add integration handlers
|
|
services.TryAddSingleton<IIntegrationHandler<SlackIntegrationConfigurationDetails>, SlackIntegrationHandler>();
|
|
services.TryAddSingleton<IIntegrationHandler<WebhookIntegrationConfigurationDetails>, WebhookIntegrationHandler>();
|
|
services.TryAddSingleton<IIntegrationHandler<DatadogIntegrationConfigurationDetails>, DatadogIntegrationHandler>();
|
|
services.TryAddSingleton<IIntegrationHandler<TeamsIntegrationConfigurationDetails>, TeamsIntegrationHandler>();
|
|
|
|
var repositoryConfiguration = new RepositoryListenerConfiguration(globalSettings);
|
|
var slackConfiguration = new SlackListenerConfiguration(globalSettings);
|
|
var webhookConfiguration = new WebhookListenerConfiguration(globalSettings);
|
|
var hecConfiguration = new HecListenerConfiguration(globalSettings);
|
|
var datadogConfiguration = new DatadogListenerConfiguration(globalSettings);
|
|
var teamsConfiguration = new TeamsListenerConfiguration(globalSettings);
|
|
|
|
if (IsAzureServiceBusEnabled(globalSettings))
|
|
{
|
|
services.TryAddEnumerable(ServiceDescriptor.Singleton<IHostedService,
|
|
AzureServiceBusEventListenerService<RepositoryListenerConfiguration>>(provider =>
|
|
new AzureServiceBusEventListenerService<RepositoryListenerConfiguration>(
|
|
configuration: repositoryConfiguration,
|
|
handler: provider.GetRequiredService<AzureTableStorageEventHandler>(),
|
|
serviceBusService: provider.GetRequiredService<IAzureServiceBusService>(),
|
|
serviceBusOptions: new ServiceBusProcessorOptions()
|
|
{
|
|
PrefetchCount = repositoryConfiguration.EventPrefetchCount,
|
|
MaxConcurrentCalls = repositoryConfiguration.EventMaxConcurrentCalls
|
|
},
|
|
loggerFactory: provider.GetRequiredService<ILoggerFactory>()
|
|
)
|
|
)
|
|
);
|
|
services.AddAzureServiceBusIntegration<SlackIntegrationConfigurationDetails, SlackListenerConfiguration>(slackConfiguration);
|
|
services.AddAzureServiceBusIntegration<WebhookIntegrationConfigurationDetails, WebhookListenerConfiguration>(webhookConfiguration);
|
|
services.AddAzureServiceBusIntegration<WebhookIntegrationConfigurationDetails, HecListenerConfiguration>(hecConfiguration);
|
|
services.AddAzureServiceBusIntegration<DatadogIntegrationConfigurationDetails, DatadogListenerConfiguration>(datadogConfiguration);
|
|
services.AddAzureServiceBusIntegration<TeamsIntegrationConfigurationDetails, TeamsListenerConfiguration>(teamsConfiguration);
|
|
|
|
return services;
|
|
}
|
|
|
|
if (IsRabbitMqEnabled(globalSettings))
|
|
{
|
|
services.TryAddEnumerable(ServiceDescriptor.Singleton<IHostedService,
|
|
RabbitMqEventListenerService<RepositoryListenerConfiguration>>(provider =>
|
|
new RabbitMqEventListenerService<RepositoryListenerConfiguration>(
|
|
handler: provider.GetRequiredService<EventRepositoryHandler>(),
|
|
configuration: repositoryConfiguration,
|
|
rabbitMqService: provider.GetRequiredService<IRabbitMqService>(),
|
|
loggerFactory: provider.GetRequiredService<ILoggerFactory>()
|
|
)
|
|
)
|
|
);
|
|
services.AddRabbitMqIntegration<SlackIntegrationConfigurationDetails, SlackListenerConfiguration>(slackConfiguration);
|
|
services.AddRabbitMqIntegration<WebhookIntegrationConfigurationDetails, WebhookListenerConfiguration>(webhookConfiguration);
|
|
services.AddRabbitMqIntegration<WebhookIntegrationConfigurationDetails, HecListenerConfiguration>(hecConfiguration);
|
|
services.AddRabbitMqIntegration<DatadogIntegrationConfigurationDetails, DatadogListenerConfiguration>(datadogConfiguration);
|
|
services.AddRabbitMqIntegration<TeamsIntegrationConfigurationDetails, TeamsListenerConfiguration>(teamsConfiguration);
|
|
}
|
|
|
|
return services;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Registers Azure Service Bus-based event integration listeners for a specific integration type.
|
|
/// </summary>
|
|
/// <typeparam name="TConfig">The integration configuration details type (e.g., SlackIntegrationConfigurationDetails).</typeparam>
|
|
/// <typeparam name="TListenerConfig">The listener configuration type implementing IIntegrationListenerConfiguration.</typeparam>
|
|
/// <param name="services">The service collection to add services to.</param>
|
|
/// <param name="listenerConfiguration">The listener configuration containing routing keys and message processing settings.</param>
|
|
/// <returns>The service collection for chaining.</returns>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// This method registers three key components:
|
|
/// 1. EventIntegrationHandler - Keyed singleton for processing integration events
|
|
/// 2. AzureServiceBusEventListenerService - Hosted service for listening to event messages from Azure Service Bus
|
|
/// for this integration type
|
|
/// 3. AzureServiceBusIntegrationListenerService - Hosted service for listening to integration messages from
|
|
/// Azure Service Bus for this integration type
|
|
/// </para>
|
|
/// <para>
|
|
/// The handler uses the listener configuration's routing key as its service key, allowing multiple
|
|
/// handlers to be registered for different integration types.
|
|
/// </para>
|
|
/// <para>
|
|
/// Service Bus processor options (PrefetchCount and MaxConcurrentCalls) are configured from the listener
|
|
/// configuration to optimize message throughput and concurrency.
|
|
/// </para>
|
|
/// </remarks>
|
|
internal static IServiceCollection AddAzureServiceBusIntegration<TConfig, TListenerConfig>(this IServiceCollection services,
|
|
TListenerConfig listenerConfiguration)
|
|
where TConfig : class
|
|
where TListenerConfig : IIntegrationListenerConfiguration
|
|
{
|
|
services.TryAddKeyedSingleton<IEventMessageHandler>(serviceKey: listenerConfiguration.RoutingKey, implementationFactory: (provider, _) =>
|
|
new EventIntegrationHandler<TConfig>(
|
|
integrationType: listenerConfiguration.IntegrationType,
|
|
eventIntegrationPublisher: provider.GetRequiredService<IEventIntegrationPublisher>(),
|
|
integrationFilterService: provider.GetRequiredService<IIntegrationFilterService>(),
|
|
cache: provider.GetRequiredKeyedService<IFusionCache>(EventIntegrationsCacheConstants.CacheName),
|
|
configurationRepository: provider.GetRequiredService<IOrganizationIntegrationConfigurationRepository>(),
|
|
groupRepository: provider.GetRequiredService<IGroupRepository>(),
|
|
organizationRepository: provider.GetRequiredService<IOrganizationRepository>(),
|
|
organizationUserRepository: provider.GetRequiredService<IOrganizationUserRepository>(), logger: provider.GetRequiredService<ILogger<EventIntegrationHandler<TConfig>>>())
|
|
);
|
|
services.TryAddEnumerable(ServiceDescriptor.Singleton<IHostedService,
|
|
AzureServiceBusEventListenerService<TListenerConfig>>(provider =>
|
|
new AzureServiceBusEventListenerService<TListenerConfig>(
|
|
configuration: listenerConfiguration,
|
|
handler: provider.GetRequiredKeyedService<IEventMessageHandler>(serviceKey: listenerConfiguration.RoutingKey),
|
|
serviceBusService: provider.GetRequiredService<IAzureServiceBusService>(),
|
|
serviceBusOptions: new ServiceBusProcessorOptions()
|
|
{
|
|
PrefetchCount = listenerConfiguration.EventPrefetchCount,
|
|
MaxConcurrentCalls = listenerConfiguration.EventMaxConcurrentCalls
|
|
},
|
|
loggerFactory: provider.GetRequiredService<ILoggerFactory>()
|
|
)
|
|
)
|
|
);
|
|
services.TryAddEnumerable(ServiceDescriptor.Singleton<IHostedService,
|
|
AzureServiceBusIntegrationListenerService<TListenerConfig>>(provider =>
|
|
new AzureServiceBusIntegrationListenerService<TListenerConfig>(
|
|
configuration: listenerConfiguration,
|
|
handler: provider.GetRequiredService<IIntegrationHandler<TConfig>>(),
|
|
serviceBusService: provider.GetRequiredService<IAzureServiceBusService>(),
|
|
serviceBusOptions: new ServiceBusProcessorOptions()
|
|
{
|
|
PrefetchCount = listenerConfiguration.IntegrationPrefetchCount,
|
|
MaxConcurrentCalls = listenerConfiguration.IntegrationMaxConcurrentCalls
|
|
},
|
|
loggerFactory: provider.GetRequiredService<ILoggerFactory>()
|
|
)
|
|
)
|
|
);
|
|
|
|
return services;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Registers RabbitMQ-based event integration listeners for a specific integration type.
|
|
/// </summary>
|
|
/// <typeparam name="TConfig">The integration configuration details type (e.g., SlackIntegrationConfigurationDetails).</typeparam>
|
|
/// <typeparam name="TListenerConfig">The listener configuration type implementing IIntegrationListenerConfiguration.</typeparam>
|
|
/// <param name="services">The service collection to add services to.</param>
|
|
/// <param name="listenerConfiguration">The listener configuration containing routing keys and message processing settings.</param>
|
|
/// <returns>The service collection for chaining.</returns>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// This method registers three key components:
|
|
/// 1. EventIntegrationHandler - Keyed singleton for processing integration events
|
|
/// 2. RabbitMqEventListenerService - Hosted service for listening to event messages from RabbitMQ for
|
|
/// this integration type
|
|
/// 3. RabbitMqIntegrationListenerService - Hosted service for listening to integration messages from RabbitMQ for
|
|
/// this integration type
|
|
/// </para>
|
|
///
|
|
/// <para>
|
|
/// The handler uses the listener configuration's routing key as its service key, allowing multiple
|
|
/// handlers to be registered for different integration types.
|
|
/// </para>
|
|
/// </remarks>
|
|
internal static IServiceCollection AddRabbitMqIntegration<TConfig, TListenerConfig>(this IServiceCollection services,
|
|
TListenerConfig listenerConfiguration)
|
|
where TConfig : class
|
|
where TListenerConfig : IIntegrationListenerConfiguration
|
|
{
|
|
services.TryAddKeyedSingleton<IEventMessageHandler>(serviceKey: listenerConfiguration.RoutingKey, implementationFactory: (provider, _) =>
|
|
new EventIntegrationHandler<TConfig>(
|
|
integrationType: listenerConfiguration.IntegrationType,
|
|
eventIntegrationPublisher: provider.GetRequiredService<IEventIntegrationPublisher>(),
|
|
integrationFilterService: provider.GetRequiredService<IIntegrationFilterService>(),
|
|
cache: provider.GetRequiredKeyedService<IFusionCache>(EventIntegrationsCacheConstants.CacheName),
|
|
configurationRepository: provider.GetRequiredService<IOrganizationIntegrationConfigurationRepository>(),
|
|
groupRepository: provider.GetRequiredService<IGroupRepository>(),
|
|
organizationRepository: provider.GetRequiredService<IOrganizationRepository>(),
|
|
organizationUserRepository: provider.GetRequiredService<IOrganizationUserRepository>(), logger: provider.GetRequiredService<ILogger<EventIntegrationHandler<TConfig>>>())
|
|
);
|
|
services.TryAddEnumerable(ServiceDescriptor.Singleton<IHostedService,
|
|
RabbitMqEventListenerService<TListenerConfig>>(provider =>
|
|
new RabbitMqEventListenerService<TListenerConfig>(
|
|
handler: provider.GetRequiredKeyedService<IEventMessageHandler>(serviceKey: listenerConfiguration.RoutingKey),
|
|
configuration: listenerConfiguration,
|
|
rabbitMqService: provider.GetRequiredService<IRabbitMqService>(),
|
|
loggerFactory: provider.GetRequiredService<ILoggerFactory>()
|
|
)
|
|
)
|
|
);
|
|
services.TryAddEnumerable(ServiceDescriptor.Singleton<IHostedService,
|
|
RabbitMqIntegrationListenerService<TListenerConfig>>(provider =>
|
|
new RabbitMqIntegrationListenerService<TListenerConfig>(
|
|
handler: provider.GetRequiredService<IIntegrationHandler<TConfig>>(),
|
|
configuration: listenerConfiguration,
|
|
rabbitMqService: provider.GetRequiredService<IRabbitMqService>(),
|
|
loggerFactory: provider.GetRequiredService<ILoggerFactory>(),
|
|
timeProvider: provider.GetRequiredService<TimeProvider>()
|
|
)
|
|
)
|
|
);
|
|
|
|
return services;
|
|
}
|
|
|
|
internal static IServiceCollection AddOrganizationIntegrationCommandsQueries(this IServiceCollection services)
|
|
{
|
|
services.TryAddScoped<ICreateOrganizationIntegrationCommand, CreateOrganizationIntegrationCommand>();
|
|
services.TryAddScoped<IUpdateOrganizationIntegrationCommand, UpdateOrganizationIntegrationCommand>();
|
|
services.TryAddScoped<IDeleteOrganizationIntegrationCommand, DeleteOrganizationIntegrationCommand>();
|
|
services.TryAddScoped<IGetOrganizationIntegrationsQuery, GetOrganizationIntegrationsQuery>();
|
|
|
|
return services;
|
|
}
|
|
|
|
internal static IServiceCollection AddOrganizationIntegrationConfigurationCommandsQueries(this IServiceCollection services)
|
|
{
|
|
services.TryAddScoped<ICreateOrganizationIntegrationConfigurationCommand, CreateOrganizationIntegrationConfigurationCommand>();
|
|
services.TryAddScoped<IUpdateOrganizationIntegrationConfigurationCommand, UpdateOrganizationIntegrationConfigurationCommand>();
|
|
services.TryAddScoped<IDeleteOrganizationIntegrationConfigurationCommand, DeleteOrganizationIntegrationConfigurationCommand>();
|
|
services.TryAddScoped<IGetOrganizationIntegrationConfigurationsQuery, GetOrganizationIntegrationConfigurationsQuery>();
|
|
|
|
return services;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines if RabbitMQ is enabled for event integrations based on configuration settings.
|
|
/// </summary>
|
|
/// <param name="settings">The global settings containing RabbitMQ configuration.</param>
|
|
/// <returns>True if all required RabbitMQ settings are present; otherwise, false.</returns>
|
|
/// <remarks>
|
|
/// Requires all the following settings to be configured:
|
|
/// <list type="bullet">
|
|
/// <item><description>EventLogging.RabbitMq.HostName</description></item>
|
|
/// <item><description>EventLogging.RabbitMq.Username</description></item>
|
|
/// <item><description>EventLogging.RabbitMq.Password</description></item>
|
|
/// <item><description>EventLogging.RabbitMq.EventExchangeName</description></item>
|
|
/// <item><description>EventLogging.RabbitMq.IntegrationExchangeName</description></item>
|
|
/// </list>
|
|
/// </remarks>
|
|
internal static bool IsRabbitMqEnabled(GlobalSettings settings)
|
|
{
|
|
return CoreHelpers.SettingHasValue(settings.EventLogging.RabbitMq.HostName) &&
|
|
CoreHelpers.SettingHasValue(settings.EventLogging.RabbitMq.Username) &&
|
|
CoreHelpers.SettingHasValue(settings.EventLogging.RabbitMq.Password) &&
|
|
CoreHelpers.SettingHasValue(settings.EventLogging.RabbitMq.EventExchangeName) &&
|
|
CoreHelpers.SettingHasValue(settings.EventLogging.RabbitMq.IntegrationExchangeName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines if Azure Service Bus is enabled for event integrations based on configuration settings.
|
|
/// </summary>
|
|
/// <param name="settings">The global settings containing Azure Service Bus configuration.</param>
|
|
/// <returns>True if all required Azure Service Bus settings are present; otherwise, false.</returns>
|
|
/// <remarks>
|
|
/// Requires all of the following settings to be configured:
|
|
/// <list type="bullet">
|
|
/// <item><description>EventLogging.AzureServiceBus.ConnectionString</description></item>
|
|
/// <item><description>EventLogging.AzureServiceBus.EventTopicName</description></item>
|
|
/// <item><description>EventLogging.AzureServiceBus.IntegrationTopicName</description></item>
|
|
/// </list>
|
|
/// </remarks>
|
|
internal static bool IsAzureServiceBusEnabled(GlobalSettings settings)
|
|
{
|
|
return CoreHelpers.SettingHasValue(settings.EventLogging.AzureServiceBus.ConnectionString) &&
|
|
CoreHelpers.SettingHasValue(settings.EventLogging.AzureServiceBus.EventTopicName) &&
|
|
CoreHelpers.SettingHasValue(settings.EventLogging.AzureServiceBus.IntegrationTopicName);
|
|
}
|
|
}
|