Skip to content

Comments

sdk: Add event streaming#672

Merged
cdecker merged 16 commits intomainfrom
2026w07-gl-sdk-complete
Feb 25, 2026
Merged

sdk: Add event streaming#672
cdecker merged 16 commits intomainfrom
2026w07-gl-sdk-complete

Conversation

@cdecker
Copy link
Collaborator

@cdecker cdecker commented Feb 23, 2026

Summary

This PR adds comprehensive SDK enhancements including real-time event streaming and node information query methods.

Changes

Event Streaming System

  • New StreamNodeEvents gRPC API: Real-time event streaming that supersedes the deprecated StreamIncoming API

    • Uses a NodeEvent wrapper with oneof for type discrimination
    • Supports multiple event types (starting with InvoicePaid)
    • Extensible design for future event types
  • Generic Event System (gl-plugin): Flexible Event<I> enum with EventBus

    • Generic over internal payload type for extension by downstream crates
    • Type erasure with Arc<dyn Any> at boundaries
    • ErasedEventExt trait for downcasting erased events
  • Python Bindings: stream_node_events() method in gl-client-py and gl-sdk

  • Deprecation Removal: Removed StreamIncoming API (replaced by StreamNodeEvents)

Node Information Methods

Added query methods to gl-sdk Node struct:

  • get_info: Basic node information (id, alias, network, etc.)
  • list_peers: Connected peer information
  • list_peer_channels: Channel information with peers
  • list_funds: On-chain and channel fund information

Documentation & Testing

  • Comprehensive rustdoc examples for the events module
  • Tests for node information methods in gl-sdk
  • Documented X.509 CN length warning in gl-testing (test infrastructure only)

Files Changed

  • libs/gl-plugin/src/events.rs - New event system implementation
  • libs/gl-plugin/src/node/ - StreamNodeEvents server implementation
  • libs/gl-sdk/src/node.rs - Node info methods and event streaming
  • libs/gl-client-py/ - Python bindings for event streaming
  • libs/proto/glclient/greenlight.proto - Proto definitions for events
  • libs/gl-sdk/bindings/ - Regenerated UniFFI Python bindings

Copy link
Collaborator

@ShahanaFarooqui ShahanaFarooqui left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cdecker I have re-based the PR and added the last commit to this PR. The commit updates gl-sdk to make the new methods and structs public so downstream crates can access them directly.

@ShahanaFarooqui ShahanaFarooqui force-pushed the 2026w07-gl-sdk-complete branch 4 times, most recently from 5f502d5 to 02d9bfd Compare February 24, 2026 00:59
@ShahanaFarooqui ShahanaFarooqui force-pushed the main branch 2 times, most recently from 7185343 to 2fafe20 Compare February 24, 2026 18:53
cdecker and others added 16 commits February 24, 2026 11:07
Replace call_raw with call_typed when creating a regular invoice in the
LSP invoice handler. This provides better type safety by using the
generated cln_rpc::model::requests::InvoiceRequest and
cln_rpc::model::responses::InvoiceResponse types.

Benefits:
- Compile-time type checking for request/response fields
- No manual hex decoding needed for payment_hash/payment_secret
- Access to created_index field from the response
- Cleaner code without custom request/response structs
Add node information query methods to the gl-sdk Node struct:
- get_info: Returns basic node information (id, alias, network, etc.)
- list_peers: Returns connected peer information
- list_peer_channels: Returns channel information with peers
- list_funds: Returns on-chain and channel fund information

Each method wraps the corresponding CLN gRPC call and converts the
response to UniFFI-compatible Record types for cross-language bindings.
Regenerate UniFFI Python bindings to include the new node information
methods and their response types (GetInfoResponse, ListPeersResponse,
ListPeerChannelsResponse, ListFundsResponse) as Python dataclasses.
Add pytest tests verifying the new node methods and response types:
- Test that all response types exist in bindings
- Test that Node class has the expected methods
- Test that response type fields are accessible and correctly typed
- Test Record types (Peer, PeerChannel, FundOutput, FundChannel)
- Test enum types (ChannelState, OutputStatus)

