jsonrpc_base/
notification.rs

1use super::{helpers, Error};
2use alloc::string::{String, ToString};
3use core::{fmt, str::FromStr};
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6
7/// JSON-RPC notification
8#[derive(Serialize, Deserialize, Debug, Clone)]
9pub struct Notification {
10    /// Protocol header
11    pub jsonrpc: String,
12    /// Method name
13    pub method: String,
14
15    /// Optional method arguments
16    #[serde(skip_serializing_if = "Option::is_none")]
17    pub params: Option<Value>,
18}
19
20impl Notification {
21    /// Create a new notification with the provided method
22    pub fn new<M>(method: M) -> Self
23    where
24        M: ToString,
25    {
26        Notification {
27            jsonrpc: "2.0".to_string(),
28            method: method.to_string(),
29            params: None,
30        }
31    }
32
33    /// Replace the methods arguments with the provided value
34    pub fn with_params<P>(self, params: P) -> Result<Self, Error>
35    where
36        P: Serialize,
37    {
38        serde_json::to_value(params)
39            .map_err(|e| Error {
40                code: Error::PARSE_ERROR,
41                message: e.to_string(),
42                data: None,
43            })
44            .map(|params| self.with_params_value(params))
45    }
46
47    /// Replace the methods arguments with the parsed value
48    pub fn with_params_value(mut self, params: Value) -> Self {
49        self.params = Some(params);
50        self
51    }
52
53    /// Parse a message into the notification
54    pub fn parse(s: &str) -> Result<(Self, &str), Error> {
55        let (message, remainder) = helpers::get_content_length(s)?;
56        let notification = Notification::parse_json(message)?;
57        Ok((notification, remainder))
58    }
59
60    /// Parse a notification from the provided JSON
61    pub fn parse_json(json: &str) -> Result<Self, Error> {
62        serde_json::from_str(json).map_err(|e| Error {
63            code: Error::INVALID_REQUEST,
64            message: e.to_string(),
65            data: Some(Value::String(json.to_string())),
66        })
67    }
68}
69
70impl FromStr for Notification {
71    type Err = Error;
72
73    fn from_str(s: &str) -> Result<Self, Self::Err> {
74        Self::parse(s).map(|(json, _)| json)
75    }
76}
77
78impl fmt::Display for Notification {
79    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
80        serde_json::to_string(&self)
81            .map_err(|_| fmt::Error)
82            .and_then(|m| write!(f, "Content-Length: {}\r\n\r\n{}", m.len(), m))
83    }
84}
85
86#[cfg(feature = "std")]
87mod io {
88    use super::*;
89    use std::io::prelude::*;
90
91    impl Notification {
92        /// Read a notification from a reader.
93        ///
94        /// Returns the number of consumed bytes and the notification.
95        pub fn try_from_reader<R>(reader: R) -> Result<(usize, Self), Error>
96        where
97            R: Read,
98        {
99            let (n, contents) = helpers::get_content_from_reader(reader)?;
100            let notification = Notification::parse_json(&contents)?;
101            Ok((n, notification))
102        }
103
104        /// Write a notification to a writer and return the number of bytes written.
105        pub fn try_to_writer<W>(&self, mut writer: W) -> Result<usize, Error>
106        where
107            W: Write,
108        {
109            writer
110                .write(self.to_string().as_bytes())
111                .map_err(|e| Error {
112                    code: Error::PARSE_ERROR,
113                    message: e.to_string(),
114                    data: serde_json::to_value(&self).ok(),
115                })
116        }
117    }
118}