tetsy_jsonrpc_stdio_server/
lib.rs

1//! jsonrpc server using stdin/stdout
2//!
3//! ```no_run
4//!
5//! use tetsy_jsonrpc_stdio_server::ServerBuilder;
6//! use tetsy_jsonrpc_stdio_server::tetsy_jsonrpc_core::*;
7//!
8//! fn main() {
9//! 	let mut io = IoHandler::default();
10//! 	io.add_method("say_hello", |_params| {
11//! 		Ok(Value::String("hello".to_owned()))
12//! 	});
13//!
14//! 	ServerBuilder::new(io).build();
15//! }
16//! ```
17
18#![deny(missing_docs)]
19
20use tokio;
21use tokio_stdin_stdout;
22#[macro_use]
23extern crate log;
24
25pub use tetsy_jsonrpc_core;
26
27use tetsy_jsonrpc_core::IoHandler;
28use std::sync::Arc;
29use tokio::prelude::{Future, Stream};
30use tokio_codec::{FramedRead, FramedWrite, LinesCodec};
31
32/// Stdio server builder
33pub struct ServerBuilder {
34	handler: Arc<IoHandler>,
35}
36
37impl ServerBuilder {
38	/// Returns a new server instance
39	pub fn new<T>(handler: T) -> Self
40	where
41		T: Into<IoHandler>,
42	{
43		ServerBuilder {
44			handler: Arc::new(handler.into()),
45		}
46	}
47
48	/// Will block until EOF is read or until an error occurs.
49	/// The server reads from STDIN line-by-line, one request is taken
50	/// per line and each response is written to STDOUT on a new line.
51	pub fn build(&self) {
52		let stdin = tokio_stdin_stdout::stdin(0);
53		let stdout = tokio_stdin_stdout::stdout(0).make_sendable();
54
55		let framed_stdin = FramedRead::new(stdin, LinesCodec::new());
56		let framed_stdout = FramedWrite::new(stdout, LinesCodec::new());
57
58		let handler = self.handler.clone();
59		let future = framed_stdin
60			.and_then(move |line| process(&handler, line).map_err(|_| unreachable!()))
61			.forward(framed_stdout)
62			.map(|_| ())
63			.map_err(|e| panic!("{:?}", e));
64
65		tokio::run(future);
66	}
67}
68
69/// Process a request asynchronously
70fn process(io: &Arc<IoHandler>, input: String) -> impl Future<Item = String, Error = ()> + Send {
71	io.handle_request(&input).map(move |result| match result {
72		Some(res) => res,
73		None => {
74			info!("JSON RPC request produced no response: {:?}", input);
75			String::from("")
76		}
77	})
78}