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,19 @@
|
||||
namespace ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Point-in-time state of a single historian cluster node, included inside
|
||||
/// <see cref="HistorianHealthSnapshot.Nodes"/> when the backend is clustered.
|
||||
/// </summary>
|
||||
/// <param name="Name">Node identifier — backend-specific (typically a hostname).</param>
|
||||
/// <param name="IsHealthy">True when the node is currently considered usable for reads.</param>
|
||||
/// <param name="CooldownUntil">When the next retry against an unhealthy node is allowed; null when no cooldown is active.</param>
|
||||
/// <param name="FailureCount">Consecutive failures observed against this node since the last success.</param>
|
||||
/// <param name="LastError">Diagnostic text from the last failure against this node; null when no failures.</param>
|
||||
/// <param name="LastFailureTime">UTC of the last failure against this node; null when no failures.</param>
|
||||
public sealed record HistorianClusterNodeState(
|
||||
string Name,
|
||||
bool IsHealthy,
|
||||
DateTime? CooldownUntil,
|
||||
int FailureCount,
|
||||
string? LastError,
|
||||
DateTime? LastFailureTime);
|
||||
@@ -0,0 +1,32 @@
|
||||
namespace ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Point-in-time runtime health of a historian data source. Returned by
|
||||
/// <see cref="IHistorianDataSource.GetHealthSnapshot"/> and projected onto the
|
||||
/// server status dashboard.
|
||||
/// </summary>
|
||||
/// <param name="TotalQueries">Lifetime count of read calls received.</param>
|
||||
/// <param name="TotalSuccesses">Subset of <paramref name="TotalQueries"/> that completed without error.</param>
|
||||
/// <param name="TotalFailures">Subset of <paramref name="TotalQueries"/> that ended in error.</param>
|
||||
/// <param name="ConsecutiveFailures">Failures since the last success — non-zero means the source is currently degraded.</param>
|
||||
/// <param name="LastSuccessTime">UTC of the most recent successful read; null if none yet.</param>
|
||||
/// <param name="LastFailureTime">UTC of the most recent failed read; null if none yet.</param>
|
||||
/// <param name="LastError">Diagnostic text from the most recent failure; null when no failures recorded.</param>
|
||||
/// <param name="ProcessConnectionOpen">True when the source's process-data connection is currently established.</param>
|
||||
/// <param name="EventConnectionOpen">True when the source's event-data connection is currently established. Some backends share one connection — implementations may report the same value here as <paramref name="ProcessConnectionOpen"/>.</param>
|
||||
/// <param name="ActiveProcessNode">Cluster node currently serving process reads; null when no node is active or the backend is non-clustered.</param>
|
||||
/// <param name="ActiveEventNode">Cluster node currently serving event reads; null when no node is active or the backend is non-clustered.</param>
|
||||
/// <param name="Nodes">Per-cluster-node state. Empty when the backend is non-clustered.</param>
|
||||
public sealed record HistorianHealthSnapshot(
|
||||
long TotalQueries,
|
||||
long TotalSuccesses,
|
||||
long TotalFailures,
|
||||
int ConsecutiveFailures,
|
||||
DateTime? LastSuccessTime,
|
||||
DateTime? LastFailureTime,
|
||||
string? LastError,
|
||||
bool ProcessConnectionOpen,
|
||||
bool EventConnectionOpen,
|
||||
string? ActiveProcessNode,
|
||||
string? ActiveEventNode,
|
||||
IReadOnlyList<HistorianClusterNodeState> Nodes);
|
||||
@@ -0,0 +1,74 @@
|
||||
namespace ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Server-side historian data source. Registered with the server's history router
|
||||
/// and resolved per OPC UA namespace, independent of any driver's lifecycle.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Distinct from <see cref="IHistoryProvider"/>:
|
||||
/// <list type="bullet">
|
||||
/// <item><see cref="IHistoryProvider"/> is a *driver capability* — the server
|
||||
/// dispatches to it via the driver instance.</item>
|
||||
/// <item><see cref="IHistorianDataSource"/> is a *server registration* — the
|
||||
/// server resolves it via namespace and calls it directly, so a single
|
||||
/// historian (e.g. Wonderware) can serve many drivers' nodes, and drivers can
|
||||
/// restart without dropping history availability.</item>
|
||||
/// </list>
|
||||
/// All values returned use the shared <see cref="DataValueSnapshot"/> /
|
||||
/// <see cref="HistoricalEvent"/> shapes; backend-specific quality / type encodings
|
||||
/// are translated to OPC UA <c>StatusCode</c> uints inside the data source.
|
||||
/// </remarks>
|
||||
public interface IHistorianDataSource : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Read raw historical samples for a single tag over a time range.
|
||||
/// </summary>
|
||||
Task<HistoryReadResult> ReadRawAsync(
|
||||
string fullReference,
|
||||
DateTime startUtc,
|
||||
DateTime endUtc,
|
||||
uint maxValuesPerNode,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Read processed (interval-bucketed) samples — average / min / max / count / etc.
|
||||
/// A bucket with no source data returns a sample whose
|
||||
/// <see cref="DataValueSnapshot.StatusCode"/> indicates BadNoData.
|
||||
/// </summary>
|
||||
Task<HistoryReadResult> ReadProcessedAsync(
|
||||
string fullReference,
|
||||
DateTime startUtc,
|
||||
DateTime endUtc,
|
||||
TimeSpan interval,
|
||||
HistoryAggregateType aggregate,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Read one sample per requested timestamp — OPC UA HistoryReadAtTime service.
|
||||
/// Implementations interpolate or return prior-boundary samples per their
|
||||
/// backend's policy. The returned list MUST be the same length and order as
|
||||
/// <paramref name="timestampsUtc"/>; gaps are returned as Bad-quality snapshots.
|
||||
/// </summary>
|
||||
Task<HistoryReadResult> ReadAtTimeAsync(
|
||||
string fullReference,
|
||||
IReadOnlyList<DateTime> timestampsUtc,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Read historical alarm / event records — OPC UA HistoryReadEvents service.
|
||||
/// Distinct from any live event stream; sources here come from the historian's
|
||||
/// event log. <paramref name="sourceName"/> is null to return all sources.
|
||||
/// </summary>
|
||||
Task<HistoricalEventsResult> ReadEventsAsync(
|
||||
string? sourceName,
|
||||
DateTime startUtc,
|
||||
DateTime endUtc,
|
||||
int maxEvents,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Point-in-time health snapshot for diagnostics and dashboards. Pure
|
||||
/// observation; never blocks on backend I/O.
|
||||
/// </summary>
|
||||
HistorianHealthSnapshot GetHealthSnapshot();
|
||||
}
|
||||
Reference in New Issue
Block a user