Skip to main content

acuity_index_substrate_api/
lib.rs

1//! A library for querying indexes built with Acuity Index Substrate.
2
3pub 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/// Errors this crate can return
18#[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
28/// Indexer state and methods
29pub struct Index {
30    ws_stream: WebSocketStream<MaybeTlsStream<TcpStream>>,
31}
32
33impl Index {
34    /// Send a RequestMessage and wait for a ResponseMessage
35    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    /// Connect to a Acuity Substrate Index node via WebSocket
44    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    /// Request status.
51    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    /// Subscribe to a stream of status updates.
59    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        // Return a stream that emits each ResponseMessage as it is received.
68        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    /// Unsubscribe to a stream of status updates.
79    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    /// Request size on disk.
87    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    /// Request a list of all event variants being indexed.
95    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    /// Get events that have emitted a specific key.
103    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    /// Subscribe to events that have emitted a specific key.
111    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        // Return a stream that emits each ResponseMessage as it is received.
125        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    /// Unsubscribe to an event subscription.
139    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/// Top-level key types that can be queried for
151#[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/// JSON request messages
159#[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/// JSON response messages
173#[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}