jsonrpc_base/
message.rs

1use super::{helpers, Error, Notification, Request, Response};
2use alloc::string::ToString;
3use core::{fmt, str::FromStr};
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6
7/// JSON-RPC message
8#[derive(Serialize, Deserialize, Debug, Clone)]
9pub enum Message {
10    /// JSON-RPC request
11    Request(Request),
12    /// JSON-RPC notification
13    Notification(Notification),
14    /// JSON-RPC response
15    Response(Response),
16}
17
18impl Message {
19    /// Parse a string into the message, returning the message and the remaining string
20    pub fn parse(s: &str) -> Result<(Self, &str), Error> {
21        let (message, remainder) = helpers::get_content_length(s)?;
22        let message = Message::parse_json(message)?;
23        Ok((message, remainder))
24    }
25
26    /// Parse a message from the provided JSON
27    pub fn parse_json(json: &str) -> Result<Self, Error> {
28        let value: Value = serde_json::from_str(json).map_err(|e| Error {
29            code: Error::INVALID_REQUEST,
30            message: e.to_string(),
31            data: Some(Value::String(json.to_string())),
32        })?;
33        if value.get("method").is_some() && value.get("id").is_some() {
34            Request::parse_json(json).map(Self::Request)
35        } else if value.get("method").is_some() {
36            Notification::parse_json(json).map(Self::Notification)
37        } else {
38            Response::parse_json(json).map(Self::Response)
39        }
40    }
41}
42
43impl fmt::Display for Message {
44    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
45        match self {
46            Message::Request(r) => r.fmt(f),
47            Message::Notification(n) => n.fmt(f),
48            Message::Response(r) => r.fmt(f),
49        }
50    }
51}
52
53impl FromStr for Message {
54    type Err = Error;
55
56    fn from_str(s: &str) -> Result<Self, Self::Err> {
57        Self::parse(s).map(|(json, _)| json)
58    }
59}
60
61impl From<Request> for Message {
62    fn from(request: Request) -> Self {
63        Self::Request(request)
64    }
65}
66
67impl From<Notification> for Message {
68    fn from(notification: Notification) -> Self {
69        Self::Notification(notification)
70    }
71}
72
73impl From<Response> for Message {
74    fn from(response: Response) -> Self {
75        Self::Response(response)
76    }
77}
78
79impl TryFrom<Message> for Request {
80    type Error = Error;
81
82    fn try_from(value: Message) -> Result<Self, Self::Error> {
83        match value {
84            Message::Request(request) => Ok(request),
85            _ => Err(Error {
86                code: Error::INVALID_REQUEST,
87                message: "the provided message is not a request".to_string(),
88                data: serde_json::to_value(value).ok(),
89            }),
90        }
91    }
92}
93
94impl TryFrom<Message> for Notification {
95    type Error = Error;
96
97    fn try_from(value: Message) -> Result<Self, Self::Error> {
98        match value {
99            Message::Notification(notification) => Ok(notification),
100            _ => Err(Error {
101                code: Error::INVALID_REQUEST,
102                message: "the provided message is not a notification".to_string(),
103                data: serde_json::to_value(value).ok(),
104            }),
105        }
106    }
107}
108
109impl TryFrom<Message> for Response {
110    type Error = Error;
111
112    fn try_from(value: Message) -> Result<Self, Self::Error> {
113        match value {
114            Message::Response(response) => Ok(response),
115            _ => Err(Error {
116                code: Error::INVALID_REQUEST,
117                message: "the provided message is not a response".to_string(),
118                data: serde_json::to_value(value).ok(),
119            }),
120        }
121    }
122}
123
124#[cfg(feature = "std")]
125mod io {
126    use super::*;
127    use std::io::prelude::*;
128
129    impl Message {
130        /// Read a message from a reader.
131        ///
132        /// Returns the number of consumed bytes and the message.
133        pub fn try_from_reader<R>(reader: R) -> Result<(usize, Self), Error>
134        where
135            R: Read,
136        {
137            let (n, contents) = helpers::get_content_from_reader(reader)?;
138            let message = Message::parse_json(&contents)?;
139            Ok((n, message))
140        }
141
142        /// Write a message to a writer and return the number of bytes written.
143        pub fn try_to_writer<W>(&self, mut writer: W) -> Result<usize, Error>
144        where
145            W: Write,
146        {
147            writer
148                .write(self.to_string().as_bytes())
149                .map_err(|e| Error {
150                    code: Error::PARSE_ERROR,
151                    message: e.to_string(),
152                    data: serde_json::to_value(&self).ok(),
153                })
154        }
155    }
156
157    #[test]
158    fn test_try_from_reader() {
159        let input = r#"Content-Length: 75
160
161{"jsonrpc":"2.0","id":"3162690c-fe69-4b78-b418-0b2e8326ac08","result":true}"#;
162
163        let (consumed, _message) = Message::try_from_reader(input.as_bytes()).unwrap();
164        assert_eq!(consumed, input.len());
165    }
166}