1use anyhow::{anyhow, Error};
2use hex::{self, FromHex};
3use serde::de::{self, Deserializer};
4use serde::ser::{self, Serializer};
5use serde::{Deserialize, Serialize};
6use serde_json::{json, Value};
7use std::collections::HashMap;
8
9#[derive(Serialize, Deserialize, Debug)]
10#[serde(tag = "method", content = "params")]
11#[serde(rename_all = "snake_case")]
12enum JsonRpcCall {
13 }
15
16#[derive(Debug)]
17pub struct ParserError {
18 reason: String,
19}
20
21impl std::fmt::Display for ParserError {
22 fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
23 f.write_fmt(format_args!("ParserError {}", self.reason))
24 }
25}
26impl std::error::Error for ParserError {}
27
28#[derive(Serialize, Deserialize, Debug)]
29struct JsonRpcRequest {
30 id: Option<Value>,
31 jsonrpc: String,
32 method: String,
33 params: JsonRpcCall,
34}
35
36#[derive(Serialize, Deserialize, Debug)]
38#[serde(tag = "method", content = "params")]
39#[serde(rename_all = "snake_case")]
40pub enum MyRequests {
41 HtlcAccepted(HtlcAcceptedCall),
42 Getmanifest(GetManifestCall),
43 Init(InitCall),
44 InvoicePayment(InvoicePaymentCall),
45 CommitmentRevocation(CommitmentRevocationCall),
46}
47
48#[derive(Serialize, Deserialize, Debug)]
49#[serde(rename_all = "snake_case")]
50pub struct HtlcAcceptedCall {
51 pub onion: HtlcAcceptedCallOnion,
52 pub htlc: HtlcAcceptedCallHtlc,
53}
54
55#[derive(Serialize, Deserialize, Debug)]
56#[serde(rename_all = "snake_case")]
57pub struct InvoicePaymentCall {
58 pub payment: InvoicePaymentCallPayment,
59}
60
61#[derive(Serialize, Deserialize, Debug)]
62#[serde(rename_all = "snake_case")]
63pub struct Custommsg {
64 pub peer_id: String,
65 pub payload: String,
66}
67
68#[derive(Serialize, Deserialize, Debug)]
69#[serde(rename_all = "snake_case")]
70pub struct CommitmentRevocationCall {
71 pub commitment_txid: String,
72 pub penalty_tx: String,
73 pub channel_id: Option<String>,
74 pub commitnum: Option<u64>,
75}
76
77#[derive(Serialize, Deserialize, Debug)]
78pub struct InvoicePaymentCallPayment {
79 pub label: String,
80 pub preimage: String,
81 #[serde(rename = "msat")]
82 pub amount: String,
83 pub extratlvs: Option<Vec<TlvField>>,
84}
85
86#[derive(Serialize, Deserialize, Debug)]
87pub struct TlvField {
88 #[serde(rename = "type")]
89 pub typ: u64,
90 pub value: String,
91}
92
93#[derive(Serialize, Deserialize, Debug)]
94#[serde(rename_all = "snake_case")]
95pub struct GetManifestCall {}
96
97#[derive(Serialize, Deserialize, Debug)]
98#[serde(rename_all = "snake_case")]
99pub struct GetManifestResult {
100 pub subscriptions: Vec<String>,
101 pub hooks: Vec<String>,
102 pub dynamic: bool,
103 pub options: Vec<PluginOption>,
104 pub rpcmethods: Vec<PluginRpcMethod>,
105}
106
107#[derive(Serialize, Deserialize, Debug)]
108pub struct PluginOption {
109 name: String,
110 default: String,
111 description: String,
112}
113
114#[derive(Serialize, Deserialize, Debug)]
115#[serde(rename_all = "snake_case")]
116pub struct PluginRpcMethod {
117 name: String,
118 usage: String,
119 description: String,
120}
121
122#[derive(Serialize, Deserialize, Debug)]
123#[serde(rename_all = "snake_case")]
124pub struct HtlcAcceptedCallOnion {
125 #[serde(serialize_with = "buffer_to_hex", deserialize_with = "hex_to_buffer")]
126 pub payload: Vec<u8>,
127 short_channel_id: Option<String>,
128 forward_amount: String,
129 outgoing_cltv_value: u64,
130
131 #[serde(serialize_with = "buffer_to_hex", deserialize_with = "hex_to_buffer")]
132 next_onion: Vec<u8>,
133
134 #[serde(serialize_with = "buffer_to_hex", deserialize_with = "hex_to_buffer")]
135 pub shared_secret: Vec<u8>,
136}
137
138#[derive(Serialize, Deserialize, Debug)]
139#[serde(rename_all = "snake_case")]
140pub struct HtlcAcceptedCallHtlc {
141 pub amount: String,
142 cltv_expiry: u64,
143 cltv_expiry_relative: u64,
144
145 #[serde(serialize_with = "buffer_to_hex", deserialize_with = "hex_to_buffer")]
146 pub payment_hash: Vec<u8>,
147}
148
149#[derive(Serialize, Deserialize, Debug)]
150#[serde(rename_all = "snake_case")]
151pub struct HtlcAcceptedResponse {
152 pub result: String,
153 #[serde(serialize_with = "buffer_to_hex", deserialize_with = "hex_to_buffer")]
154 pub payment_key: Vec<u8>,
155}
156
157#[derive(Serialize, Deserialize, Debug)]
158pub struct InitCall {
159 pub options: Value,
160 pub configuration: HashMap<String, Value>,
161}
162
163#[derive(Serialize, Deserialize, Debug)]
164#[serde(tag = "method", content = "params")]
165#[serde(rename_all = "snake_case")]
166pub enum MyNotifications {
167 Disconnect(DisconnectNotification),
168}
169
170#[derive(Serialize, Deserialize, Debug)]
171pub struct DisconnectNotification {
172 pub id: String,
173}
174
175#[derive(Debug)]
176pub enum JsonRpc<N, R> {
177 Request(usize, R),
178 Notification(N),
179}
180
181impl<N, R> Serialize for JsonRpc<N, R>
182where
183 N: Serialize,
184 R: Serialize,
185{
186 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
187 where
188 S: Serializer,
189 {
190 match *self {
191 JsonRpc::Request(id, ref r) => {
192 let mut v = serde_json::to_value(r).map_err(ser::Error::custom)?;
193 v["id"] = json!(id);
194 v.serialize(serializer)
195 }
196 JsonRpc::Notification(ref n) => n.serialize(serializer),
197 }
198 }
199}
200
201impl<'de, N, R> Deserialize<'de> for JsonRpc<N, R>
202where
203 N: Deserialize<'de>,
204 R: Deserialize<'de>,
205{
206 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
207 where
208 D: Deserializer<'de>,
209 {
210 #[derive(Deserialize)]
211 struct IdHelper {
212 id: Option<usize>,
213 }
214
215 let v = Value::deserialize(deserializer)?;
216 let helper = IdHelper::deserialize(&v).map_err(de::Error::custom)?;
217 match helper.id {
218 Some(id) => {
219 let r = R::deserialize(v).map_err(de::Error::custom)?;
220 Ok(JsonRpc::Request(id, r))
221 }
222 None => {
223 let n = N::deserialize(v).map_err(de::Error::custom)?;
224 Ok(JsonRpc::Notification(n))
225 }
226 }
227 }
228}
229pub fn buffer_to_hex<T, S>(buffer: &T, serializer: S) -> Result<S::Ok, S::Error>
231where
232 T: AsRef<[u8]>,
233 S: Serializer,
234{
235 serializer.serialize_str(&hex::encode(buffer))
236}
237
238pub fn hex_to_buffer<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
240where
241 D: Deserializer<'de>,
242{
243 use serde::de::Error;
244 String::deserialize(deserializer)
245 .and_then(|string| Vec::from_hex(&string).map_err(|err| Error::custom(err.to_string())))
246}
247
248#[derive(Serialize, Deserialize, Debug)]
249pub struct Amount {
250 pub msatoshi: i64,
251}
252
253impl Amount {
254 pub fn from_string(s: &str) -> Result<Amount, Error> {
255 if !s.ends_with("msat") {
256 return Err(anyhow!("Amount string does not end with msat."));
257 }
258
259 let amount_string: &str = s[0..s.len() - 4].into();
260
261 let amount: i64 = match amount_string.parse::<i64>() {
262 Ok(v) => v,
263 Err(e) => return Err(anyhow!(e)),
264 };
265
266 Ok(Amount { msatoshi: amount })
267 }
268}
269
270fn _string_to_amount<'de, D>(deserializer: D) -> Result<Amount, D::Error>
271where
272 D: Deserializer<'de>,
273{
274 use serde::de::Error;
275 String::deserialize(deserializer).and_then(|string| {
276 Amount::from_string(&string).map_err(|_| Error::custom("could not parse amount"))
277 })
278}
279
280fn _amount_to_string<S>(amount: &Amount, serializer: S) -> Result<S::Ok, S::Error>
281where
282 S: Serializer,
283{
284 let s = format!("{}msat", amount.msatoshi);
285 serializer.serialize_str(&s)
286}
287
288#[derive(Serialize, Deserialize, Debug)]
291pub struct PeerConnectedCall {
292 pub peer: Peer
293}
294
295#[derive(Serialize, Deserialize, Debug)]
296pub struct Peer {
297 pub id: String,
298 pub direction: Direction,
299 pub addr: String,
300 pub features: String,
301}
302
303#[derive(Serialize, Deserialize, Debug, PartialEq)]
304#[serde(rename_all = "snake_case")]
305pub enum Direction {
306 In,
307 Out
308}
309
310
311#[cfg(test)]
312mod test {
313 use super::*;
314
315 #[test]
316 fn test_peer_connected_call() {
317 let msg = json!({
318 "peer": {
319 "id": "03864ef025fde8fb587d989186ce6a4a186895ee44a926bfc370e2c366597a3f8f",
320 "direction": "in",
321 "addr": "34.239.230.56:9735",
322 "features": ""
323 }
324 });
325
326 let call = serde_json::from_str::<PeerConnectedCall>(&msg.to_string()).unwrap();
327 assert_eq!(call.peer.id, "03864ef025fde8fb587d989186ce6a4a186895ee44a926bfc370e2c366597a3f8f");
328 assert_eq!(call.peer.direction, Direction::In);
329 assert_eq!(call.peer.addr, "34.239.230.56:9735");
330 assert_eq!(call.peer.features, "");
331 }
332
333 #[test]
334 fn test_htlc_accepted_call() {
335 let req = json!({"id": 1, "jsonrpc": "2.0", "method": "htlc_accepted", "params": {
336 "onion": {
337 "payload": "",
338 "type": "legacy",
339 "short_channel_id": "1x2x3",
340 "forward_amount": "42msat",
341 "outgoing_cltv_value": 500014,
342 "shared_secret": "0000000000000000000000000000000000000000000000000000000000000000",
343 "next_onion": "00DEADBEEF00",
344 },
345 "htlc": {
346 "amount": "43msat",
347 "cltv_expiry": 500028,
348 "cltv_expiry_relative": 10,
349 "payment_hash": "0000000000000000000000000000000000000000000000000000000000000000"
350 }
351 }
352 });
353
354 type T = JsonRpc<MyNotifications, MyRequests>;
355 let req = serde_json::from_str::<T>(&req.to_string()).unwrap();
356 match req {
357 T::Request(id, c) => {
358 assert_eq!(id, 1);
359 match c {
360 MyRequests::HtlcAccepted(c) => {
361 assert_eq!(c.onion.forward_amount, "42msat");
363 assert_eq!(c.onion.outgoing_cltv_value, 500014);
364 }
374 _ => panic!("This was supposed to be an htlc_accepted call"),
375 }
376 }
377 _ => panic!("This was supposed to be a request"),
378 }
379 }
380}