gl_client/lsps/
message.rs

1// TODO: Implement parsing of error types for lsps2.getinfo
2use crate::lsps::error::LspsError;
3pub use crate::lsps::json_rpc::{DefaultError, JsonRpcMethod, NoParams};
4use crate::lsps::json_rpc_erased::{JsonRpcMethodErased, JsonRpcMethodUnerased};
5
6use crate::lsps::lsps0::schema::ProtocolList;
7use crate::lsps::lsps1::schema::{Lsps1GetOrderRequest, Lsps1GetOrderResponse, Lsps1InfoResponse};
8use crate::lsps::lsps2::schema::{
9    Lsps2BuyError, Lsps2BuyRequest, Lsps2BuyResponse, Lsps2GetInfoError, Lsps2GetInfoRequest,
10    Lsps2GetInfoResponse, Lsps2GetVersionsResponse,
11};
12
13// All rpc-methods defined in the LSPS standard
14// The generics are <I,O,E> where
15// - I represents the params
16// - O represents the result data
17// - E represents the error if present
18//
19// To create language bindings for a new rpc-call you must
20// 1. Add it to the JsonRpcMethodEnum
21// 2. Add it to the from_method_name function
22// 3. Add it to the ref_erase function
23pub type Lsps0ListProtocols = JsonRpcMethod<NoParams, ProtocolList, DefaultError>;
24pub type Lsps1Info = JsonRpcMethod<NoParams, Lsps1InfoResponse, DefaultError>;
25pub type Lsps1Order = JsonRpcMethod<Lsps1GetOrderRequest, Lsps1GetOrderResponse, DefaultError>;
26pub type Lsps2GetVersions = JsonRpcMethod<NoParams, Lsps2GetVersionsResponse, DefaultError>;
27pub type Lsps2GetInfo = JsonRpcMethod<Lsps2GetInfoRequest, Lsps2GetInfoResponse, Lsps2GetInfoError>;
28pub type Lsps2Buy = JsonRpcMethod<Lsps2BuyRequest, Lsps2BuyResponse, Lsps2BuyError>;
29
30pub const LSPS0_LIST_PROTOCOLS: Lsps0ListProtocols =
31    Lsps0ListProtocols::new("lsps0.list_protocols");
32
33// LSPS1: Buy Channels
34pub const LSPS1_GETINFO: Lsps1Info = Lsps1Info::new("lsps1.info");
35pub const LSPS1_GETORDER: Lsps1Order = Lsps1Order::new("lsps1.order");
36
37// LSPS2: JIT-channels
38pub const LSPS2_GET_VERSIONS: Lsps2GetVersions = Lsps2GetVersions::new("lsps2.get_versions");
39pub const LSPS2_GET_INFO: Lsps2GetInfo = Lsps2GetInfo::new("lsps2.get_info");
40pub const LSPS2_BUY: Lsps2Buy = Lsps2Buy::new("lsps2.buy");
41
42pub enum JsonRpcMethodEnum {
43    Lsps0ListProtocols(Lsps0ListProtocols),
44    Lsps1Info(Lsps1Info),
45    Lsps1Order(Lsps1Order),
46    Lsp2GetVersions(Lsps2GetVersions),
47    Lsps2GetInfo(Lsps2GetInfo),
48    Lsps2Buy(Lsps2Buy),
49}
50
51impl JsonRpcMethodEnum {
52    pub fn from_method_name(value: &str) -> Result<JsonRpcMethodEnum, LspsError> {
53        match value {
54            "lsps0.list_protocols" => Ok(Self::Lsps0ListProtocols(LSPS0_LIST_PROTOCOLS)),
55            "lsps1.info" => Ok(Self::Lsps1Info(LSPS1_GETINFO)),
56            "lsps1.order" => Ok(Self::Lsps1Order(LSPS1_GETORDER)),
57            "lsps2.get_versions" => Ok(Self::Lsp2GetVersions(LSPS2_GET_VERSIONS)),
58            "lsps2.get_info" => Ok(Self::Lsps2GetInfo(LSPS2_GET_INFO)),
59            "lsps2.buy" => Ok(Self::Lsps2Buy(LSPS2_BUY)),
60            default => Err(LspsError::MethodUnknown(String::from(default))),
61        }
62    }
63
64    // Useful for language bindings.
65    // The python code can
66    pub fn ref_erase(&self) -> &dyn JsonRpcMethodErased {
67        match self {
68            Self::Lsps0ListProtocols(list_protocol) => list_protocol.ref_erase(),
69            Self::Lsps1Info(info) => info.ref_erase(),
70            Self::Lsps1Order(order) => order.ref_erase(),
71            Self::Lsp2GetVersions(order) => order.ref_erase(),
72            Self::Lsps2GetInfo(order) => order.ref_erase(),
73            Self::Lsps2Buy(buy) => buy.ref_erase(),
74        }
75    }
76}
77
78impl<'a> JsonRpcMethodUnerased<'a, Vec<u8>, Vec<u8>, Vec<u8>> for JsonRpcMethodEnum {
79    fn name(&self) -> &str {
80        self.ref_erase().name()
81    }
82
83    fn create_request(
84        &self,
85        params: Vec<u8>,
86        json_rpc_id: String,
87    ) -> Result<super::json_rpc::JsonRpcRequest<Vec<u8>>, serde_json::Error> {
88        self.ref_erase().create_request(params, json_rpc_id)
89    }
90
91    fn parse_json_response_str(
92        &self,
93        json_str: &str,
94    ) -> Result<super::json_rpc::JsonRpcResponse<Vec<u8>, Vec<u8>>, serde_json::Error> {
95        self.ref_erase().parse_json_response_str(json_str)
96    }
97
98    fn parse_json_response_value(
99        &self,
100        json_value: serde_json::Value,
101    ) -> Result<super::json_rpc::JsonRpcResponse<Vec<u8>, Vec<u8>>, serde_json::Error> {
102        self.ref_erase().parse_json_response_value(json_value)
103    }
104}
105
106#[cfg(test)]
107mod test {
108
109    use crate::lsps::json_rpc::generate_random_rpc_id;
110
111    use super::*;
112    use serde_json::{from_str, to_string, Value};
113
114    #[test]
115    fn serialize_request_with_no_params() {
116        let method = LSPS0_LIST_PROTOCOLS;
117        let json_rpc_id = generate_random_rpc_id();
118        let rpc_request = method.create_request_no_params(json_rpc_id);
119        let json_str = to_string(&rpc_request).unwrap();
120
121        // Test that params is an empty dict
122        //
123        // LSPS-0 spec demands that a parameter-by-name scheme is always followed
124        let v: Value = from_str(&json_str).unwrap();
125        assert_eq!(v.get("jsonrpc").unwrap(), "2.0");
126        assert_eq!(
127            v.get("method").unwrap().as_str().unwrap(),
128            "lsps0.list_protocols"
129        );
130        assert!(v.get("params").unwrap().as_object().unwrap().is_empty())
131    }
132}