Skip to content

Commit 4ca0614

Browse files
committed
refactor!: simplify request/response system and split ambiguous types
BREAKING CHANGE: Request/Response API completely redesigned - Replace macro-based system with simple Request/Response enums - Inline all request parameters directly in enum variants - Split HeaderResp into HeaderResp/HeaderWithProofResp - Split HeadersResp into HeadersResp/HeadersWithCheckpointResp - Add clean ClientError enum for all client methods - Fix blocking client tests to use proper synchronization
1 parent d384cf2 commit 4ca0614

11 files changed

Lines changed: 1457 additions & 2009 deletions

File tree

CLAUDE.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
This is a streaming, sans-IO Electrum client library for Rust that provides low-level primitives and high-level clients for communicating with Electrum servers over JSON-RPC. The library supports both async (`futures`/`tokio`) and blocking transport models.
8+
9+
## Common Development Commands
10+
11+
### Build and Check
12+
- `cargo build` - Build the project
13+
- `cargo check` - Check if the project compiles without building
14+
- `cargo clippy` - Run the Rust linter for code quality
15+
- `cargo clippy --fix` - Auto-fix clippy warnings
16+
17+
### Testing
18+
- `cargo test` - Run all tests
19+
- `cargo test [TESTNAME]` - Run tests containing specific string in their names
20+
- `cargo test --no-fail-fast` - Run all tests regardless of failures
21+
22+
### Documentation
23+
- `cargo doc --open` - Build and open the documentation
24+
25+
## Architecture
26+
27+
### Core Components
28+
29+
1. **State Management (`src/state.rs`)**
30+
- Central `State<T>` struct that tracks pending requests and processes server messages
31+
- Maps request IDs to pending requests
32+
- Processes incoming notifications and responses into `Event`s
33+
34+
2. **Client Implementations (`src/client.rs`)**
35+
- `AsyncClient`: Async client for `futures`/`tokio` based transports
36+
- `BlockingClient`: Blocking client for synchronous operations
37+
- Both use channels to communicate between request sending and response handling
38+
39+
3. **Request/Response System**
40+
- `src/request.rs`: Strongly typed Electrum method wrappers
41+
- `src/response.rs`: Response type definitions
42+
- `src/batch_request.rs`: Support for batched requests
43+
- `src/pending_request.rs`: Tracks in-flight requests
44+
45+
4. **I/O Layer (`src/io.rs`)**
46+
- Transport-agnostic read/write utilities
47+
- `ReadStreamer`: Parses incoming JSON-RPC messages from a stream
48+
- Handles both single and batched messages
49+
50+
5. **Type System**
51+
- `MaybeBatch<T>`: Handles both single items and batches
52+
- `Event`: High-level events (responses, errors, notifications)
53+
- Custom serde implementations in `src/custom_serde.rs`
54+
55+
### Key Design Patterns
56+
57+
- **Sans-IO Core**: The `State` struct is transport-agnostic, handling protocol logic without I/O
58+
- **Channel-based Architecture**: Clients use channels to separate request sending from response handling
59+
- **Future-based Async**: Async requests return futures that resolve when responses arrive
60+
- **Type Safety**: Each Electrum method has its own strongly-typed request and response structs
61+
62+
## Dependencies
63+
64+
- `bitcoin 0.32`: Bitcoin primitives and types
65+
- `serde`/`serde_json`: JSON serialization
66+
- `futures 0.3`: Async runtime abstractions
67+
- `tokio` (optional): Tokio-specific async support via feature flag
68+
69+
## Testing Infrastructure
70+
71+
The project uses `bdk_testenv` for integration testing against real Electrum servers. Tests are located in `tests/synopsis.rs`.

examples/blocking_example.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
use electrum_streaming_client::BlockingClient;
2+
use std::net::TcpStream;
3+
use std::time::Duration;
4+
5+
fn main() -> Result<(), Box<dyn std::error::Error>> {
6+
// Connect to a public Electrum server (blockstream.info)
7+
let stream = TcpStream::connect("blockstream.info:110")?;
8+
stream.set_nonblocking(false)?;
9+
stream.set_read_timeout(Some(Duration::from_secs(10)))?;
10+
stream.set_write_timeout(Some(Duration::from_secs(10)))?;
11+
12+
let (reader, writer) = (stream.try_clone()?, stream);
13+
let (client, _event_rx, _handle) = BlockingClient::new(reader, writer);
14+
15+
// Test ping
16+
println!("Sending ping...");
17+
client.ping()?;
18+
println!("Ping successful!");
19+
20+
// Test getting relay fee
21+
println!("Getting relay fee...");
22+
let relay_fee = client.relay_fee()?;
23+
println!("Relay fee: {:?}", relay_fee.fee);
24+
25+
// Test getting a banner
26+
println!("Getting server banner...");
27+
let banner = client.banner()?;
28+
println!("Server banner: {}", banner);
29+
30+
// Test getting a header
31+
println!("Getting header at height 100000...");
32+
let header = client.header(100000)?;
33+
println!("Block hash at height 100000: {}", header.header.block_hash());
34+
35+
Ok(())
36+
}

src/batch_request.rs

Lines changed: 0 additions & 209 deletions
This file was deleted.

0 commit comments

Comments
 (0)