rmp_rpc/
message.rs

1use errors::*;
2use rmpv::{decode, encode, Integer, Utf8String, Value};
3use std::convert::From;
4use std::io::{self, Read};
5
6/// Represents a `MessagePack-RPC` message as described in the
7/// [specifications](https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md#messagepack-rpc-protocol-specification).
8#[derive(PartialEq, Clone, Debug)]
9pub enum Message {
10    Request(Request),
11    Response(Response),
12    Notification(Notification),
13}
14
15/// Represents a `MessagePack-RPC` request as described in the
16/// [specifications](https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md#messagepack-rpc-protocol-specification).
17///
18/// A request is a message that a client sends to a server when it expects a response. Sending a
19/// request is like calling a method: it includes a method name and an array of parameters. The
20/// response is like the return value.
21#[derive(PartialEq, Clone, Debug)]
22pub struct Request {
23    /// The `id` is used to associate a response with a request. If a client sends a request with a
24    /// particular `id`, the server should send a response with the same `id`.
25    pub id: u32,
26    /// A string representing the method name.
27    pub method: String,
28    /// An array of parameters to the method.
29    pub params: Vec<Value>,
30}
31
32/// Represents a `MessagePack-RPC` response as described in the
33/// [specifications](https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md#messagepack-rpc-protocol-specification).
34///
35/// After a client sends a [`Request`], the server will send a response back.
36#[derive(PartialEq, Clone, Debug)]
37pub struct Response {
38    /// The `id` of the [`Request`] that triggered this response.
39    pub id: u32,
40    /// The result of the [`Request`] that triggered this response.
41    pub result: Result<Value, Value>,
42}
43
44/// Represents a `MessagePack-RPC` notification as described in the
45/// [specifications](https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md#messagepack-rpc-protocol-specification).
46///
47/// A notification is a message that a client sends to a server when it doesn't expect a response.
48/// Sending a notification is like calling a method with no return value: the notification includes
49/// a method name and an array of parameters.
50#[derive(PartialEq, Clone, Debug)]
51pub struct Notification {
52    /// A string representing the method name.
53    pub method: String,
54    /// An array of parameters to the method.
55    pub params: Vec<Value>,
56}
57
58const REQUEST_MESSAGE: u64 = 0;
59const RESPONSE_MESSAGE: u64 = 1;
60const NOTIFICATION_MESSAGE: u64 = 2;
61
62impl Message {
63    pub fn decode<R>(rd: &mut R) -> Result<Message, DecodeError>
64    where
65        R: Read,
66    {
67        let msg = decode::value::read_value(rd)?;
68        if let Value::Array(ref array) = msg {
69            if array.len() < 3 {
70                // notification are the shortest message and have 3 items
71                return Err(DecodeError::Invalid);
72            }
73            if let Value::Integer(msg_type) = array[0] {
74                match msg_type.as_u64() {
75                    Some(REQUEST_MESSAGE) => {
76                        return Ok(Message::Request(Request::decode(array)?));
77                    }
78                    Some(RESPONSE_MESSAGE) => {
79                        return Ok(Message::Response(Response::decode(array)?));
80                    }
81                    Some(NOTIFICATION_MESSAGE) => {
82                        return Ok(Message::Notification(Notification::decode(array)?));
83                    }
84                    _ => {
85                        return Err(DecodeError::Invalid);
86                    }
87                }
88            } else {
89                return Err(DecodeError::Invalid);
90            }
91        } else {
92            return Err(DecodeError::Invalid);
93        }
94    }
95
96    pub fn as_value(&self) -> Value {
97        match *self {
98            Message::Request(Request {
99                id,
100                ref method,
101                ref params,
102            }) => Value::Array(vec![
103                Value::Integer(Integer::from(REQUEST_MESSAGE)),
104                Value::Integer(Integer::from(id)),
105                Value::String(Utf8String::from(method.as_str())),
106                Value::Array(params.clone()),
107            ]),
108            Message::Response(Response { id, ref result }) => {
109                let (error, result) = match *result {
110                    Ok(ref result) => (Value::Nil, result.to_owned()),
111                    Err(ref err) => (err.to_owned(), Value::Nil),
112                };
113                Value::Array(vec![
114                    Value::Integer(Integer::from(RESPONSE_MESSAGE)),
115                    Value::Integer(Integer::from(id)),
116                    error,
117                    result,
118                ])
119            }
120            Message::Notification(Notification {
121                ref method,
122                ref params,
123            }) => Value::Array(vec![
124                Value::Integer(Integer::from(NOTIFICATION_MESSAGE)),
125                Value::String(Utf8String::from(method.as_str())),
126                Value::Array(params.to_owned()),
127            ]),
128        }
129    }
130
131    pub fn pack(&self) -> io::Result<Vec<u8>> {
132        let mut bytes = vec![];
133        encode::write_value(&mut bytes, &self.as_value())?;
134        Ok(bytes)
135    }
136}
137
138impl Notification {
139    fn decode(array: &[Value]) -> Result<Self, DecodeError> {
140        if array.len() < 3 {
141            return Err(DecodeError::Invalid);
142        }
143
144        let method = if let Value::String(ref method) = array[1] {
145            method
146                .as_str()
147                .and_then(|s| Some(s.to_string()))
148                .ok_or(DecodeError::Invalid)?
149        } else {
150            return Err(DecodeError::Invalid);
151        };
152
153        let params = if let Value::Array(ref params) = array[2] {
154            params.clone()
155        } else {
156            return Err(DecodeError::Invalid);
157        };
158
159        Ok(Notification { method, params })
160    }
161}
162
163impl Request {
164    fn decode(array: &[Value]) -> Result<Self, DecodeError> {
165        if array.len() < 4 {
166            return Err(DecodeError::Invalid);
167        }
168
169        let id = if let Value::Integer(id) = array[1] {
170            id.as_u64()
171                .and_then(|id| Some(id as u32))
172                .ok_or(DecodeError::Invalid)?
173        } else {
174            return Err(DecodeError::Invalid);
175        };
176
177        let method = if let Value::String(ref method) = array[2] {
178            method
179                .as_str()
180                .and_then(|s| Some(s.to_string()))
181                .ok_or(DecodeError::Invalid)?
182        } else {
183            return Err(DecodeError::Invalid);
184        };
185
186        let params = if let Value::Array(ref params) = array[3] {
187            params.clone()
188        } else {
189            return Err(DecodeError::Invalid);
190        };
191
192        Ok(Request { id, method, params })
193    }
194}
195
196impl Response {
197    fn decode(array: &[Value]) -> Result<Self, DecodeError> {
198        if array.len() < 2 {
199            return Err(DecodeError::Invalid);
200        }
201
202        let id = if let Value::Integer(id) = array[1] {
203            id.as_u64()
204                .and_then(|id| Some(id as u32))
205                .ok_or(DecodeError::Invalid)?
206        } else {
207            return Err(DecodeError::Invalid);
208        };
209
210        match array[2] {
211            Value::Nil => Ok(Response {
212                id,
213                result: Ok(array[3].clone()),
214            }),
215            ref error => Ok(Response {
216                id,
217                result: Err(error.clone()),
218            }),
219        }
220    }
221}
222
223#[test]
224fn test_decode_request() {
225    let valid = Message::Request(Request {
226        id: 1234,
227        method: "dummy".to_string(),
228        params: Vec::new(),
229    });
230    let bytes = valid.pack().unwrap();
231
232    // valid message
233    {
234        let mut buf = io::Cursor::new(&bytes);
235        assert_eq!(valid, Message::decode(&mut buf).unwrap());
236    }
237
238    // truncated
239    {
240        let bytes = Vec::from(&bytes[0..bytes.len() - 1]);
241        let mut buf = io::Cursor::new(&bytes);
242        assert!(match Message::decode(&mut buf) {
243            Err(DecodeError::Truncated) => true,
244            _ => false,
245        });
246    }
247
248    // invalid message type
249    {
250        let mut bytes = Vec::from(&bytes[..]);
251        bytes[1] = 5;
252        let mut buf = io::Cursor::new(&bytes);
253        assert!(match Message::decode(&mut buf) {
254            Err(DecodeError::Invalid) => true,
255            _ => false,
256        });
257    }
258}