2 releases (1 stable)
| 1.0.0 | Mar 23, 2026 |
|---|---|
| 0.1.0 | Jan 24, 2026 |
#1370 in Encoding
31KB
521 lines
OpenCore JSON-RPC Rust
A simple and elegant library for creating JSON-RPC servers that communicate with TypeScript frameworks via stdin/stdout.
Features
- Simple API - Register handlers with a clean, type-safe interface
- Line-delimited JSON - Easy integration with any language that can spawn processes
- Automatic serialization - Request/response handling is transparent
- Binary events - Emit messages that map to OpenCore
@BinaryEventlisteners - Robust error handling - Clear error messages and graceful failure modes
- Well-tested - Comprehensive unit and integration tests
- Fully documented - Complete API documentation with examples
Installation
Add this to your Cargo.toml:
[dependencies]
opencore-jsonrpc-rust = "0.1.0"
Quick Start
use opencore_jsonrpc_rust::server::BinaryServer;
use serde_json::Value;
fn add(params: Vec<Value>) -> Result<Value, String> {
if params.len() != 2 {
return Err("Expected 2 parameters".into());
}
let a = params[0].as_i64().ok_or("Invalid number")?;
let b = params[1].as_i64().ok_or("Invalid number")?;
Ok(Value::from(a + b))
}
fn main() {
let mut server = BinaryServer::new();
server.register("add", add);
server
.emit_event("worker.ready", serde_json::json!({ "pid": std::process::id() }))
.unwrap();
server.run();
}
Protocol
Request Format
Requests are sent as line-delimited JSON to stdin:
{"id": "req-123", "action": "add", "params": [5, 10]}
Response Format
Responses are written as line-delimited JSON to stdout:
Success:
{"status": "ok", "id": "req-123", "result": 15}
Error:
{"status": "error", "id": "req-123", "error": "Invalid parameters"}
Event:
{"type": "event", "event": "worker.ready", "data": {"pid": 1234}}
Examples
Basic Math Operations
use opencore_jsonrpc_rust::server::BinaryServer;
use serde_json::Value;
fn multiply(params: Vec<Value>) -> Result<Value, String> {
if params.len() != 2 {
return Err("Expected 2 parameters".into());
}
let a = params[0].as_f64().ok_or("Invalid number")?;
let b = params[1].as_f64().ok_or("Invalid number")?;
Ok(Value::from(a * b))
}
fn main() {
let mut server = BinaryServer::new();
server.register("multiply", multiply);
server.run();
}
Emitting Events
let emitter = server.emitter();
emitter.emit("worker.ready", serde_json::json!({ "pid": std::process::id() }))?;
String Operations
use opencore_jsonrpc_rust::server::BinaryServer;
use serde_json::Value;
fn concat(params: Vec<Value>) -> Result<Value, String> {
let strings: Result<Vec<String>, String> = params
.iter()
.map(|v| {
v.as_str()
.map(|s| s.to_string())
.ok_or_else(|| "All parameters must be strings".to_string())
})
.collect();
Ok(Value::from(strings?.join("")))
}
fn main() {
let mut server = BinaryServer::new();
server.register("concat", concat);
server.run();
}
Complex Data Structures
use opencore_jsonrpc_rust::server::BinaryServer;
use serde_json::{json, Value};
fn process_user(params: Vec<Value>) -> Result<Value, String> {
let user = params.first().ok_or("No user data provided")?;
let name = user["name"].as_str().ok_or("Missing name")?;
let age = user["age"].as_i64().ok_or("Missing age")?;
Ok(json!({
"message": format!("Hello, {}!", name),
"is_adult": age >= 18
}))
}
fn main() {
let mut server = BinaryServer::new();
server.register("process_user", process_user);
server.run();
}
TypeScript Integration
Here's how to use this library from TypeScript (Using OpenCore Framework):
import { Server } from '@open-core/framework/server'
@Server.BinaryService({
name: 'math',
binary: 'math',
timeoutMs: 2000,
})
export class MathBinaryService {
@Server.BinaryCall({ action: 'sum' })
sum(a: number, b: number): Promise<number> {
throw new Error('BinaryCall proxy')
// or return null as any
}
}
Error Handling
Handlers should return Result<Value, String>:
Ok(value)- Success with a JSON valueErr(message)- Error with a descriptive message
The server automatically handles:
- Invalid JSON in requests
- Unknown actions
- Serialization errors
- I/O errors
Use stdout only for protocol traffic and write logs to stderr.
Testing
Run the test suite:
cargo test
Run with output:
cargo test -- --nocapture
Documentation
Generate and view the full API documentation:
cargo doc --open
License
MIT
Contributing
Contributions are welcome! Please ensure:
- All tests pass (
cargo test) - Code is formatted (
cargo fmt) - No clippy warnings (
cargo clippy) - Documentation is updated
Dependencies
~0.5–1.4MB
~29K SLoC