Add high-performance PubSub transcoders (subscriber-to-publisher)#3956
Add high-performance PubSub transcoders (subscriber-to-publisher)#3956marcschier wants to merge 4 commits into
Conversation
Add Opc.Ua.PubSub.Transcoding: transcode subscriber-received NetworkMessages to a publisher side with UADP<->JSON cross-encoding, an ordered transform pipeline (id remap, field encoding, projection, rename, value, message-type, metadata), transcoder-managed re-securing (AllowInsecureCrossEncoding policy), a raw-frame zero-copy passthrough fast path, an opt-in receive hook on PubSubConnection, and a fluent AddTranscodingBridge DI surface. Adds unit + integration tests, benchmarks, and Docs/PubSubTranscoding.md.
There was a problem hiding this comment.
Pull request overview
Note
Copilot couldn't run its full agentic review because no GitHub Actions runner was available. Make sure your repository has a runner available to run Copilot's review, or add a copilot-setup-steps.yml file specifying one with the runs-on attribute. See the docs for more details.
Adds a new Opc.Ua.PubSub.Transcoding feature set enabling high-performance subscriber-to-publisher PubSub message transcoding (UADP↔JSON), including transform pipelines, optional receive hooks, and egress support, with accompanying tests and documentation.
Changes:
- Introduces new transcoding public APIs (spec/context/input/result, projector/transcoder engine, built-in transforms, bridge + DI hosted service).
- Extends
PubSubConnection/IPubSubConnectionwith an opt-in receive-path sink registration and a target-connection egress send helper (incl. chunking reuse). - Adds unit/integration tests, micro-benchmarks, and documentation for the transcoding feature.
Reviewed changes
Copilot reviewed 43 out of 43 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| Tests/Opc.Ua.PubSub.Tests/Transcoding/TranscodingTestUtilities.cs | Adds shared helpers for transcoding unit/integration tests (context, encoders, sample messages, decode helpers). |
| Tests/Opc.Ua.PubSub.Tests/Transcoding/TranscodeTransformTests.cs | Adds unit tests for built-in message transforms. |
| Tests/Opc.Ua.PubSub.Tests/Transcoding/TranscodeSecurityAndBuilderTests.cs | Adds unit tests for TranscodeSecurity and fluent builder behavior. |
| Tests/Opc.Ua.PubSub.Tests/Transcoding/PubSubTranscodingBridgeIntegrationTests.cs | Adds end-to-end integration tests for receive-hook → transcode → egress pipeline. |
| Tests/Opc.Ua.PubSub.Tests/Transcoding/PubSubTranscoderTests.cs | Adds unit tests for frame-level transcoder behavior (fast path, cross-encoding, security policy, missing encoder). |
| Tests/Opc.Ua.PubSub.Tests/Transcoding/NetworkMessageProfileProjectorTests.cs | Adds unit tests for projector across encoding combinations and target options. |
| Tests/Opc.Ua.PubSub.Tests/Connections/PubSubConnectionPrivateMethodTests.cs | Updates reflection-based test after SendChunkedAsync signature refactor. |
| Tests/Opc.Ua.PubSub.Tests/Benchmarks/TranscodingBenchmarks.cs | Adds micro-benchmarks for transcoding paths (UADP↔JSON, identity fast path, projection). |
| Libraries/Opc.Ua.PubSub/Transcoding/ValueTransform.cs | Adds per-field value transform implementation. |
| Libraries/Opc.Ua.PubSub/Transcoding/TranscodeTargetOptions.cs | Adds target format options (field encoding override, JSON single-message mode, metadata version preservation). |
| Libraries/Opc.Ua.PubSub/Transcoding/TranscodeSpec.cs | Adds declarative transcode specification and identity detection. |
| Libraries/Opc.Ua.PubSub/Transcoding/TranscodeSecurity.cs | Adds security policy and UADP re-wrapping support with downgrade refusal logic. |
| Libraries/Opc.Ua.PubSub/Transcoding/TranscodeResult.cs | Adds structured output for frames/messages + fast-path indicator. |
| Libraries/Opc.Ua.PubSub/Transcoding/TranscodeInput.cs | Adds input record including decoded message + optional wire frame for fast path. |
| Libraries/Opc.Ua.PubSub/Transcoding/TranscodeEncoding.cs | Adds encoding family enum + helper conversions/classification. |
| Libraries/Opc.Ua.PubSub/Transcoding/TranscodeContext.cs | Adds shared per-run context (encoding context + telemetry + metadata registry access). |
| Libraries/Opc.Ua.PubSub/Transcoding/ReceivedNetworkMessage.cs | Adds received-message envelope for receive-path sinks. |
| Libraries/Opc.Ua.PubSub/Transcoding/PubSubTranscodingBridgeHostedService.cs | Adds DI/hosting integration to resolve connections and start a bridge. |
| Libraries/Opc.Ua.PubSub/Transcoding/PubSubTranscodingBridge.cs | Adds in-process bridge implementing receive-path sink and forwarding to egress. |
| Libraries/Opc.Ua.PubSub/Transcoding/PubSubTranscoderBuilder.cs | Adds fluent builder for bridge/spec configuration + internal descriptor. |
| Libraries/Opc.Ua.PubSub/Transcoding/PubSubTranscoder.cs | Adds frame-level transcoder (fast path, structured transcode, encode + UADP re-securing). |
| Libraries/Opc.Ua.PubSub/Transcoding/NetworkMessageTranscoder.cs | Adds structured transcoder applying transforms + projector. |
| Libraries/Opc.Ua.PubSub/Transcoding/NetworkMessageProfileProjector.cs | Adds UADP↔JSON projector and same-encoding option application. |
| Libraries/Opc.Ua.PubSub/Transcoding/MetaDataTransform.cs | Adds transform for metadata-announcement message rewriting. |
| Libraries/Opc.Ua.PubSub/Transcoding/MessageTypeTransform.cs | Adds message-type filter/relabel transform. |
| Libraries/Opc.Ua.PubSub/Transcoding/IdRemapTransform.cs | Adds identifier remap transform (publisher/group/class/writer ids). |
| Libraries/Opc.Ua.PubSub/Transcoding/ITranscoder.cs | Adds frame-level transcoder interface. |
| Libraries/Opc.Ua.PubSub/Transcoding/IReceivedNetworkMessageSink.cs | Adds receive-path sink interface. |
| Libraries/Opc.Ua.PubSub/Transcoding/IPubSubTranscodeEgress.cs | Adds egress abstraction for sending transcoded frames. |
| Libraries/Opc.Ua.PubSub/Transcoding/IPubSubMessageTransform.cs | Adds transform interface for message-level pipeline steps. |
| Libraries/Opc.Ua.PubSub/Transcoding/INetworkMessageTranscoder.cs | Adds interface for structured transcoding primitive. |
| Libraries/Opc.Ua.PubSub/Transcoding/INetworkMessageProfileProjector.cs | Adds interface for profile projection (UADP/JSON concrete rematerialization). |
| Libraries/Opc.Ua.PubSub/Transcoding/FieldRenameTransform.cs | Adds field rename transform. |
| Libraries/Opc.Ua.PubSub/Transcoding/FieldProjectionTransform.cs | Adds include/exclude field projection transform. |
| Libraries/Opc.Ua.PubSub/Transcoding/FieldEncodingTransform.cs | Adds field-encoding conversion transform. |
| Libraries/Opc.Ua.PubSub/Transcoding/DelegateMessageTransform.cs | Adds delegate-backed transform escape hatch. |
| Libraries/Opc.Ua.PubSub/Transcoding/ConnectionTranscodeEgress.cs | Adds default-connection egress that sends frames (and relies on connection chunking helper). |
| Libraries/Opc.Ua.PubSub/DependencyInjection/PubSubTranscodingBuilderExtensions.cs | Adds IPubSubBuilder.AddTranscodingBridge(...) extension to register hosted service. |
| Libraries/Opc.Ua.PubSub/Connections/PubSubConnection.cs | Adds receive-sink registration + notification; refactors chunking helper signature; adds SendTranscodedFrameAsync. |
| Libraries/Opc.Ua.PubSub/Connections/IPubSubConnection.cs | Adds RegisterReceivedNetworkMessageSink(...) API. |
| Docs/README.md | Links new transcoding documentation. |
| Docs/PubSubTranscoding.md | Adds detailed feature guide for transcoding architecture/configuration/security/bridge/DI. |
| Docs/PubSub.md | Adds transcoding section and links to the new guide. |
Comments suppressed due to low confidence (1)
Libraries/Opc.Ua.PubSub/Transcoding/TranscodeSpec.cs:1
TranscodeSpec.IsIdentityignoresTargetOptions.PreserveMetaDataVersion. IfPreserveMetaDataVersionis set tofalseon a same-encoding route, the frame-level transcoder may incorrectly take the raw-frame fast path and skip the requested format change. IncludeTargetOptions.PreserveMetaDataVersionin the identity check (and consider comparing all current options) so the fast path is only eligible when no target option changes output.
- Projector: clear JsonNetworkMessageContentMask.SingleDataSetMessage when single-message mode is disabled; preserve source UADP DataSetMessage ContentMask on UADP->UADP rebuilds instead of forcing the default mask. - Receive hook: forward the original raw frame.Payload (not the mutated, unwrapped framePayload) to IReceivedNetworkMessageSink; disable the fast-path frame for chunk-reassembled messages. - FieldProjectionTransform: precompute the exclude HashSet in the ctor. - Docs: merge PubSubTranscoding.md into Docs/PubSub.md (## Transcoding) and update the Docs/README.md link.
|
|
||
| The DI bridge is started as a hosted service after the PubSub application is available. `PubSubTranscodingBridgeHostedService` resolves source and target connections by `Name` from `IPubSubApplication.Connections`, builds the shared `TranscodeContext`, resolves registered `INetworkMessageEncoder` instances, resolves target security through `IPubSubSecurityWrapperResolver`, and starts the bridge. | ||
|
|
||
| ### Fluent `AddTranscodingBridge` walkthrough |
There was a problem hiding this comment.
Just like in the adapter package it shall be possible to set all of it up via (reloadable) configuration. When configuration changes only the areas that were reconfigured shall change.
| .To("mqtt-out", TranscodeEncoding.Json) | ||
| .RemapIds(publisherId: PublisherId.FromUInt16(42)) | ||
| .RenameField("Temp", "Temperature") | ||
| .SelectFields("Temperature", "Pressure") |
There was a problem hiding this comment.
It shall be possible to promote fields into mqtt headers.
Description
Adds high-performance PubSub transcoders to the
Opc.Ua.PubSublibrary (newOpc.Ua.PubSub.Transcodingnamespace) that take subscriber-received NetworkMessages and transcode them for re-publishing on a publisher connection, supporting all transformations.The transcoder operates on the decoded
PubSubNetworkMessageintermediate representation — the seam between the pluggableINetworkMessageDecoder/INetworkMessageEncoder— so cross-encoding and structural transforms happen without a full dataset re-sampling round-trip. Pipeline per message:decode(+unwrap) → transforms → project-to-target-profile → encode(+wrap), with a raw-frame zero-copy passthrough fast path for identity same-encoding routes.What's included
PubSubTranscoder(frame-levelITranscoder) +NetworkMessageTranscoder(structured primitive),TranscodeSpec/TranscodeInput/TranscodeResult/TranscodeContext.NetworkMessageProfileProjectormaps UADP↔JSON (all four source/target combinations), translating content masks, DataSetMessage subtypes, identifiers, timestamps, and metadata.TranscodeSecurityre-secures via the existing UADPUadpSecurityWrapper; anAllowInsecureCrossEncodingpolicy (default off) refuses silent security downgrades, since message-layer security in Part 14 is UADP-only (secured→JSON relies on transport-layer security).IReceivedNetworkMessageSinkreceive hook onPubSubConnection,PubSubTranscodingBridge, andConnectionTranscodeEgress(chunk/MaxNetworkMessageSize-aware send).IPubSubBuilder.AddTranscodingBridge(...)+PubSubTranscoderBuilder; the bridge is started as a hosted service after the PubSub application and resolves source/target connections by name.Design notes
PubSubConnection.SendChunkedAsync) was refactored to be identifier-based so the egress can reuse chunking; its reflection-based unit test was updated accordingly.UadpEncoder.EncodeWithSecurityBoundaryandUadpDecoder.TryReadOuterPrefixrather than duplicating the fragile UADP security-splitting logic.ArrayOf<T>,Variant, spans/ByteString, sealed-by-default, async-only, AOT-clean, license headers,.editorconfig).Testing & docs
PubSubConnectionreceive path through the bridge and egress.TranscodingBenchmarks(UADP↔JSON, identity fast path, projection).Docs/PubSubTranscoding.mdwith links fromDocs/README.mdand a Transcoding section inDocs/PubSub.md.Verified locally: the
Opc.Ua.PubSublibrary builds 0 warnings/errors on all target frameworks (net472/net48/netstandard2.1/net8.0/net9.0/net10.0); the transcoding tests pass on net10.0 and net48; the fullOpc.Ua.PubSub.Testssuite passes (1167 passed, 1 skipped, 0 failed) with no regressions.Related Issues
No tracking issue yet — new feature. Happy to open one to host the ADR discussion if preferred.
Checklist
Put an
xin the boxes that apply. You can complete these step by step after opening the PR.Opc.Ua.PubSub.Testssuite on net10.0 and the transcoding tests on net48; full-solution run pending.)