Skip to content

Phase D3b: C++ and Python wrappers for the streamrNode* full-node API#96

Merged
ptesavol merged 1 commit into
claude/d3a-streamr-api-renamefrom
claude/d3b-wrapper-node-api
Jul 18, 2026
Merged

Phase D3b: C++ and Python wrappers for the streamrNode* full-node API#96
ptesavol merged 1 commit into
claude/d3a-streamr-api-renamefrom
claude/d3b-wrapper-node-api

Conversation

@ptesavol

Copy link
Copy Markdown
Collaborator

Stacked on #95 (D3a rename; retarget to main after it merges). Implements the wrapper half of phase D3 for the two wrappers that build and test natively on the CI/dev hosts.

Changes

  • C++ wrapper (wrappers/cpp/include/StreamrNode.hpp): RAII StreamrNode — create/start/stop, joinStreamPart/leaveStreamPart, publish, subscribe with a std::function callback, neighborCount, setProxies; errors thrown as StreamrNodeError with a std::variant code, mirroring the existing proxy-wrapper idioms. Subscription callbacks stay owned by the node until destruction (the C API may still dispatch a message whose delivery already started when unsubscribe returns).
  • Python wrapper: StreamrNode context manager over new streamrNode* ctypes bindings, same shape as the existing ProxyClient; message callbacks bound with an explicit content length (payloads are opaque bytes, not NUL-terminated strings); ctypes callback objects kept alive until node deletion.
  • Tests (the plan's StreamrNodeTest-style round-trips):
    • StreamrNodeCppWrapperTest.TwoNodesExchangeMessages — two wrapper-created nodes, entry-point + joining client, signed and unsigned message exchange, SUBSCRIPTION_NOT_FOUND error mapping. Wired into ctest with the 600 s networked budget. Local: 2/2 in ~850 ms.
    • wrappers/python/tests/test_streamr_node.py — the same round-trip via ctypes; scripts/run-python-tests.sh stages the built library and runs pytest (or the direct fallback). Local: green against the 3.0.0 dylib.
  • One D3a straggler fixed (std::vector<Proxy>StreamrPeer in the proxy wrapper).

Scope decisions for review

  • Swift/Kotlin (dist/ios-swift-package, dist/android-library-module): next increment, together with the D2 mobile verification they depend on (iostest.sh/androidtest.sh).
  • Go wrapper (wrappers/go): an uninitialized submodule pointing at a separate repository — proposing to drop it from D3 scope (no CI coverage, separate release lifecycle); say the word and I'll extend it instead.

🤖 Generated with Claude Code

- wrappers/cpp: new StreamrNode.hpp — RAII node wrapper (create/start/
  stop, joinStreamPart/leaveStreamPart, publish, subscribe with a
  std::function callback, neighborCount, setProxies), errors thrown as
  StreamrNodeError with a variant code, mirroring the existing
  StreamrProxyClient wrapper idioms. Subscription callbacks stay owned
  by the node until its destruction: the C API may still dispatch a
  message whose delivery already started when unsubscribe returns.
- wrappers/python: StreamrNode context manager over the streamrNode*
  ctypes bindings (same shape as ProxyClient); the message callback is
  bound with an explicit content length (payloads are opaque bytes).
  ctypes callback objects are kept alive until node deletion.
- Tests: StreamrNodeCppWrapperTest (two wrapper-created nodes form a
  stream-part topology and exchange a signed and an unsigned message;
  error mapping) wired into ctest with the streamrnode integration
  tests' 600 s budget, and the same round-trip in
  wrappers/python/tests/test_streamr_node.py with
  scripts/run-python-tests.sh staging the built library (pytest or
  direct run).
- StreamrProxyClient.hpp: one leftover deprecated-alias use
  (std::vector<Proxy>) moved to the final StreamrPeer name.

Local runs: cpp wrapper round-trip 2/2 in ~850 ms; python round-trip
green against the freshly built 3.0.0 dylib.

Swift (dist/ios-swift-package) and Kotlin (dist/android-library-module)
follow in the next increment together with the D2 mobile-platform
verification they depend on; the Go wrapper (wrappers/go, an
uninitialized submodule pointing at a separate repo) is proposed for
dropping from the D3 scope — decision left to review.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ptesavol
ptesavol merged commit dd1c448 into claude/d3a-streamr-api-rename Jul 18, 2026
1 check passed
ptesavol added a commit that referenced this pull request Jul 18, 2026
…#96)

- wrappers/cpp: new StreamrNode.hpp — RAII node wrapper (create/start/
  stop, joinStreamPart/leaveStreamPart, publish, subscribe with a
  std::function callback, neighborCount, setProxies), errors thrown as
  StreamrNodeError with a variant code, mirroring the existing
  StreamrProxyClient wrapper idioms. Subscription callbacks stay owned
  by the node until its destruction: the C API may still dispatch a
  message whose delivery already started when unsubscribe returns.
- wrappers/python: StreamrNode context manager over the streamrNode*
  ctypes bindings (same shape as ProxyClient); the message callback is
  bound with an explicit content length (payloads are opaque bytes).
  ctypes callback objects are kept alive until node deletion.
- Tests: StreamrNodeCppWrapperTest (two wrapper-created nodes form a
  stream-part topology and exchange a signed and an unsigned message;
  error mapping) wired into ctest with the streamrnode integration
  tests' 600 s budget, and the same round-trip in
  wrappers/python/tests/test_streamr_node.py with
  scripts/run-python-tests.sh staging the built library (pytest or
  direct run).
- StreamrProxyClient.hpp: one leftover deprecated-alias use
  (std::vector<Proxy>) moved to the final StreamrPeer name.

Local runs: cpp wrapper round-trip 2/2 in ~850 ms; python round-trip
green against the freshly built 3.0.0 dylib.

Swift (dist/ios-swift-package) and Kotlin (dist/android-library-module)
follow in the next increment together with the D2 mobile-platform
verification they depend on; the Go wrapper (wrappers/go, an
uninitialized submodule pointing at a separate repo) is proposed for
dropping from the D3 scope — decision left to review.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
ptesavol added a commit that referenced this pull request Jul 18, 2026
)

