using Microsoft.Extensions.Configuration;
namespace ZB.MOM.WW.OtOpcUa.Host.OpcUa;
///
/// The pre-authentication guards puts in front of the ConfigDb key
/// lookup (R03:3.3). Bound from the same Security:ApiKeys section as ApiKeyOptions but
/// owned by the Host, where the store lives.
///
///
///
/// Why. The negative cache was keyed by key id, so a flood of DISTINCT well-formed
/// otua_<random>_x credentials missed it every time and cost one indexed SQL query per
/// attempt — under the SDK's SessionManager-wide lock — with no credential needed. Two guards close
/// that: a known-id set (every ApiKeyId the ConfigDb holds, refreshed every
/// StoreCacheSeconds) rejects an unknown id in memory, and a miss budget (token
/// bucket) bounds how many lookups that reach the store and MISS are allowed per second when the
/// set is unavailable.
///
///
/// The budget is process-wide, not per remote endpoint: the OPC UA SDK's impersonation callback
/// (the IOpcUaUserAuthenticator seam) does not carry the client's address. Per-endpoint
/// accounting needs that seam widened in the OpcUaServer project — a follow-up, not this lane.
///
///
public sealed class ApiKeyStoreGuardOptions
{
/// The configuration section the knobs live in (shared with ApiKeyOptions).
public const string SectionName = "Security:ApiKeys";
///
/// Whether the known-id set is consulted. restores a store read per unknown
/// id. Only meaningful when the inner store can list ids (the ConfigDb store can; the artifact
/// store is never wrapped).
///
public bool KnownIdSet { get; set; } = true;
///
/// How many store MISSES (lookups that reach the inner store and find no key) may burst before
/// further lookups for unknown ids are refused without a store read. 0 disables the budget.
///
public int MissBurst { get; set; } = 100;
/// How many miss tokens are restored per second, up to .
public double MissRefillPerSecond { get; set; } = 20;
/// Binds the section, with defaults for anything absent.
/// The app configuration; null yields the defaults.
/// The bound options.
public static ApiKeyStoreGuardOptions Bind(IConfiguration? configuration)
{
var options = new ApiKeyStoreGuardOptions();
configuration?.GetSection(SectionName).Bind(options);
return options;
}
}