06e1046317
Reconcile load-bearing docs with shipped behavior: - IPC-06: gateway.md Worker Envelope sketch -> points to mxaccess_worker.proto as source of truth (string correlation_id, real oneof arms incl. worker_shutdown_ack/worker_ready). - IPC-07: docs/Grpc.md six RPCs -> seven; document QueryActiveAlarms handler + validation row. - IPC-21: gateway.md Session RPC moved from live API into a 'Future work: not implemented' subsection. - TST-13: drop stale design-era sketches from gateway.md; correct the single-subscriber-default (config-gated fan-out) note. - SEC-09: dashboard GroupToRole sample GwAdmin:Admin -> Administrator so it passes GatewayOptionsValidator; clarify Administrator is the canonical role. - SEC-22: rewrite docs/Authentication.md to the pipeline that actually ships (ZB.MOM.WW.Auth.ApiKeys package + gateway-owned CachingApiKeyVerifier, CoalescingMarkApiKeyStore, CanonicalForwardingApiKeyAuditStore, etc.); remove 18 stale type names (grep-verified absent). - IPC-17: correct wrong Python generated dir (mxgateway -> zb_mom_ww_mxgateway) in CLAUDE.md + 3 docs. - CLI-12: Java docs Java 21 -> Java 17 (JDK17 retarget for Ignition 8.3). - CLI-16: docs/ClientPackaging.md reconciled with real .slnx, Python package name, and gradle project names; fix stale generateProto task name. Docs-only; type/path/version claims verified against source. Claude-Session: https://claude.ai/code/session_01DMXXvNuPekkkrTEyPNxEkW
237 lines
9.6 KiB
Markdown
237 lines
9.6 KiB
Markdown
# Client Proto Generation
|
|
|
|
This document defines the stable protobuf inputs that official clients use to
|
|
generate language-specific gRPC bindings. The checked-in `.proto` files remain
|
|
the source of truth so clients do not drift from the gateway and worker
|
|
contracts.
|
|
|
|
## Stable Inputs
|
|
|
|
The stable client input manifest is `clients/proto/proto-inputs.json`. It
|
|
records:
|
|
|
|
- the public gateway protocol version,
|
|
- the worker IPC protocol version,
|
|
- the protobuf import root,
|
|
- the public and worker source files,
|
|
- the descriptor set path,
|
|
- golden fixture locations,
|
|
- behavior fixture locations,
|
|
- generated-code output directories for each planned client.
|
|
|
|
The source files listed by the manifest are:
|
|
|
|
- `src/ZB.MOM.WW.MxGateway.Contracts/Protos/mxaccess_gateway.proto`
|
|
- `src/ZB.MOM.WW.MxGateway.Contracts/Protos/mxaccess_worker.proto`
|
|
- `src/ZB.MOM.WW.MxGateway.Contracts/Protos/galaxy_repository.proto`
|
|
|
|
`mxaccess_gateway.proto` defines the public gRPC service and shared DTOs.
|
|
`mxaccess_worker.proto` is included in the descriptor because worker-aware
|
|
tests and fake-worker clients need the same command, reply, event, value, and
|
|
status shapes. `galaxy_repository.proto` defines the read-only Galaxy
|
|
Repository browse service used by clients to enumerate the deployed object
|
|
hierarchy and dynamic attributes; see
|
|
[Galaxy Repository Browse](./GalaxyRepository.md).
|
|
|
|
## Protocol Version
|
|
|
|
`GatewayContractInfo.GatewayProtocolVersion` is the public gateway protocol
|
|
version. `OpenSessionReply.gateway_protocol_version` returns the same value so
|
|
clients can compare their generated bindings against the gateway before issuing
|
|
MXAccess commands.
|
|
|
|
`GatewayContractInfo.WorkerProtocolVersion` remains the gateway-to-worker IPC
|
|
protocol version. It is also present in `OpenSessionReply` because parity
|
|
fixtures and fake-worker tests need to know the worker contract used by the
|
|
session.
|
|
|
|
## Descriptor Publishing
|
|
|
|
Run this command after changing either source `.proto` file or the client proto
|
|
manifest, with the **pinned protoc 34.1** (see [Toolchain Links](./ToolchainLinks.md)):
|
|
|
|
```powershell
|
|
pwsh -File scripts/publish-client-proto-inputs.ps1
|
|
```
|
|
|
|
The script writes
|
|
`clients/proto/descriptors/mxaccessgw-client-v1.protoset` with imports and
|
|
source information included. The descriptor is a generated artifact; do not edit
|
|
it by hand. Generating the committed artifact requires the pinned protoc version
|
|
so the checked-in bytes are reproducible; the script fails fast on a version
|
|
mismatch when generating.
|
|
|
|
Use the check mode in CI or before committing:
|
|
|
|
```powershell
|
|
pwsh -File scripts/publish-client-proto-inputs.ps1 -Check
|
|
```
|
|
|
|
`-Check` rebuilds the descriptor and fails when the checked-in descriptor is
|
|
stale. The comparison normalizes both the committed and freshly built descriptor
|
|
through the same protoc with `source_code_info` stripped, so it is tolerant of
|
|
protoc-version encoding drift and does not false-fail across protoc releases
|
|
(it warns, rather than fails, when protoc is off the pin).
|
|
|
|
The gateway test project carries an independent, protoc-free freshness guard:
|
|
`ClientProtoInputTests.Descriptor_ContainsEveryContractMessageAndField` reflects
|
|
over the in-process contract descriptors and fails if any contract message or
|
|
field is missing from the committed protoset. This is the primary CI gate for
|
|
descriptor staleness; a red test means "regenerate and commit the protoset."
|
|
|
|
### Pinned generator versions
|
|
|
|
Regeneration is reproducible only with the pinned toolchain. Regenerating with a
|
|
different version silently produces incompatible or noisy output, so the per-client
|
|
scripts assert the pin and resolve tools from `PATH`:
|
|
|
|
| Generator | Pinned version | Guard |
|
|
|-----------|----------------|-------|
|
|
| protoc (descriptor set) | 34.1 | version assertion in `scripts/publish-client-proto-inputs.ps1` |
|
|
| `Grpc.Tools` (C# `Generated/`) | 2.80.0 (contracts csproj) | `scripts/check-codegen.ps1` git-diff of `Generated/` |
|
|
| `grpcio-tools` (Python) | 1.80.0 (protobuf runtime 6.31.1) | version assertion in `clients/python/generate-proto.ps1` |
|
|
| protobuf / grpc-java (Java) | `protobufVersion` / `grpcVersion` in `clients/java/build.gradle` | `checkGeneratedClean` gradle task |
|
|
|
|
A newer `grpcio-tools` stamps a `GRPC_GENERATED_VERSION` above the pinned grpcio
|
|
runtime and breaks Python `pytest`; the Java protobuf plugin rewrites
|
|
`MxaccessGateway.java` with spurious protobuf-runtime-version churn on every build
|
|
(revert that one file when no `.proto` changed — see
|
|
[Gateway Testing](./GatewayTesting.md) "Continuous Integration").
|
|
|
|
## Output Directories
|
|
|
|
The manifest declares these generated-code directories:
|
|
|
|
| Client | Directory |
|
|
|--------|-----------|
|
|
| .NET | `clients/dotnet/generated` |
|
|
| Go | `clients/go/internal/generated` |
|
|
| Rust | `clients/rust/src/generated` |
|
|
| Python | `clients/python/src/zb_mom_ww_mxgateway/generated` |
|
|
| Java | `clients/java/src/main/generated` |
|
|
|
|
Only generator output belongs in these directories. Handwritten client wrappers
|
|
belong in the language-specific source trees created by the client scaffold
|
|
issues.
|
|
|
|
## Language Generation Inputs
|
|
|
|
All generators use `src/ZB.MOM.WW.MxGateway.Contracts/Protos` as the protobuf import
|
|
root. The checked-in descriptor is available when a language build prefers a
|
|
descriptor input, but the `.proto` files remain canonical.
|
|
|
|
Use these commands to regenerate language-specific client bindings:
|
|
|
|
| Client | Command |
|
|
|--------|---------|
|
|
| .NET | `dotnet build src/ZB.MOM.WW.MxGateway.Contracts/ZB.MOM.WW.MxGateway.Contracts.csproj` |
|
|
| Go | `Push-Location clients/go; ./generate-proto.ps1; Pop-Location` |
|
|
| Rust | `Push-Location clients/rust; cargo check --workspace; Pop-Location` |
|
|
| Python | `Push-Location clients/python; ./generate-proto.ps1; Pop-Location` |
|
|
| Java | `Push-Location clients/java; gradle :zb-mom-ww-mxgateway-client:generateProto; Pop-Location` |
|
|
|
|
.NET generation currently runs through the contracts project:
|
|
|
|
```powershell
|
|
dotnet build src/ZB.MOM.WW.MxGateway.Contracts/ZB.MOM.WW.MxGateway.Contracts.csproj
|
|
```
|
|
|
|
Future .NET client projects may either reference `ZB.MOM.WW.MxGateway.Contracts` or
|
|
generate client-local files into `clients/dotnet/generated` with `Grpc.Tools`.
|
|
|
|
Go clients should generate `mxaccess_gateway.proto` and
|
|
`mxaccess_worker.proto` into `clients/go/internal/generated` with
|
|
`protoc-gen-go` and `protoc-gen-go-grpc`. Keep generated packages internal
|
|
unless the wrapper API intentionally exposes raw protobuf messages.
|
|
|
|
The Go scaffold provides a repo-local generation script:
|
|
|
|
```powershell
|
|
clients/go/generate-proto.ps1
|
|
```
|
|
|
|
The script maps both proto files into the internal Go package
|
|
`gitea.dohertylan.com/dohertj2/mxaccessgw/clients/go/internal/generated` because
|
|
the source `.proto` files do not carry Go-specific `go_package` options. This
|
|
keeps language-specific packaging outside the public contract files.
|
|
|
|
Rust clients use `tonic-build` from `clients/rust/build.rs`. The build script
|
|
reads the shared `.proto` files and emits generated `tonic`/`prost` modules
|
|
into Cargo build output. `clients/rust/src/generated.rs` contains the module
|
|
declarations that include those generated files. `clients/rust/src/generated`
|
|
remains reserved for checked-in generator output if the crate later changes to
|
|
source-tree generation, and handwritten wrapper code stays outside that
|
|
directory.
|
|
|
|
Run the Rust workspace checks from `clients/rust`:
|
|
|
|
```powershell
|
|
cargo fmt --all --check
|
|
cargo test --workspace
|
|
cargo check --workspace
|
|
```
|
|
|
|
Python clients should use `grpc_tools.protoc` and write generated modules under
|
|
`clients/python/src/zb_mom_ww_mxgateway/generated` so imports stay separate from
|
|
handwritten async wrappers.
|
|
|
|
The Python scaffold provides a repo-local generation script:
|
|
|
|
```powershell
|
|
clients/python/generate-proto.ps1
|
|
```
|
|
|
|
Java clients use the Gradle protobuf plugin from `clients/java`. The
|
|
`mxgateway-client` project reads the shared `.proto` files and writes generated
|
|
Java protobuf and gRPC sources under `clients/java/src/main/generated`, matching
|
|
the manifest output path. Handwritten client and CLI code stays in the
|
|
`mxgateway-client` and `mxgateway-cli` project source trees.
|
|
|
|
Run the Java workspace checks from `clients/java`:
|
|
|
|
```powershell
|
|
gradle test
|
|
```
|
|
|
|
## Golden Fixtures
|
|
|
|
Golden protobuf JSON fixtures live in `clients/proto/fixtures/golden`. They
|
|
exercise payloads that every language client must parse:
|
|
|
|
- `open-session-reply.ok.json`
|
|
- `register-command-request.json`
|
|
- `on-data-change-event.json`
|
|
|
|
The fixtures use protobuf JSON field names and enum values. Contract tests parse
|
|
them with the generated C# types so schema drift is caught before client
|
|
generation work starts.
|
|
|
|
## Behavior Fixtures
|
|
|
|
Cross-language behavior fixtures live in
|
|
`clients/proto/fixtures/behavior`. The manifest
|
|
`clients/proto/fixtures/behavior/manifest.json` lists command replies, ordered
|
|
event stream samples, value conversion cases, status conversion cases, auth
|
|
error expectations, and timeout/cancel expectations.
|
|
|
|
The behavior fixtures let each generated client wrapper test the same
|
|
expectations without a live gateway. Protobuf message fixtures parse with the
|
|
generated types. Auth and timeout/cancel files describe wrapper behavior above
|
|
the generated transport layer, including credential redaction and the rule that
|
|
client cancellation does not abort an in-flight MXAccess COM call.
|
|
|
|
Run the focused validation script after changing these fixtures:
|
|
|
|
```powershell
|
|
scripts/validate-client-behavior-fixtures.ps1
|
|
```
|
|
|
|
## Related Documentation
|
|
|
|
- [Protobuf Contracts](./Contracts.md)
|
|
- [Client Libraries Detailed Design](./ClientLibrariesDesign.md)
|
|
- [Client Packaging](./ClientPackaging.md)
|
|
- [Client Behavior Fixtures](./ClientBehaviorFixtures.md)
|
|
- [Client Libraries Implementation Plan](./ImplementationPlanClients.md)
|
|
- [Protobuf Style Guide](./style-guides/ProtobufStyleGuide.md)
|