1#![warn(missing_docs)]
2use std::time::Duration;
20
21use async_stream::stream;
22use futures::pin_mut;
23use futures::select;
24use futures::FutureExt;
25use futures::Stream;
26use futures_timer::Delay;
27use rings_rpc::jsonrpc::Client as RpcClient;
28use rings_rpc::protos::rings_node::*;
29
30use crate::seed::Seed;
31use crate::util::loader::ResourceLoader;
32
33type Output<T> = anyhow::Result<ClientOutput<T>>;
35
36pub struct Client {
38 client: RpcClient,
39}
40
41pub struct ClientOutput<T> {
43 pub result: T,
45 display: String,
46}
47
48impl Client {
49 pub fn new(endpoint_url: &str) -> anyhow::Result<Self> {
51 let rpc_client = RpcClient::new(endpoint_url);
52 Ok(Self { client: rpc_client })
53 }
54
55 pub async fn connect_peer_via_http(&mut self, url: &str) -> Output<String> {
64 let peer_did = self
65 .client
66 .connect_peer_via_http(&ConnectPeerViaHttpRequest {
67 url: url.to_string(),
68 })
69 .await
70 .map_err(|e| anyhow::anyhow!("{}", e))?
71 .did;
72
73 ClientOutput::ok(format!("Remote did: {peer_did}"), peer_did)
74 }
75
76 pub async fn connect_with_seed(&mut self, source: &str) -> Output<()> {
78 let seed = Seed::load(source).await?;
79 let req = seed.into_connect_with_seed_request();
80
81 self.client
82 .connect_with_seed(&req)
83 .await
84 .map_err(|e| anyhow::anyhow!("{}", e))?;
85
86 ClientOutput::ok("Successful!".to_string(), ())
87 }
88
89 pub async fn connect_with_did(&mut self, did: &str) -> Output<()> {
91 self.client
92 .connect_with_did(&ConnectWithDidRequest {
93 did: did.to_string(),
94 })
95 .await
96 .map_err(|e| anyhow::anyhow!("{}", e))?;
97 ClientOutput::ok("Successful!".to_owned(), ())
98 }
99
100 pub async fn list_peers(&mut self) -> Output<()> {
104 let peers = self
105 .client
106 .list_peers(&ListPeersRequest {})
107 .await
108 .map_err(|e| anyhow::anyhow!("{}", e))?
109 .peers;
110
111 let mut display = String::new();
112 display.push_str("Did, TransportId, Status\n");
113 display.push_str(
114 peers
115 .iter()
116 .map(|peer| format!("{}, {}, {}", peer.did, peer.did, peer.state))
117 .collect::<Vec<_>>()
118 .join("\n")
119 .as_str(),
120 );
121
122 ClientOutput::ok(display, ())
123 }
124
125 pub async fn disconnect(&mut self, did: &str) -> Output<()> {
127 self.client
128 .disconnect(&DisconnectRequest {
129 did: did.to_string(),
130 })
131 .await
132 .map_err(|e| anyhow::anyhow!("{}", e))?;
133
134 ClientOutput::ok("Done.".into(), ())
135 }
136
137 pub async fn send_message(&self, did: &str, namespace: &str, data: &str) -> Output<()> {
140 self.client
141 .send_backend_message(&SendBackendMessageRequest {
142 destination_did: did.to_string(),
143 namespace: namespace.to_string(),
144 data: base64::encode(data.as_bytes()),
146 })
147 .await
148 .map_err(|e| anyhow::anyhow!("{}", e))?;
149 ClientOutput::ok("Done.".into(), ())
150 }
151
152 pub async fn register_service(&self, name: &str) -> Output<()> {
154 self.client
155 .register_service(&RegisterServiceRequest {
156 name: name.to_string(),
157 })
158 .await
159 .map_err(|e| anyhow::anyhow!("{}", e))?;
160 ClientOutput::ok("Done.".into(), ())
161 }
162
163 pub async fn lookup_service(&self, name: &str) -> Output<()> {
165 let dids = self
166 .client
167 .lookup_service(&LookupServiceRequest {
168 name: name.to_string(),
169 })
170 .await
171 .map_err(|e| anyhow::anyhow!("{}", e))?
172 .dids;
173
174 ClientOutput::ok(dids.join("\n"), ())
175 }
176
177 pub async fn publish_message_to_topic(&self, topic: &str, data: &str) -> Output<()> {
179 self.client
180 .publish_message_to_topic(&PublishMessageToTopicRequest {
181 topic: topic.to_string(),
182 data: data.to_string(),
183 })
184 .await
185 .map_err(|e| anyhow::anyhow!("{}", e))?;
186 ClientOutput::ok("Done.".into(), ())
187 }
188
189 pub async fn subscribe_topic<'a, 'b>(
191 &'a self,
192 topic: String,
193 ) -> impl Stream<Item = String> + 'b
194 where
195 'a: 'b,
196 {
197 let mut skip = 0usize;
198
199 stream! {
200 loop {
201 let timeout = Delay::new(Duration::from_secs(5)).fuse();
202 pin_mut!(timeout);
203
204 select! {
205 _ = timeout => {
206 let result = self
207 .client
208 .fetch_topic_messages(&FetchTopicMessagesRequest {
209 topic: topic.clone(),
210 skip: skip as i64,
211 })
212 .await;
213
214 if let Err(e) = result {
215 tracing::error!("Failed to fetch messages of topic: {}, {}", topic, e);
216 continue;
217 }
218 let messages = result.unwrap().data;
219 for msg in messages.iter().cloned() {
220 yield msg
221 }
222 skip += messages.len();
223 }
224 }
225 }
226 }
227 }
228
229 pub async fn inspect(&self) -> Output<SwarmInfo> {
231 let swarm_info = self
232 .client
233 .node_info(&NodeInfoRequest {})
234 .await
235 .map_err(|e| anyhow::anyhow!("{}", e))?
236 .swarm
237 .unwrap();
238
239 let display =
240 serde_json::to_string_pretty(&swarm_info).map_err(|e| anyhow::anyhow!("{}", e))?;
241
242 ClientOutput::ok(display, swarm_info)
243 }
244}
245
246impl<T> ClientOutput<T> {
247 pub fn ok(display: String, result: T) -> anyhow::Result<Self> {
249 Ok(Self { result, display })
250 }
251
252 pub fn display(&self) {
254 println!("{}", self.display);
255 }
256}