1use serde::de::DeserializeOwned;
4use serde::Serialize;
5
6use crate::method::Method;
7use crate::prelude::reqwest::Client as HttpClient;
8use crate::protos::rings_node::*;
9
10pub struct Client {
12 client: HttpClient,
13 endpoint_url: String,
14}
15
16#[derive(Debug, thiserror::Error)]
18pub enum RpcError {
19 #[error("Server returned rpc error {0}")]
21 JsonClientError(jsonrpc_core::Error),
22 #[error("Failed to parse server response as {0}: {1}")]
24 ParseError(String, Box<dyn std::error::Error + Send>),
25 #[error("Request timed out")]
27 Timeout,
28 #[error("Client error: {0}")]
30 Client(String),
31 #[error("{0}")]
33 Other(Box<dyn std::error::Error + Send>),
34}
35
36type Result<T> = std::result::Result<T, RpcError>;
38
39impl Client {
40 pub fn new(endpoint_url: &str) -> Self {
42 Self {
43 client: HttpClient::default(),
44 endpoint_url: endpoint_url.to_string(),
45 }
46 }
47
48 pub async fn call_method<T>(&self, method: Method, req: &impl Serialize) -> Result<T>
49 where T: DeserializeOwned {
50 use jsonrpc_core::*;
51
52 let params = serde_json::to_value(req)
53 .map_err(|e| RpcError::Client(e.to_string()))?
54 .as_object()
55 .ok_or(RpcError::Client("params should be an object".to_string()))?
56 .clone();
57
58 let jsonrpc_request = Request::Single(Call::MethodCall(MethodCall {
59 jsonrpc: Some(Version::V2),
60 method: method.to_string(),
61 params: Params::Map(params),
62 id: Id::Num(1),
63 }));
64
65 let result = self.do_jsonrpc_request(&jsonrpc_request).await?;
66 serde_json::from_value(result).map_err(|e| RpcError::ParseError(e.to_string(), Box::new(e)))
67 }
68
69 async fn do_jsonrpc_request(&self, req: &jsonrpc_core::Request) -> Result<serde_json::Value> {
70 let body = serde_json::to_string(req).map_err(|e| RpcError::Client(e.to_string()))?;
71
72 let req = self
73 .client
74 .post(self.endpoint_url.as_str())
75 .header("content-type", "application/json")
76 .header("accept", "application/json")
77 .body(body);
78
79 let resp = req
80 .send()
81 .await
82 .map_err(|e| RpcError::Client(e.to_string()))?
83 .error_for_status()
84 .map_err(|e| RpcError::Client(e.to_string()))?
85 .bytes()
86 .await
87 .map_err(|e| RpcError::ParseError(e.to_string(), Box::new(e)))?;
88
89 let jsonrpc_resp = jsonrpc_core::Response::from_json(&String::from_utf8_lossy(&resp))
90 .map_err(|e| RpcError::ParseError(e.to_string(), Box::new(e)))?;
91
92 match jsonrpc_resp {
93 jsonrpc_core::Response::Single(resp) => match resp {
94 jsonrpc_core::Output::Success(success) => Ok(success.result),
95 jsonrpc_core::Output::Failure(failure) => {
96 Err(RpcError::JsonClientError(failure.error))
97 }
98 },
99 jsonrpc_core::Response::Batch(_) => Err(RpcError::Client(
100 "Batch response is not supported".to_string(),
101 )),
102 }
103 }
104
105 pub async fn connect_peer_via_http(
114 &self,
115 req: &ConnectPeerViaHttpRequest,
116 ) -> Result<ConnectPeerViaHttpResponse> {
117 self.call_method(Method::ConnectPeerViaHttp, req).await
118 }
119
120 pub async fn connect_with_did(
122 &self,
123 req: &ConnectWithDidRequest,
124 ) -> Result<ConnectWithSeedResponse> {
125 self.call_method(Method::ConnectWithDid, req).await
126 }
127
128 pub async fn connect_with_seed(
130 &self,
131 req: &ConnectWithSeedRequest,
132 ) -> Result<ConnectWithSeedResponse> {
133 self.call_method(Method::ConnectWithSeed, req).await
134 }
135
136 pub async fn list_peers(&self, req: &ListPeersRequest) -> Result<ListPeersResponse> {
140 self.call_method(Method::ListPeers, req).await
141 }
142
143 pub async fn create_offer(&self, req: &CreateOfferRequest) -> Result<CreateOfferResponse> {
144 self.call_method(Method::CreateOffer, req).await
145 }
146
147 pub async fn answer_offer(&self, req: &AnswerOfferRequest) -> Result<AnswerOfferResponse> {
148 self.call_method(Method::AnswerOffer, req).await
149 }
150
151 pub async fn accept_answer(&self, req: &AcceptAnswerRequest) -> Result<AcceptAnswerResponse> {
152 self.call_method(Method::AcceptAnswer, req).await
153 }
154
155 pub async fn disconnect(&self, req: &DisconnectRequest) -> Result<DisconnectResponse> {
157 self.call_method(Method::Disconnect, req).await
158 }
159
160 pub async fn send_backend_message(
161 &self,
162 req: &SendBackendMessageRequest,
163 ) -> Result<SendBackendMessageResponse> {
164 self.call_method(Method::SendBackendMessage, req).await
165 }
166
167 pub async fn send_e2e_handshake(
168 &self,
169 req: &SendE2eHandshakeRequest,
170 ) -> Result<SendE2eHandshakeResponse> {
171 self.call_method(Method::SendE2eHandshake, req).await
172 }
173
174 pub async fn send_e2e_message(
175 &self,
176 req: &SendE2eMessageRequest,
177 ) -> Result<SendE2eMessageResponse> {
178 self.call_method(Method::SendE2eMessage, req).await
179 }
180
181 pub async fn publish_message_to_topic(
183 &self,
184 req: &PublishMessageToTopicRequest,
185 ) -> Result<PublishMessageToTopicResponse> {
186 self.call_method(Method::PublishMessageToTopic, req).await
187 }
188
189 pub async fn fetch_topic_messages(
190 &self,
191 req: &FetchTopicMessagesRequest,
192 ) -> Result<FetchTopicMessagesResponse> {
193 self.call_method(Method::FetchTopicMessages, req).await
194 }
195
196 pub async fn register_service(
198 &self,
199 req: &RegisterServiceRequest,
200 ) -> Result<RegisterServiceResponse> {
201 self.call_method(Method::RegisterService, req).await
202 }
203
204 pub async fn lookup_service(
206 &self,
207 req: &LookupServiceRequest,
208 ) -> Result<LookupServiceResponse> {
209 self.call_method(Method::LookupService, req).await
210 }
211
212 pub async fn node_info(&self, req: &NodeInfoRequest) -> Result<NodeInfoResponse> {
214 self.call_method(Method::NodeInfo, req).await
215 }
216
217 pub async fn node_did(&self, req: &NodeDidRequest) -> Result<NodeDidResponse> {
218 self.call_method(Method::NodeDid, req).await
219 }
220}