* Phase D3a: rename the shared C API infrastructure to streamr* names

The proxy-prefixed shared infrastructure both APIs use moves to neutral
names in a new streamrcommon.h, per phase D3 of the completion plan (the
naming decision deferred from the D1 review):

- struct Proxy        -> struct StreamrPeer (StreamrEntryPoint stays as
                         an alias of it in streamrnode.h)
- struct Error        -> struct StreamrError; its 'proxy' member is now
                         'peer', with the old spelling kept usable
                         through an anonymous union (same storage)
- struct ProxyResult  -> struct StreamrResult
- proxyClientResultDelete   -> streamrResultDelete
- proxyClientInitLibrary    -> streamrInitLibrary
- proxyClientCleanupLibrary -> streamrCleanupLibrary

The old type names remain as typedef aliases and the old C symbols stay
exported (delegating to the new ones), marked deprecated for one
release, so existing proxy-API consumers keep compiling and linking. The
shared-library major version bumps to 3.0.0 (SOVERSION 3). The proxy
client calls (proxyClientNew/Delete/Connect/Publish) keep their names —
the API is about proxies; only the shared types in their signatures
changed spelling.

In-repo consumers (C++ wrapper header, Python wrapper bindings, the
integration/end-to-end/ts-interop tests) now use the final names, so the
D3b wrapper extensions are written against them once. A dedicated test
exercises the deprecated aliases and the pre-3.0 member spelling.

All 11 proxy-client integration tests and 9 streamrnode integration
tests pass in the per-test-process mode CI uses. (Running several tests
in ONE process crashes in the second test — a pre-existing library
re-init-after-cleanup bug, unaffected by the rename; follow-up filed.)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Phase D3b: C++ and Python wrappers for the streamrNode* full-node API (#96)

- wrappers/cpp: new StreamrNode.hpp — RAII node wrapper (create/start/
  stop, joinStreamPart/leaveStreamPart, publish, subscribe with a
  std::function callback, neighborCount, setProxies), errors thrown as
  StreamrNodeError with a variant code, mirroring the existing
  StreamrProxyClient wrapper idioms. Subscription callbacks stay owned
  by the node until its destruction: the C API may still dispatch a
  message whose delivery already started when unsubscribe returns.
- wrappers/python: StreamrNode context manager over the streamrNode*
  ctypes bindings (same shape as ProxyClient); the message callback is
  bound with an explicit content length (payloads are opaque bytes).
  ctypes callback objects are kept alive until node deletion.
- Tests: StreamrNodeCppWrapperTest (two wrapper-created nodes form a
  stream-part topology and exchange a signed and an unsigned message;
  error mapping) wired into ctest with the streamrnode integration
  tests' 600 s budget, and the same round-trip in
  wrappers/python/tests/test_streamr_node.py with
  scripts/run-python-tests.sh staging the built library (pytest or
  direct run).
- StreamrProxyClient.hpp: one leftover deprecated-alias use
  (std::vector<Proxy>) moved to the final StreamrPeer name.

Local runs: cpp wrapper round-trip 2/2 in ~850 ms; python round-trip
green against the freshly built 3.0.0 dylib.

Swift (dist/ios-swift-package) and Kotlin (dist/android-library-module)
follow in the next increment together with the D2 mobile-platform
verification they depend on; the Go wrapper (wrappers/go, an
uninitialized submodule pointing at a separate repo) is proposed for
dropping from the D3 scope — decision left to review.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* Port the use-after-cleanup regression test to the streamr* names

Rebase fallout: #97 wrote ApiIsUsableAfterCleanupLibrary against the
pre-3.0 proxyClient* names, which this branch deprecates — the lint
step (deprecation warnings as errors) failed on every CI leg. The test
verifies the re-init contract, not the aliases, so it now uses the
final names; the dedicated deprecated-alias test keeps covering the old
ones.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* CI: bump the build-tree cache generation to v2

The buildtree cache restores the newest previous tree on any key miss
and rebuilds incrementally. The repeated force-pushes on this branch fed
the legs an inconsistent restored state: ninja under-rebuilt, linking
the freshly named libstreamrproxyclient from a stale pre-rename object
(undefined streamrResultDelete/streamrInitLibrary in the wrapper test)
and failing dyndep generation in streamr-proto-rpc. Bumping the
generation forces one clean full build per leg and starts a fresh cache
lineage — the same documented remedy the v1 suffix itself came from.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Point the go wrapper submodule at the streamrNode* API branch

goproxyclient PR 1 (branch streamr-node-api, commit c500e43) adds the
full-node API to the Go wrapper — the last wrapper of phase D3b's
native-host set. The pointer references the pushed PR branch; advance it
to the merge commit when that PR lands.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant