1#![warn(missing_docs)]
2
3use std::collections::HashSet;
9use std::str::FromStr;
10
11use async_trait::async_trait;
12use futures::future::join_all;
13use jsonrpc_core::types::error::Error;
14use jsonrpc_core::types::error::ErrorCode;
15use jsonrpc_core::Result;
16use rings_core::dht::Did;
17use rings_core::message::Decoder;
18use rings_core::message::Encoded;
19use rings_core::message::Encoder;
20use rings_core::message::MessagePayload;
21use rings_core::message::MessageVerificationExt;
22use rings_core::prelude::entry::Entry;
23use rings_rpc::protos::rings_node::*;
24use rings_rpc::protos::rings_node_handler::HandleRpc;
25
26use crate::error::Error as ServerError;
27use crate::processor::Processor;
28use crate::seed::Seed;
29
30#[cfg_attr(feature = "browser", async_trait(?Send))]
31#[cfg_attr(not(feature = "browser"), async_trait)]
32impl HandleRpc<ConnectPeerViaHttpRequest, ConnectPeerViaHttpResponse> for Processor {
33 async fn handle_rpc(
34 &self,
35 req: ConnectPeerViaHttpRequest,
36 ) -> Result<ConnectPeerViaHttpResponse> {
37 let client = rings_rpc::jsonrpc::Client::new(&req.url);
38
39 let did = client
40 .node_did(&NodeDidRequest {})
41 .await
42 .map_err(|e| ServerError::RemoteRpcError(e.to_string()))?
43 .did;
44
45 let offer = self
46 .handle_rpc(CreateOfferRequest { did: did.clone() })
47 .await?
48 .offer;
49
50 let answer = client
51 .answer_offer(&AnswerOfferRequest { offer })
52 .await
53 .map_err(|e| ServerError::RemoteRpcError(e.to_string()))?
54 .answer;
55
56 self.handle_rpc(AcceptAnswerRequest { answer }).await?;
57
58 Ok(ConnectPeerViaHttpResponse { did })
59 }
60}
61
62#[cfg_attr(feature = "browser", async_trait(?Send))]
63#[cfg_attr(not(feature = "browser"), async_trait)]
64impl HandleRpc<ConnectWithDidRequest, ConnectWithDidResponse> for Processor {
65 async fn handle_rpc(&self, req: ConnectWithDidRequest) -> Result<ConnectWithDidResponse> {
66 let did = s2d(&req.did)?;
67 self.connect_with_did(did).await.map_err(Error::from)?;
68 Ok(ConnectWithDidResponse {})
69 }
70}
71
72#[cfg_attr(feature = "browser", async_trait(?Send))]
73#[cfg_attr(not(feature = "browser"), async_trait)]
74impl HandleRpc<ConnectWithSeedRequest, ConnectWithSeedResponse> for Processor {
75 async fn handle_rpc(&self, req: ConnectWithSeedRequest) -> Result<ConnectWithSeedResponse> {
76 let seed: Seed = Seed::try_from(req)?;
77
78 let mut connected: HashSet<String> =
79 HashSet::from_iter(self.swarm.peers().into_iter().map(|peer| peer.did));
80 connected.insert(self.swarm.did().to_string());
81
82 let tasks = seed
83 .peers
84 .iter()
85 .filter(|&x| !connected.contains(&x.did))
86 .map(|x| {
87 self.handle_rpc(ConnectPeerViaHttpRequest {
88 url: x.url.to_string(),
89 })
90 });
91
92 let results = join_all(tasks).await;
93
94 let first_err = results.into_iter().find(|x| x.is_err());
95 if let Some(err) = first_err {
96 err?;
97 }
98
99 Ok(ConnectWithSeedResponse {})
100 }
101}
102
103#[cfg_attr(feature = "browser", async_trait(?Send))]
104#[cfg_attr(not(feature = "browser"), async_trait)]
105impl HandleRpc<ListPeersRequest, ListPeersResponse> for Processor {
106 async fn handle_rpc(&self, _req: ListPeersRequest) -> Result<ListPeersResponse> {
107 let peers = self
108 .swarm
109 .peers()
110 .into_iter()
111 .map(|peer| peer.into())
112 .collect();
113 Ok(ListPeersResponse { peers })
114 }
115}
116
117#[cfg_attr(feature = "browser", async_trait(?Send))]
118#[cfg_attr(not(feature = "browser"), async_trait)]
119impl HandleRpc<CreateOfferRequest, CreateOfferResponse> for Processor {
120 async fn handle_rpc(&self, req: CreateOfferRequest) -> Result<CreateOfferResponse> {
121 let did = s2d(&req.did)?;
122 let offer_payload = self
123 .swarm
124 .create_offer(did)
125 .await
126 .map_err(ServerError::CreateOffer)
127 .map_err(Error::from)?;
128
129 let encoded = offer_payload
130 .encode()
131 .map_err(|_| ServerError::EncodeError)?;
132
133 Ok(CreateOfferResponse {
134 offer: encoded.to_string(),
135 })
136 }
137}
138
139#[cfg_attr(feature = "browser", async_trait(?Send))]
140#[cfg_attr(not(feature = "browser"), async_trait)]
141impl HandleRpc<AnswerOfferRequest, AnswerOfferResponse> for Processor {
142 async fn handle_rpc(&self, req: AnswerOfferRequest) -> Result<AnswerOfferResponse> {
143 if req.offer.is_empty() {
144 return Err(Error::invalid_params("Offer is empty"));
145 }
146 let encoded: Encoded = <Encoded as From<String>>::from(req.offer);
147
148 let offer_payload =
149 MessagePayload::from_encoded(&encoded).map_err(|_| ServerError::DecodeError)?;
150
151 let answer_payload = self
152 .swarm
153 .answer_offer(offer_payload)
154 .await
155 .map_err(ServerError::AnswerOffer)
156 .map_err(Error::from)?;
157
158 tracing::debug!("connect_peer_via_ice response: {:?}", answer_payload);
159 let encoded = answer_payload
160 .encode()
161 .map_err(|_| ServerError::EncodeError)?;
162
163 Ok(AnswerOfferResponse {
164 answer: encoded.to_string(),
165 })
166 }
167}
168
169#[cfg_attr(feature = "browser", async_trait(?Send))]
170#[cfg_attr(not(feature = "browser"), async_trait)]
171impl HandleRpc<AcceptAnswerRequest, AcceptAnswerResponse> for Processor {
172 async fn handle_rpc(&self, req: AcceptAnswerRequest) -> Result<AcceptAnswerResponse> {
173 if req.answer.is_empty() {
174 return Err(Error::invalid_params("Answer is empty"));
175 }
176 let encoded = Encoded::from(req.answer);
177
178 let answer_payload =
179 MessagePayload::from_encoded(&encoded).map_err(|_| ServerError::DecodeError)?;
180 answer_payload.transaction.signer();
181
182 self.swarm
183 .accept_answer(answer_payload)
184 .await
185 .map_err(ServerError::AcceptAnswer)?;
186
187 Ok(AcceptAnswerResponse {})
188 }
189}
190
191#[cfg_attr(feature = "browser", async_trait(?Send))]
192#[cfg_attr(not(feature = "browser"), async_trait)]
193impl HandleRpc<DisconnectRequest, DisconnectResponse> for Processor {
194 async fn handle_rpc(&self, req: DisconnectRequest) -> Result<DisconnectResponse> {
195 let did = s2d(&req.did)?;
196 self.disconnect(did).await?;
197 Ok(DisconnectResponse {})
198 }
199}
200
201#[cfg_attr(feature = "browser", async_trait(?Send))]
202#[cfg_attr(not(feature = "browser"), async_trait)]
203impl HandleRpc<SendBackendMessageRequest, SendBackendMessageResponse> for Processor {
204 async fn handle_rpc(
205 &self,
206 req: SendBackendMessageRequest,
207 ) -> Result<SendBackendMessageResponse> {
208 let destination = s2d(&req.destination_did)?;
209 let payload = base64::decode(req.data.as_str())
210 .map_err(|e| Error::invalid_params(format!("data is not valid base64: {e:?}")))?;
211 let envelope =
212 crate::extension::ext::Envelope::new(req.namespace, bytes::Bytes::from(payload));
213 self.send_envelope(destination, &envelope).await?;
214 Ok(SendBackendMessageResponse {})
215 }
216}
217
218#[cfg_attr(feature = "browser", async_trait(?Send))]
219#[cfg_attr(not(feature = "browser"), async_trait)]
220impl HandleRpc<PublishMessageToTopicRequest, PublishMessageToTopicResponse> for Processor {
221 async fn handle_rpc(
222 &self,
223 req: PublishMessageToTopicRequest,
224 ) -> Result<PublishMessageToTopicResponse> {
225 let encoded = req
226 .data
227 .encode()
228 .map_err(|e| Error::invalid_params(format!("Failed to encode data: {e:?}")))?;
229 self.storage_append_data(&req.topic, encoded).await?;
230 Ok(PublishMessageToTopicResponse {})
231 }
232}
233
234#[cfg_attr(feature = "browser", async_trait(?Send))]
235#[cfg_attr(not(feature = "browser"), async_trait)]
236impl HandleRpc<FetchTopicMessagesRequest, FetchTopicMessagesResponse> for Processor {
237 async fn handle_rpc(
238 &self,
239 req: FetchTopicMessagesRequest,
240 ) -> Result<FetchTopicMessagesResponse> {
241 let entry_key = Entry::gen_did(&req.topic)
242 .map_err(|_| Error::invalid_params("Failed to get id of topic"))?;
243
244 self.storage_fetch(entry_key).await?;
245 let result = self.storage_check_cache(entry_key).await;
246
247 let Some(entry) = result else {
248 return Ok(FetchTopicMessagesResponse { data: vec![] });
249 };
250
251 let data = entry
252 .data
253 .iter()
254 .skip(req.skip as usize)
255 .map(|v| v.decode())
256 .filter_map(|v| v.ok())
257 .collect::<Vec<String>>();
258
259 Ok(FetchTopicMessagesResponse { data })
260 }
261}
262
263#[cfg_attr(feature = "browser", async_trait(?Send))]
264#[cfg_attr(not(feature = "browser"), async_trait)]
265impl HandleRpc<RegisterServiceRequest, RegisterServiceResponse> for Processor {
266 async fn handle_rpc(&self, req: RegisterServiceRequest) -> Result<RegisterServiceResponse> {
267 self.register_service(&req.name).await?;
268 Ok(RegisterServiceResponse {})
269 }
270}
271
272#[cfg_attr(feature = "browser", async_trait(?Send))]
273#[cfg_attr(not(feature = "browser"), async_trait)]
274impl HandleRpc<LookupServiceRequest, LookupServiceResponse> for Processor {
275 async fn handle_rpc(&self, req: LookupServiceRequest) -> Result<LookupServiceResponse> {
276 let entry_key = Entry::gen_did(&req.name)
277 .map_err(|_| Error::invalid_params("Failed to get id of topic"))?;
278
279 self.storage_fetch(entry_key).await?;
280 let result = self.storage_check_cache(entry_key).await;
281
282 let Some(entry) = result else {
283 return Ok(LookupServiceResponse { dids: vec![] });
284 };
285
286 let dids = entry
287 .data
288 .iter()
289 .map(|v| v.decode())
290 .filter_map(|v| v.ok())
291 .collect::<Vec<String>>();
292
293 Ok(LookupServiceResponse { dids })
294 }
295}
296
297#[cfg_attr(feature = "browser", async_trait(?Send))]
298#[cfg_attr(not(feature = "browser"), async_trait)]
299impl HandleRpc<NodeInfoRequest, NodeInfoResponse> for Processor {
300 async fn handle_rpc(&self, _req: NodeInfoRequest) -> Result<NodeInfoResponse> {
301 self.get_node_info()
302 .await
303 .map_err(|_| Error::new(ErrorCode::InternalError))
304 }
305}
306
307#[cfg_attr(feature = "browser", async_trait(?Send))]
308#[cfg_attr(not(feature = "browser"), async_trait)]
309impl HandleRpc<NodeDidRequest, NodeDidResponse> for Processor {
310 async fn handle_rpc(&self, _req: NodeDidRequest) -> Result<NodeDidResponse> {
311 let did = self.did();
312 Ok(NodeDidResponse {
313 did: did.to_string(),
314 })
315 }
316}
317
318fn s2d(s: &str) -> Result<Did> {
320 Did::from_str(s).map_err(|_| Error::invalid_params(format!("Invalid Did: {s}")))
321}