diff --git a/CHANGELOG.md b/CHANGELOG.md index c57846c44..16ecf08c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,14 +15,17 @@ ## Website +- Added dashboards +- Added a Home option +- Added a library of PDFs viewable inside the app - Fixed service worker not passing 304 (not modified) response and instead serving cached responses - Fixed history not being properly registered -- Fixed prices on charts not having a wide enough background due to the font not being fully loaded during the creation of the chart - Fixed window being moveable on iOS when in standalone mode when it shouldn't be ## Parser - Added a `/datasets/last` json file with all the latest values +- Added `--rpcconnect` parameter to the config ## Server diff --git a/README.md b/README.md index b3d17d3d2..c2060b96a 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,10 @@ For the first launch, the parser will need several information such as: - `--rpcuser`: the username of the RPC credentials to talk to the bitcoin server - `--rpcpassword`: the password of the RPC credentials +Optionally you can also specify: +- `--rpcconnect`: if the bitcoin core server's IP is different than `localhost` +- `--rpcport`: if the port is different than `8332` + Everything will be saved in a `config.toml` file, which will allow you to simply run `./run.sh` next time Here's an example diff --git a/docker/Dockerfile b/docker/Dockerfile index 178f27880..efbc23a86 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,10 +1,11 @@ FROM rust:1.81 +ENV rpcconnect=localhost +ENV rpcport=8332 ENV rpcuser=satoshi ENV rpcpassword=nakamoto -ENV rpcport=8332 WORKDIR /container COPY . . -CMD ["sh", "-c", "bash cmd.sh ${rpcuser} ${rpcpassword} ${rpcport}"] +CMD ["sh", "-c", "bash cmd.sh ${rpcconnect} ${rpcport} ${rpcuser} ${rpcpassword}"] diff --git a/docker/cmd.sh b/docker/cmd.sh index 9de5d847d..28afa9a41 100755 --- a/docker/cmd.sh +++ b/docker/cmd.sh @@ -1,11 +1,13 @@ #!/usr/bin/env bash cd kibo/parser + ./run.sh \ --datadir=/bitcoin \ - --rpcuser=$1 \ - --rpcpassword=$2 \ - --rpcport=$3 + --rpcconnect=$1 \ + --rpcport=$2 \ + --rpcuser=$3 \ + --rpcpassword=$4 # cd ../server # ./run.sh & diff --git a/docker/run.sh b/docker/run.sh index a08f60d2f..01c26800c 100755 --- a/docker/run.sh +++ b/docker/run.sh @@ -1,6 +1,7 @@ docker run \ --env rpcuser=satoshi \ --env rpcpassword=nakamoto \ + --env rpcport=localhost \ --env rpcport=8332 \ --volume /tmp/kibo/datasets:/container/kibo/datasets \ --volume /tmp/kibo/price:/container/kibo/price \ diff --git a/parser/src/structs/config.rs b/parser/src/structs/config.rs index 8fd648d1d..c4a9a8fb2 100644 --- a/parser/src/structs/config.rs +++ b/parser/src/structs/config.rs @@ -10,6 +10,10 @@ pub struct Config { #[arg(long, value_name = "DIR")] pub datadir: Option, + /// Bitcoin RPC ip, default: localhost, saved + #[arg(long, value_name = "IP")] + pub rpcconnect: Option, + /// Bitcoin RPC port, default: 8332, saved #[arg(long, value_name = "PORT")] pub rpcport: Option, @@ -42,6 +46,12 @@ impl Config { config_saved.datadir = Some(datadir); } + if let Some(rpcconnect) = config_args.rpcconnect { + config_saved.rpcconnect = Some(rpcconnect); + } else { + config_saved.rpcconnect = Some("localhost".to_string()) + } + if let Some(rpcport) = config_args.rpcport { config_saved.rpcport = Some(rpcport); } else { diff --git a/parser/src/utils/rpc.rs b/parser/src/utils/rpc.rs index 92934127e..5c55f60e4 100644 --- a/parser/src/utils/rpc.rs +++ b/parser/src/utils/rpc.rs @@ -4,7 +4,11 @@ use crate::Config; pub fn create_rpc(config: &Config) -> color_eyre::Result { Ok(Client::new( - &format!("http://localhost:{}", config.rpcport.unwrap()), + &format!( + "http://{}:{}", + config.rpcconnect.as_ref().unwrap(), + config.rpcport.unwrap() + ), Auth::UserPass( config.rpcuser.clone().unwrap(), config.rpcpassword.clone().unwrap(), diff --git a/server/src/header_map.rs b/server/src/header_map.rs index f73dd18bb..8f09ddd66 100644 --- a/server/src/header_map.rs +++ b/server/src/header_map.rs @@ -41,6 +41,7 @@ pub trait HeaderMapUtils { fn insert_content_type_application_javascript(&mut self); fn insert_content_type_application_json(&mut self); fn insert_content_type_application_manifest_json(&mut self); + fn insert_content_type_application_pdf(&mut self); fn insert_content_type_text_css(&mut self); fn insert_content_type_text_html(&mut self); fn insert_content_type_text_plain(&mut self); @@ -148,6 +149,7 @@ impl HeaderMapUtils for HeaderMap { "html" => self.insert_content_type_text_html(), "css" => self.insert_content_type_text_css(), "txt" => self.insert_content_type_text_plain(), + "pdf" => self.insert_content_type_application_pdf(), "woff2" => self.insert_content_type_font_woff2(), "ico" => self.insert_content_type_image_icon(), "jpg" | "jpeg" => self.insert_content_type_image_jpeg(), @@ -190,6 +192,10 @@ impl HeaderMapUtils for HeaderMap { ); } + fn insert_content_type_application_pdf(&mut self) { + self.insert(header::CONTENT_TYPE, "application/pdf".parse().unwrap()); + } + fn insert_content_type_text_css(&mut self) { self.insert(header::CONTENT_TYPE, "text/css".parse().unwrap()); } diff --git a/server/src/website/handlers/file.rs b/server/src/website/handlers/file.rs index c04617f3b..7302ea070 100644 --- a/server/src/website/handlers/file.rs +++ b/server/src/website/handlers/file.rs @@ -16,7 +16,7 @@ use crate::header_map::HeaderMapUtils; use super::minify_js; -const WEBSITE_PATH: &str = "../website"; +const WEBSITE_PATH: &str = "../website/"; pub async fn file_handler(headers: HeaderMap, path: extract::Path) -> Response { let path = path.0.replace("..", "").replace("\\", ""); @@ -46,6 +46,8 @@ pub async fn index_handler(headers: HeaderMap) -> Response { } fn path_to_response(headers: HeaderMap, path: &Path) -> Response { + log(&path.to_str().unwrap().replace(WEBSITE_PATH, "")); + let (date, response) = headers.check_if_modified_since(path).unwrap(); if let Some(response) = response { @@ -79,8 +81,14 @@ fn path_to_response(headers: HeaderMap, path: &Path) -> Response { let serialized_path = path.to_str().unwrap(); if serialized_path.contains("fonts/") - || serialized_path.contains("assets/pwa/") + || serialized_path.contains("assets/") || serialized_path.contains("packages/") + || path.extension().is_some_and(|extension| { + extension == "pdf" + || extension == "jpg" + || extension == "png" + || extension == "woff2" + }) { headers.insert_cache_control_immutable(); } else { @@ -94,5 +102,5 @@ fn path_to_response(headers: HeaderMap, path: &Path) -> Response { } fn str_to_path(path: &str) -> PathBuf { - PathBuf::from(&format!("{WEBSITE_PATH}/{path}")) + PathBuf::from(&format!("{WEBSITE_PATH}{path}")) } diff --git a/website/fonts/satoshi/2024-09/font.var.woff2 b/website/assets/fonts/satoshi/2024-09/font.var.woff2 similarity index 100% rename from website/fonts/satoshi/2024-09/font.var.woff2 rename to website/assets/fonts/satoshi/2024-09/font.var.woff2 diff --git a/website/fonts/satoshi/FFL.txt b/website/assets/fonts/satoshi/FFL.txt similarity index 100% rename from website/fonts/satoshi/FFL.txt rename to website/assets/fonts/satoshi/FFL.txt diff --git a/website/assets/pdfs/block/2022-report.pdf b/website/assets/pdfs/block/2022-report.pdf new file mode 100644 index 000000000..90fde250f Binary files /dev/null and b/website/assets/pdfs/block/2022-report.pdf differ diff --git a/website/assets/pdfs/braiins/building-bitcoin-in-rust.pdf b/website/assets/pdfs/braiins/building-bitcoin-in-rust.pdf new file mode 100644 index 000000000..10d333f23 Binary files /dev/null and b/website/assets/pdfs/braiins/building-bitcoin-in-rust.pdf differ diff --git a/website/assets/pdfs/glassnode/cointime-economics.pdf b/website/assets/pdfs/glassnode/cointime-economics.pdf new file mode 100644 index 000000000..529d2e64f Binary files /dev/null and b/website/assets/pdfs/glassnode/cointime-economics.pdf differ diff --git a/website/assets/pdfs/nakamoto-project/understanding-bitcoin-adoption-in-the-united-states.pdf b/website/assets/pdfs/nakamoto-project/understanding-bitcoin-adoption-in-the-united-states.pdf new file mode 100644 index 000000000..a33034490 Binary files /dev/null and b/website/assets/pdfs/nakamoto-project/understanding-bitcoin-adoption-in-the-united-states.pdf differ diff --git a/website/assets/pdfs/nydig/protection-under-first-amendment.pdf b/website/assets/pdfs/nydig/protection-under-first-amendment.pdf new file mode 100644 index 000000000..8ef988be3 Binary files /dev/null and b/website/assets/pdfs/nydig/protection-under-first-amendment.pdf differ diff --git a/website/assets/pdfs/satoshi-nakamoto/whitepaper.pdf b/website/assets/pdfs/satoshi-nakamoto/whitepaper.pdf new file mode 100644 index 000000000..1e19b739f Binary files /dev/null and b/website/assets/pdfs/satoshi-nakamoto/whitepaper.pdf differ diff --git a/website/assets/pdfs/square/2021-bitcoin-clean-energy-initiative.pdf b/website/assets/pdfs/square/2021-bitcoin-clean-energy-initiative.pdf new file mode 100644 index 000000000..f99f655c1 Binary files /dev/null and b/website/assets/pdfs/square/2021-bitcoin-clean-energy-initiative.pdf differ diff --git a/website/index.html b/website/index.html index 004d2e0ad..d74b6585f 100644 --- a/website/index.html +++ b/website/index.html @@ -291,7 +291,8 @@ */ @font-face { font-family: "Satoshi"; - src: url("./fonts/satoshi/2024-09/font.var.woff2") format("woff2"); + src: url("./assets/fonts/satoshi/2024-09/font.var.woff2") + format("woff2"); font-weight: 100 900; font-display: block; font-style: normal; @@ -299,7 +300,8 @@ @font-face { font-family: "Satoshi Chart"; - src: url("./fonts/satoshi/2024-09/font.var.woff2") format("woff2"); + src: url("./assets/fonts/satoshi/2024-09/font.var.woff2") + format("woff2"); font-weight: 500 900; font-display: block; font-style: normal; @@ -478,6 +480,7 @@ } header { + flex-shrink: 0; display: flex; padding-top: 0.25rem /* 4px */; white-space: nowrap; @@ -755,6 +758,10 @@ } } + object { + background-color: white; + } + p { margin-top: 1rem; } @@ -976,7 +983,6 @@ #selected-frame { flex-direction: column; display: flex; - opacity: 0; > header { button { @@ -1002,6 +1008,71 @@ } } + > #home { + flex: 1; + margin-top: 0 !important; + font-size: var(--font-size-base); + line-height: var(--line-height-base); + text-wrap: pretty; + display: flex; + justify-content: center; + align-items: center; + + > div { + max-width: 32rem; + } + } + + > #dashboards { + display: flex; + flex-direction: column; + z-index: 50; + margin: -0.5px calc(-1.5rem - 1px); + + > table { + flex: 1; + table-layout: auto; + border-collapse: separate; + border-spacing: 0px 1px; + border: 1px; + border-top: 0; + padding: 0.25rem 0; + margin: -0.5px; + font-size: var(--font-size-xs); + line-height: var(--line-height-xs); + + caption { + border-bottom-style: dashed !important; + border-width: 1px; + padding: 0.375rem 0.625rem; + text-align: left; + } + + tr { + border: 1px; + + &:hover, + &:hover * { + color: var(--orange) !important; + } + + td { + padding: 0.125rem 0.625rem; + text-align: right; + + &:first-child { + text-align: left; + color: var(--off-color); + } + + > i { + color: var(--off-color); + } + } + } + } + } + > #charts { display: flex; flex-direction: column; @@ -1163,6 +1234,12 @@ } } } + + > object { + margin: -1.5rem; + flex: 1; + z-index: 100; + } } #share-div { @@ -1722,9 +1799,9 @@ // Prevent width jumping const savedWidth = localStorage.getItem("bar-width"); if (savedWidth) { - const mainFrames = window.document.getElementById("frames"); - if (!mainFrames) throw "Should exist"; - mainFrames.style.width = `${savedWidth}px`; + const main = window.document.getElementById("main"); + if (!main) throw "Should exist"; + main.style.width = `${savedWidth}px`; }
@@ -1827,7 +1904,7 @@

If you can't think of anything, you might want to try to - +