docs(sphistorianclient): approved design for ZB.MOM.WW.SPHistorianClient port
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
# 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#). ~165–188 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.
|
||||
Reference in New Issue
Block a user