chore: organize solution into module folders (Core/Server/Drivers/Client/Tooling)
Group all 69 projects into category subfolders under src/ and tests/ so the Rider Solution Explorer mirrors the module structure. Folders: Core, Server, Drivers (with a nested Driver CLIs subfolder), Client, Tooling. - Move every project folder on disk with git mv (history preserved as renames). - Recompute relative paths in 57 .csproj files: cross-category ProjectReferences, the lib/ HintPath+None refs in Driver.Historian.Wonderware, and the external mxaccessgw refs in Driver.Galaxy and its test project. - Rebuild ZB.MOM.WW.OtOpcUa.slnx with nested solution folders. - Re-prefix project paths in functional scripts (e2e, compliance, smoke SQL, integration, install). Build green (0 errors); unit tests pass. Docs left for a separate pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
using Serilog;
|
||||
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.Core.Scripting;
|
||||
|
||||
/// <summary>
|
||||
/// The API user scripts see as the global <c>ctx</c>. Abstract — concrete subclasses
|
||||
/// (e.g. <c>VirtualTagScriptContext</c>, <c>AlarmScriptContext</c>) plug in the
|
||||
/// actual tag-backend + logger + virtual-tag writer for each evaluation. Phase 7 plan
|
||||
/// decision #6: scripts can read any tag, write only to virtual tags, and have no
|
||||
/// other .NET reach — no HttpClient, no File, no Process, no reflection.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Every member on this type MUST be serializable in the narrow sense that
|
||||
/// <see cref="DependencyExtractor"/> can recognize tag-access call sites from the
|
||||
/// script AST. Method names used from scripts are locked — renaming
|
||||
/// <see cref="GetTag"/> or <see cref="SetVirtualTag"/> is a breaking change for every
|
||||
/// authored script and the dependency extractor must update in lockstep.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// New helpers (<see cref="Now"/>, <see cref="Deadband"/>) are additive: adding a
|
||||
/// method doesn't invalidate existing scripts. Do not remove or rename without a
|
||||
/// plan-level decision + migration for authored scripts.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public abstract class ScriptContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Read a tag's current value + quality + source timestamp. Path syntax is
|
||||
/// <c>Enterprise/Site/Area/Line/Equipment/TagName</c> (forward-slash delimited,
|
||||
/// matching the Equipment-namespace browse tree). Returns a
|
||||
/// <see cref="DataValueSnapshot"/> so scripts branch on quality without a second
|
||||
/// call.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <paramref name="path"/> MUST be a string literal in the script source — dynamic
|
||||
/// paths (variables, concatenation, method-returned strings) are rejected at
|
||||
/// publish by <see cref="DependencyExtractor"/>. This is intentional: the static
|
||||
/// dependency set is required for the change-driven scheduler to subscribe to the
|
||||
/// right upstream tags at load time.
|
||||
/// </remarks>
|
||||
public abstract DataValueSnapshot GetTag(string path);
|
||||
|
||||
/// <summary>
|
||||
/// Write a value to a virtual tag. Operator scripts cannot write to driver-sourced
|
||||
/// tags — the OPC UA dispatch in <c>DriverNodeManager</c> rejects that separately
|
||||
/// per ADR-002 with <c>BadUserAccessDenied</c>. This method is the only write path
|
||||
/// virtual tags have.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Path rules identical to <see cref="GetTag"/> — literal only, dependency
|
||||
/// extractor tracks the write targets so the engine knows what downstream
|
||||
/// subscribers to notify.
|
||||
/// </remarks>
|
||||
public abstract void SetVirtualTag(string path, object? value);
|
||||
|
||||
/// <summary>
|
||||
/// Current UTC timestamp. Prefer this over <see cref="DateTime.UtcNow"/> in
|
||||
/// scripts so the harness can supply a deterministic clock for tests.
|
||||
/// </summary>
|
||||
public abstract DateTime Now { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Per-script Serilog logger. Output lands in the dedicated <c>scripts-*.log</c>
|
||||
/// sink with structured property <c>ScriptName</c> = the script's configured name.
|
||||
/// Use at error level to surface problems; main <c>opcua-*.log</c> receives a
|
||||
/// companion WARN entry so operators see script errors in the primary log.
|
||||
/// </summary>
|
||||
public abstract ILogger Logger { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Deadband helper — returns <c>true</c> when <paramref name="current"/> differs
|
||||
/// from <paramref name="previous"/> by more than <paramref name="tolerance"/>.
|
||||
/// Useful for alarm predicates that shouldn't flicker on small noise. Pure
|
||||
/// function; no side effects.
|
||||
/// </summary>
|
||||
public static bool Deadband(double current, double previous, double tolerance)
|
||||
=> Math.Abs(current - previous) > tolerance;
|
||||
}
|
||||
Reference in New Issue
Block a user