feat(sms): Twilio SmsNotificationDeliveryAdapter + classifier + options + DI (S3)
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Kpi;
|
||||
using ZB.MOM.WW.ScadaBridge.NotificationOutbox.Delivery;
|
||||
using ZB.MOM.WW.ScadaBridge.NotificationOutbox.Kpi;
|
||||
@@ -15,6 +16,9 @@ public static class ServiceCollectionExtensions
|
||||
/// <summary>Configuration section bound to <see cref="NotificationOutboxOptions"/>.</summary>
|
||||
public const string OptionsSection = "ScadaBridge:NotificationOutbox";
|
||||
|
||||
/// <summary>Configuration section bound to <see cref="SmsOptions"/>.</summary>
|
||||
public const string SmsOptionsSection = "ScadaBridge:Sms";
|
||||
|
||||
/// <summary>
|
||||
/// Registers the Notification Outbox services: the <see cref="NotificationOutboxOptions"/>
|
||||
/// binding and the channel delivery adapters.
|
||||
@@ -32,6 +36,13 @@ public static class ServiceCollectionExtensions
|
||||
/// directly. The <see cref="NotificationOutboxActor"/> resolves the adapters from a fresh
|
||||
/// scope per dispatch sweep rather than holding them, so no scoped adapter is captured by
|
||||
/// the singleton actor.
|
||||
///
|
||||
/// The <see cref="SmsNotificationDeliveryAdapter"/> (Twilio-REST) is registered the same
|
||||
/// way alongside the Email adapter, so both resolve from
|
||||
/// <c>GetServices<INotificationDeliveryAdapter>()</c>. It also binds + validates
|
||||
/// <see cref="SmsOptions"/> (<c>ScadaBridge:Sms</c>) and the named <c>"Twilio"</c>
|
||||
/// <see cref="HttpClient"/>; unlike the Email adapter it needs no NotificationService
|
||||
/// machinery (a single outbound HTTPS POST per recipient).
|
||||
/// </summary>
|
||||
/// <param name="services">The DI service collection to register notification outbox services into.</param>
|
||||
/// <returns>The same <paramref name="services"/> instance for chaining.</returns>
|
||||
@@ -42,13 +53,33 @@ public static class ServiceCollectionExtensions
|
||||
services.AddOptions<NotificationOutboxOptions>()
|
||||
.BindConfiguration(OptionsSection);
|
||||
|
||||
// Scoped: the adapter holds a scoped INotificationRepository. Registered both under
|
||||
// the interface (so the dispatch sweep can enumerate every channel adapter) and as
|
||||
// the concrete type (so callers and tests can resolve it directly).
|
||||
// Bind + validate SmsOptions (ScadaBridge:Sms): the SMS adapter's body cap and
|
||||
// per-request timeout fallback. ValidateOnStart surfaces a bad option at host
|
||||
// startup rather than at first delivery; the validator is registered via
|
||||
// TryAddEnumerable so a re-call of AddNotificationOutbox does not double-register it.
|
||||
services.AddOptions<SmsOptions>()
|
||||
.BindConfiguration(SmsOptionsSection)
|
||||
.ValidateOnStart();
|
||||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Singleton<IValidateOptions<SmsOptions>, SmsOptionsValidator>());
|
||||
|
||||
// Named HTTP client backing the Twilio-REST SMS adapter. Pooled handler lifetime
|
||||
// is managed by IHttpClientFactory; the adapter applies the per-request timeout
|
||||
// via a linked CTS (so the client's own Timeout stays at its default).
|
||||
services.AddHttpClient(SmsNotificationDeliveryAdapter.HttpClientName);
|
||||
|
||||
// Scoped: the adapters hold a scoped INotificationRepository. Each is registered
|
||||
// both under the interface (so the dispatch sweep can enumerate every channel
|
||||
// adapter — both Email and SMS must resolve from GetServices<INotificationDeliveryAdapter>())
|
||||
// and as the concrete type (so callers and tests can resolve it directly).
|
||||
services.AddScoped<EmailNotificationDeliveryAdapter>();
|
||||
services.AddScoped<INotificationDeliveryAdapter>(
|
||||
sp => sp.GetRequiredService<EmailNotificationDeliveryAdapter>());
|
||||
|
||||
services.AddScoped<SmsNotificationDeliveryAdapter>();
|
||||
services.AddScoped<INotificationDeliveryAdapter>(
|
||||
sp => sp.GetRequiredService<SmsNotificationDeliveryAdapter>());
|
||||
|
||||
// KPI history (M6): the recorder singleton enumerates every IKpiSampleSource each
|
||||
// sampling pass to snapshot the outbox delivery KPIs into the central history store.
|
||||
// TryAddEnumerable is idempotent — no double-registration if AddNotificationOutbox
|
||||
|
||||
Reference in New Issue
Block a user