Also add pytest-cov dev dependency and configure warning filter to
suppress X.509 CN length warnings from gl-testing certificate generation.
Add documentation explaining the UserWarning about X.509 CN field length
exceeding 64 characters (RFC 5280 limit). The warning occurs because test
certificates include the full node_id (66 hex chars) in the CN field.

This is safe to ignore because:
- We control both client (gl-client) and server sides
- gl-client doesn't enforce strict X.509 CN length validation
- Only affects test infrastructure, not production certificates

Added:
- "Known Warnings" section in README.md with suppression instructions
- Explanatory comment in certs.py where the warning originates
Introduce a flexible event system that supports extension by downstream
crates like gl-plugin-internal:

- Event<I> is generic over internal payload type I
- In gl-plugin, I defaults to () (no internal events)
- EventBus uses Arc<dyn Any> for type erasure at the boundary
- Provides map_internal/try_map_internal for transformations
- ErasedEventExt trait for downcasting erased events
- Includes unit tests for the event system

This prepares for real-time event streaming to gl-sdk clients while
allowing gl-plugin-internal to inject its own event types.
Sync Python bindings with current Rust library to fix symbol mismatch.
Add NodeEvent protobuf messages and StreamNodeEvents RPC method:

- NodeEventsRequest: Empty request (extensible for future filters)
- NodeEvent: Wrapper with oneof for event discrimination
- InvoicePaid: Event emitted when an invoice is paid

The stream_node_events method converts internal Event<I> to NodeEvent
protobuf, filtering out internal-only events and exposing only
client-relevant events like invoice payments.
Add NodeEvent, NodeEventsRequest, InvoicePaid messages and
StreamNodeEvents RPC method.
Add Python bindings for the StreamNodeEvents gRPC method, enabling
clients to receive real-time notifications when events occur on their
node (e.g., invoice payments).

- Add stream_node_events() method to Node class in Python
- Add NodeEventStream wrapper for the streaming response
- Sync greenlight.proto with NodeEventsRequest, NodeEvent, InvoicePaid
- Regenerate Python protobuf files
Document the event system with examples covering:
- Type alias pattern for Event<I> (recommended approach)
- Publishing internal events with custom payload types
- Subscribing to internal events with downcast_internal
- Publishing public events (IncomingPayment, etc.)
- Subscribing to public events server-side
- Client-side consumption via gl-sdk (Python and Rust)
StreamIncoming was a specialized streaming RPC that only delivered
IncomingPayment events. StreamNodeEvents supersedes it with a unified
event streaming API that:
- Uses a NodeEvent wrapper with oneof for type discrimination
- Supports multiple event types (InvoicePaid, and future events)
- Is already exposed via gl-sdk (UniFFI bindings)

This removes:
- rpc StreamIncoming and StreamIncomingFilter from proto
- stream_incoming() from gl-client-py Python and Rust bindings
- Server implementation in gl-plugin
Move tonic to workspace dependencies for version consistency across
crates. Update gl-client to use workspace = true.
Add NodeEventStream iterator interface for streaming node events via
UniFFI bindings:

- NodeEventStream: Object wrapping gRPC streaming with blocking next()
- NodeEvent: Enum with InvoicePaid and Unknown variants
- InvoicePaidEvent: Record with payment details

The next() method blocks the calling thread but not the tokio runtime,
allowing concurrent node operations from other threads.

Includes Python binding regeneration and type tests.
Output uniffi-bindgen Python bindings directly to glsdk/ instead of
bindings/, eliminating the duplicate file and manual copy step.
Make the new query methods and related struct fields public so downstream crates like `gl-sdk-napi` can access them directly from Rust, rather than only through UniFFI bindings.
@cdecker cdecker merged commit d3f7047 into main Feb 25, 2026
16 checks passed
@cdecker cdecker deleted the 2026w07-gl-sdk-complete branch February 25, 2026 13:30
@ShahanaFarooqui ShahanaFarooqui linked an issue Feb 25, 2026 that may be closed by this pull request
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.

Issues from gl-sdk testing on Python

2 participants