use anyhow::Result;
use json_rpc::{Error, JsonRpc};
use serde_json::Value;
use tokio::io::AsyncBufReadExt;
use tracing::info;
async fn hello(params: String) -> Result<String, Error> {
if params == "world" {
Ok(format!("Hello, {}!", params))
} else {
Err(Error::rpc(-32000, "text must be 'world'"))
}
}
async fn subtract(params: (i32, i32)) -> Result<i32, Error> {
Ok(params.0 - params.1)
}
async fn sum(params: Vec<i32>) -> Result<i32, Error> {
Ok(params.into_iter().sum())
}
async fn internal_error(_params: Value) -> Result<String, Error> {
Err(Error::protocol("Internal error occurred"))
}
#[tokio::main]
async fn main() -> Result<()> {
tracing_subscriber::fmt()
.with_max_level(tracing::Level::DEBUG)
.with_writer(std::io::stderr)
.init();
info!("Initializing basic JSON-RPC handler");
let json_rpc = JsonRpc::new()
.add("hello", hello)
.add("subtract", subtract)
.add("sum", sum)
.add("internal_error", internal_error);
info!("Basic handler started. Send JSON-RPC messages via stdin.");
info!("Available methods:");
info!(" - hello(name: string): Returns greeting");
info!(" - subtract(a: number, b: number): Returns a - b");
info!(" -sum(numbers: array): Returns sum of numbers");
info!(" - internal_error(): Demonstrates internal error");
info!("");
info!("Examples:");
info!(" {{\"jsonrpc\":\"2.0\",\"method\":\"hello\",\"params\":\"world\",\"id\":1}}");
info!(" {{\"jsonrpc\":\"2.0\",\"method\":\"subtract\",\"params\":[10,5],\"id\":2}}");
info!(" {{\"jsonrpc\":\"2.0\",\"method\":\"sum\",\"params\":[1,2,3,4,5],\"id\":3}}");
let stdin = tokio::io::stdin();
let mut reader = tokio::io::BufReader::new(stdin);
let mut line = String::new();
info!("Starting message processing loop");
while reader.read_line(&mut line).await? > 0 {
let trimmed = line.trim();
if trimmed.is_empty() {
line.clear();
continue;
}
info!("Processing message: {}", trimmed);
match json_rpc.call(trimmed).await {
Some(response) => {
info!("Sending response: {}", response);
println!("{}", response);
}
None => {
info!("Notification processed - no response needed");
}
}
line.clear();
}
info!("Message processing loop completed");
Ok(())
}