1pub use acuity_index_substrate::shared::{
4 Bytes32, Event, EventMeta, PalletMeta, Span, SubstrateKey,
5};
6use futures_util::{SinkExt, StreamExt};
7use serde::{Deserialize, Serialize};
8use thiserror::Error;
9use tokio::net::TcpStream;
10use tokio_tungstenite::{
11 MaybeTlsStream, WebSocketStream, connect_async, tungstenite, tungstenite::protocol::Message,
12};
13
14#[cfg(test)]
15use tokio::net::TcpListener;
16
17#[derive(Error, Debug)]
19pub enum IndexError {
20 #[error("connection error")]
21 Websocket(#[from] tungstenite::Error),
22 #[error("decoding error")]
23 SerdeJson(#[from] serde_json::Error),
24 #[error("no message")]
25 NoMessage,
26}
27
28pub struct Index {
30 ws_stream: WebSocketStream<MaybeTlsStream<TcpStream>>,
31}
32
33impl Index {
34 async fn send_recv(&mut self, send_msg: RequestMessage) -> Result<ResponseMessage, IndexError> {
36 self.ws_stream
37 .send(Message::Text(serde_json::to_string(&send_msg)?))
38 .await?;
39 let msg = self.ws_stream.next().await.ok_or(IndexError::NoMessage)??;
40 Ok(serde_json::from_str(msg.to_text()?)?)
41 }
42
43 pub async fn connect(url: String) -> Result<Self, IndexError> {
45 let (ws_stream, _) = connect_async(url).await?;
46 let index = Index { ws_stream };
47 Ok(index)
48 }
49
50 pub async fn status(&mut self) -> Result<Vec<Span>, IndexError> {
52 match self.send_recv(RequestMessage::Status).await? {
53 ResponseMessage::Status(spans) => Ok(spans),
54 _ => Err(IndexError::NoMessage),
55 }
56 }
57
58 pub async fn subscribe_status(
60 &mut self,
61 ) -> Result<impl futures_util::Stream<Item = Result<Vec<Span>, IndexError>> + '_, IndexError>
62 {
63 if self.send_recv(RequestMessage::SubscribeStatus).await? != ResponseMessage::Subscribed {
64 return Err(IndexError::NoMessage);
65 };
66
67 Ok(self.ws_stream.by_ref().map(|msg| {
69 let response: ResponseMessage = serde_json::from_str(msg?.to_text()?)?;
70
71 match response {
72 ResponseMessage::Status(spans) => Ok(spans),
73 _ => Err(IndexError::NoMessage),
74 }
75 }))
76 }
77
78 pub async fn unsubscribe_status(&mut self) -> Result<(), IndexError> {
80 match self.send_recv(RequestMessage::UnsubscribeStatus).await? {
81 ResponseMessage::Unsubscribed => Ok(()),
82 _ => Err(IndexError::NoMessage),
83 }
84 }
85
86 pub async fn size_on_disk(&mut self) -> Result<u64, IndexError> {
88 match self.send_recv(RequestMessage::SizeOnDisk).await? {
89 ResponseMessage::SizeOnDisk(size) => Ok(size),
90 _ => Err(IndexError::NoMessage),
91 }
92 }
93
94 pub async fn get_variants(&mut self) -> Result<Vec<PalletMeta>, IndexError> {
96 match self.send_recv(RequestMessage::Variants).await? {
97 ResponseMessage::Variants(pallet_meta) => Ok(pallet_meta),
98 _ => Err(IndexError::NoMessage),
99 }
100 }
101
102 pub async fn get_events(&mut self, key: Key) -> Result<Vec<Event>, IndexError> {
104 match self.send_recv(RequestMessage::GetEvents { key }).await? {
105 ResponseMessage::Events { events, .. } => Ok(events),
106 _ => Err(IndexError::NoMessage),
107 }
108 }
109
110 pub async fn subscribe_events(
112 &mut self,
113 key: Key,
114 ) -> Result<impl futures_util::Stream<Item = Result<Vec<Event>, IndexError>> + '_, IndexError>
115 {
116 if self
117 .send_recv(RequestMessage::SubscribeEvents { key: key.clone() })
118 .await?
119 != ResponseMessage::Subscribed
120 {
121 return Err(IndexError::NoMessage);
122 };
123
124 Ok(self.ws_stream.by_ref().map(move |msg| {
126 let response: ResponseMessage = serde_json::from_str(msg?.to_text()?)?;
127
128 match response {
129 ResponseMessage::Events {
130 key: response_key,
131 events,
132 } => Ok(if response_key != key { vec![] } else { events }),
133 _ => Err(IndexError::NoMessage),
134 }
135 }))
136 }
137
138 pub async fn unsubscribe_events(&mut self, key: Key) -> Result<(), IndexError> {
140 match self
141 .send_recv(RequestMessage::UnsubscribeEvents { key })
142 .await?
143 {
144 ResponseMessage::Unsubscribed => Ok(()),
145 _ => Err(IndexError::NoMessage),
146 }
147 }
148}
149
150#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Hash)]
152#[serde(tag = "type", content = "value")]
153pub enum Key {
154 Variant(u8, u8),
155 Substrate(SubstrateKey),
156}
157
158#[derive(Serialize, Deserialize, Debug, Clone)]
160#[serde(tag = "type")]
161pub enum RequestMessage {
162 Status,
163 SubscribeStatus,
164 UnsubscribeStatus,
165 Variants,
166 GetEvents { key: Key },
167 SubscribeEvents { key: Key },
168 UnsubscribeEvents { key: Key },
169 SizeOnDisk,
170}
171
172#[derive(Deserialize, Serialize, Debug, Clone, PartialEq)]
174#[serde(tag = "type", content = "data")]
175#[serde(rename_all = "camelCase")]
176pub enum ResponseMessage {
177 Status(Vec<Span>),
178 Variants(Vec<PalletMeta>),
179 Events { key: Key, events: Vec<Event> },
180 Subscribed,
181 Unsubscribed,
182 SizeOnDisk(u64),
183 Error,
184}
185
186#[cfg(test)]
187impl Index {
188 pub async fn test_connect() -> Result<Self, IndexError> {
189 let try_socket = TcpListener::bind("127.0.0.1:0").await;
190 let listener = try_socket.expect("Failed to bind");
191
192 let addr = listener.local_addr().unwrap().to_string();
193 let mut url = "ws://".to_string();
194 url.push_str(&addr);
195
196 tokio::spawn(handle_connection(listener));
197
198 Index::connect(url).await
199 }
200}
201
202#[cfg(test)]
203async fn handle_connection(listener: TcpListener) {
204 let (raw_stream, addr) = listener.accept().await.unwrap();
205 println!("Incoming TCP connection from: {}", addr);
206
207 let ws_stream = tokio_tungstenite::accept_async(raw_stream)
208 .await
209 .expect("Error during the websocket handshake occurred");
210 println!("WebSocket connection established: {}", addr);
211
212 let (mut ws_sender, mut ws_receiver) = ws_stream.split();
213 let msg = ws_receiver.next().await.unwrap().unwrap();
214 let request_msg: RequestMessage = serde_json::from_str(msg.to_text().unwrap()).unwrap();
215
216 let response_msg = match request_msg {
217 RequestMessage::Status => ResponseMessage::Status(vec![
218 Span { start: 2, end: 4 },
219 Span { start: 9, end: 23 },
220 Span {
221 start: 20002,
222 end: 400000,
223 },
224 ]),
225 RequestMessage::SubscribeStatus => {
226 let response_msg = ResponseMessage::Subscribed;
227 let response_json = serde_json::to_string(&response_msg).unwrap();
228 ws_sender
229 .send(tungstenite::Message::Text(response_json))
230 .await
231 .unwrap();
232
233 let response_msg = ResponseMessage::Status(vec![
234 Span { start: 2, end: 4 },
235 Span { start: 9, end: 23 },
236 Span {
237 start: 20002,
238 end: 400000,
239 },
240 ]);
241
242 let response_json = serde_json::to_string(&response_msg).unwrap();
243 ws_sender
244 .send(tungstenite::Message::Text(response_json))
245 .await
246 .unwrap();
247
248 let response_msg = ResponseMessage::Status(vec![
249 Span { start: 2, end: 4 },
250 Span { start: 9, end: 23 },
251 Span {
252 start: 20002,
253 end: 400008,
254 },
255 ]);
256
257 let response_json = serde_json::to_string(&response_msg).unwrap();
258 ws_sender
259 .send(tungstenite::Message::Text(response_json))
260 .await
261 .unwrap();
262
263 let response_msg = ResponseMessage::Status(vec![
264 Span { start: 2, end: 4 },
265 Span { start: 9, end: 23 },
266 Span {
267 start: 20002,
268 end: 400028,
269 },
270 ]);
271
272 let response_json = serde_json::to_string(&response_msg).unwrap();
273 ws_sender
274 .send(tungstenite::Message::Text(response_json))
275 .await
276 .unwrap();
277 let msg = ws_receiver.next().await.unwrap().unwrap();
278 let request_msg: RequestMessage = serde_json::from_str(msg.to_text().unwrap()).unwrap();
279 match request_msg {
280 RequestMessage::UnsubscribeStatus => ResponseMessage::Unsubscribed,
281 _ => ResponseMessage::Error,
282 }
283 }
284 RequestMessage::Variants => ResponseMessage::Variants(vec![PalletMeta {
285 index: 0,
286 name: "test1".to_string(),
287 events: vec![EventMeta {
288 index: 0,
289 name: "event1".to_string(),
290 }],
291 }]),
292 RequestMessage::GetEvents { .. } => ResponseMessage::Events {
293 key: Key::Variant(0, 0),
294 events: vec![
295 Event {
296 block_number: 82,
297 event_index: 16,
298 },
299 Event {
300 block_number: 86,
301 event_index: 17,
302 },
303 ],
304 },
305 RequestMessage::SubscribeEvents { .. } => {
306 let response_msg = ResponseMessage::Subscribed;
307 let response_json = serde_json::to_string(&response_msg).unwrap();
308 ws_sender
309 .send(tungstenite::Message::Text(response_json))
310 .await
311 .unwrap();
312
313 let response_msg = ResponseMessage::Events {
314 key: Key::Variant(0, 0),
315 events: vec![
316 Event {
317 block_number: 82,
318 event_index: 16,
319 },
320 Event {
321 block_number: 86,
322 event_index: 17,
323 },
324 ],
325 };
326
327 let response_json = serde_json::to_string(&response_msg).unwrap();
328 ws_sender
329 .send(tungstenite::Message::Text(response_json))
330 .await
331 .unwrap();
332 let response_msg = ResponseMessage::Events {
333 key: Key::Variant(0, 1),
334 events: vec![Event {
335 block_number: 102,
336 event_index: 12,
337 }],
338 };
339
340 let response_json = serde_json::to_string(&response_msg).unwrap();
341 ws_sender
342 .send(tungstenite::Message::Text(response_json))
343 .await
344 .unwrap();
345
346 let response_msg = ResponseMessage::Events {
347 key: Key::Variant(0, 0),
348 events: vec![Event {
349 block_number: 102,
350 event_index: 12,
351 }],
352 };
353
354 let response_json = serde_json::to_string(&response_msg).unwrap();
355 ws_sender
356 .send(tungstenite::Message::Text(response_json))
357 .await
358 .unwrap();
359
360 let response_msg = ResponseMessage::Events {
361 key: Key::Variant(0, 0),
362 events: vec![Event {
363 block_number: 108,
364 event_index: 0,
365 }],
366 };
367
368 let response_json = serde_json::to_string(&response_msg).unwrap();
369 ws_sender
370 .send(tungstenite::Message::Text(response_json))
371 .await
372 .unwrap();
373 let msg = ws_receiver.next().await.unwrap().unwrap();
374 let request_msg: RequestMessage = serde_json::from_str(msg.to_text().unwrap()).unwrap();
375 match request_msg {
376 RequestMessage::UnsubscribeEvents { .. } => ResponseMessage::Unsubscribed,
377 _ => ResponseMessage::Error,
378 }
379 }
380 RequestMessage::SizeOnDisk => ResponseMessage::SizeOnDisk(640),
381 _ => ResponseMessage::Error,
382 };
383 let response_json = serde_json::to_string(&response_msg).unwrap();
384 ws_sender
385 .send(tungstenite::Message::Text(response_json))
386 .await
387 .unwrap();
388}
389
390#[cfg(test)]
391mod tests {
392 use super::*;
393
394 #[tokio::test]
395 async fn test_status() {
396 let mut index = Index::test_connect().await.unwrap();
397 let status = index.status().await.unwrap();
398
399 assert_eq!(
400 status,
401 vec![
402 Span { start: 2, end: 4 },
403 Span { start: 9, end: 23 },
404 Span {
405 start: 20002,
406 end: 400000,
407 },
408 ]
409 );
410 }
411
412 #[tokio::test]
413 async fn test_subscribe_status() {
414 let mut index = Index::test_connect().await.unwrap();
415 let mut stream = index.subscribe_status().await.unwrap();
416 let status = stream.next().await.unwrap().unwrap();
417
418 assert_eq!(
419 status,
420 vec![
421 Span { start: 2, end: 4 },
422 Span { start: 9, end: 23 },
423 Span {
424 start: 20002,
425 end: 400000,
426 },
427 ]
428 );
429
430 let status = stream.next().await.unwrap().unwrap();
431
432 assert_eq!(
433 status,
434 vec![
435 Span { start: 2, end: 4 },
436 Span { start: 9, end: 23 },
437 Span {
438 start: 20002,
439 end: 400008,
440 },
441 ]
442 );
443 let status = stream.next().await.unwrap().unwrap();
444
445 assert_eq!(
446 status,
447 vec![
448 Span { start: 2, end: 4 },
449 Span { start: 9, end: 23 },
450 Span {
451 start: 20002,
452 end: 400028,
453 },
454 ]
455 );
456 drop(stream);
457 index.unsubscribe_status().await.unwrap();
458 }
459
460 #[tokio::test]
461 async fn test_variants() {
462 let mut index = Index::test_connect().await.unwrap();
463 let variants = index.get_variants().await.unwrap();
464
465 assert_eq!(
466 variants,
467 vec![PalletMeta {
468 index: 0,
469 name: "test1".to_string(),
470 events: vec![EventMeta {
471 index: 0,
472 name: "event1".to_string()
473 }]
474 },]
475 );
476 }
477
478 #[tokio::test]
479 async fn test_get_events() {
480 let mut index = Index::test_connect().await.unwrap();
481 let events = index.get_events(Key::Variant(0, 0)).await.unwrap();
482
483 assert_eq!(
484 events,
485 vec![
486 Event {
487 block_number: 82,
488 event_index: 16,
489 },
490 Event {
491 block_number: 86,
492 event_index: 17,
493 },
494 ]
495 );
496 }
497
498 #[tokio::test]
499 async fn test_subscribe_events() {
500 let mut index = Index::test_connect().await.unwrap();
501 let mut stream = index.subscribe_events(Key::Variant(0, 0)).await.unwrap();
502 let events = stream.next().await.unwrap().unwrap();
503
504 assert_eq!(
505 events,
506 vec![
507 Event {
508 block_number: 82,
509 event_index: 16,
510 },
511 Event {
512 block_number: 86,
513 event_index: 17,
514 },
515 ]
516 );
517
518 let events = stream.next().await.unwrap().unwrap();
519
520 assert_eq!(events, vec![]);
521 let events = stream.next().await.unwrap().unwrap();
522
523 assert_eq!(
524 events,
525 vec![Event {
526 block_number: 102,
527 event_index: 12,
528 }]
529 );
530 let events = stream.next().await.unwrap().unwrap();
531
532 assert_eq!(
533 events,
534 vec![Event {
535 block_number: 108,
536 event_index: 0,
537 }]
538 );
539 drop(stream);
540 index.unsubscribe_events(Key::Variant(0, 0)).await.unwrap();
541 }
542
543 #[tokio::test]
544 async fn test_size_on_disk() {
545 let mut index = Index::test_connect().await.unwrap();
546 let size = index.size_on_disk().await.unwrap();
547
548 assert_eq!(size, 640);
549 }
550}