using Deal.Modules.Settings.Application.Abstractions;
using Deal.Modules.Settings.Application.Models;
using Deal.Modules.Settings.Application.Registrars;
using Deal.Modules.Settings.Application.Services;
using Deal.Modules.Discovery.Application.Abstractions;
using Deal.Modules.Discovery.Application.Exceptions;
using Deal.Modules.Discovery.Application.Extensions;
using Deal.Modules.Discovery.Application.Models;
using Deal.Modules.Discovery.Application.Registrars;
namespace Deal.Modules.Discovery.Application.Services;
///
/// Продовая реализация : случайная пауза из настроек тенанта (ban_guard L44–56).
///
///
/// Защита инварианта min ≤ max как в python L47–51: настройки мог изменить один конец интервала (single-key
/// PATCH), поэтому при инверсии концы меняются местами. Обе настройки не заданы/≤0 — паузы нет (крайний случай
/// L52–53). Детерминизма нет: интервал сэмплируется из .
///
public sealed class DiscoveryPacer(ISettingsStore settings) : IDiscoveryPacer
{
///
public async Task WaitJoinDelayAsync(CancellationToken ct)
{
TenantSettingsSnapshot snapshot = await TenantSettingsSnapshot.LoadAsync(settings, ct);
int low = snapshot.GetInt(SettingsKeys.DiscJoinDelayMin, SettingsDefaults.DiscJoinDelayMin);
int high = snapshot.GetInt(SettingsKeys.DiscJoinDelayMax, SettingsDefaults.DiscJoinDelayMax);
if (low <= 0 && high <= 0)
{
return;
}
if (low > high)
{
(low, high) = (high, low);
}
double seconds = low + Random.Shared.NextDouble() * (high - low);
await Task.Delay(TimeSpan.FromSeconds(seconds), ct).ConfigureAwait(false);
}
}