global: one big snapshot

This commit is contained in:
nym21
2025-08-02 16:59:22 +02:00
parent aa8b47a3dd
commit f7aa9424db
252 changed files with 6283 additions and 5264 deletions
+4 -4
View File
@@ -12,8 +12,7 @@ axum = { workspace = true }
bitcoincore-rpc = { workspace = true }
brk_bundler = { workspace = true }
brk_computer = { workspace = true }
brk_core = { workspace = true }
brk_exit = { workspace = true }
brk_error = { workspace = true }
brk_fetcher = { workspace = true }
brk_indexer = { workspace = true }
brk_interface = { workspace = true }
@@ -23,16 +22,17 @@ brk_parser = { workspace = true }
brk_vecs = { workspace = true }
clap = { workspace = true }
clap_derive = { workspace = true }
color-eyre = { workspace = true }
jiff = { workspace = true }
log = { workspace = true }
minreq = { workspace = true }
owo-colors = { workspace = true }
quick_cache = "0.6.15"
serde = { workspace = true }
serde_json = { workspace = true }
tokio = { workspace = true }
tower-http = { version = "0.6.6", features = ["compression-full", "trace"] }
tracing = "0.1.41"
zip = "4.3.0"
zip = { version = "4.3.0", default-features = false, features = ["deflate"] }
[package.metadata.cargo-machete]
ignored = ["clap"]
-6
View File
@@ -23,12 +23,6 @@
<a href="https://primal.net/p/nprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6">
<img src="https://img.shields.io/badge/nostr-purple?link=https%3A%2F%2Fprimal.net%2Fp%2Fnprofile1qqsfw5dacngjlahye34krvgz7u0yghhjgk7gxzl5ptm9v6n2y3sn03sqxu2e6" alt="Nostr" />
</a>
<a href="https://bsky.app/profile/bitcoinresearchkit.org">
<img src="https://img.shields.io/badge/bluesky-blue?link=https%3A%2F%2Fbsky.app%2Fprofile%2Fbitcoinresearchkit.org" alt="Bluesky" />
</a>
<a href="https://x.com/brkdotorg">
<img src="https://img.shields.io/badge/x.com-black" alt="X" />
</a>
</p>
A crate that serves Bitcoin data and swappable front-ends, built on top of `brk_indexer`, `brk_computer` and `brk_interface`.
+17 -16
View File
@@ -2,42 +2,38 @@ use std::{path::Path, thread::sleep, time::Duration};
use bitcoincore_rpc::RpcApi;
use brk_computer::Computer;
use brk_core::{default_bitcoin_path, default_brk_path};
use brk_exit::Exit;
use brk_error::Result;
use brk_fetcher::Fetcher;
use brk_indexer::Indexer;
use brk_parser::Parser;
use brk_server::{Server, Website};
use brk_vecs::{Computation, Format};
pub fn main() -> color_eyre::Result<()> {
color_eyre::install()?;
use brk_vecs::Exit;
pub fn main() -> Result<()> {
brk_logger::init(Some(Path::new(".log")));
let process = true;
let bitcoin_dir = default_bitcoin_path();
let brk_dir = default_brk_path();
let bitcoin_dir = Path::new("");
let brk_dir = Path::new("");
let rpc = Box::leak(Box::new(bitcoincore_rpc::Client::new(
"http://localhost:8332",
bitcoincore_rpc::Auth::CookieFile(bitcoin_dir.join(".cookie")),
)?));
let exit = Exit::new();
exit.set_ctrlc_handler();
let parser = Parser::new(bitcoin_dir.join("blocks"), brk_dir, rpc);
let parser = Parser::new(bitcoin_dir.join("blocks"), brk_dir.to_path_buf(), rpc);
let outputs_dir = Path::new("../../_outputs");
let format = Format::Compressed;
let mut indexer = Indexer::forced_import(outputs_dir)?;
let fetcher = Some(Fetcher::import(None)?);
let mut computer =
Computer::forced_import(outputs_dir, &indexer, Computation::Lazy, fetcher, format)?;
let mut computer = Computer::forced_import(outputs_dir, &indexer, fetcher)?;
tokio::runtime::Builder::new_multi_thread()
.enable_all()
@@ -46,7 +42,12 @@ pub fn main() -> color_eyre::Result<()> {
let served_indexer = indexer.clone();
let served_computer = computer.clone();
let server = Server::new(served_indexer, served_computer, Website::Default)?;
let server = Server::new(
served_indexer,
served_computer,
Website::Default,
Path::new(""),
)?;
let server = tokio::spawn(async move {
server.serve(true, true).await.unwrap();
@@ -58,7 +59,7 @@ pub fn main() -> color_eyre::Result<()> {
let starting_indexes = indexer.index(&parser, rpc, &exit, true)?;
computer.compute(&mut indexer, starting_indexes, &exit)?;
computer.compute(&indexer, starting_indexes, &exit)?;
while block_count == rpc.get_block_count()? {
sleep(Duration::from_secs(1))
@@ -70,5 +71,5 @@ pub fn main() -> color_eyre::Result<()> {
server.await.unwrap();
Ok(())
}) as color_eyre::Result<()>
})
}
+11 -4
View File
@@ -4,8 +4,9 @@ use axum::{
http::{HeaderMap, StatusCode},
response::{IntoResponse, Response},
};
use brk_error::{Error, Result};
use brk_interface::{Format, Output, Params};
use color_eyre::eyre::eyre;
use brk_vecs::Stamp;
use crate::traits::{HeaderMapExtended, ResponseExtended};
@@ -37,7 +38,7 @@ fn req_to_response_res(
headers: HeaderMap,
Query(params): Query<Params>,
AppState { interface, .. }: AppState,
) -> color_eyre::Result<Response> {
) -> Result<Response> {
let vecs = interface.search(&params);
if vecs.is_empty() {
@@ -56,11 +57,17 @@ fn req_to_response_res(
.sum::<usize>();
if weight > MAX_WEIGHT {
return Err(eyre!("Request is too heavy, max weight is {MAX_WEIGHT}"));
return Err(Error::Str(
"Request is too heavy, max weight is {MAX_WEIGHT}",
));
}
// TODO: height should be from vec, but good enough for now
let etag = vecs.first().unwrap().1.etag(interface.get_height(), to);
let etag = vecs
.first()
.unwrap()
.1
.etag(Stamp::from(u64::from(interface.get_height())), to);
if headers
.get_if_none_match()
+2 -1
View File
@@ -6,6 +6,7 @@ use axum::{
http::{HeaderMap, StatusCode},
response::{IntoResponse, Response},
};
use brk_error::Result;
use log::{error, info};
use crate::{
@@ -73,7 +74,7 @@ fn path_to_response(headers: &HeaderMap, path: &Path) -> Response {
}
}
fn path_to_response_(headers: &HeaderMap, path: &Path) -> color_eyre::Result<Response> {
fn path_to_response_(headers: &HeaderMap, path: &Path) -> Result<Response> {
let (modified, date) = headers.check_if_modified_since(path)?;
if modified == ModifiedState::NotModifiedSince {
return Ok(Response::new_not_modified());
+11 -9
View File
@@ -21,13 +21,13 @@ use axum::{
};
use brk_bundler::bundle;
use brk_computer::Computer;
use brk_core::dot_brk_path;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_interface::Interface;
use brk_mcp::route::MCPRoutes;
use color_eyre::owo_colors::OwoColorize;
use files::FilesRoutes;
use log::{error, info};
use owo_colors::OwoColorize;
use tokio::net::TcpListener;
use tower_http::{compression::CompressionLayer, trace::TraceLayer};
@@ -57,13 +57,17 @@ impl AppState {
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
const DEV_PATH: &str = "../..";
const DOWNLOADS: &str = "downloads";
const WEBSITES: &str = "websites";
pub struct Server(AppState);
impl Server {
pub fn new(indexer: Indexer, computer: Computer, website: Website) -> color_eyre::Result<Self> {
pub fn new(
indexer: Indexer,
computer: Computer,
website: Website,
downloads_path: &Path,
) -> Result<Self> {
let indexer = Box::leak(Box::new(indexer));
let computer = Box::leak(Box::new(computer));
let interface = Box::leak(Box::new(Interface::build(indexer, computer)));
@@ -74,8 +78,6 @@ impl Server {
let websites_path = if fs::exists(&websites_dev_path)? {
websites_dev_path
} else {
let downloads_path = dot_brk_path().join(DOWNLOADS);
let downloaded_websites_path =
downloads_path.join(format!("brk-{VERSION}")).join(WEBSITES);
@@ -90,9 +92,9 @@ impl Server {
let bytes = response.as_bytes();
let cursor = Cursor::new(bytes);
let mut zip = zip::ZipArchive::new(cursor)?;
let mut zip = zip::ZipArchive::new(cursor).unwrap();
zip.extract(&downloads_path)?;
zip.extract(downloads_path).unwrap();
}
downloaded_websites_path
@@ -112,7 +114,7 @@ impl Server {
}))
}
pub async fn serve(self, watch: bool, mcp: bool) -> color_eyre::Result<()> {
pub async fn serve(self, watch: bool, mcp: bool) -> Result<()> {
let state = self.0;
if let Some(websites_path) = state.websites_path.clone() {
+5 -14
View File
@@ -7,6 +7,7 @@ use axum::http::{
HeaderMap,
header::{self, IF_MODIFIED_SINCE, IF_NONE_MATCH},
};
use brk_error::Result;
use jiff::{Timestamp, civil::DateTime, fmt::strtime, tz::TimeZone};
const MODIFIED_SINCE_FORMAT: &str = "%a, %d %b %Y %H:%M:%S GMT";
@@ -23,12 +24,8 @@ pub trait HeaderMapExtended {
fn get_if_none_match(&self) -> Option<&str>;
fn get_if_modified_since(&self) -> Option<DateTime>;
fn check_if_modified_since(&self, path: &Path)
-> color_eyre::Result<(ModifiedState, DateTime)>;
fn check_if_modified_since_(
&self,
duration: Duration,
) -> color_eyre::Result<(ModifiedState, DateTime)>;
fn check_if_modified_since(&self, path: &Path) -> Result<(ModifiedState, DateTime)>;
fn check_if_modified_since_(&self, duration: Duration) -> Result<(ModifiedState, DateTime)>;
fn insert_cache_control_must_revalidate(&mut self);
fn insert_cache_control_immutable(&mut self);
@@ -91,10 +88,7 @@ impl HeaderMapExtended for HeaderMap {
self.insert(header::ETAG, etag.parse().unwrap());
}
fn check_if_modified_since(
&self,
path: &Path,
) -> color_eyre::Result<(ModifiedState, DateTime)> {
fn check_if_modified_since(&self, path: &Path) -> Result<(ModifiedState, DateTime)> {
self.check_if_modified_since_(
path.metadata()?
.modified()?
@@ -102,10 +96,7 @@ impl HeaderMapExtended for HeaderMap {
)
}
fn check_if_modified_since_(
&self,
duration: Duration,
) -> color_eyre::Result<(ModifiedState, DateTime)> {
fn check_if_modified_since_(&self, duration: Duration) -> Result<(ModifiedState, DateTime)> {
let date = Timestamp::new(duration.as_secs() as i64, 0)
.unwrap()
.to_zoned(TimeZone::UTC)