diff --git a/README.md b/README.md index 36de80bf0..ed0b230b2 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ Please open an issue if you want to add another instance - `-txindex=1` - `-blocksxor=0` - RPC credentials - - Example: `bitcoind -datadir="$HOME/.bitcoin" -blocksonly -txindex=1 -blocksxor=0 -rpcuser="satoshi" -rpcpassword="nakamoto"` + - Example: `bitcoind -datadir="$HOME/.bitcoin" -blocksonly -txindex=1 -blocksxor=0` - Git ### Manual @@ -122,11 +122,12 @@ Now we can finally start by running the parser, you need to use the `./run.sh` s For the first launch, the parser will need several information such as: - `--datadir`: which is bitcoin data directory path, prefer `$HOME` to `~` as the latter might not work -- `--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: +- `--rpccookiefile`: the path to the cookie file if not default +- `--rpcuser`: the username of the RPC credentials to talk to the bitcoin server if set +- `--rpcpassword`: the password of the RPC credentials if set - `--rpcconnect`: if the bitcoin core server's IP is different than `localhost` - `--rpcport`: if the port is different than `8332` @@ -135,7 +136,7 @@ Everything will be saved in a `config.toml` file, which will allow you to simply Here's an example ```bash -./run.sh --datadir=$HOME/Developer/bitcoin --rpcuser=satoshi --rpcpassword=nakamoto +./run.sh --datadir=$HOME/Developer/bitcoin ``` In a **new** terminal, go to the `server`'s folder of the repository diff --git a/parser/src/price/binance.rs b/parser/src/price/binance.rs index dd0bab870..bbd988b13 100644 --- a/parser/src/price/binance.rs +++ b/parser/src/price/binance.rs @@ -145,8 +145,8 @@ impl Binance { }) .collect::>()) }, + 30, 10, - 5, ) } @@ -195,7 +195,7 @@ impl Binance { }) .collect::>()) }, - 10, + 30, 10, ) } diff --git a/parser/src/price/kibo.rs b/parser/src/price/kibo.rs index ae6e8dadf..51a48adc0 100644 --- a/parser/src/price/kibo.rs +++ b/parser/src/price/kibo.rs @@ -55,7 +55,7 @@ impl Kibo { .map(Self::value_to_ohlc) .collect_vec()) }, - 10, + 30, RETRIES, ) } @@ -92,7 +92,7 @@ impl Kibo { }) .collect::>()) }, - 10, + 30, RETRIES, ) } diff --git a/parser/src/price/kraken.rs b/parser/src/price/kraken.rs index 922c308e5..7567964b1 100644 --- a/parser/src/price/kraken.rs +++ b/parser/src/price/kraken.rs @@ -60,7 +60,7 @@ impl Kraken { }) .collect::>()) }, - 10, + 30, 10, ) } @@ -115,7 +115,7 @@ impl Kraken { }) .collect::>()) }, - 10, + 30, 10, ) } diff --git a/parser/src/structs/config.rs b/parser/src/structs/config.rs index bf88dca8b..db7287c24 100644 --- a/parser/src/structs/config.rs +++ b/parser/src/structs/config.rs @@ -1,6 +1,11 @@ -use std::fs::{self}; +use std::{ + fs::{self}, + path::{Path, PathBuf}, +}; +use biter::bitcoincore_rpc::Auth; use clap::Parser; +use color_eyre::eyre::eyre; use serde::{Deserialize, Serialize}; use crate::log; @@ -20,6 +25,10 @@ pub struct Config { #[arg(long, value_name = "PORT")] pub rpcport: Option, + /// Bitcoin RPC cookie file, saved + #[arg(long, value_name = "PATH")] + pub rpccookiefile: Option, + /// Bitcoin RPC username, saved #[arg(long, value_name = "USERNAME")] pub rpcuser: Option, @@ -75,6 +84,10 @@ impl Config { config_saved.rpcport = Some(rpcport); } + if let Some(rpccookiefile) = config_args.rpccookiefile.take() { + config_saved.rpccookiefile = Some(rpccookiefile); + } + if let Some(rpcuser) = config_args.rpcuser.take() { config_saved.rpcuser = Some(rpcuser); } @@ -109,6 +122,7 @@ impl Config { log(&format!("datadir: {:?}", config.datadir)); log(&format!("rpcconnect: {:?}", config.rpcconnect)); log(&format!("rpcport: {:?}", config.rpcport)); + log(&format!("rpccookiefile: {:?}", config.rpccookiefile)); log(&format!("rpcuser: {:?}", config.rpcuser)); log(&format!("rpcpassword: {:?}", config.rpcpassword)); log(&format!("delay: {:?}", config.delay)); @@ -132,30 +146,53 @@ impl Config { fn check(&self) { if self.datadir.is_none() { - Self::exit("datadir"); + println!( + "You need to set the --datadir parameter at least once to run the parser.\nRun the program with '-h' for help." + ); + std::process::exit(1); } - if self.rpcuser.is_none() { - Self::exit("rpcuser"); + let path = Path::new(self.datadir.as_ref().unwrap()); + if !path.is_dir() { + println!("Expect path '{:#?}' to be a directory.", path); + std::process::exit(1); } - if self.rpcpassword.is_none() { - Self::exit("rpcpassword"); + if self.to_rpc_auth().is_err() { + println!( + "No way found to authenticate the RPC client, please either set --rpccookiefile or --rpcuser and --rpcpassword.\nRun the program with '-h' for help." + ); + std::process::exit(1); } } - fn exit(attribute: &str) { - println!( - "You need to set the --{} parameter at least once to run the parser.\nRun the program with '-h' for help.", attribute - ); - - std::process::exit(1); - } - fn write(&self) -> std::io::Result<()> { fs::write(Self::PATH, toml::to_string(self).unwrap()) } + pub fn to_rpc_auth(&self) -> color_eyre::Result { + let cookie = Path::new(self.datadir.as_ref().unwrap()).join(".cookie"); + + if cookie.is_file() { + Ok(Auth::CookieFile(cookie)) + } else if self + .rpccookiefile + .as_ref() + .is_some_and(|cookie| Path::new(cookie).is_file()) + { + Ok(Auth::CookieFile(PathBuf::from( + self.rpccookiefile.as_ref().unwrap(), + ))) + } else if self.rpcuser.is_some() && self.rpcpassword.is_some() { + Ok(Auth::UserPass( + self.rpcuser.clone().unwrap(), + self.rpcpassword.clone().unwrap(), + )) + } else { + Err(eyre!("Failed to find correct auth")) + } + } + pub fn dry_run(&self) -> bool { self.dry_run.is_some_and(|b| b) } diff --git a/parser/src/structs/generic_map.rs b/parser/src/structs/generic_map.rs index f7dd6e1cc..a384f6619 100644 --- a/parser/src/structs/generic_map.rs +++ b/parser/src/structs/generic_map.rs @@ -699,7 +699,7 @@ where }) .into(); - if previous_average.is_nan() { + if previous_average.is_nan() || previous_average.is_infinite() { previous_average = 0.0; } @@ -708,17 +708,11 @@ where panic!() })); - if last_value.is_nan() { + if last_value.is_nan() || last_value.is_infinite() { last_value = 0.0; } - let _average = (previous_average * (len - 1.0) + last_value) / len; - - if _average.is_nan() || _average.is_infinite() { - average.replace(0.0.into()); - } else { - average.replace(_average.into()); - } + average.replace(((previous_average * (len - 1.0) + last_value) / len).into()); self.insert_computed(*key, average.unwrap()); }); diff --git a/parser/src/utils/rpc.rs b/parser/src/utils/rpc.rs index f2dc7c6c2..4e65bd8aa 100644 --- a/parser/src/utils/rpc.rs +++ b/parser/src/utils/rpc.rs @@ -1,4 +1,4 @@ -use biter::bitcoincore_rpc::{Auth, Client}; +use biter::bitcoincore_rpc::Client; use crate::Config; @@ -12,9 +12,6 @@ pub fn create_rpc(config: &Config) -> color_eyre::Result { .unwrap_or(&"localhost".to_owned()), config.rpcport.unwrap_or(8332) ), - Auth::UserPass( - config.rpcuser.clone().unwrap(), - config.rpcpassword.clone().unwrap(), - ), + config.to_rpc_auth().unwrap(), )?) } diff --git a/website/index.html b/website/index.html index 75797aca3..a26b0c989 100644 --- a/website/index.html +++ b/website/index.html @@ -37,11 +37,10 @@ line-height: 1.5; -webkit-text-size-adjust: 100%; tab-size: 4; - font-family: var(--default-font-family), ui-sans-serif, system-ui, - sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", + font-family: "Satoshi", ui-sans-serif, system-ui, sans-serif, + "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; - font-feature-settings: var(--default-font-feature-settings, normal); - font-variation-settings: var(--default-font-variation-settings, normal); + font-feature-settings: "ss03"; -webkit-tap-highlight-color: transparent; } @@ -137,12 +136,6 @@ background: transparent; } - input:where(:not([type="button"], [type="reset"], [type="submit"])), - select, - textarea { - border: 1px solid; - } - button, input:where([type="button"], [type="reset"], [type="submit"]), ::file-selector-button { @@ -221,10 +214,6 @@ :root { color-scheme: light dark; - --default-font-family: "Satoshi"; - --default-font-feature-settings: "normal"; - --default-font-variation-settings: "normal"; - /* before: #ffffe3 */ /* current: oklch(99% 0.01 44) */ --white: #fffaf6; @@ -243,9 +232,27 @@ /* before: #10100e */ /* current: oklch(17.5% 0.005 44) */ --black: #12100f; + --red: oklch(0.607 0.241 26.328); /* before: #f26610 */ /* current: oklch(67.64% 0.191 44.41) */ - --orange: #f26610; + --orange: oklch(67.64% 0.191 44.41); /*oklch(0.6755 0.2175 44.36); */ + --amber: oklch(0.7175 0.1835 64.199); + --yellow: oklch(0.738 0.173 80.9405); + --avocado: oklch(0.72 0.19 110); + --lime: oklch(0.708 0.2165 131.267); + --green: oklch(0.675 0.2065 149.3965); + --emerald: oklch(0.646 0.1575 162.8525); + --teal: oklch(0.652 0.129 183.6035); + --cyan: oklch(0.662 0.1345 218.472); + --sky: oklch(0.6365 0.1635 239.6445); + --blue: oklch(0.5845 0.2295 261.348); + --indigo: oklch(0.548 0.2475 277.0415); + --violet: oklch(0.5735 0.2655 292.863); + --purple: oklch(0.5925 0.2765 303.1105); + --fuchsia: oklch(0.629 0.294 322.523); + --pink: oklch(0.624 0.245 357.444); + --rose: oklch(0.6155 0.2495 17.012); + --dollar: var(--green); --font-size-2xs: 0.625rem; --line-height-2xs: 1rem; @@ -273,12 +280,19 @@ --transform-scale-active: scaleY(0.9); - --default-main-width: 400px; + --default-main-width: 25rem; --background-color: light-dark(var(--white), var(--black)); --color: light-dark(var(--black), var(--white)); --off-color: light-dark(var(--light-gray), var(--dark-gray)); --border-color: light-dark(var(--lighter-gray), var(--darker-gray)); + + --emoji-filter: grayscale(1) contrast(5) invert(1); + @media (prefers-color-scheme: dark) { + --emoji-filter: grayscale(1) contrast(5); + } + + --bottom-area: 69vh; } [data-resize] { @@ -377,7 +391,13 @@ display: flex; width: 100%; flex: 1; - margin-bottom: 4rem; + margin-bottom: calc(var(--main-padding) + 1.5rem); + + @media (max-width: 767px) { + html[data-display="standalone"] & { + margin-bottom: calc(var(--main-padding) + 2rem); + } + } @media (min-width: 768px) { border-left: 1px; @@ -386,23 +406,7 @@ } header { - flex-shrink: 0; - display: flex; - - white-space: nowrap; - overflow-x: auto; - padding-bottom: 1rem; - margin-bottom: -1rem; - padding-left: var(--main-padding); - margin-left: var(--negative-main-padding); - padding-right: var(--main-padding); - margin-right: var(--negative-main-padding); - - & > * { - flex: 1; - } - - & > div > small { + small { font-weight: var(--font-weight-base); font-size: var(--font-size-base); line-height: var(--line-height-base); @@ -596,11 +600,17 @@ left: 0; display: flex; margin: var(--main-padding); - margin-bottom: calc(var(--main-padding) + 0.5rem); + margin-bottom: var(--main-padding); z-index: 20; pointer-events: none; justify-content: center; + @media (max-width: 767px) { + html[data-display="standalone"] & { + margin-bottom: calc(var(--main-padding) + 0.5rem); + } + } + > fieldset { background-color: var(--border-color); display: flex; @@ -639,22 +649,22 @@ background-color: white; } - nav, - search, section { + flex: 1; + min-width: 0; + } + + nav, + search { flex: 1; overflow-x: hidden; overflow-y: auto; padding: var(--main-padding); height: 100%; - - &:not(#selected-frame) { - padding-bottom: 69vh; - } - - > * + * { - margin-top: 2rem; - } + display: flex; + flex-direction: column; + gap: 2rem; + padding-bottom: var(--bottom-area); } sup { @@ -727,6 +737,7 @@ user-select: none; -webkit-user-select: none; text-transform: capitalize; + margin-top: -0.375rem; button::after { color: var(--off-color); @@ -1459,7 +1470,7 @@ Bitcoin is hope - 🕊️ + 🕊️ @@ -1517,19 +1528,19 @@