| Crates.io | zel_core |
| lib.rs | zel_core |
| version | 0.5.0 |
| created_at | 2025-12-04 18:42:11.163989+00 |
| updated_at | 2025-12-12 13:35:32.055147+00 |
| description | Type-safe RPC framework built on Iroh with support for methods, subscriptions, notifications, and raw streams |
| homepage | |
| repository | https://github.com/SuddenlyHazel/zel |
| max_upload_size | |
| id | 1966865 |
| size | 526,710 |
A type-safe RPC framework built on Iroh! Out of the box support for methods, subscriptions (server to client stream), notifications (client to server stream), and raw bidirectional streams.
# Cargo.toml
[dependencies]
zel_core = "0.3.2"
# Note: No need to add zel_types or zel_macros - everything is re-exported!
// Import everything with the prelude
use zel_core::prelude::*;
// Define your service
#[zel_service(name = "math")]
trait Math {
#[method(name = "add")]
async fn add(&self, a: i32, b: i32) -> Result<i32, ResourceError>;
}
// Implement it
#[derive(Clone)]
struct MathService;
#[async_trait]
impl MathServer for MathService {
async fn add(&self, ctx: RequestContext, a: i32, b: i32)
-> Result<i32, ResourceError>
{
Ok(a + b)
}
}
Zel RPC provides four types of endpoints:
#[method]) - Request/response RPC calls#[subscription]) - Server-to-client streaming#[notification]) - Client-to-server streaming#[stream]) - Bidirectional custom protocols (BYOP)All endpoints receive a RequestContext providing access to:
sequenceDiagram
participant C as Client
participant S as Server<br/>(ALPN: myapp/1)
participant SVC as Service: users
participant RES as Resource: create
Note over C,S: Connection Setup
C->>S: connect(peer_id, "myapp/1")
S->>S: accept connection
Note over C,RES: Request Flow
C->>S: open_bi() stream
S->>S: accept_bi() → spawn handler
C->>S: Request { service: "users", resource: "create", body: {...} }
S->>SVC: Route to service "users"
SVC->>RES: Route to resource "create"
RES->>RES: Handle with RequestContext
RES->>S: Response
S->>C: Response
Note over C,S: Each request gets own stream
Zel uses a three-tier extension system to share context across different scopes:
📚 For complete documentation, see doc_more/EXTENSIONS.MD
💡 For working examples, see examples/context_extensions_demo.rs
Request/response RPC - handler receives RequestContext as first parameter
Server-to-client streaming - handler receives RequestContext and typed sink
Client-to-server streaming - handler receives RequestContext, receive stream, and ack sender
Custom bidirectional protocols - handler receives RequestContext, SendStream, RecvStream
See examples/macro_service_example.rs and examples/notification_example.rs for complete service definitions
Zel provides a few resilience tools out of the box:
RpcServerBuilder::with_circuit_breaker(CircuitBreakerConfig::builder().failure_threshold(0.5).build())).RpcClient::builder().with_retry_config(RetryConfig::builder().max_attempts(3).build())).RequestContext::remote_id(), connection_rtt(), connection_stats().Example:
let server = RpcServerBuilder::new(b"app/1", endpoint)
.with_circuit_breaker(CircuitBreakerConfig::builder()
.failure_threshold(0.5)
.consecutive_failures(5)
.build())
.build();
See doc_more/P2P-RESILIENCE.md for complete details.
Beyond transport, leverage:
IrohBundle::watch_addr(): Subscribe to EndpointAddr changes (NAT rebinding via netwatch).IrohBundle::notify_network_change(): Trigger addr refresh.IrohBundle::wait_online() / is_online(): Ensure node ready before RPCs.P2P Quickstart Extension:
let bundle = IrohBundle::builder(None).await?.finish().await;
bundle.wait_online().await; // Wait for holepunching/relays
See zel_core/examples/README.md for full list/table.
Quick Start: macro_service_example.rs