jsonrpc_sdk_prelude/
kernel.rs

1// Copyright (C) 2019 Boyu Yang
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use core::convert::{TryFrom, TryInto};
10
11use jsonrpc_core::{
12    id::Id,
13    params::Params,
14    request::{Call, MethodCall, Notification, Request},
15    response::{Failure, Output, Response, Success},
16    types::to_string,
17    version::Version,
18    Value,
19};
20use log::trace;
21
22use crate::{Error, Result};
23
24pub struct CommonPart {
25    pub jsonrpc: Option<Version>,
26    pub id_opt: Option<Id>,
27}
28
29impl Default for CommonPart {
30    fn default() -> Self {
31        Self::num(0)
32    }
33}
34
35impl CommonPart {
36    pub fn num(n: u64) -> Self {
37        Self {
38            jsonrpc: Some(Version::V2),
39            id_opt: Some(Id::Num(n)),
40        }
41    }
42
43    pub fn str(s: String) -> Self {
44        Self {
45            jsonrpc: Some(Version::V2),
46            id_opt: Some(Id::Str(s)),
47        }
48    }
49}
50
51pub trait JsonRpcRequest
52where
53    Self: TryInto<Params> + Sized,
54{
55    type Output: TryFrom<Value>;
56
57    fn method() -> &'static str;
58
59    fn to_string(self, c: CommonPart) -> Result<String> {
60        self.to_single_request(c).and_then(|sc| {
61            to_string(&sc).map_err(|_| Error::serde("failed to convert a single request to string"))
62        })
63    }
64
65    fn to_single_request(self, c: CommonPart) -> Result<Request> {
66        self.to_call(c).map(Request::Single)
67    }
68
69    fn to_call(self, c: CommonPart) -> Result<Call> {
70        let CommonPart { jsonrpc, id_opt } = c;
71        let method = Self::method().to_owned();
72        self.try_into()
73            .map_err(|_| Error::serde("failed to parse a request core"))
74            .map(|params: Params| {
75                if let Some(id) = id_opt {
76                    Call::MethodCall(MethodCall {
77                        jsonrpc,
78                        method,
79                        params,
80                        id,
81                    })
82                } else {
83                    Call::Notification(Notification {
84                        jsonrpc,
85                        method,
86                        params,
87                    })
88                }
89            })
90    }
91
92    fn parse_single_response(response: Response) -> Result<Self::Output> {
93        match response {
94            Response::Single(output) => match output {
95                Output::Success(success) => {
96                    let Success {
97                        jsonrpc,
98                        result,
99                        id,
100                    } = success;
101                    trace!("Success {{ jsonrpc: {:#?}, id: {:#?} }}", jsonrpc, id);
102                    result
103                        .try_into()
104                        .map_err(|_| Error::custom("failed to parse the result"))
105                }
106                Output::Failure(failure) => {
107                    let Failure { jsonrpc, error, id } = failure;
108                    trace!("Failure {{ jsonrpc: {:#?}, id: {:#?} }}", jsonrpc, id);
109                    Err(error.into())
110                }
111            },
112            Response::Batch(_) => Err(Error::custom("could not be a batch response")),
113        }
114    }
115}