diff --git a/crates/brk_cli/src/query.rs b/crates/brk_cli/src/query.rs index 50372c45e..5dfbc45b8 100644 --- a/crates/brk_cli/src/query.rs +++ b/crates/brk_cli/src/query.rs @@ -1,4 +1,5 @@ use brk_computer::Computer; +use brk_fetcher::Fetcher; use brk_indexer::Indexer; use brk_query::{Index, Output, Params as QueryParams, Query, Tabled, Value}; use tabled::settings::Style; @@ -13,7 +14,7 @@ pub fn query(params: QueryParams) -> color_eyre::Result<()> { let mut indexer = Indexer::new(config.indexeddir(), compressed, config.check_collisions())?; indexer.import_vecs()?; - let mut computer = Computer::new(config.computeddir(), None, compressed); + let mut computer = Computer::new(config.computeddir(), config.fetcher(), compressed); computer.import_vecs()?; let query = Query::build(&indexer, &computer); diff --git a/crates/brk_cli/src/run.rs b/crates/brk_cli/src/run.rs index f376f9714..4526ece6a 100644 --- a/crates/brk_cli/src/run.rs +++ b/crates/brk_cli/src/run.rs @@ -32,11 +32,7 @@ pub fn run(config: RunConfig) -> color_eyre::Result<()> { indexer.import_stores()?; indexer.import_vecs()?; - let fetcher = config - .fetch() - .then(|| Fetcher::import(Some(config.harsdir().as_path())).unwrap()); - - let mut computer = Computer::new(config.computeddir(), fetcher, compressed); + let mut computer = Computer::new(config.computeddir(), config.fetcher(), compressed); computer.import_stores()?; computer.import_vecs()?; @@ -401,6 +397,11 @@ impl RunConfig { self.fetch.is_none_or(|b| b) } + pub fn fetcher(&self) -> Option { + self.fetch() + .then(|| Fetcher::import(Some(self.harsdir().as_path())).unwrap()) + } + pub fn compressed(&self) -> bool { self.compressed.is_none_or(|b| b) } diff --git a/crates/brk_computer/src/storage/vecs/indexes.rs b/crates/brk_computer/src/storage/vecs/indexes.rs index 9ab3d2a19..b4fb180dd 100644 --- a/crates/brk_computer/src/storage/vecs/indexes.rs +++ b/crates/brk_computer/src/storage/vecs/indexes.rs @@ -1,8 +1,8 @@ use std::{fs, ops::Deref, path::Path}; use brk_core::{ - Date, Dateindex, Decadeindex, Difficultyepoch, Halvingepoch, Height, Monthindex, Timestamp, - Txindex, Txinindex, Txoutindex, Weekindex, Yearindex, + Date, Dateindex, Decadeindex, Difficultyepoch, Halvingepoch, Height, Monthindex, Quarterindex, + Timestamp, Txindex, Txinindex, Txoutindex, Weekindex, Yearindex, }; use brk_exit::Exit; use brk_indexer::Indexer; @@ -35,8 +35,8 @@ pub struct Vecs { pub halvingepoch_to_timestamp: StorableVec, pub height_to_dateindex: StorableVec, pub height_to_difficultyepoch: StorableVec, - pub height_to_fixed_timestamp: StorableVec, pub height_to_fixed_date: StorableVec, + pub height_to_fixed_timestamp: StorableVec, pub height_to_halvingepoch: StorableVec, pub height_to_height: StorableVec, pub height_to_last_txindex: StorableVec, @@ -44,8 +44,13 @@ pub struct Vecs { pub monthindex_to_first_dateindex: StorableVec, pub monthindex_to_last_dateindex: StorableVec, pub monthindex_to_monthindex: StorableVec, + pub monthindex_to_quarterindex: StorableVec, pub monthindex_to_timestamp: StorableVec, pub monthindex_to_yearindex: StorableVec, + pub quarterindex_to_first_monthindex: StorableVec, + pub quarterindex_to_last_monthindex: StorableVec, + pub quarterindex_to_quarterindex: StorableVec, + pub quarterindex_to_timestamp: StorableVec, pub txindex_to_last_txinindex: StorableVec, pub txindex_to_last_txoutindex: StorableVec, pub weekindex_to_first_dateindex: StorableVec, @@ -279,6 +284,31 @@ impl Vecs { Version::from(1), compressed, )?, + monthindex_to_quarterindex: StorableVec::forced_import( + &path.join("monthindex_to_quarterindex"), + Version::from(1), + compressed, + )?, + quarterindex_to_first_monthindex: StorableVec::forced_import( + &path.join("quarterindex_to_first_monthindex"), + Version::from(1), + compressed, + )?, + quarterindex_to_last_monthindex: StorableVec::forced_import( + &path.join("quarterindex_to_last_monthindex"), + Version::from(1), + compressed, + )?, + quarterindex_to_quarterindex: StorableVec::forced_import( + &path.join("quarterindex_to_quarterindex"), + Version::from(1), + compressed, + )?, + quarterindex_to_timestamp: StorableVec::forced_import( + &path.join("quarterindex_to_timestamp"), + Version::from(1), + compressed, + )?, }) } @@ -509,6 +539,52 @@ impl Vecs { // --- + let starting_quarterindex = self + .monthindex_to_quarterindex + .get(starting_monthindex)? + .copied() + .unwrap_or_default(); + + self.monthindex_to_quarterindex.compute_transform( + starting_monthindex, + self.monthindex_to_monthindex.mut_vec(), + |(mi, ..)| (mi, Quarterindex::from(mi)), + exit, + )?; + + self.quarterindex_to_first_monthindex + .compute_inverse_more_to_less( + starting_monthindex, + self.monthindex_to_quarterindex.mut_vec(), + exit, + )?; + + // let quarter_count = self.quarterindex_to_first_monthindex.len(); + + self.quarterindex_to_last_monthindex + .compute_last_index_from_first( + starting_quarterindex, + self.quarterindex_to_first_monthindex.mut_vec(), + month_count, + exit, + )?; + + self.quarterindex_to_quarterindex.compute_transform( + starting_quarterindex, + self.quarterindex_to_first_monthindex.mut_vec(), + |(yi, ..)| (yi, yi), + exit, + )?; + + self.quarterindex_to_timestamp.compute_transform( + starting_quarterindex, + self.quarterindex_to_first_monthindex.mut_vec(), + |(i, m, ..)| (i, *self.monthindex_to_timestamp.get(m).unwrap().unwrap()), + exit, + )?; + + // --- + let starting_yearindex = self .monthindex_to_yearindex .get(starting_monthindex)? @@ -700,6 +776,7 @@ impl Vecs { dateindex: starting_dateindex, weekindex: starting_weekindex, monthindex: starting_monthindex, + quarterindex: starting_quarterindex, yearindex: starting_yearindex, decadeindex: starting_decadeindex, difficultyepoch: starting_difficultyepoch, @@ -752,6 +829,11 @@ impl Vecs { self.weekindex_to_timestamp.any_vec(), self.yearindex_to_timestamp.any_vec(), self.height_to_fixed_timestamp.any_vec(), + self.monthindex_to_quarterindex.any_vec(), + self.quarterindex_to_first_monthindex.any_vec(), + self.quarterindex_to_last_monthindex.any_vec(), + self.quarterindex_to_quarterindex.any_vec(), + self.quarterindex_to_timestamp.any_vec(), ] } } @@ -761,6 +843,7 @@ pub struct Indexes { pub dateindex: Dateindex, pub weekindex: Weekindex, pub monthindex: Monthindex, + pub quarterindex: Quarterindex, pub yearindex: Yearindex, pub decadeindex: Decadeindex, pub difficultyepoch: Difficultyepoch, diff --git a/crates/brk_computer/src/storage/vecs/marketprice.rs b/crates/brk_computer/src/storage/vecs/marketprice.rs index a7ad2e19e..acc78acfd 100644 --- a/crates/brk_computer/src/storage/vecs/marketprice.rs +++ b/crates/brk_computer/src/storage/vecs/marketprice.rs @@ -2,7 +2,7 @@ use std::{fs, path::Path}; use brk_core::{ Cents, Close, Dateindex, Decadeindex, Difficultyepoch, Dollars, Height, High, Low, Monthindex, - OHLCCents, OHLCDollars, Open, Sats, Weekindex, Yearindex, + OHLCCents, OHLCDollars, Open, Quarterindex, Sats, Weekindex, Yearindex, }; use brk_exit::Exit; use brk_fetcher::Fetcher; @@ -53,6 +53,7 @@ pub struct Vecs { pub weekindex_to_ohlc: StorableVec, pub difficultyepoch_to_ohlc: StorableVec, pub monthindex_to_ohlc: StorableVec, + pub quarterindex_to_ohlc: StorableVec, pub yearindex_to_ohlc: StorableVec, // pub halvingepoch_to_ohlc: StorableVec, pub decadeindex_to_ohlc: StorableVec, @@ -238,6 +239,11 @@ impl Vecs { Version::from(1), compressed, )?, + quarterindex_to_ohlc: StorableVec::forced_import( + &path.join("quarterindex_to_ohlc"), + Version::from(1), + compressed, + )?, yearindex_to_ohlc: StorableVec::forced_import( &path.join("yearindex_to_ohlc"), Version::from(1), @@ -623,6 +629,52 @@ impl Vecs { exit, )?; + self.quarterindex_to_ohlc.compute_transform( + starting_indexes.quarterindex, + self.timeindexes_to_close + .quarterindex + .last + .as_mut() + .unwrap() + .mut_vec(), + |(i, close, ..)| { + ( + i, + OHLCDollars { + open: *self + .timeindexes_to_open + .quarterindex + .first + .as_mut() + .unwrap() + .get(i) + .unwrap() + .unwrap(), + high: *self + .timeindexes_to_high + .quarterindex + .max + .as_mut() + .unwrap() + .get(i) + .unwrap() + .unwrap(), + low: *self + .timeindexes_to_low + .quarterindex + .min + .as_mut() + .unwrap() + .get(i) + .unwrap() + .unwrap(), + close, + }, + ) + }, + exit, + )?; + self.yearindex_to_ohlc.compute_transform( starting_indexes.yearindex, self.timeindexes_to_close @@ -750,6 +802,7 @@ impl Vecs { self.weekindex_to_ohlc.any_vec(), self.difficultyepoch_to_ohlc.any_vec(), self.monthindex_to_ohlc.any_vec(), + self.quarterindex_to_ohlc.any_vec(), self.yearindex_to_ohlc.any_vec(), // self.halvingepoch_to_ohlc.any_vec(), self.decadeindex_to_ohlc.any_vec(), diff --git a/crates/brk_computer/src/storage/vecs/stats/from_date.rs b/crates/brk_computer/src/storage/vecs/stats/from_date.rs index bde328afb..20517e732 100644 --- a/crates/brk_computer/src/storage/vecs/stats/from_date.rs +++ b/crates/brk_computer/src/storage/vecs/stats/from_date.rs @@ -1,6 +1,6 @@ use std::path::Path; -use brk_core::{Dateindex, Decadeindex, Monthindex, Weekindex, Yearindex}; +use brk_core::{Dateindex, Decadeindex, Monthindex, Quarterindex, Weekindex, Yearindex}; use brk_exit::Exit; use brk_vec::{AnyStorableVec, Compressed}; @@ -15,6 +15,7 @@ where { pub weekindex: StorableVecBuilder, pub monthindex: StorableVecBuilder, + pub quarterindex: StorableVecBuilder, pub yearindex: StorableVecBuilder, pub decadeindex: StorableVecBuilder, } @@ -34,6 +35,7 @@ where Ok(Self { weekindex: StorableVecBuilder::forced_import(path, compressed, options)?, monthindex: StorableVecBuilder::forced_import(path, compressed, options)?, + quarterindex: StorableVecBuilder::forced_import(path, compressed, options)?, yearindex: StorableVecBuilder::forced_import(path, compressed, options)?, decadeindex: StorableVecBuilder::forced_import(path, compressed, options)?, }) @@ -62,6 +64,14 @@ where exit, )?; + self.quarterindex.from_aligned( + starting_indexes.quarterindex, + &mut self.monthindex, + indexes.quarterindex_to_first_monthindex.mut_vec(), + indexes.quarterindex_to_last_monthindex.mut_vec(), + exit, + )?; + self.yearindex.from_aligned( starting_indexes.yearindex, &mut self.monthindex, @@ -85,6 +95,7 @@ where [ self.weekindex.as_any_vecs(), self.monthindex.as_any_vecs(), + self.quarterindex.as_any_vecs(), self.yearindex.as_any_vecs(), self.decadeindex.as_any_vecs(), ] diff --git a/crates/brk_computer/src/storage/vecs/stats/from_height.rs b/crates/brk_computer/src/storage/vecs/stats/from_height.rs index baa859c86..8d9625a41 100644 --- a/crates/brk_computer/src/storage/vecs/stats/from_height.rs +++ b/crates/brk_computer/src/storage/vecs/stats/from_height.rs @@ -1,6 +1,8 @@ use std::path::Path; -use brk_core::{Dateindex, Decadeindex, Difficultyepoch, Height, Monthindex, Weekindex, Yearindex}; +use brk_core::{ + Dateindex, Decadeindex, Difficultyepoch, Height, Monthindex, Quarterindex, Weekindex, Yearindex, +}; use brk_exit::Exit; use brk_vec::{AnyStorableVec, Compressed}; @@ -17,6 +19,7 @@ where pub weekindex: StorableVecBuilder, pub difficultyepoch: StorableVecBuilder, pub monthindex: StorableVecBuilder, + pub quarterindex: StorableVecBuilder, pub yearindex: StorableVecBuilder, // TODO: pub halvingepoch: StorableVecGeneator, pub decadeindex: StorableVecBuilder, @@ -41,6 +44,7 @@ where weekindex: StorableVecBuilder::forced_import(path, compressed, options)?, difficultyepoch: StorableVecBuilder::forced_import(path, compressed, options)?, monthindex: StorableVecBuilder::forced_import(path, compressed, options)?, + quarterindex: StorableVecBuilder::forced_import(path, compressed, options)?, yearindex: StorableVecBuilder::forced_import(path, compressed, options)?, // halvingepoch: StorableVecGeneator::forced_import(path, compressed, options)?, decadeindex: StorableVecBuilder::forced_import(path, compressed, options)?, @@ -78,6 +82,14 @@ where exit, )?; + self.quarterindex.from_aligned( + starting_indexes.quarterindex, + &mut self.monthindex, + indexes.quarterindex_to_first_monthindex.mut_vec(), + indexes.quarterindex_to_last_monthindex.mut_vec(), + exit, + )?; + self.yearindex.from_aligned( starting_indexes.yearindex, &mut self.monthindex, @@ -111,6 +123,7 @@ where self.weekindex.as_any_vecs(), self.difficultyepoch.as_any_vecs(), self.monthindex.as_any_vecs(), + self.quarterindex.as_any_vecs(), self.yearindex.as_any_vecs(), // self.halvingepoch.as_any_vecs(), self.decadeindex.as_any_vecs(), diff --git a/crates/brk_core/src/structs/mod.rs b/crates/brk_core/src/structs/mod.rs index cad8d3cb8..1436328c5 100644 --- a/crates/brk_core/src/structs/mod.rs +++ b/crates/brk_core/src/structs/mod.rs @@ -18,6 +18,7 @@ mod height; mod locktime; mod monthindex; mod ohlc; +mod quarterindex; mod sats; mod timestamp; mod txid; @@ -52,6 +53,7 @@ pub use height::*; pub use locktime::*; pub use monthindex::*; pub use ohlc::*; +pub use quarterindex::*; pub use sats::*; pub use timestamp::*; pub use txid::*; diff --git a/crates/brk_core/src/structs/quarterindex.rs b/crates/brk_core/src/structs/quarterindex.rs new file mode 100644 index 000000000..e3b2fbb33 --- /dev/null +++ b/crates/brk_core/src/structs/quarterindex.rs @@ -0,0 +1,64 @@ +use std::{fmt::Debug, ops::Add}; + +use serde::{Deserialize, Serialize}; +use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout}; + +use crate::CheckedSub; + +use super::Monthindex; + +#[derive( + Debug, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Default, + Serialize, + Deserialize, + FromBytes, + Immutable, + IntoBytes, + KnownLayout, +)] +pub struct Quarterindex(u16); + +impl From for Quarterindex { + fn from(value: u16) -> Self { + Self(value) + } +} + +impl From for Quarterindex { + fn from(value: usize) -> Self { + Self(value as u16) + } +} + +impl From for usize { + fn from(value: Quarterindex) -> Self { + value.0 as usize + } +} + +impl Add for Quarterindex { + type Output = Self; + + fn add(self, rhs: usize) -> Self::Output { + Self::from(self.0 + rhs as u16) + } +} + +impl From for Quarterindex { + fn from(value: Monthindex) -> Self { + Self((usize::from(value) / 3) as u16) + } +} + +impl CheckedSub for Quarterindex { + fn checked_sub(self, rhs: Self) -> Option { + self.0.checked_sub(rhs.0).map(Self) + } +} diff --git a/crates/brk_query/src/index.rs b/crates/brk_query/src/index.rs index 03a2d2238..1a44ee37f 100644 --- a/crates/brk_query/src/index.rs +++ b/crates/brk_query/src/index.rs @@ -19,6 +19,7 @@ pub enum Index { Txoutindex, Weekindex, Monthindex, + Quarterindex, Yearindex, Decadeindex, Difficultyepoch, @@ -26,11 +27,18 @@ pub enum Index { } impl Index { - pub fn all() -> [Self; 19] { + pub fn all() -> [Self; 20] { [ - Self::Addressindex, - Self::Dateindex, Self::Height, + Self::Dateindex, + Self::Weekindex, + Self::Difficultyepoch, + Self::Monthindex, + Self::Quarterindex, + Self::Yearindex, + Self::Decadeindex, + Self::Halvingepoch, + Self::Addressindex, Self::P2PK33index, Self::P2PK65index, Self::P2PKHindex, @@ -41,37 +49,32 @@ impl Index { Self::Txindex, Self::Txinindex, Self::Txoutindex, - Self::Weekindex, - Self::Monthindex, - Self::Yearindex, - Self::Decadeindex, - Self::Difficultyepoch, - Self::Halvingepoch, ] } pub fn possible_values(&self) -> &[&str] { // Always have the "correct" id at the end match self { - Self::Dateindex => &["d", "date", "di", "dateindex"], Self::Height => &["h", "height"], - Self::Txindex => &["txi", "txindex"], - Self::Txinindex => &["txini", "txinindex"], - Self::Txoutindex => &["txouti", "txoutindex"], - Self::Addressindex => &["addri", "addressindex"], - Self::P2PK33index => &["p2pk33i", "p2pk33index"], - Self::P2PK65index => &["p2pk65i", "p2pk65index"], - Self::P2PKHindex => &["p2pkhi", "p2pkhindex"], - Self::P2SHindex => &["p2shi", "p2shindex"], - Self::P2TRindex => &["p2tri", "p2trindex"], - Self::P2WPKHindex => &["p2wpkhi", "p2wpkhindex"], - Self::P2WSHindex => &["p2wshi", "p2wshindex"], - Self::Weekindex => &["w", "wi", "week", "weekindex"], - Self::Monthindex => &["m", "mi", "month", "monthindex"], - Self::Yearindex => &["y", "yi", "year", "yearindex"], - Self::Decadeindex => &["decade", "decadeindex"], + Self::Dateindex => &["d", "date", "dateindex"], + Self::Weekindex => &["w", "week", "weekindex"], Self::Difficultyepoch => &["difficulty", "difficultyepoch"], - Self::Halvingepoch => &["halving", "halvingepoch"], + Self::Monthindex => &["m", "month", "monthindex"], + Self::Quarterindex => &["q", "quarter", "quarterindex"], + Self::Yearindex => &["y", "year", "yearindex"], + Self::Decadeindex => &["decade", "decadeindex"], + Self::Halvingepoch => &["h", "halving", "halvingepoch"], + Self::Txindex => &["tx", "txindex"], + Self::Txinindex => &["txin", "txinindex"], + Self::Txoutindex => &["txout", "txoutindex"], + Self::Addressindex => &["a", "address", "addressindex"], + Self::P2PK33index => &["p2pk33", "p2pk33index"], + Self::P2PK65index => &["p2pk65", "p2pk65index"], + Self::P2PKHindex => &["p2pkh", "p2pkhindex"], + Self::P2SHindex => &["p2sh", "p2shindex"], + Self::P2TRindex => &["p2tr", "p2trindex"], + Self::P2WPKHindex => &["p2wpkh", "p2wpkhindex"], + Self::P2WSHindex => &["p2wsh", "p2wshindex"], } } @@ -81,6 +84,18 @@ impl Index { .flat_map(|i| i.possible_values().iter().map(|s| s.to_string())) .collect::>() } + + pub fn serialize_short(&self) -> String { + self.possible_values() + .iter() + .find(|str| str.len() > 1) + .unwrap() + .to_string() + } + + pub fn serialize_long(&self) -> String { + self.possible_values().last().unwrap().to_string() + } } impl TryFrom<&str> for Index { @@ -106,6 +121,7 @@ impl TryFrom<&str> for Index { v if (Self::Decadeindex).possible_values().contains(&v) => Self::Decadeindex, v if (Self::Difficultyepoch).possible_values().contains(&v) => Self::Difficultyepoch, v if (Self::Halvingepoch).possible_values().contains(&v) => Self::Halvingepoch, + v if (Self::Quarterindex).possible_values().contains(&v) => Self::Quarterindex, _ => return Err(eyre!("Bad index")), }) } diff --git a/crates/brk_query/src/lib.rs b/crates/brk_query/src/lib.rs index 9ed1522d8..a08e7396d 100644 --- a/crates/brk_query/src/lib.rs +++ b/crates/brk_query/src/lib.rs @@ -13,39 +13,39 @@ mod index; mod output; mod params; mod table; -mod tree; +mod vec_trees; pub use format::Format; pub use index::Index; pub use output::{Output, Value}; pub use params::Params; pub use table::Tabled; -use tree::VecIdToIndexToVec; +use vec_trees::VecTrees; pub struct Query<'a> { - pub vecid_to_index_to_vec: VecIdToIndexToVec<'a>, + pub vec_trees: VecTrees<'a>, _indexer: &'a Indexer, _computer: &'a Computer, } impl<'a> Query<'a> { pub fn build(indexer: &'a Indexer, computer: &'a Computer) -> Self { - let mut vecs = VecIdToIndexToVec::default(); + let mut vec_trees = VecTrees::default(); indexer .vecs() .as_any_vecs() .into_iter() - .for_each(|vec| vecs.insert(vec)); + .for_each(|vec| vec_trees.insert(vec)); computer .vecs() .as_any_vecs() .into_iter() - .for_each(|vec| vecs.insert(vec)); + .for_each(|vec| vec_trees.insert(vec)); Self { - vecid_to_index_to_vec: vecs, + vec_trees, _indexer: indexer, _computer: computer, } @@ -65,11 +65,11 @@ impl<'a> Query<'a> { .collect::>() }) .map(|mut id| { - let mut res = self.vecid_to_index_to_vec.get(&id); + let mut res = self.vec_trees.id_to_index_to_vec.get(&id); if res.is_none() { if let Ok(index) = Index::try_from(id.as_str()) { id = index.possible_values().last().unwrap().to_string(); - res = self.vecid_to_index_to_vec.get(&id) + res = self.vec_trees.id_to_index_to_vec.get(&id) } } (id, res) diff --git a/crates/brk_query/src/tree.rs b/crates/brk_query/src/tree.rs deleted file mode 100644 index 193510ff1..000000000 --- a/crates/brk_query/src/tree.rs +++ /dev/null @@ -1,44 +0,0 @@ -use std::collections::BTreeMap; - -use brk_vec::AnyStorableVec; -use derive_deref::{Deref, DerefMut}; - -use super::index::Index; - -#[derive(Default, Deref, DerefMut)] -pub struct VecIdToIndexToVec<'a>(BTreeMap>); - -impl<'a> VecIdToIndexToVec<'a> { - // Not the most performant or type safe but only built once so that's okay - pub fn insert(&mut self, vec: &'a dyn AnyStorableVec) { - let file_name = vec.file_name(); - let split = file_name.split("_to_").collect::>(); - if split.len() != 2 { - panic!(); - } - let str = vec - .index_type_to_string() - .split("::") - .last() - .unwrap() - .to_lowercase(); - let index = Index::try_from(str.as_str()) - .inspect_err(|_| { - dbg!(&str); - }) - .unwrap(); - if split[0] != index.to_string().to_lowercase() { - dbg!(&file_name, split[0], index.to_string()); - panic!(); - } - let key = split[1].to_string().replace("_", "-"); - let prev = self.entry(key.clone()).or_default().insert(index, vec); - if prev.is_some() { - dbg!(&key, str, file_name); - panic!() - } - } -} - -#[derive(Default, Deref, DerefMut)] -pub struct IndexToVec<'a>(BTreeMap); diff --git a/crates/brk_query/src/vec_trees.rs b/crates/brk_query/src/vec_trees.rs new file mode 100644 index 000000000..982f1f2bc --- /dev/null +++ b/crates/brk_query/src/vec_trees.rs @@ -0,0 +1,93 @@ +use std::collections::BTreeMap; + +use brk_vec::AnyStorableVec; +use derive_deref::{Deref, DerefMut}; + +use super::index::Index; + +#[derive(Default)] +pub struct VecTrees<'a> { + pub id_to_index_to_vec: BTreeMap>, + pub index_to_id_to_vec: BTreeMap>, +} + +impl<'a> VecTrees<'a> { + // Not the most performant or type safe but only built once so that's okay + pub fn insert(&mut self, vec: &'a dyn AnyStorableVec) { + let file_name = vec.file_name(); + let split = file_name.split("_to_").collect::>(); + if split.len() != 2 { + panic!(); + } + let str = vec + .index_type_to_string() + .split("::") + .last() + .unwrap() + .to_lowercase(); + let index = Index::try_from(str.as_str()) + .inspect_err(|_| { + dbg!(&str); + }) + .unwrap(); + if split[0] != index.to_string().to_lowercase() { + dbg!(&file_name, split[0], index.to_string()); + panic!(); + } + let key = split[1].to_string().replace("_", "-"); + let prev = self + .id_to_index_to_vec + .entry(key.clone()) + .or_default() + .insert(index.clone(), vec); + if prev.is_some() { + dbg!(&key, str, file_name); + panic!() + } + let prev = self + .index_to_id_to_vec + .entry(index) + .or_default() + .insert(key.clone(), vec); + if prev.is_some() { + dbg!(&key, str, file_name); + panic!() + } + } + + pub fn serialize_id_to_index_to_vec(&self) -> BTreeMap> { + self.id_to_index_to_vec + .iter() + .map(|(id, index_to_vec)| { + ( + id.to_string(), + index_to_vec + .keys() + .map(|i| i.serialize_long()) + .collect::>(), + ) + }) + .collect() + } + + pub fn serialize_index_to_id_to_vec(&self) -> BTreeMap> { + self.index_to_id_to_vec + .iter() + .map(|(index, id_to_vec)| { + ( + index.serialize_long(), + id_to_vec + .keys() + .map(|id| id.to_string()) + .collect::>(), + ) + }) + .collect() + } +} + +#[derive(Default, Deref, DerefMut)] +pub struct IndexToVec<'a>(BTreeMap); + +#[derive(Default, Deref, DerefMut)] +pub struct IdToVec<'a>(BTreeMap); diff --git a/crates/brk_server/README.md b/crates/brk_server/README.md index 5e8c1283c..c07a4dc66 100644 --- a/crates/brk_server/README.md +++ b/crates/brk_server/README.md @@ -39,3 +39,52 @@ A crate that serves Bitcoin data and swappable front-ends, built on top of `brk_ The file handler, will serve the website specified by the user if any, which can be *no website*, *kibo.money* or *custom* (which is a blank folder for people to experiment). If a website is specified and the server is ran outside of the brk project and thus can't find the requested website, it will download the whole project with the correct version from Github and store it in `.brk` to be able to serve to website. This is due to the crate size limit on [crates.io](https://crates.io) and the various shenanigans that need to be done to have a website in a crate. The API uses `brk_query` and so inherites all of its features including formats. + +## Endpoints + +### `GET /api/vecs/indexes` + +A list of all possible vec indexes and their accepted format + +### `GET /api/vecs/ids` + +A list of all possible vec ids + +### `GET /api/vecs/id-to-indexes` + +A list of all possible vec ids and their supported vec indexes + +### `GET /api/vecs/index-to-ids` + +A list of all possible vec indexes and their supported vec ids + +### `GET /api/query` + +This endpoint retrieves data based on the specified vector index and values. + +**Parameters:** + +| Parameter | Type | Required | Description | +| --- | --- | --- | --- | +| `index` | `VecIndex` | Yes | The vector index to query. | +| `values` | `VecId[]` | Yes | A comma or space-separated list of vector IDs to retrieve. | +| `from` | `unsigned int` | No | The starting index for pagination (default is 0). | +| `to` | `unsigned int` | No | The ending index for pagination (default is the total number of results). | +| `format` | `string` | No | The format of the response. Options include `json`, `csv`, `tsv`, or `md` (default is `json`). | + +**Examples:** + +``` +GET /api/query?index=date&values=ohlc +GET /api/query?index=week&values=ohlc,block-interval-average&from=0&to=20&format=md +``` + +### `GET /version` + +The version of the server and thus BRK. + +### `GET /*` + +Catch all. + +When no pattern is found, the server will look for a match inside the folder of the chosen website, if any. diff --git a/crates/brk_server/src/api/mod.rs b/crates/brk_server/src/api/mod.rs index b20d3652a..142802125 100644 --- a/crates/brk_server/src/api/mod.rs +++ b/crates/brk_server/src/api/mod.rs @@ -1,4 +1,11 @@ -use axum::{Router, routing::get}; +use std::collections::BTreeMap; + +use axum::{ + Router, + extract::State, + response::{IntoResponse, Response}, + routing::get, +}; use super::AppState; @@ -14,5 +21,42 @@ pub trait ApiRoutes { impl ApiRoutes for Router { fn add_api_routes(self) -> Self { self.route("/api/query", get(query::handler)) + .route("/api/vecs/ids", get(vecids_handler)) + .route("/api/vecs/indexes", get(vecindexes_handler)) + .route("/api/vecs/id-to-indexes", get(vecid_to_vecindexes_handler)) + .route("/api/vecs/index-to-ids", get(vecindex_to_vecids_handler)) } } + +pub async fn vecids_handler(State(app_state): State) -> Response { + axum::Json( + app_state + .query + .vec_trees + .id_to_index_to_vec + .keys() + .collect::>(), + ) + .into_response() +} + +pub async fn vecindexes_handler(State(app_state): State) -> Response { + axum::Json( + app_state + .query + .vec_trees + .index_to_id_to_vec + .keys() + .map(|i| (i.to_string().to_lowercase(), i.possible_values())) + .collect::>(), + ) + .into_response() +} + +pub async fn vecid_to_vecindexes_handler(State(app_state): State) -> Response { + axum::Json(app_state.query.vec_trees.serialize_id_to_index_to_vec()).into_response() +} + +pub async fn vecindex_to_vecids_handler(State(app_state): State) -> Response { + axum::Json(app_state.query.vec_trees.serialize_index_to_id_to_vec()).into_response() +} diff --git a/crates/brk_server/src/api/query/dts.rs b/crates/brk_server/src/api/query/dts.rs index 3163543f1..a9a42dd4b 100644 --- a/crates/brk_server/src/api/query/dts.rs +++ b/crates/brk_server/src/api/query/dts.rs @@ -64,7 +64,8 @@ impl DTS for Query<'static> { contents += "\n\n return {\n"; - self.vecid_to_index_to_vec + self.vec_trees + .id_to_index_to_vec .iter() .for_each(|(id, index_to_vec)| { let indexes = index_to_vec diff --git a/crates/brk_server/src/lib.rs b/crates/brk_server/src/lib.rs index 472837a1f..c14625b26 100644 --- a/crates/brk_server/src/lib.rs +++ b/crates/brk_server/src/lib.rs @@ -4,9 +4,11 @@ #![doc = "```"] use std::{ + collections::BTreeMap, fs, io::Cursor, path::{Path, PathBuf}, + sync::Arc, time::Instant, }; diff --git a/websites/kibo.money/assets/fonts/geist_mono/1.4.01/GeistMono[wght].woff2 b/websites/kibo.money/assets/fonts/geist_mono_var_1_4_01.woff2 similarity index 100% rename from websites/kibo.money/assets/fonts/geist_mono/1.4.01/GeistMono[wght].woff2 rename to websites/kibo.money/assets/fonts/geist_mono_var_1_4_01.woff2 diff --git a/websites/kibo.money/assets/fonts/satoshi/2024-09/font.var.woff2 b/websites/kibo.money/assets/fonts/satoshi/2024-09/font.var.woff2 deleted file mode 100644 index b00e833ed..000000000 Binary files a/websites/kibo.money/assets/fonts/satoshi/2024-09/font.var.woff2 and /dev/null differ diff --git a/websites/kibo.money/assets/fonts/satoshi/FFL.txt b/websites/kibo.money/assets/fonts/satoshi/FFL.txt deleted file mode 100644 index f14ebbaa1..000000000 --- a/websites/kibo.money/assets/fonts/satoshi/FFL.txt +++ /dev/null @@ -1,57 +0,0 @@ -Fontshare EULA - ----—---------------------------------—------------------------------ -Free Font - End User License Agreement (FF EULA) ----—---------------------------------—------------------------------ -Notice to User -Indian Type Foundry designs, produces and distributes font software as digital fonts to end users worldwide. In addition to commercial fonts that are available for a fee, ITF also offers several fonts which can be used free of charge. The free fonts are distributed through a dedicated platform called www.fontshare.com (“Fontshare”) to end users worldwide. These free fonts are subject to this legally binding EULA between the Indian Type Foundry (“Indian Type Foundry” or “Licensor”) and you (“Licensee”).  -You acknowledge that the Font Software and designs embodied therein are protected by the copyright, other intellectual property rights and industrial property rights and by international treaties. They are and remain at all times the intellectual property of the Indian Type Foundry. -In addition to direct download, Fontshare also offers these free fonts via Fonthsare API using a code. In this case, the Font Software is delivered directly from the servers used by Indian Type Foundry to the Licensee's website, without the Licensee having to download the Font Software. -By downloading, accessing the API, installing, storing, copying or using one of any Font Software, you agree to the following terms.  - -Definitions -“Font Software” refers to the set of computer files or programs released under this license that instructs your computer to display and/or print each letters, characters, typographic designs, ornament and so forth. Font Software includes all bitmap and vector representations of fonts and typographic representations and embellishments created by or derived from the Font Software.  -“Original Version” refers to the Font Software as distributed by the Indian Type Foundry as the copyright holder.  -“Derivative Work” refers to the pictorial representation of the font created by the Font Software, including typographic characters such as letters, numerals, ornaments, symbols, or punctuation and special characters. - -01. Grant of License -You are hereby granted a non-exclusive, non-assignable, non-transferrable, terminable license to access, download and use the Font Software for your personal or commercial use for an unlimited period of time for free of charge.  -You may use the font Software in any media (including Print, Web, Mobile, Digital, Apps, ePub, Broadcasting and OEM) at any scale, at any location worldwide.  -You may use the Font Software to create logos and other graphic elements, images on any surface, vector files or other scalable drawings and static images.  -You may use the Font Software on any number of devices (computer, tablet, phone). The number of output devices (Printers) is not restricted.  -You may make only such reasonable number of back-up copies suitable to your permitted use.  -You may but are not required to identify Indian Type Foundry Fonts in your work credits.  - -02. Limitations of usage -You may not modify, edit, adapt, translate, reverse engineer, decompile or disassemble, alter or otherwise copy the Font Software or the designs embodied therein in whole or in part, without the prior written consent of the Licensor.  -The Fonts may not - beyond the permitted copies and the uses defined herein - be distributed, duplicated, loaned, resold or licensed in any way, whether by lending, donating or give otherwise to a person or entity. This includes the distribution of the Fonts by e-mail, on USB sticks, CD-ROMs, or other media, uploading them in a public server or making the fonts available on peer-to-peer networks. A passing on to external designers or service providers (design agencies, repro studios, printers, etc.) is also not permitted.  -You are not allowed to transmit the Font Software over the Internet in font serving or for font replacement by means of technologies such as but not limited to EOT, Cufon, sIFR or similar technologies that may be developed in the future without the prior written consent of the Licensor.  - -03. Embedding -You may embed the Font Software in PDF and other digital documents provided that is done in a secured, read-only mode. It must be ensured beyond doubt that the recipient cannot use the Font Software to edit or to create new documents. The design data (PDFs) created in this way and under these created design data (PDFs) may be distributed in any number.  -The extraction of the Font Software in whole or in part is prohibited.  - -04. Third party use, Commercial print service provider -You may include the Font Software in a non-editable electronic document solely for printing and display purposes and provide that electronic document to the commercial print service provider for the purpose of printing. If the print service needs to install the fonts, they too need to download the Font Software from the Licensor's website. - -05. Derivative Work -You are allowed to make derivative works as far as you use them for your personal or commercial use. However, you cannot modify, make changes or reverse engineer the original font software provided to you. Any derivative works are the exclusive property of the Licensor and shall be subject to the terms and conditions of this EULA. Derivative works may not be sub-licensed, sold, leased, rented, loaned, or given away without the express written permission of the Licensor.  - -06. Warranty and Liability -BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, INDIAN TYPE FOUNDRY MAKES NO WARRANTIES, EXPRESS OR IMPLIED AS TO THE MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR OTHERWISE. THE FONT SOFTWARE WAS NOT MANUFACTURED FOR USE IN MANUFACTURING CONTROL DEVICES OR NAVIGATION DEVICES OR IN CIRCUMSTANCES THAT COULD RESULT IN ENVIRONMENTAL DAMAGE OR PERSONAL INJURY. WITHOUT LIMITING THE FOREGOING, INDIAN TYPE FOUNDRY SHALL IN NO EVENT BE LIABLE TO THE LICENSED USER OR ANY OTHER THIRD PARTY FOR ANY DIRECT, CONSEQUENTIAL OR INCIDENTAL DAMAGES, INCLUDING DAMAGES FROM LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION NOR FOR LOST PROFITS OR SAVINGS ARISING OUT OF THE USE OR INABILITY TO USE THE PRODUCT EVEN IF NOTIFIED IN ADVANCE, UNDER NO CIRCUMSTANCES SHALL INDIAN TYPE FOUNDRY’S LIABILITY EXCEED THE REPLACEMENT COST OF THE SOFTWARE.  -IF LICENSEE CHOOSES TO ACCESS THE FONT SOFTWARE THROUGH A CODE (API), IT MAY HAVE A DIRECT IMPACT ON LICENSEE'S WEBSITE OR APPLICATIONS. INDIAN TYPE FOUNDRY IS NOT RESPONSIBLE OR LIABLE FOR ANY INTERRUPTION, MALFUNCTION, DOWNTIME OR OTHER FAILURE OF THE WEBSITE OR ITS API. - -07. Updates, Maintenance and Support Services -Licensor will not provide you with any support services for the Software under this Agreement. - -08. Termination  -Any breach of the terms of this agreement shall be a cause for termination, provided that such breach is notified in writing to the Licensee by the Licensor and the Licensee failed to rectify the breach within 30 days of the receipt of such notification.  -In the event of termination and without limitation of any remedies under law or equity, you must delete the Font Software and all copies thereof. Proof of this must be provided upon request of the Licensor.   -We reserve the right to claim damages for the violation of the conditions.  - -09. Final Provisions -If individual provisions of this agreement are or become invalid, the validity of the remaining provisions shall remain unaffected. Invalid provisions shall be replaced by mutual agreement by such provisions that are suitable to achieve the desired economic purpose, taking into account the interests of both parties. The same shall apply mutatis mutandis to the filling of any gaps which may arise in this agreement. -This contract is subject to laws of the Republic of India. Place of performance and exclusive place of jurisdiction for all disputes between the parties arising out of or in connection with this contract is, as far as legally permissible, Ahmedabad, India. --  -Last Updated on 22 March 2021 -Copyright 2021 Indian Type Foundry. All rights reserved.  \ No newline at end of file diff --git a/websites/kibo.money/index.html b/websites/kibo.money/index.html index 63cf67801..7431a609b 100644 --- a/websites/kibo.money/index.html +++ b/websites/kibo.money/index.html @@ -283,9 +283,8 @@ @font-face { font-family: "Geist mono"; - src: url("./assets/fonts/geist_mono/1.4.01/GeistMono[wght].woff2") - format("woff2"); - font-weight: 100 900; + src: url("./assets/fonts/geist_mono_var_1_4_01.woff2") format("woff2"); + font-weight: 300 500; font-display: block; font-style: normal; } @@ -521,7 +520,7 @@ gap: 0.25rem; > span.colors { - margin-top: 0.25rem; + margin-top: 0.15rem; display: flex; width: 0.625rem; height: 0.625rem; @@ -670,6 +669,7 @@ sup { opacity: 0.5; margin-left: 0.25rem; + font-weight: 500; } small { @@ -779,7 +779,7 @@ line-height: var(--line-height-base); ul { - margin-left: 0.375rem; + margin-left: 0.25rem; } } diff --git a/websites/kibo.money/packages/lightweight-charts/wrapper.js b/websites/kibo.money/packages/lightweight-charts/wrapper.js index 8879a619a..8b592184f 100644 --- a/websites/kibo.money/packages/lightweight-charts/wrapper.js +++ b/websites/kibo.money/packages/lightweight-charts/wrapper.js @@ -77,7 +77,10 @@ export default import("./v5.0.5/script.js").then((lc) => { }, timeScale: { borderVisible: false, - timeVisible: index === /** @satisfies {Height} */ (2), + timeVisible: + index === /** @satisfies {Height} */ (0) || + index === /** @satisfies {Difficultyepoch} */ (3) || + index === /** @satisfies {Halvingepoch} */ (8), }, crosshair: { horzLine: { @@ -193,8 +196,9 @@ export default import("./v5.0.5/script.js").then((lc) => { timeScaleSetCallback?.(); if ( !timeScaleSet && - (vecIndex === /** @satisfies {Yearindex} */ (15) || - vecIndex === /** @satisfies {Decadeindex} */ (16)) + (vecIndex === /** @satisfies {Quarterindex} */ (5) || + vecIndex === /** @satisfies {Yearindex} */ (6) || + vecIndex === /** @satisfies {Decadeindex} */ (7)) ) { ichart .timeScale() @@ -231,7 +235,7 @@ export default import("./v5.0.5/script.js").then((lc) => { timeResource = vecsResources.getOrCreate( vecIndex, - vecIndex === /** @satisfies {Height} */ (2) + vecIndex === /** @satisfies {Height} */ (0) ? "fixed-timestamp" : "timestamp", ); @@ -277,7 +281,6 @@ export default import("./v5.0.5/script.js").then((lc) => { legend.add({ series, name, - id: vecId, defaultActive, colors: [colors.green, colors.red], url: valuesResource.url, @@ -318,7 +321,6 @@ export default import("./v5.0.5/script.js").then((lc) => { legend.add({ series, colors: [color], - id: vecId, name, defaultActive, url: valuesResource.url, @@ -368,13 +370,12 @@ function createLegend({ parent, signals, utils }) { /** * @param {Object} args * @param {ISeriesApi} args.series - * @param {string} args.id * @param {string} args.name * @param {Color[]} args.colors * @param {boolean} [args.defaultActive] * @param {string} [args.url] */ - add({ series, id, name, colors, defaultActive, url }) { + add({ series, name, colors, defaultActive, url }) { const div = window.document.createElement("div"); legendElement.append(div); @@ -383,7 +384,7 @@ function createLegend({ parent, signals, utils }) { const active = signals.createSignal(defaultActive ?? true, { save: { - keyPrefix: id, + keyPrefix: "", key: nameId, ...utils.serde.boolean, }, @@ -396,8 +397,8 @@ function createLegend({ parent, signals, utils }) { }); const { input, label } = utils.dom.createLabeledInput({ - inputId: utils.stringToId(`legend-${id}-${nameId}`), - inputName: utils.stringToId(`selected-${id}-${nameId}`), + inputId: utils.stringToId(`legend-${nameId}`), + inputName: utils.stringToId(`selected-${nameId}`), inputValue: "value", labelTitle: "Click to toggle", inputChecked: active(), diff --git a/websites/kibo.money/scripts/chart.js b/websites/kibo.money/scripts/chart.js index adf80af60..a2cf93616 100644 --- a/websites/kibo.money/scripts/chart.js +++ b/websites/kibo.money/scripts/chart.js @@ -143,6 +143,7 @@ function createIndexSelector({ elements, signals, utils }) { "week", // "difficulty epoch", "month", + "quarter", "year", // "halving epoch", "decade", @@ -173,17 +174,19 @@ function createIndexSelector({ elements, signals, utils }) { /** @returns {Index} */ () => { switch (serializedIndex()) { case "timestamp": - return /** @satisfies {Height} */ (2); + return /** @satisfies {Height} */ (0); case "date": return /** @satisfies {Dateindex} */ (1); case "week": - return /** @satisfies {Weekindex} */ (13); + return /** @satisfies {Weekindex} */ (2); case "month": - return /** @satisfies {Monthindex} */ (14); + return /** @satisfies {Monthindex} */ (4); + case "quarter": + return /** @satisfies {Quarterindex} */ (5); case "year": - return /** @satisfies {Yearindex} */ (15); + return /** @satisfies {Yearindex} */ (6); case "decade": - return /** @satisfies {Decadeindex} */ (16); + return /** @satisfies {Decadeindex} */ (7); } }, ); diff --git a/websites/kibo.money/scripts/main.js b/websites/kibo.money/scripts/main.js index 7d813b5c6..ee6f31b77 100644 --- a/websites/kibo.money/scripts/main.js +++ b/websites/kibo.money/scripts/main.js @@ -9,7 +9,7 @@ * @import { getOwner as GetOwner, onCleanup as OnCleanup, Owner } from "../packages/solid-signals/2024-11-02/types/core/owner" * @import { createSignal as CreateSignal, createEffect as CreateEffect, Accessor, Setter, createMemo as CreateMemo, createRoot as CreateRoot, runWithOwner as RunWithOwner } from "../packages/solid-signals/2024-11-02/types/signals"; * @import {Signal, Signals} from "../packages/solid-signals/types"; - * @import {Addressindex, Dateindex, Decadeindex, Difficultyepoch, Index, Halvingepoch, Height, Monthindex, P2PK33index, P2PK65index, P2PKHindex, P2SHindex, P2TRindex, P2WPKHindex, P2WSHindex, Txindex, Txinindex, Txoutindex, VecId, Weekindex, Yearindex, VecIdToIndexes} from "./vecid-to-indexes" + * @import {Addressindex, Dateindex, Decadeindex, Difficultyepoch, Index, Halvingepoch, Height, Monthindex, P2PK33index, P2PK65index, P2PKHindex, P2SHindex, P2TRindex, P2WPKHindex, P2WSHindex, Txindex, Txinindex, Txoutindex, VecId, Weekindex, Yearindex, VecIdToIndexes, Quarterindex} from "./vecid-to-indexes" */ function initPackages() { @@ -1135,45 +1135,47 @@ function createUtils() { /** * @param {Index} index */ - function indexToString(index) { + function vecIndexToString(index) { switch (index) { - case /** @satisfies {Addressindex} */ (0): + case /** @satisfies {Addressindex} */ (9): return "Addressindex"; case /** @satisfies {Dateindex} */ (1): return "Dateindex"; - case /** @satisfies {Height} */ (2): + case /** @satisfies {Height} */ (0): return "Height"; - case /** @satisfies {P2PK33index} */ (3): + case /** @satisfies {P2PK33index} */ (10): return "P2PK33index"; - case /** @satisfies {P2PK65index} */ (4): + case /** @satisfies {P2PK65index} */ (11): return "P2PK65index"; - case /** @satisfies {P2PKHindex} */ (5): + case /** @satisfies {P2PKHindex} */ (12): return "P2PKHindex"; - case /** @satisfies {P2SHindex} */ (6): + case /** @satisfies {P2SHindex} */ (13): return "P2SHindex"; - case /** @satisfies {P2TRindex} */ (7): + case /** @satisfies {P2TRindex} */ (14): return "P2TRindex"; - case /** @satisfies {P2WPKHindex} */ (8): + case /** @satisfies {P2WPKHindex} */ (15): return "P2WPKHindex"; - case /** @satisfies {P2WSHindex} */ (9): + case /** @satisfies {P2WSHindex} */ (16): return "P2WSHindex"; - case /** @satisfies {Txindex} */ (10): + case /** @satisfies {Txindex} */ (17): return "Txindex"; - case /** @satisfies {Txinindex} */ (11): + case /** @satisfies {Txinindex} */ (18): return "Txinindex"; - case /** @satisfies {Txoutindex} */ (12): + case /** @satisfies {Txoutindex} */ (19): return "Txoutindex"; - case /** @satisfies {Weekindex} */ (13): + case /** @satisfies {Weekindex} */ (2): return "Weekindex"; - case /** @satisfies {Monthindex} */ (14): + case /** @satisfies {Monthindex} */ (4): return "Monthindex"; - case /** @satisfies {Yearindex} */ (15): + case /** @satisfies {Quarterindex} */ (5): + return "Quarterindex"; + case /** @satisfies {Yearindex} */ (6): return "Yearindex"; - case /** @satisfies {Decadeindex} */ (16): + case /** @satisfies {Decadeindex} */ (7): return "Decadeindex"; - case /** @satisfies {Difficultyepoch} */ (17): + case /** @satisfies {Difficultyepoch} */ (3): return "Difficultyepoch"; - case /** @satisfies {Halvingepoch} */ (18): + case /** @satisfies {Halvingepoch} */ (8): return "Halvingepoch"; } } @@ -1185,7 +1187,7 @@ function createUtils() { * @param {number} [to] */ function genPath(index, vecId, from, to) { - let path = `/query?index=${indexToString(index)}&values=${vecId}`; + let path = `/query?index=${vecIndexToString(index)}&values=${vecId}`; if (from !== undefined) { path += `&from=${from}`; } @@ -1309,10 +1311,8 @@ function createVecsResources(signals, utils) { const key = `${index},${id}`; const found = map.get(key); if (found) { - console.log("found"); return found; } - console.log("not found"); const vec = createVecResource(index, id); if (!vec) throw Error("vec is undefined"); @@ -1892,7 +1892,7 @@ function main() { (h) => { lastHeight.set(h); }, - /** @satisfies {Height} */ (2), + /** @satisfies {Height} */ (0), "height", ); } diff --git a/websites/kibo.money/scripts/service-worker.js b/websites/kibo.money/scripts/service-worker.js index 24c3630cf..8514a2e08 100644 --- a/websites/kibo.money/scripts/service-worker.js +++ b/websites/kibo.money/scripts/service-worker.js @@ -12,7 +12,7 @@ self.addEventListener("install", (_event) => { return cache.addAll([ "/", "/index.html", - "/assets/fonts/satoshi/2024-09/font.var.woff2", + "/assets/fonts/geist_mono_var_1_4_01.woff2", "/scripts/main.js", "/scripts/options.js", "/scripts/chart.js", diff --git a/websites/kibo.money/scripts/vecid-to-indexes.js b/websites/kibo.money/scripts/vecid-to-indexes.js index bedb9bcd6..63abbc3db 100644 --- a/websites/kibo.money/scripts/vecid-to-indexes.js +++ b/websites/kibo.money/scripts/vecid-to-indexes.js @@ -1,45 +1,47 @@ -/** @typedef {0} Addressindex */ +/** @typedef {0} Height */ /** @typedef {1} Dateindex */ -/** @typedef {2} Height */ -/** @typedef {3} P2PK33index */ -/** @typedef {4} P2PK65index */ -/** @typedef {5} P2PKHindex */ -/** @typedef {6} P2SHindex */ -/** @typedef {7} P2TRindex */ -/** @typedef {8} P2WPKHindex */ -/** @typedef {9} P2WSHindex */ -/** @typedef {10} Txindex */ -/** @typedef {11} Txinindex */ -/** @typedef {12} Txoutindex */ -/** @typedef {13} Weekindex */ -/** @typedef {14} Monthindex */ -/** @typedef {15} Yearindex */ -/** @typedef {16} Decadeindex */ -/** @typedef {17} Difficultyepoch */ -/** @typedef {18} Halvingepoch */ +/** @typedef {2} Weekindex */ +/** @typedef {3} Difficultyepoch */ +/** @typedef {4} Monthindex */ +/** @typedef {5} Quarterindex */ +/** @typedef {6} Yearindex */ +/** @typedef {7} Decadeindex */ +/** @typedef {8} Halvingepoch */ +/** @typedef {9} Addressindex */ +/** @typedef {10} P2PK33index */ +/** @typedef {11} P2PK65index */ +/** @typedef {12} P2PKHindex */ +/** @typedef {13} P2SHindex */ +/** @typedef {14} P2TRindex */ +/** @typedef {15} P2WPKHindex */ +/** @typedef {16} P2WSHindex */ +/** @typedef {17} Txindex */ +/** @typedef {18} Txinindex */ +/** @typedef {19} Txoutindex */ -/** @typedef {Addressindex | Dateindex | Height | P2PK33index | P2PK65index | P2PKHindex | P2SHindex | P2TRindex | P2WPKHindex | P2WSHindex | Txindex | Txinindex | Txoutindex | Weekindex | Monthindex | Yearindex | Decadeindex | Difficultyepoch | Halvingepoch} Index */ +/** @typedef {Height | Dateindex | Weekindex | Difficultyepoch | Monthindex | Quarterindex | Yearindex | Decadeindex | Halvingepoch | Addressindex | P2PK33index | P2PK65index | P2PKHindex | P2SHindex | P2TRindex | P2WPKHindex | P2WSHindex | Txindex | Txinindex | Txoutindex} Index */ export function createVecIdToIndexes() { - const Addressindex = /** @satisfies {Addressindex} */ (0); + const Height = /** @satisfies {Height} */ (0); const Dateindex = /** @satisfies {Dateindex} */ (1); - const Height = /** @satisfies {Height} */ (2); - const P2PK33index = /** @satisfies {P2PK33index} */ (3); - const P2PK65index = /** @satisfies {P2PK65index} */ (4); - const P2PKHindex = /** @satisfies {P2PKHindex} */ (5); - const P2SHindex = /** @satisfies {P2SHindex} */ (6); - const P2TRindex = /** @satisfies {P2TRindex} */ (7); - const P2WPKHindex = /** @satisfies {P2WPKHindex} */ (8); - const P2WSHindex = /** @satisfies {P2WSHindex} */ (9); - const Txindex = /** @satisfies {Txindex} */ (10); - const Txinindex = /** @satisfies {Txinindex} */ (11); - const Txoutindex = /** @satisfies {Txoutindex} */ (12); - const Weekindex = /** @satisfies {Weekindex} */ (13); - const Monthindex = /** @satisfies {Monthindex} */ (14); - const Yearindex = /** @satisfies {Yearindex} */ (15); - const Decadeindex = /** @satisfies {Decadeindex} */ (16); - const Difficultyepoch = /** @satisfies {Difficultyepoch} */ (17); - const Halvingepoch = /** @satisfies {Halvingepoch} */ (18); + const Weekindex = /** @satisfies {Weekindex} */ (2); + const Difficultyepoch = /** @satisfies {Difficultyepoch} */ (3); + const Monthindex = /** @satisfies {Monthindex} */ (4); + const Quarterindex = /** @satisfies {Quarterindex} */ (5); + const Yearindex = /** @satisfies {Yearindex} */ (6); + const Decadeindex = /** @satisfies {Decadeindex} */ (7); + const Halvingepoch = /** @satisfies {Halvingepoch} */ (8); + const Addressindex = /** @satisfies {Addressindex} */ (9); + const P2PK33index = /** @satisfies {P2PK33index} */ (10); + const P2PK65index = /** @satisfies {P2PK65index} */ (11); + const P2PKHindex = /** @satisfies {P2PKHindex} */ (12); + const P2SHindex = /** @satisfies {P2SHindex} */ (13); + const P2TRindex = /** @satisfies {P2TRindex} */ (14); + const P2WPKHindex = /** @satisfies {P2WPKHindex} */ (15); + const P2WSHindex = /** @satisfies {P2WSHindex} */ (16); + const Txindex = /** @satisfies {Txindex} */ (17); + const Txinindex = /** @satisfies {Txinindex} */ (18); + const Txoutindex = /** @satisfies {Txoutindex} */ (19); return { addressindex: [Txoutindex], @@ -52,12 +54,12 @@ export function createVecIdToIndexes() { "block-interval-25p": [Dateindex], "block-interval-75p": [Dateindex], "block-interval-90p": [Dateindex], - "block-interval-average": [Dateindex, Weekindex, Monthindex, Yearindex, Decadeindex, Difficultyepoch], - "block-interval-max": [Dateindex, Weekindex, Monthindex, Yearindex, Decadeindex, Difficultyepoch], + "block-interval-average": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], + "block-interval-max": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "block-interval-median": [Dateindex], - "block-interval-min": [Dateindex, Weekindex, Monthindex, Yearindex, Decadeindex, Difficultyepoch], + "block-interval-min": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], blockhash: [Height], - close: [Dateindex, Height, Weekindex, Monthindex, Yearindex, Decadeindex, Difficultyepoch], + close: [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "close-in-cents": [Dateindex, Height], date: [Dateindex], dateindex: [Dateindex, Height], @@ -68,9 +70,9 @@ export function createVecIdToIndexes() { "first-dateindex": [Weekindex, Monthindex], "first-emptyindex": [Height], "first-height": [Dateindex, Difficultyepoch, Halvingepoch], - "first-monthindex": [Yearindex], + "first-monthindex": [Quarterindex, Yearindex], "first-multisigindex": [Height], - "first-open": [Weekindex, Monthindex, Yearindex, Decadeindex, Difficultyepoch], + "first-open": [Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "first-opreturnindex": [Height], "first-p2pk33index": [Height], "first-p2pk65index": [Height], @@ -91,13 +93,13 @@ export function createVecIdToIndexes() { height: [Addressindex, Height, Txindex], high: [Dateindex, Height], "high-in-cents": [Dateindex, Height], - "high-max": [Weekindex, Monthindex, Yearindex, Decadeindex, Difficultyepoch], + "high-max": [Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "inputs-count": [Txindex], "is-coinbase": [Txindex], "is-explicitly-rbf": [Txindex], "last-dateindex": [Weekindex, Monthindex], "last-height": [Dateindex, Difficultyepoch, Halvingepoch], - "last-monthindex": [Yearindex], + "last-monthindex": [Quarterindex, Yearindex], "last-txindex": [Height], "last-txinindex": [Txindex], "last-txoutindex": [Txindex], @@ -105,9 +107,9 @@ export function createVecIdToIndexes() { locktime: [Txindex], low: [Dateindex, Height], "low-in-cents": [Dateindex, Height], - "low-min": [Weekindex, Monthindex, Yearindex, Decadeindex, Difficultyepoch], + "low-min": [Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], monthindex: [Dateindex, Monthindex], - ohlc: [Dateindex, Height, Weekindex, Monthindex, Yearindex, Decadeindex, Difficultyepoch], + ohlc: [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "ohlc-in-cents": [Dateindex, Height], open: [Dateindex, Height], "open-in-cents": [Dateindex, Height], @@ -119,10 +121,11 @@ export function createVecIdToIndexes() { p2traddressbytes: [P2TRindex], p2wpkhaddressbytes: [P2WPKHindex], p2wshaddressbytes: [P2WSHindex], + quarterindex: [Monthindex, Quarterindex], "real-date": [Height], "sats-per-dollar": [Dateindex, Height], size: [Height], - timestamp: [Dateindex, Height, Weekindex, Monthindex, Yearindex, Decadeindex, Difficultyepoch, Halvingepoch], + timestamp: [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch, Halvingepoch], "total-block-count": [Dateindex], "total-size": [Txindex], txid: [Txindex],