This document describes the mapping between the C++ publisher implementation and the Python port.
The Python publisher implementation is a feature-complete port of the C++ STTP publisher, maintaining wire protocol compatibility while following Python idioms and conventions.
| C++ Class | C++ Location | Python Module | Notes |
|---|---|---|---|
DataPublisher |
cppapi/src/lib/transport/DataPublisher.{h,cpp} |
pyapi/src/sttp/transport/datapublisher.py |
Main publisher class managing connections and metadata |
SubscriberConnection |
cppapi/src/lib/transport/SubscriberConnection.{h,cpp} |
pyapi/src/sttp/transport/subscriberconnection.py |
Individual client connection handler |
PublisherInstance |
cppapi/src/lib/transport/PublisherInstance.{h,cpp} |
pyapi/src/sttp/publisher.py |
User-facing wrapper, similar to Subscriber pattern |
RoutingTables |
cppapi/src/lib/transport/RoutingTables.{h,cpp} |
pyapi/src/sttp/transport/routingtables.py |
Routes measurements to subscribed connections |
| C++ Class | C++ Location | Python Module | Notes |
|---|---|---|---|
SignalIndexCache |
cppapi/src/lib/transport/SignalIndexCache.{h,cpp} |
pyapi/src/sttp/transport/signalindexcache.py |
Already exists (shared) |
CompactMeasurement |
cppapi/src/lib/transport/CompactMeasurement.{h,cpp} |
pyapi/src/sttp/transport/compactmeasurement.py |
Already exists (shared) |
Measurement |
cppapi/src/lib/transport/TransportTypes.h |
pyapi/src/sttp/transport/measurement.py |
Already exists (shared) |
Constants |
cppapi/src/lib/transport/Constants.{h,cpp} |
pyapi/src/sttp/transport/constants.py |
Already exists (shared) |
TSSC Encoder |
cppapi/src/lib/transport/tssc/TSSCEncoder.{h,cpp} |
pyapi/src/sttp/transport/tssc/encoder.py |
New - counterpart to decoder |
| C++ Class | C++ Location | Python Module | Notes |
|---|---|---|---|
DataSet |
cppapi/src/lib/data/DataSet.{h,cpp} |
pyapi/src/sttp/data/dataset.py |
Already exists (shared) |
DataTable |
cppapi/src/lib/data/DataTable.{h,cpp} |
pyapi/src/sttp/data/datatable.py |
Already exists (shared) |
FilterExpression |
cppapi/src/lib/filterexpressions/ |
pyapi/src/sttp/data/filterexpressionparser.py |
Already exists (shared) |
- Initialization:
DataPublisher.__init__()sets up state - Start:
DataPublisher.start(port)creates TCP listener socket - Accept Loop: Background thread accepts connections via
_accept_connection() - Handshake: Each connection creates a
SubscriberConnectioninstance - Protocol Negotiation: Via command channel messages (already defined in constants)
- Subscription: Client sends subscribe request, publisher builds routing table
- Publication:
publish_measurements()routes data viaRoutingTables - Shutdown:
stop()closes all connections gracefully
-
Threading Model:
- C++: Uses Boost.Asio async I/O with thread pools
- Python: Uses
asynciofor I/O,ThreadPoolExecutorfor callbacks (similar to existing subscriber)
-
Memory Management:
- C++: Shared pointers (
SharedPtr<T>) - Python: Native garbage collection, weak references where needed
- C++: Shared pointers (
-
Networking:
- C++: Boost.Asio sockets
- Python: Standard
socketlibrary (consistent with subscriber)
-
Timers:
- C++: Boost.Asio timers
- Python:
threading.Timer(consistent with subscriber)
The Python implementation maintains full wire protocol parity with C++:
- Same command/response byte sequences (defined in
constants.py) - Same compact measurement encoding
- Same TSSC compression algorithm
- Same metadata XML schema
- Same operational modes and encoding flags
- Same cipher key rotation for security
DataPublisherclass with connection managementSubscriberConnectionclass for individual clients- Command channel protocol handlers
RoutingTablesfor measurement routing- TSSC encoder implementation
- Compact measurement serialization (publisher side)
Publisherwrapper class (mirrorsSubscriber)- Metadata definition helpers
- Example applications
- Python publisher → Python subscriber
- Python publisher → C++ subscriber
- Wire protocol validation
All deviations from C++ implementation follow the same patterns as the existing Python subscriber:
- Snake_case naming: All Python code uses snake_case (e.g.,
publish_measurementsvsPublishMeasurements) - Properties vs Getters/Setters: Python uses
@propertydecorators - Callbacks: Python uses simple callable assignment vs registration methods
- Exceptions: Python uses standard exception hierarchy vs custom C++ exceptions
- Async patterns: Python uses asyncio/threading consistently with subscriber
pyapi/src/sttp/
├── publisher.py # NEW: User-facing Publisher class
├── transport/
│ ├── datapublisher.py # NEW: Core publisher
│ ├── subscriberconnection.py # NEW: Connection handler
│ ├── routingtables.py # NEW: Measurement routing
│ ├── tssc/
│ │ └── encoder.py # NEW: TSSC encoder
│ ├── datasubscriber.py # EXISTING: Subscriber
│ ├── signalindexcache.py # EXISTING: Shared
│ ├── compactmeasurement.py # EXISTING: Shared
│ ├── measurement.py # EXISTING: Shared
│ └── constants.py # EXISTING: Shared
└── data/ # EXISTING: All shared
- Unit tests: Test individual components (routing, encoding)
- Integration tests: Python pub → Python sub loopback
- Interop tests: Python pub → C++ sub (manual verification)
- Wire validation: Capture and compare packets with C++ publisher
- Initial implementation focuses on TCP command channel (UDP data channel deferred)
- Temporal subscriptions supported but not deeply tested initially
- Reverse connections (publisher connecting to subscriber) implemented for parity but examples focus on normal mode
Last Updated: 2026-01-05 Ported By: GitHub Copilot C++ Reference Version: As of cppapi commit at time of port