dcl_rpc/rpc_protocol/
parse.rs

1//! Parsing functions for the messages that are sent on communications between two different ends using the Decentraland RPC implementation.
2use super::{fill_remote_error, RemoteError, RpcMessageHeader, RpcMessageTypes};
3use prost::Message;
4
5/// Build message identifier from type and number, and returns one number which it's the `message_identifier`
6///
7/// `message_identifier` packs two numbers:
8///
9/// Bits from 1 to 28 correspond to the sequential message number (analogous to JSON-RPC 2)
10///
11/// Bits from 28 to 32 correspond to message type
12pub fn build_message_identifier(message_type: u32, message_number: u32) -> u32 {
13    ((message_type & 0xf) << 27) | (message_number & 0x07ffffff)
14}
15
16/// Parse message type and number from message identifier
17///
18/// Do the inverse calculation of `build_message_identifier`
19pub fn parse_message_identifier(value: u32) -> (u32, u32) {
20    ((value >> 27) & 0xf, value & 0x07ffffff)
21}
22
23/// Decode bytes into [`RpcMessageHeader`] to get message type and message number
24/// which are two number that compose the `message_identifier` in the [`RpcMessageHeader`] struct
25pub fn parse_header(data: &[u8]) -> Option<(RpcMessageTypes, u32)> {
26    let message_header = RpcMessageHeader::decode(data).ok()?;
27    let (message_type, message_number) =
28        parse_message_identifier(message_header.message_identifier);
29    let rpc_message_type = RpcMessageTypes::from_i32(message_type as i32)?;
30    Some((rpc_message_type, message_number))
31}
32
33/// Errors produced by [`parse_protocol_message`]
34#[derive(Debug)]
35pub enum ParseErrors {
36    /// Found a RemoteError message instead of the given type parameter
37    IsARemoteError((u32, RemoteError)),
38    /// The bytes failed decoding into the given type
39    DecodingFailed,
40    /// It's an error when the [`RpcMessageHeader`] has: [`RpcMessageTypes::Empty`] or
41    /// [`RpcMessageTypes::ServerReady`] as `message_type` in its identifier. These message types don't have
42    /// a message itself, they come as a [`RpcMessageHeader`]
43    NotMessageType,
44    /// The function, first, tries to decode the bytes into [`RpcMessageHeader`] to get the `message_type` and `message_number`
45    ///
46    /// If it fails, the bytes are fully invalid.
47    InvalidHeader,
48}
49
50type ParseMessageResult<R> = Result<(u32, u32, R), ParseErrors>;
51
52/// Parse protocol message from bytes
53///
54/// A type parameter `R` (generic) is passed to try to decode the bytes into the given type.
55///
56/// If all went well, an `Ok(Option<u32, u32, R>)` is returned.
57///
58/// If the bytes cannot be decoded into the given type or the [`RpcMessageHeader`]'s message type of the given bytes is a [`RpcMessageTypes::Empty`] or a [`RpcMessageTypes::ServerReady`], a `Ok(None)`  is returned.
59///
60/// Also, if the [`RpcMessageHeader`] cannot be gotten from the given bytes, a `Ok(None)` is returned because the bytes are fully invalid.
61///
62/// If the [`RpcMessageHeader`]'s message type of the given bytes is a [`RpcMessageTypes::RemoteErrorResponse`], an Err((u32, [`RemoteError`])) is returned.
63///
64pub fn parse_protocol_message<R: Message + Default>(data: &[u8]) -> ParseMessageResult<R> {
65    let (message_type, message_number) = match parse_header(data) {
66        Some(header) => header,
67        None => return Err(ParseErrors::InvalidHeader),
68    };
69
70    if matches!(message_type, RpcMessageTypes::RemoteErrorResponse) {
71        match RemoteError::decode(data) {
72            Ok(remote_error) => {
73                return Err(ParseErrors::IsARemoteError((message_number, remote_error)))
74            }
75            Err(_) => {
76                let mut remote_error_default = RemoteError::default();
77                fill_remote_error(&mut remote_error_default, message_number);
78
79                return Err(ParseErrors::IsARemoteError((
80                    message_number,
81                    remote_error_default,
82                )));
83            }
84        }
85    }
86
87    if matches!(
88        message_type,
89        RpcMessageTypes::Empty | RpcMessageTypes::ServerReady
90    ) {
91        return Err(ParseErrors::NotMessageType);
92    }
93
94    let message = R::decode(data);
95
96    match message {
97        Ok(message) => Ok((message_type as u32, message_number, message)),
98        Err(_) => Err(ParseErrors::DecodingFailed),
99    }
100}
101
102#[cfg(test)]
103mod tests {
104    use crate::rpc_protocol::*;
105    use prost::Message;
106
107    use super::{build_message_identifier, parse_protocol_message};
108
109    #[test]
110    fn test_parse_protocol_message() {
111        let port = CreatePort {
112            message_identifier: build_message_identifier(RpcMessageTypes::CreatePort as u32, 1),
113            port_name: "port_name".to_string(),
114        };
115
116        let vec = port.encode_to_vec();
117
118        let parse_back = parse_protocol_message::<CreatePortResponse>(&vec).unwrap();
119
120        assert_eq!(parse_back.0, RpcMessageTypes::CreatePort as u32);
121        // parse_protocol_message dont add the port_id, just parse it
122        assert_eq!(parse_back.2.port_id, 0);
123    }
124
125    #[test]
126    fn test_remote_error_in_parse_protocol_message() {
127        let remote_error = RemoteError {
128            message_identifier: build_message_identifier(
129                RpcMessageTypes::RemoteErrorResponse as u32,
130                1,
131            ),
132            error_code: 400,
133            error_message: "Bad request error".to_string(),
134        };
135        let vec = remote_error.encode_to_vec();
136
137        let parse_back = parse_protocol_message::<CreatePortResponse>(&vec).unwrap_err();
138        match parse_back {
139            parse::ParseErrors::IsARemoteError((message_number, remote_error_produced)) => {
140                assert_eq!(message_number, 1);
141                assert_eq!(remote_error, remote_error_produced);
142            }
143            _ => panic!(),
144        }
145    }
146}