using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Extensions.Logging;
using ZB.MOM.WW.OtOpcUa.Core.Hosting;
using ZB.MOM.WW.Secrets.Abstractions;
namespace ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient;
///
/// Registers the OPC UA Client driver with the . The driver's
/// DriverConfig JSON deserialises directly into
/// (the same shape reads), so no separate DTO is needed —
/// unlike the protocol drivers, this driver has no pre-declared "Tags" DTO path to retire.
/// v3: the deploy artifact's authored raw tags bind straight onto
/// (a RawTagEntry list) through the same
/// deserialiser; the EndpointUrl binding is unchanged (endpoint→DeviceConfig is Wave C).
/// Mirrors ModbusDriverFactoryExtensions / GalaxyDriverFactoryExtensions.
///
public static class OpcUaClientDriverFactoryExtensions
{
/// Driver type name — matches DriverInstance.DriverType values.
public const string DriverTypeName = "OpcUaClient";
// Match OpcUaClientDriverProbe exactly so factory + probe parse a config identically.
// The JsonStringEnumConverter lets enum-valued knobs (SecurityMode / SecurityPolicy /
// AuthType / TargetNamespaceKind) be authored as their string names — the natural form
// for human-edited + AdminUI-emitted DriverConfig JSON.
private static readonly JsonSerializerOptions JsonOptions = new()
{
PropertyNameCaseInsensitive = true,
UnmappedMemberHandling = JsonUnmappedMemberHandling.Skip,
Converters = { new JsonStringEnumConverter() },
};
/// Register the OpcUaClient factory with the driver registry, threading the shared secret resolver.
/// The driver factory registry to register with.
/// Optional logger factory used to create per-instance loggers.
///
/// The shared secret resolver (from DI) used to resolve the secret: arm of each
/// instance's Password / UserCertificatePassword at session-open. Defaults to
/// the null-object for the test/standalone path — callers
/// that need a working secret: credential ref must thread the DI resolver.
///
public static void Register(
DriverFactoryRegistry registry,
ILoggerFactory? loggerFactory = null,
ISecretResolver? secretResolver = null)
{
ArgumentNullException.ThrowIfNull(registry);
var resolver = secretResolver ?? NullSecretResolver.Instance;
registry.Register(DriverTypeName, (id, json) => CreateInstance(id, json, loggerFactory, resolver));
}
/// Public for the Server-side bootstrapper + test consumers.
/// The unique identifier for the driver instance.
/// The JSON configuration string for the driver.
/// Optional logger factory for the per-instance logger.
///
/// Optional shared secret resolver for the driver's secret: credential arm; defaults
/// to the null-object (fail-closed on a secret: ref).
///
/// A configured .
public static OpcUaClientDriver CreateInstance(
string driverInstanceId, string driverConfigJson, ILoggerFactory? loggerFactory = null,
ISecretResolver? secretResolver = null)
{
ArgumentException.ThrowIfNullOrWhiteSpace(driverInstanceId);
ArgumentException.ThrowIfNullOrWhiteSpace(driverConfigJson);
var options = JsonSerializer.Deserialize(driverConfigJson, JsonOptions)
?? throw new InvalidOperationException(
$"OpcUaClient driver config for '{driverInstanceId}' deserialised to null");
return new OpcUaClientDriver(
options, driverInstanceId, loggerFactory?.CreateLogger(),
secretResolver ?? NullSecretResolver.Instance);
}
}