diff --git a/crates/brk_cli/src/config.rs b/crates/brk_cli/src/config.rs new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/crates/brk_cli/src/config.rs @@ -0,0 +1 @@ + diff --git a/crates/brk_cli/src/run.rs b/crates/brk_cli/src/run.rs index 7a416f74d..28faa5912 100644 --- a/crates/brk_cli/src/run.rs +++ b/crates/brk_cli/src/run.rs @@ -10,7 +10,7 @@ use brk_core::path_dot_brk; use brk_exit::Exit; use brk_indexer::Indexer; use brk_parser::rpc::{self, Auth, Client, RpcApi}; -use brk_server::{Frontend, tokio}; +use brk_server::{Frontend, Server, tokio}; use clap::{Parser, ValueEnum}; use color_eyre::eyre::eyre; use log::info; @@ -37,15 +37,14 @@ pub fn run(config: RunConfig) -> color_eyre::Result<()> { .enable_all() .build()? .block_on(async { - let served_indexer = indexer.clone(); - let served_computer = computer.clone(); - let frontend = config.frontend(); - let server = if config.serve() { + let served_indexer = indexer.clone(); + let served_computer = computer.clone(); + + let server = Server::new(served_indexer, served_computer, config.frontend())?; + Some(tokio::spawn(async move { - brk_server::main(served_indexer, served_computer, frontend) - .await - .unwrap(); + server.serve().await.unwrap(); })) } else { None @@ -84,11 +83,11 @@ pub fn run(config: RunConfig) -> color_eyre::Result<()> { #[derive(Parser, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)] pub struct RunConfig { /// Bitcoin data directory path, saved - #[arg(short, long, value_name = "PATH")] + #[arg(long, value_name = "PATH")] bitcoindir: Option, /// Bitcoin Research Kit outputs directory path, saved - #[arg(short, long, value_name = "PATH")] + #[arg(long, value_name = "PATH")] brkdir: Option, /// Executed by the runner, default: all, saved diff --git a/crates/brk_computer/src/lib.rs b/crates/brk_computer/src/lib.rs index 1e90c5d51..9f328dd0b 100644 --- a/crates/brk_computer/src/lib.rs +++ b/crates/brk_computer/src/lib.rs @@ -58,6 +58,7 @@ impl Computer { let txinindexes_count = indexer.vecs().txinindex_to_txoutindex.len(); let txoutindexes_count = indexer.vecs().txoutindex_to_addressindex.len(); + // self.vecs.txindex_to_last_txinindex.compute_last_index_from_first( // starting_indexes.txindex, // &mut indexer.vecs().txindex_to_first_txinindex, // txinindexes_count, diff --git a/crates/brk_query/src/params.rs b/crates/brk_query/src/params.rs index 31040e279..167c86467 100644 --- a/crates/brk_query/src/params.rs +++ b/crates/brk_query/src/params.rs @@ -24,7 +24,7 @@ pub struct Params { #[serde(default, alias = "t")] /// Inclusive ending index, if negative will be from the end pub to: Option, - #[clap(long)] + #[clap(short = 'F', long)] /// Format of the output pub format: Option, } diff --git a/crates/brk_server/examples/main.rs b/crates/brk_server/examples/main.rs index b0f383ee0..83b6ee16e 100644 --- a/crates/brk_server/examples/main.rs +++ b/crates/brk_server/examples/main.rs @@ -7,7 +7,7 @@ use brk_parser::{ Parser, rpc::{self, RpcApi}, }; -use brk_server::Frontend; +use brk_server::{Frontend, Server}; use log::info; pub fn main() -> color_eyre::Result<()> { @@ -43,10 +43,10 @@ pub fn main() -> color_eyre::Result<()> { let served_indexer = indexer.clone(); let served_computer = computer.clone(); + let server = Server::new(served_indexer, served_computer, Frontend::KiboMoney)?; + let server = tokio::spawn(async move { - brk_server::main(served_indexer, served_computer, Frontend::KiboMoney) - .await - .unwrap(); + server.serve().await.unwrap(); }); if process { diff --git a/crates/brk_server/src/api/mod.rs b/crates/brk_server/src/api/mod.rs index 4ad69b941..b20d3652a 100644 --- a/crates/brk_server/src/api/mod.rs +++ b/crates/brk_server/src/api/mod.rs @@ -3,9 +3,9 @@ use axum::{Router, routing::get}; use super::AppState; mod explorer; -mod vecs; +mod query; -pub use vecs::DTS; +pub use query::DTS; pub trait ApiRoutes { fn add_api_routes(self) -> Self; @@ -13,6 +13,6 @@ pub trait ApiRoutes { impl ApiRoutes for Router { fn add_api_routes(self) -> Self { - self.route("/api/vecs", get(vecs::handler)) + self.route("/api/query", get(query::handler)) } } diff --git a/crates/brk_server/src/api/vecs/dts.rs b/crates/brk_server/src/api/query/dts.rs similarity index 100% rename from crates/brk_server/src/api/vecs/dts.rs rename to crates/brk_server/src/api/query/dts.rs diff --git a/crates/brk_server/src/api/vecs/mod.rs b/crates/brk_server/src/api/query/mod.rs similarity index 92% rename from crates/brk_server/src/api/vecs/mod.rs rename to crates/brk_server/src/api/query/mod.rs index 7aacbad3f..5af0c5e56 100644 --- a/crates/brk_server/src/api/vecs/mod.rs +++ b/crates/brk_server/src/api/query/mod.rs @@ -7,8 +7,6 @@ use axum::{ response::{IntoResponse, Response}, }; use brk_query::{Format, Index, Output, Params}; -use color_eyre::eyre::eyre; -use serde_json::Value; use crate::{log_result, traits::HeaderMapExtended}; @@ -26,17 +24,15 @@ pub async fn handler( ) -> Response { let instant = Instant::now(); - let path = uri.path(); - match req_to_response_res(headers, query, app_state) { Ok(response) => { - log_result(response.status(), path, instant); + log_result(response.status(), &uri, instant); response } Err(error) => { let mut response = (StatusCode::INTERNAL_SERVER_ERROR, error.to_string()).into_response(); - log_result(response.status(), path, instant); + log_result(response.status(), &uri, instant); response.headers_mut().insert_cors(); response } diff --git a/crates/brk_server/src/files/file.rs b/crates/brk_server/src/files/file.rs index ee26ccaa3..36a6a607a 100644 --- a/crates/brk_server/src/files/file.rs +++ b/crates/brk_server/src/files/file.rs @@ -7,7 +7,7 @@ use std::{ use axum::{ body::Body, extract::{self, State}, - http::{HeaderMap, StatusCode}, + http::{HeaderMap, StatusCode, Uri}, response::{IntoResponse, Response}, }; use log::{error, info}; @@ -22,18 +22,24 @@ use super::minify::minify_js; pub async fn file_handler( headers: HeaderMap, State(app_state): State, + uri: Uri, path: extract::Path, ) -> Response { - any_handler(headers, app_state, Some(path)) + any_handler(headers, app_state, uri, Some(path)) } -pub async fn index_handler(headers: HeaderMap, State(app_state): State) -> Response { - any_handler(headers, app_state, None) +pub async fn index_handler( + headers: HeaderMap, + State(app_state): State, + uri: Uri, +) -> Response { + any_handler(headers, app_state, uri, None) } fn any_handler( headers: HeaderMap, app_state: AppState, + uri: Uri, path: Option>, ) -> Response { let website_path = app_state @@ -70,11 +76,7 @@ fn any_handler( path_to_response(&headers, &website_path.join("index.html")) }; - log_result( - response.status(), - &format!("/{}", path.map_or("".to_owned(), |p| p.0)), - instant, - ); + log_result(response.status(), &uri, instant); response } diff --git a/crates/brk_server/src/lib.rs b/crates/brk_server/src/lib.rs index 6b3d589bf..2dd3170f5 100644 --- a/crates/brk_server/src/lib.rs +++ b/crates/brk_server/src/lib.rs @@ -11,7 +11,12 @@ use std::{ }; use api::{ApiRoutes, DTS}; -use axum::{Json, Router, http::StatusCode, routing::get, serve}; +use axum::{ + Json, Router, + http::{StatusCode, Uri}, + routing::get, + serve, +}; use brk_computer::Computer; use brk_core::path_dot_brk; use brk_indexer::Indexer; @@ -31,6 +36,8 @@ pub use files::Frontend; #[derive(Clone)] pub struct AppState { + // indexer: &'static Indexer, + // computer: &'static Computer, query: &'static Query<'static>, frontend: Frontend, websites_path: Option, @@ -41,99 +48,106 @@ const DOWNLOADS: &str = "downloads"; const WEBSITES: &str = "websites"; // TODO -pub struct Server; +pub struct Server(AppState); -pub async fn main( - indexer: Indexer, - computer: Computer, - frontend: Frontend, -) -> color_eyre::Result<()> { - let indexer = Box::leak(Box::new(indexer)); - let computer = Box::leak(Box::new(computer)); - let query = Box::leak(Box::new(Query::build(indexer, computer))); +impl Server { + pub fn new( + indexer: Indexer, + computer: Computer, + frontend: Frontend, + ) -> color_eyre::Result { + let indexer = Box::leak(Box::new(indexer)); + let computer = Box::leak(Box::new(computer)); + let query = Box::leak(Box::new(Query::build(indexer, computer))); - let websites_path = if frontend.is_some() { - let websites_dev_path = Path::new(DEV_PATH).join(WEBSITES); + let websites_path = if frontend.is_some() { + let websites_dev_path = Path::new(DEV_PATH).join(WEBSITES); - let websites_path = if fs::exists(&websites_dev_path)? { - websites_dev_path + let websites_path = if fs::exists(&websites_dev_path)? { + websites_dev_path + } else { + let downloads_path = path_dot_brk().join(DOWNLOADS); + + let downloaded_websites_path = downloads_path.join("brk-main").join(WEBSITES); + + if !fs::exists(&downloaded_websites_path)? { + info!("Downloading websites from Github..."); + + // TODO + // Need to download versioned, this is only for testing ! + let url = + "https://github.com/bitcoinresearchkit/brk/archive/refs/heads/main.zip"; + + let response = minreq::get(url).send()?; + let bytes = response.as_bytes(); + let cursor = Cursor::new(bytes); + + let mut zip = zip::ZipArchive::new(cursor)?; + + zip.extract(&downloads_path)?; + } + + downloaded_websites_path + }; + + query.generate_dts_file(frontend, websites_path.as_path())?; + + Some(websites_path) } else { - let downloads_path = path_dot_brk().join(DOWNLOADS); - - let downloaded_websites_path = downloads_path.join("brk-main").join(WEBSITES); - - if !fs::exists(&downloaded_websites_path)? { - info!("Downloading websites from Github..."); - - // TODO - // Need to download versioned, this is only for testing ! - let url = "https://github.com/bitcoinresearchkit/brk/archive/refs/heads/main.zip"; - - let response = minreq::get(url).send()?; - let bytes = response.as_bytes(); - let cursor = Cursor::new(bytes); - - let mut zip = zip::ZipArchive::new(cursor)?; - - zip.extract(&downloads_path)?; - } - - downloaded_websites_path + None }; - query.generate_dts_file(frontend, websites_path.as_path())?; - - Some(websites_path) - } else { - None - }; - - let state = AppState { - query, - frontend, - websites_path, - }; - - let compression_layer = CompressionLayer::new() - .br(true) - .deflate(true) - .gzip(true) - .zstd(true); - - let router = Router::new() - .add_api_routes() - .add_website_routes(frontend) - .route("/version", get(Json(env!("CARGO_PKG_VERSION")))) - .with_state(state) - .layer(compression_layer); - - let mut port = 3110; - - let mut listener; - loop { - listener = TcpListener::bind(format!("0.0.0.0:{port}")).await; - if listener.is_ok() { - break; - } - port += 1; + Ok(Self(AppState { + query, + frontend, + websites_path, + })) } - info!("Starting server on port {port}..."); + pub async fn serve(self) -> color_eyre::Result<()> { + let state = self.0; - let listener = listener.unwrap(); + let compression_layer = CompressionLayer::new() + .br(true) + .deflate(true) + .gzip(true) + .zstd(true); - serve(listener, router).await?; + let router = Router::new() + .add_api_routes() + .add_website_routes(state.frontend) + .route("/version", get(Json(env!("CARGO_PKG_VERSION")))) + .with_state(state) + .layer(compression_layer); - Ok(()) + let mut port = 3110; + + let mut listener; + loop { + listener = TcpListener::bind(format!("0.0.0.0:{port}")).await; + if listener.is_ok() { + break; + } + port += 1; + } + + info!("Starting server on port {port}..."); + + let listener = listener.unwrap(); + + serve(listener, router).await?; + + Ok(()) + } } -pub fn log_result(code: StatusCode, path: &str, instant: Instant) { +pub fn log_result(code: StatusCode, uri: &Uri, instant: Instant) { let time = format!("{}µs", instant.elapsed().as_micros()); let time = time.bright_black(); match code { - StatusCode::INTERNAL_SERVER_ERROR => error!("{} {} {}", code.as_u16().red(), path, time), - StatusCode::NOT_MODIFIED => info!("{} {} {}", code.as_u16().bright_black(), path, time), - StatusCode::OK => info!("{} {} {}", code.as_u16().green(), path, time), - _ => error!("{} {} {}", code.as_u16().red(), path, time), + StatusCode::INTERNAL_SERVER_ERROR => error!("{} {} {}", code.as_u16().red(), uri, time), + StatusCode::NOT_MODIFIED => info!("{} {} {}", code.as_u16().bright_black(), uri, time), + StatusCode::OK => info!("{} {} {}", code.as_u16().green(), uri, time), + _ => error!("{} {} {}", code.as_u16().red(), uri, time), } }