Files
scadaproj/docs/plans/2026-06-19-sphistorianclient-design.md
T

123 lines
6.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ZB.MOM.WW.SPHistorianClient — Design
**Date:** 2026-06-19
**Status:** Approved — proceeding to implementation plan.
## Goal
Repackage the proven, pure-managed .NET 10 `AVEVA.Historian.Client` SDK (delivered in
`HistorianSDK_2023R2/histsdk-migration.zip` from `10.100.0.48`) as the family-branded shared
library **`ZB.MOM.WW.SPHistorianClient`** (System Platform Historian Client), following the same
conventions as the other `ZB.MOM.WW.*` shared libraries in this repo.
## Context — what the source bundle contains
`histsdk-migration.zip``histsdk-migration/`:
- `histsdk/` — the SDK git repo. `src/AVEVA.Historian.Client/` is a **pure-managed .NET 10** client
for AVEVA Historian (no `aahClientManaged.dll` / `aahClient.dll` / native AVEVA runtime — the wire
protocol is reverse-engineered and re-implemented in C#). ~165188 unit + gated-live tests pass.
- `analysis-2023r2/` — reverse-engineering analysis (recovered protos, decompiled stock contract,
transport writeup). **Kept separate from the repo on purpose.**
Two transport families exist in the SDK:
| Transport | Protocol | Platform | Verification |
|---|---|---|---|
| `LocalPipe`, `RemoteTcpIntegrated`, `RemoteTcpCertificate` | WCF/MDAS (2020) | **Windows-only** | **live-verified**: raw/aggregate(16 modes)/at-time/event reads, browse, metadata, status, `EnsureTag`/`DeleteTag` |
| `RemoteGrpc` | gRPC (2023 R2) | cross-platform (Grpc.Net.Client/.Web) | unit-tested; **not yet live-verified** against a real 2023 R2 server (`ExchangeKey` auth step unproven) |
## Decisions (locked)
1. **Approach: port + rebrand.** Copy the SDK source into `ZB.MOM.WW.SPHistorianClient`, rename the
root namespace, adopt ZB conventions, bring the unit tests, drop non-shippable artifacts. One
coherent shared library — a published package should not ship a third-party (AVEVA) namespace or
non-redistributable reverse-engineering artifacts.
2. **Transports: both WCF + gRPC.** Ship everything that works. WCF members keep
`[SupportedOSPlatform("windows")]`; the gRPC path runs anywhere. No working code discarded.
3. **Not a "component normalization."** There is no duplicated historian code across the three apps
to converge — this is a net-new shared library that simply follows ZB packaging conventions.
## Repository layout
Plain files committed into this repo (NOT a nested git repo — see the
`shared-libs-are-plain-files-not-nested-repos` convention):
```
ZB.MOM.WW.SPHistorianClient/
Directory.Build.props # net10.0, Nullable, ImplicitUsings, LangVersion latest, Version 0.1.0, central pkg mgmt
Directory.Packages.props # central PackageVersion entries
ZB.MOM.WW.SPHistorianClient.slnx
CLAUDE.md README.md .gitignore
src/ZB.MOM.WW.SPHistorianClient/ # the single package
HistorianClient.cs, HistorianClientOptions.cs, HistorianTransport.cs
Models/ Protocol/ Transport/ Wcf/ Wcf/Contracts/ Grpc/ Grpc/Protos/*.proto
DependencyInjection/AddZbSpHistorianClient (ZB-idiomatic DI extension)
tests/ZB.MOM.WW.SPHistorianClient.Tests/ # offline unit/golden-byte + gated-live integration
artifacts/ # dotnet pack output
```
## Port mechanics
- Copy `src/AVEVA.Historian.Client/` and `tests/AVEVA.Historian.Client.Tests/` from the bundle.
- Rename the C# root namespace `AVEVA.Historian.Client``ZB.MOM.WW.SPHistorianClient` across all
files: 74 `namespace` declarations spanning the root + 6 sub-namespaces
(`.Models`, `.Wcf`, `.Wcf.Contracts`, `.Protocol`, `.Transport`, `.Grpc`), all `using` directives,
and the `InternalsVisibleTo` to the test assembly. Drop the `InternalsVisibleTo` to
`AVEVA.Historian.ReverseEngineering` (tool not shipped).
- **Leave the proto wire contracts untouched:** the 6 `Grpc/Protos/*.proto` keep
`option csharp_namespace = "ArchestrA.Grpc.Contract.*"` — that is AVEVA's wire contract, not ours.
`Grpc.Tools` keeps generating the client stubs at build.
- Convert inline `PackageReference` versions to central management in `Directory.Packages.props`,
matching the `ZB.MOM.WW.Telemetry` template.
## Dependencies
- **Library:** `Google.Protobuf`, `Grpc.Net.Client`, `Grpc.Net.Client.Web`, `Grpc.Tools` (build-only,
`PrivateAssets=all`), `System.ServiceModel.NetNamedPipe`, `System.ServiceModel.NetTcp`,
`System.Security.Cryptography.Xml`. Add `Microsoft.Extensions.DependencyInjection.Abstractions` +
`Microsoft.Extensions.Options` for the DI extension.
- **Tests:** `xunit`, `xunit.runner.visualstudio`, `Microsoft.NET.Test.Sdk`, `coverlet.collector`,
`Microsoft.Data.SqlClient` (SQL post-check tests).
## Excluded (safety / non-redistributable / Windows-native)
- `tools/` reverse-engineering harnesses (.NET Framework, reference native AVEVA binaries).
- `analysis-2023r2/decompiled/` — proprietary AVEVA decompilations (not redistributable).
- `scripts/` — Frida / PowerShell / Python capture tooling.
- `docs/reverse-engineering/` — identity-bearing `.ndjson` / capture evidence.
**Kept:** the recovered `.proto` files (needed to build), the offline unit tests, and a sanitized
architecture/surface summary folded into `CLAUDE.md` / `README.md`. `.gitignore` blocks the
identity-bearing patterns (`*.ndjson`, `current/`, `aveva-install-*/`, `artifacts/`-raw, etc.).
## Public surface (preserved 1:1)
`HistorianClient` + `HistorianClientOptions` façade; `Models/*`; `HistorianTransport` enum
(`LocalPipe` / `RemoteTcpIntegrated` / `RemoteTcpCertificate` / `RemoteGrpc`); operations:
`ProbeAsync`, `ReadRawAsync` / `ReadAggregateAsync` / `ReadAtTimeAsync`, `ReadEventsAsync`,
`BrowseTagNamesAsync`, `GetTagMetadataAsync`, status calls, `EnsureTagAsync` / `DeleteTagAsync`.
**One ZB-idiomatic addition:** `AddZbSpHistorianClient(...)` DI extension mirroring `AddZbTelemetry`
— thin: binds `HistorianClientOptions` and registers `HistorianClient`. Optional to consumers.
## Cross-platform & testing posture
- WCF members already carry `[SupportedOSPlatform("windows")]`; the library builds and unit-tests on
macOS/Linux. gRPC path is portable.
- Offline unit/golden-byte tests run anywhere. Live integration tests stay gated by `HISTORIAN_*`
env vars and skip cleanly when unset.
- Verify `dotnet build` + `dotnet test` pass locally (macOS) before finishing.
## Packaging
`dotnet pack -c Release -o ./artifacts``ZB.MOM.WW.SPHistorianClient.0.1.0.nupkg`. Gitea URLs in
package metadata. **Not pushed/published** to any feed unless explicitly requested.
## Out of scope (this pass)
- Wiring `ZB.MOM.WW.SPHistorianClient` into any consumer (e.g. OtOpcUa Phase C HistoryRead) — a
separate follow-on.
- Live-verifying the gRPC `RemoteGrpc` path against a real 2023 R2 server.
- Writing samples (`AddS2`) — architecturally blocked in the source SDK; remains out of scope.