feat(ipc): JSON-RPC envelope types
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Request {
|
||||
pub jsonrpc: String,
|
||||
pub id: serde_json::Value,
|
||||
pub method: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub params: Option<Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Notification {
|
||||
pub jsonrpc: String,
|
||||
pub method: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub params: Option<Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Response {
|
||||
pub jsonrpc: String,
|
||||
pub id: serde_json::Value,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub result: Option<Value>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub error: Option<RpcError>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct RpcError {
|
||||
pub code: i32,
|
||||
pub message: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub data: Option<Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum Incoming {
|
||||
Request(Request),
|
||||
Response(Response),
|
||||
Notification(Notification),
|
||||
}
|
||||
|
||||
pub const JSONRPC_VERSION: &str = "2.0";
|
||||
|
||||
pub fn request(id: u64, method: &str, params: Option<Value>) -> Request {
|
||||
Request {
|
||||
jsonrpc: JSONRPC_VERSION.into(),
|
||||
id: serde_json::json!(id),
|
||||
method: method.into(),
|
||||
params,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn notification(method: &str, params: Option<Value>) -> Notification {
|
||||
Notification {
|
||||
jsonrpc: JSONRPC_VERSION.into(),
|
||||
method: method.into(),
|
||||
params,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ok_response(id: serde_json::Value, result: Value) -> Response {
|
||||
Response {
|
||||
jsonrpc: JSONRPC_VERSION.into(),
|
||||
id,
|
||||
result: Some(result),
|
||||
error: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn err_response(id: serde_json::Value, code: i32, message: String) -> Response {
|
||||
Response {
|
||||
jsonrpc: JSONRPC_VERSION.into(),
|
||||
id,
|
||||
result: None,
|
||||
error: Some(RpcError {
|
||||
code,
|
||||
message,
|
||||
data: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn request_round_trip() {
|
||||
let r = request(7, "list", None);
|
||||
let s = serde_json::to_string(&r).unwrap();
|
||||
let back: Request = serde_json::from_str(&s).unwrap();
|
||||
assert_eq!(back.method, "list");
|
||||
assert_eq!(back.id, serde_json::json!(7));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn incoming_is_response() {
|
||||
let s = r#"{"jsonrpc":"2.0","id":1,"result":{"ok":true}}"#;
|
||||
let i: Incoming = serde_json::from_str(s).unwrap();
|
||||
assert!(matches!(i, Incoming::Response(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn incoming_is_notification() {
|
||||
let s = r#"{"jsonrpc":"2.0","method":"log","params":{}}"#;
|
||||
let i: Incoming = serde_json::from_str(s).unwrap();
|
||||
assert!(matches!(i, Incoming::Notification(_)));
|
||||
}
|
||||
}
|
||||
@@ -1 +1,8 @@
|
||||
//! JSON-RPC 2.0 over newline-delimited JSON on a Unix socket.
|
||||
|
||||
pub mod envelope;
|
||||
|
||||
pub use envelope::{
|
||||
err_response, notification, ok_response, request, Incoming, Notification, Request, Response,
|
||||
RpcError,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user