| Crates.io | rpcnet |
| lib.rs | rpcnet |
| version | 0.1.0 |
| created_at | 2025-10-07 10:16:30.038058+00 |
| updated_at | 2025-10-07 10:16:30.038058+00 |
| description | RPC library based on QUIC+TLS encryption |
| homepage | https://github.com/jsam/rpcnet |
| repository | https://github.com/jsam/rpcnet |
| max_upload_size | |
| id | 1871455 |
| size | 5,849,003 |
A low latency RPC library for cluster building with full QUIC+TLS and SWIM support
Getting Started โข Documentation โข User Guide โข Examples โข Benchmarks
Add rpcnet to your Cargo.toml:
[dependencies]
rpcnet = "0.1.0"
tokio = { version = "1.0", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
async-trait = "0.1"
# Optional: For code generation in build.rs
[build-dependencies]
rpcnet = { version = "0.1.0", features = ["codegen"] }
The rpcnet-gen CLI tool generates type-safe client and server code from service definitions. The CLI is included by default when you install rpcnet.
# Install from crates.io (includes rpcnet-gen CLI)
cargo install rpcnet
# Or install from source
cargo install --path .
Verify installation:
rpcnet-gen --help
RpcNet includes a code generator that creates type-safe client and server code from service definitions.
Create a .rpc.rs file using standard Rust syntax:
// calculator.rpc.rs
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct AddRequest {
pub a: i64,
pub b: i64,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct AddResponse {
pub result: i64,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum CalculatorError {
Overflow,
InvalidInput(String),
}
#[rpcnet::service]
pub trait Calculator {
async fn add(&self, request: AddRequest) -> Result<AddResponse, CalculatorError>;
}
Use the CLI tool to generate client and server code:
# Generate code from service definition
rpcnet-gen --input calculator.rpc.rs --output src/generated
# Multiple files
rpcnet-gen --input definitions/ --output src/generated
use rpcnet::RpcConfig;
use generated::calculator::{Calculator, CalculatorHandler, CalculatorServer};
use generated::calculator::{AddRequest, AddResponse, CalculatorError};
struct MyCalculator;
#[async_trait::async_trait]
impl CalculatorHandler for MyCalculator {
async fn add(&self, request: AddRequest) -> Result<AddResponse, CalculatorError> {
let result = request.a.checked_add(request.b)
.ok_or(CalculatorError::Overflow)?;
Ok(AddResponse { result })
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = RpcConfig::new("cert.pem", "127.0.0.1:8090");
let server = CalculatorServer::new(MyCalculator, config);
server.serve().await?;
Ok(())
}
use rpcnet::RpcConfig;
use generated::calculator::{CalculatorClient, AddRequest};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = RpcConfig::new("cert.pem", "127.0.0.1:0")
.with_server_name("localhost");
let client = CalculatorClient::connect("127.0.0.1:8090".parse()?, config).await?;
let response = client.add(AddRequest { a: 10, b: 20 }).await?;
println!("Result: {}", response.result);
Ok(())
}
Add to your build.rs:
fn main() {
// Regenerate code when service definitions change
println!("cargo:rerun-if-changed=definitions/");
rpcnet::codegen::Builder::new()
.input("definitions/calculator.rpc.rs")
.output("src/generated")
.build()
.expect("Failed to generate RPC code");
}
Cargo.toml:[dependencies]
rpcnet = "0.1.0"
tokio = { version = "1.0", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
# Create a certs directory
mkdir certs && cd certs
# Generate a self-signed certificate for development
openssl req -x509 -newkey rsa:4096 -keyout test_key.pem -out test_cert.pem -days 365 -nodes \
-subj "/CN=localhost"
cd ..
use rpcnet::{RpcServer, RpcConfig};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = RpcConfig::new("certs/test_cert.pem", "127.0.0.1:8080")
.with_key_path("certs/test_key.pem")
.with_server_name("localhost");
let mut server = RpcServer::new(config);
server.register("greet", |params| async move {
let name = String::from_utf8_lossy(¶ms);
let response = format!("Hello, {}!", name);
Ok(response.into_bytes())
}).await;
let quic_server = server.bind()?;
server.start(quic_server).await?;
Ok(())
}
use rpcnet::{RpcClient, RpcConfig};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = RpcConfig::new("certs/test_cert.pem", "127.0.0.1:0")
.with_server_name("localhost");
let client = RpcClient::connect("127.0.0.1:8080".parse().unwrap(), config).await?;
let response = client.call("greet", b"World".to_vec()).await?;
println!("Response: {}", String::from_utf8_lossy(&response));
Ok(())
}
RpcNet maintains 65%+ test coverage with comprehensive unit tests, integration tests, and examples:
# Run all tests
cargo test
# Generate coverage report
make coverage
# Check coverage meets 65% threshold
make coverage-check
# Analyze coverage gaps
make coverage-gaps
# Test examples
cargo run --example basic_client_server
See docs/COVERAGE.md for detailed coverage information and TESTING.md for testing guidelines.
RpcNet includes comprehensive benchmarks demonstrating its exceptional performance:
# Run benchmarks (standard)
cargo bench
# Run benchmarks with performance optimizations (jemalloc allocator)
cargo bench --features perf
# Specific benchmark scenarios
cargo bench --bench simple max_throughput # Test maximum throughput
cargo bench --bench simple concurrent # Test concurrent operations
Simple examples using the low-level API that work immediately:
# Basic server and client
cargo run --example basic_server
cargo run --example basic_client
# Echo server with text/binary handling
cargo run --example simple_echo_server
cargo run --example simple_echo_client
Complete, self-contained examples demonstrating code generation:
| Example | Description |
|---|---|
basic_greeting/ |
Simple request/response service |
echo/ |
Binary data and multiple methods |
file_transfer/ |
Chunked operations and stateful services |
calculator/ |
Mathematical operations with error handling |
concurrent_demo/ |
Concurrent operations and shared state |
# Generated code examples (require codegen feature)
cargo run --example basic_greeting_server --features codegen
cargo run --example basic_greeting_client --features codegen
Production-ready cluster example demonstrating distributed systems:
# Terminal 1 - Start director/coordinator
DIRECTOR_ADDR=127.0.0.1:61000 RUST_LOG=info \
cargo run --manifest-path examples/cluster/Cargo.toml --bin director
# Terminal 2 - Start worker A
WORKER_LABEL=worker-a WORKER_ADDR=127.0.0.1:62001 \
DIRECTOR_ADDR=127.0.0.1:61000 WORKER_FAILURE_ENABLED=true RUST_LOG=info \
cargo run --manifest-path examples/cluster/Cargo.toml --bin worker
# Terminal 3 - Start worker B
WORKER_LABEL=worker-b WORKER_ADDR=127.0.0.1:62002 \
DIRECTOR_ADDR=127.0.0.1:61000 WORKER_FAILURE_ENABLED=true RUST_LOG=info \
cargo run --manifest-path examples/cluster/Cargo.toml --bin worker
# Terminal 4 - Start client
DIRECTOR_ADDR=127.0.0.1:61000 RUST_LOG=info \
cargo run --manifest-path examples/cluster/Cargo.toml --bin client
# See examples/cluster/README.md for detailed setup and configuration
Key cluster features demonstrated:
๐ For comprehensive tutorials and documentation, see cargo doc --open
The comprehensive user guide is available online at jsam.github.io/rpcnet and includes:
# Open the API reference documentation locally
cargo doc --features codegen --open
The API documentation includes: