bitcoins_provider/rpc/common.rs
1use async_trait::async_trait;
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4use std::{
5 fmt,
6 sync::atomic::{AtomicU64, Ordering},
7};
8use thiserror::Error;
9
10use crate::provider::ProviderError;
11
12#[derive(Serialize, Deserialize, Debug, Clone, Error)]
13/// A JSON-RPC 2.0 error
14pub struct ErrorResponse {
15 /// The error code
16 pub code: i64,
17 /// The error message
18 pub message: String,
19 /// Additional data
20 pub data: Option<Value>,
21}
22
23impl fmt::Display for ErrorResponse {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 write!(
26 f,
27 "(code: {}, message: {}, data: {:?})",
28 self.code, self.message, self.data
29 )
30 }
31}
32
33impl From<ErrorResponse> for ProviderError {
34 fn from(e: ErrorResponse) -> Self {
35 ProviderError::RpcErrorResponse(e)
36 }
37}
38
39#[derive(Serialize, Deserialize, Debug)]
40/// A JSON-RPC request
41pub struct Request<'a, T> {
42 id: u64,
43 jsonrpc: &'a str,
44 method: &'a str,
45 params: T,
46}
47
48impl<'a, T> Request<'a, T> {
49 /// Creates a new JSON RPC request
50 pub fn new(id: u64, method: &'a str, params: T) -> Self {
51 Self {
52 id,
53 jsonrpc: "2.0",
54 method,
55 params,
56 }
57 }
58}
59
60// In case the node doesn't conform properly
61static RPC2: &str = "2.0";
62fn rpc_version() -> String {
63 RPC2.to_owned()
64}
65
66#[derive(Serialize, Deserialize, Debug, Clone)]
67/// A succesful response
68pub struct Response<T> {
69 id: u64,
70 #[serde(default = "rpc_version")]
71 jsonrpc: String,
72 /// The response payload
73 #[serde(flatten)]
74 pub data: ResponseData<T>,
75}
76
77#[derive(Serialize, Deserialize, Debug, Clone)]
78#[serde(untagged)]
79/// The two possible responses from the API
80pub enum ResponseData<R> {
81 /// Error Response
82 Error {
83 /// The Error
84 error: ErrorResponse,
85 },
86 /// Succesful response
87 Success {
88 /// The response
89 result: R,
90 },
91}
92
93impl<R> ResponseData<R> {
94 /// Consume response and return value
95 pub fn into_result(self) -> Result<R, ErrorResponse> {
96 match self {
97 ResponseData::Success { result } => Ok(result),
98 ResponseData::Error { error } => Err(error),
99 }
100 }
101}
102
103/// A JSON RPC transport
104#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
105#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
106pub trait JsonRpcTransport: Default {
107 /// Return a reference to the underlying AtomicU64 used for creating request IDs
108 fn id(&self) -> &AtomicU64;
109
110 /// Get the next request ID
111 fn next_id(&self) -> u64 {
112 self.id().fetch_add(1, Ordering::SeqCst)
113 }
114
115 /// Make a request, and receive a future with the response
116 async fn request<T: Serialize + Send + Sync, R: for<'a> Deserialize<'a>>(
117 &self,
118 method: &str,
119 params: T,
120 ) -> Result<R, ProviderError>;
121}
122
123/*
124
125 https://github.com/gakonst/ethers-rs
126
127 Copyright (c) 2020 Georgios Konstantopoulos
128
129 Permission is hereby granted, free of charge, to any
130 person obtaining a copy of this software and associated
131 documentation files (the "Software"), to deal in the
132 Software without restriction, including without
133 limitation the rights to use, copy, modify, merge,
134 publish, distribute, sublicense, and/or sell copies of
135 the Software, and to permit persons to whom the Software
136 is furnished to do so, subject to the following
137 conditions:
138
139 The above copyright notice and this permission notice
140 shall be included in all copies or substantial portions
141 of the Software.
142
143 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
144 ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
145 TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
146 PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
147 SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
148 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
149 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
150 IN CONNECTION WITH THE SOFTWARE O THE USE OR OTHER
151 DEALINGS IN THE SOFTWARE.R
152*/