1#![doc = include_str!("../README.md")]
2#![allow(clippy::module_inception)]
3
4use std::{
5 path::Path,
6 sync::{Arc, RwLock},
7};
8
9use brk_computer::Computer;
10use brk_error::{OptionData, Result};
11use brk_indexer::{Indexer, Lengths};
12use brk_mempool::Mempool;
13use brk_oracle::Oracle;
14use brk_reader::Reader;
15use brk_rpc::Client;
16use brk_types::{BlockHash, BlockHashPrefix, Height, SyncStatus};
17use vecdb::{ReadOnlyClone, ReadableVec, Ro};
18
19#[cfg(feature = "tokio")]
20mod r#async;
21mod vecs;
22
23mod r#impl;
24
25#[cfg(feature = "tokio")]
26pub use r#async::*;
27pub use r#impl::ResolvedQuery;
28pub use vecs::Vecs;
29
30#[derive(Clone)]
31pub struct Query(Arc<QueryInner<'static>>);
32struct QueryInner<'a> {
33 vecs: &'a Vecs<'a>,
34 client: Client,
35 reader: Reader,
36 indexer: &'a Indexer<Ro>,
37 computer: &'a Computer<Ro>,
38 mempool: Option<Mempool>,
39 live_oracle: RwLock<Option<(Height, Arc<Oracle>)>>,
40}
41
42impl Query {
43 pub fn build(
44 reader: &Reader,
45 indexer: &Indexer,
46 computer: &Computer,
47 mempool: Option<Mempool>,
48 ) -> Self {
49 let client = reader.client().clone();
50 let reader = reader.clone();
51 let indexer = Box::leak(Box::new(indexer.read_only_clone()));
52 let computer = Box::leak(Box::new(computer.read_only_clone()));
53 let vecs = Box::leak(Box::new(Vecs::build(indexer, computer)));
54
55 Self(Arc::new(QueryInner {
56 vecs,
57 client,
58 reader,
59 indexer,
60 computer,
61 mempool,
62 live_oracle: RwLock::new(None),
63 }))
64 }
65
66 pub fn height(&self) -> Height {
77 self.safe_lengths().height.decremented().unwrap_or_default()
78 }
79
80 pub(crate) fn safe_lengths(&self) -> Lengths {
83 self.indexer().safe_lengths()
84 }
85
86 #[inline]
88 pub fn tip_blockhash(&self) -> BlockHash {
89 self.indexer().tip_blockhash()
90 }
91
92 #[inline]
94 pub fn tip_hash_prefix(&self) -> BlockHashPrefix {
95 BlockHashPrefix::from(&self.tip_blockhash())
96 }
97
98 pub fn sync_status(&self, tip_height: Height) -> Result<SyncStatus> {
103 let indexed_height = self.indexer().indexed_height();
104 let computed_height = self.computer().computed_height();
105 let blocks_behind = Height::from(tip_height.saturating_sub(*indexed_height));
106 let last_indexed_at_unix = self
107 .indexer()
108 .vecs
109 .blocks
110 .timestamp
111 .collect_one(self.height())
112 .data()?;
113
114 Ok(SyncStatus {
115 indexed_height,
116 computed_height,
117 tip_height,
118 blocks_behind,
119 last_indexed_at: last_indexed_at_unix.to_iso8601(),
120 last_indexed_at_unix,
121 })
122 }
123
124 #[inline]
125 pub fn reader(&self) -> &Reader {
126 &self.0.reader
127 }
128
129 #[inline]
130 pub fn client(&self) -> &Client {
131 &self.0.client
132 }
133
134 #[inline]
135 pub fn blocks_dir(&self) -> &Path {
136 self.0.reader.blocks_dir()
137 }
138
139 #[inline]
140 pub fn indexer(&self) -> &Indexer<Ro> {
141 self.0.indexer
142 }
143
144 #[inline]
145 pub fn computer(&self) -> &Computer<Ro> {
146 self.0.computer
147 }
148
149 #[inline]
150 pub fn mempool(&self) -> Option<&Mempool> {
151 self.0.mempool.as_ref()
152 }
153
154 #[inline]
155 pub fn vecs(&self) -> &'static Vecs<'static> {
156 self.0.vecs
157 }
158}