refactor: rename ScadaLink → ZB.MOM.WW.ScadaBridge (code + projects + namespaces)
Solution + 23 src projects + 26 test projects renamed; folders, csproj, namespaces, and ScadaLinkDbContext/ScadaBridgeDbContext class updated. ActorSystem "scadalink" → "scadabridge", Akka seed-node URLs migrated. SQL roles/logins, LDAP domains, CLI command name, and CLI config dir (~/.scadalink → ~/.scadabridge) also renamed. Build green; 5 Host.Tests fail awaiting SQL login rename in next commit. Pre-existing StaleTagMonitor timing flakes unchanged. Rename script committed at tools/rename-to-scadabridge.sh.
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
using System.Text.Json;
|
||||
|
||||
namespace ZB.MOM.WW.ScadaBridge.SiteRuntime.Scripts;
|
||||
|
||||
/// <summary>
|
||||
/// Read-only globals a trigger expression is compiled against. Exposes only
|
||||
/// attribute reads, backed by an in-memory snapshot — no I/O, no actor Ask,
|
||||
/// no side-effecting APIs. A missing attribute key reads as <c>null</c> and
|
||||
/// never throws.
|
||||
///
|
||||
/// Canonical attribute keys are dotted (e.g. "TempSensor.Reading"); the prefix
|
||||
/// logic here mirrors <see cref="AttributeAccessor.Resolve"/>.
|
||||
/// </summary>
|
||||
public sealed class TriggerExpressionGlobals
|
||||
{
|
||||
/// <summary>
|
||||
/// Extracts the <c>"expression"</c> field from an Expression-trigger config
|
||||
/// JSON document. Returns <c>null</c> for a missing, blank, or malformed
|
||||
/// config — the single parsing idiom shared by InstanceActor, ScriptActor,
|
||||
/// and AlarmActor.
|
||||
/// </summary>
|
||||
/// <param name="triggerConfigJson">JSON string of the trigger configuration, or null.</param>
|
||||
public static string? ExtractExpression(string? triggerConfigJson)
|
||||
{
|
||||
if (string.IsNullOrEmpty(triggerConfigJson)) return null;
|
||||
try
|
||||
{
|
||||
using var doc = JsonDocument.Parse(triggerConfigJson);
|
||||
var expr = doc.RootElement.TryGetProperty("expression", out var e)
|
||||
? e.GetString()
|
||||
: null;
|
||||
return string.IsNullOrWhiteSpace(expr) ? null : expr;
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly IReadOnlyDictionary<string, object?> _snapshot;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the globals with a flat attribute snapshot.
|
||||
/// </summary>
|
||||
/// <param name="snapshot">Flat dictionary of canonical attribute key to current value.</param>
|
||||
public TriggerExpressionGlobals(IReadOnlyDictionary<string, object?> snapshot)
|
||||
=> _snapshot = snapshot;
|
||||
|
||||
/// <summary>Attributes in the expression's own scope (root prefix).</summary>
|
||||
public ReadOnlyAttributes Attributes => new(_snapshot, "");
|
||||
|
||||
/// <summary>Indexed access to child compositions' attributes.</summary>
|
||||
public ReadOnlyChildren Children => new(_snapshot);
|
||||
|
||||
/// <summary>
|
||||
/// Parent composition (null at root). Set by the caller for derived/composed
|
||||
/// scopes; the runtime actors evaluate at root scope, so this stays null.
|
||||
/// </summary>
|
||||
public ReadOnlyComposition? Parent { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Read-only attribute view anchored at a canonical-name prefix. Indexing
|
||||
/// resolves to the canonical key ("" → key, "TempSensor" → "TempSensor.key").
|
||||
/// </summary>
|
||||
public sealed class ReadOnlyAttributes
|
||||
{
|
||||
private readonly IReadOnlyDictionary<string, object?> _s;
|
||||
private readonly string _prefix;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a read-only attribute view anchored at the given prefix.
|
||||
/// </summary>
|
||||
/// <param name="s">The backing attribute snapshot.</param>
|
||||
/// <param name="prefix">Canonical name prefix; empty string for root scope.</param>
|
||||
public ReadOnlyAttributes(IReadOnlyDictionary<string, object?> s, string prefix)
|
||||
{
|
||||
_s = s;
|
||||
_prefix = prefix;
|
||||
}
|
||||
|
||||
/// <summary>Returns the attribute value for <paramref name="key"/>, or null if absent.</summary>
|
||||
/// <param name="key">The attribute key, relative to the prefix.</param>
|
||||
public object? this[string key] =>
|
||||
_s.TryGetValue(_prefix.Length == 0 ? key : _prefix + "." + key, out var v) ? v : null;
|
||||
}
|
||||
|
||||
/// <summary>A read-only view of one composition at a canonical-name path.</summary>
|
||||
public sealed class ReadOnlyComposition
|
||||
{
|
||||
private readonly IReadOnlyDictionary<string, object?> _s;
|
||||
private readonly string _path;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a read-only composition view anchored at a canonical path.
|
||||
/// </summary>
|
||||
/// <param name="s">The backing attribute snapshot.</param>
|
||||
/// <param name="path">Canonical path prefix for this composition's attributes.</param>
|
||||
public ReadOnlyComposition(IReadOnlyDictionary<string, object?> s, string path)
|
||||
{
|
||||
_s = s;
|
||||
_path = path;
|
||||
}
|
||||
|
||||
/// <summary>Read-only attribute view scoped to this composition's canonical path.</summary>
|
||||
public ReadOnlyAttributes Attributes => new(_s, _path);
|
||||
}
|
||||
|
||||
/// <summary>Dictionary-style accessor for child compositions.</summary>
|
||||
public sealed class ReadOnlyChildren
|
||||
{
|
||||
private readonly IReadOnlyDictionary<string, object?> _s;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a children accessor over the supplied attribute snapshot.
|
||||
/// </summary>
|
||||
/// <param name="s">The backing attribute snapshot.</param>
|
||||
public ReadOnlyChildren(IReadOnlyDictionary<string, object?> s) => _s = s;
|
||||
|
||||
/// <summary>Returns a read-only composition view for the named child composition.</summary>
|
||||
/// <param name="compositionName">The canonical composition name.</param>
|
||||
public ReadOnlyComposition this[string compositionName] => new(_s, compositionName);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user