From 99fdb00f1878d2895208ba6b7765110bc5fee2ed Mon Sep 17 00:00:00 2001 From: aglkm <39521015+aglkm@users.noreply.github.com> Date: Sat, 1 Jun 2024 16:28:19 +0300 Subject: [PATCH 01/13] bump version --- Cargo.lock | 2 +- Cargo.toml | 2 +- templates/base.html.tera | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5cc456a..daf2511 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -736,7 +736,7 @@ dependencies = [ [[package]] name = "grin-explorer" -version = "0.1.4" +version = "0.1.5" dependencies = [ "anyhow", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 8d3ddc1..648f13c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "grin-explorer" -version = "0.1.4" +version = "0.1.5" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/templates/base.html.tera b/templates/base.html.tera index 4b3bb6a..584869d 100644 --- a/templates/base.html.tera +++ b/templates/base.html.tera @@ -212,7 +212,7 @@
- v.0.1.4 + v.0.1.5 search From 8f5d015f6a2fa607fe7cb038d09be3d516687f53 Mon Sep 17 00:00:00 2001 From: aglkm <39521015+aglkm@users.noreply.github.com> Date: Sat, 1 Jun 2024 17:38:13 +0300 Subject: [PATCH 02/13] adjust coingecko option --- src/data.rs | 3 --- src/main.rs | 38 ++++++++++++++++++++++++++------------ src/requests.rs | 5 +---- templates/base.html.tera | 4 +++- 4 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/data.rs b/src/data.rs index bae2440..a9e8139 100644 --- a/src/data.rs +++ b/src/data.rs @@ -35,8 +35,6 @@ pub struct Dashboard { // mempool pub txns: String, pub stem: String, - // coingecko api - pub cg_api: String, } impl Dashboard { @@ -66,7 +64,6 @@ impl Dashboard { breakeven_cost: String::new(), txns: String::new(), stem: String::new(), - cg_api: String::new(), } } } diff --git a/src/main.rs b/src/main.rs index 5e74b06..80dde39 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,6 +19,7 @@ use crate::data::Dashboard; use crate::data::Block; use crate::data::Transactions; use crate::data::Kernel; +use crate::requests::CONFIG; // Rendering main (Dashboard) page. @@ -30,7 +31,7 @@ fn index(dashboard: &State>>) -> Template { route: "index", node_ver: &data.node_ver, proto_ver: &data.proto_ver, - cg_api: &data.cg_api, + cg_api: CONFIG.coingecko_api.clone(), }) } @@ -39,7 +40,8 @@ fn index(dashboard: &State>>) -> Template { #[get("/block_list")] fn block_list() -> Template { Template::render("block_list", context! { - route: "block_list", + route: "block_list", + cg_api: CONFIG.coingecko_api.clone(), }) } @@ -60,11 +62,13 @@ async fn block_list_by_height(input_height: &str) -> Template { if index >= height { Template::render("block_list", context! { - route: "block_list", + route: "block_list", + cg_api: CONFIG.coingecko_api.clone(), }) } else { Template::render("block_list", context! { - route: "block_list_by_height", + route: "block_list_by_height", + cg_api: CONFIG.coingecko_api.clone(), index, blocks, height, @@ -72,7 +76,8 @@ async fn block_list_by_height(input_height: &str) -> Template { } } else { Template::render("block_list", context! { - route: "block_list", + route: "block_list", + cg_api: CONFIG.coingecko_api.clone(), }) } } @@ -88,14 +93,16 @@ async fn block_details_by_height(height: &str) -> Template { if block.height.is_empty() == false { return Template::render("block_details", context! { - route: "block_details", + route: "block_details", + cg_api: CONFIG.coingecko_api.clone(), block, }); } } Template::render("error", context! { - route: "error", + route: "error", + cg_api: CONFIG.coingecko_api.clone(), }) } @@ -114,7 +121,8 @@ async fn block_header_by_hash(hash: &str) -> Either { } return Either::Left(Template::render("error", context! { - route: "error", + route: "error", + cg_api: CONFIG.coingecko_api.clone(), })) } @@ -128,13 +136,15 @@ async fn kernel(excess: &str) -> Template { if kernel.excess.is_empty() == false { return Template::render("kernel", context! { - route: "kernel", + route: "kernel", + cg_api: CONFIG.coingecko_api.clone(), kernel, }) } return Template::render("error", context! { - route: "error", + route: "error", + cg_api: CONFIG.coingecko_api.clone(), }) } @@ -147,7 +157,10 @@ fn search(input: Option<&str>) -> Either { // Unwrap Option and forward to Search page if no parameters let input = match input { Some(value) => value, - None => return Either::Left(Template::render("search", context! { route: "search", })), + None => return Either::Left(Template::render("search", context! { + route: "search", + cg_api: CONFIG.coingecko_api.clone(), + })), }; // Check for valid chars @@ -168,7 +181,8 @@ fn search(input: Option<&str>) -> Either { } Either::Left(Template::render("error", context! { - route: "error", + route: "error", + cg_api: CONFIG.coingecko_api.clone(), })) } diff --git a/src/requests.rs b/src/requests.rs index b6f62dd..30e10f6 100644 --- a/src/requests.rs +++ b/src/requests.rs @@ -21,7 +21,7 @@ use crate::Kernel; // Static explorer config structure lazy_static! { - static ref CONFIG: ExplorerConfig = { + pub static ref CONFIG: ExplorerConfig = { let mut cfg = ExplorerConfig::new(); let settings = Config::builder().add_source(config::File::with_name("Explorer")) .build().unwrap(); @@ -94,9 +94,6 @@ pub async fn get_status(dashboard: Arc>) -> Result<(), anyhow:: data.proto_ver = resp["result"]["Ok"]["protocol_version"].to_string(); } - // Also set cg_api value - data.cg_api = CONFIG.coingecko_api.clone(); - Ok(()) } diff --git a/templates/base.html.tera b/templates/base.html.tera index 584869d..e4da64b 100644 --- a/templates/base.html.tera +++ b/templates/base.html.tera @@ -215,15 +215,17 @@ v.0.1.5 - search + Search
+ {% if cg_api == "on" %}
Powered by CoinGecko
+ {% endif %}
From e81e53979121ec0e53e3d7b766dd3cda3f92ca71 Mon Sep 17 00:00:00 2001 From: aglkm <39521015+aglkm@users.noreply.github.com> Date: Sat, 1 Jun 2024 18:00:06 +0300 Subject: [PATCH 03/13] add ability to disable public api --- Explorer.toml | 10 +++-- src/data.rs | 2 + src/main.rs | 78 +++++++++++++++++++++------------------ src/requests.rs | 9 +++-- templates/base.html.tera | 2 +- templates/index.html.tera | 2 +- 6 files changed, 59 insertions(+), 44 deletions(-) diff --git a/Explorer.toml b/Explorer.toml index cd1dd2d..ac73530 100644 --- a/Explorer.toml +++ b/Explorer.toml @@ -19,8 +19,11 @@ foreign_api_secret_path = "~/.grin/main/.foreign_api_secret" # Path to Grin directory. grin_dir = "~/.grin" -# CoinGecko API on/off switch. -coingecko_api = "on" +# Enable or disable CoinGecko API. +coingecko_api = "enabled" + +# Enable or disable node POST API public access. +public_api = "enabled" # Testnet config @@ -31,5 +34,6 @@ coingecko_api = "on" # api_secret_path = "~/.grin/test/.api_secret" # foreign_api_secret_path = "~/.grin/test/.foreign_api_secret" # grin_dir = "~/.grin" -# coingecko_api = "off" +# coingecko_api = "disabled" +# public_api = "enabled" diff --git a/src/data.rs b/src/data.rs index a9e8139..5622eea 100644 --- a/src/data.rs +++ b/src/data.rs @@ -167,6 +167,7 @@ pub struct ExplorerConfig { pub api_secret: String, pub foreign_api_secret: String, pub coingecko_api: String, + pub public_api: String, } impl ExplorerConfig { @@ -182,6 +183,7 @@ impl ExplorerConfig { api_secret: String::new(), foreign_api_secret: String::new(), coingecko_api: String::new(), + public_api: String::new(), } } } diff --git a/src/main.rs b/src/main.rs index 80dde39..e44474c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -190,31 +190,35 @@ fn search(input: Option<&str>) -> Either { // Owner API. #[post("/v2/owner", data="")] async fn api_owner(data: &str) -> String { - let result = serde_json::from_str(data); + if CONFIG.public_api == "enabled" { + let result = serde_json::from_str(data); - let v: Value = match result { - Ok(value) => value, - Err(_err) => return "{\"error\":\"bad syntax\"}".to_string(), - }; - - let method = match v["method"].as_str() { - Some(value) => value, - _ => return "{\"error\":\"bad syntax\"}".to_string(), - }; - - // Whitelisted methods: get_connected_peer, get_peers, get_status. - if method == "get_connected_peers" || method == "get_peers" || method == "get_status" { - let resp = requests::call(method, v["params"].to_string().as_str(), v["id"].to_string().as_str(), "owner").await; - - let result = match resp { + let v: Value = match result { Ok(value) => value, - Err(_err) => return "{\"error\":\"rpc call failed\"}".to_string(), + Err(_err) => return "{\"error\":\"bad syntax\"}".to_string(), }; - return result.to_string(); - } + let method = match v["method"].as_str() { + Some(value) => value, + _ => return "{\"error\":\"bad syntax\"}".to_string(), + }; + + // Whitelisted methods: get_connected_peer, get_peers, get_status. + if method == "get_connected_peers" || method == "get_peers" || method == "get_status" { + let resp = requests::call(method, v["params"].to_string().as_str(), v["id"].to_string().as_str(), "owner").await; - "{\"error\":\"not allowed\"}".to_string() + let result = match resp { + Ok(value) => value, + Err(_err) => return "{\"error\":\"rpc call failed\"}".to_string(), + }; + + return result.to_string(); + } + + "{\"error\":\"not allowed\"}".to_string() + } else { + "{\"error\":\"not allowed\"}".to_string() + } } @@ -222,26 +226,30 @@ async fn api_owner(data: &str) -> String { // All methods are whitelisted. #[post("/v2/foreign", data="")] async fn api_foreign(data: &str) -> String { - let result = serde_json::from_str(data); + if CONFIG.public_api == "enabled" { + let result = serde_json::from_str(data); - let v: Value = match result { - Ok(value) => value, - Err(_err) => return "{\"error\":\"bad syntax\"}".to_string(), - }; + let v: Value = match result { + Ok(value) => value, + Err(_err) => return "{\"error\":\"bad syntax\"}".to_string(), + }; - let method = match v["method"].as_str() { - Some(value) => value, - _ => return "{\"error\":\"bad syntax\"}".to_string(), - }; + let method = match v["method"].as_str() { + Some(value) => value, + _ => return "{\"error\":\"bad syntax\"}".to_string(), + }; - let resp = requests::call(method, v["params"].to_string().as_str(), v["id"].to_string().as_str(), "foreign").await; + let resp = requests::call(method, v["params"].to_string().as_str(), v["id"].to_string().as_str(), "foreign").await; - let result = match resp { - Ok(value) => value, - Err(_err) => return "{\"error\":\"rpc call failed\"}".to_string(), - }; + let result = match resp { + Ok(value) => value, + Err(_err) => return "{\"error\":\"rpc call failed\"}".to_string(), + }; - result.to_string() + result.to_string() + } else { + "{\"error\":\"not allowed\"}".to_string() + } } diff --git a/src/requests.rs b/src/requests.rs index 30e10f6..bf64796 100644 --- a/src/requests.rs +++ b/src/requests.rs @@ -38,6 +38,7 @@ lazy_static! { "foreign_api_secret_path" => cfg.foreign_api_secret_path = value, "grin_dir" => cfg.grin_dir = value, "coingecko_api" => cfg.coingecko_api = value, + "public_api" => cfg.public_api = value, _ => println!("{} Unknown config setting '{}'.", "[ ERROR ]".red(), name), } } @@ -147,7 +148,7 @@ pub async fn get_market(dashboard: Arc>) -> Result<(), Error> { let result; let mut val = Value::Null; - if CONFIG.coingecko_api == "on" { + if CONFIG.coingecko_api == "enabled" { client = reqwest::Client::new(); result = client.get("https://api.coingecko.com/api/v3/simple/price?ids=grin&vs_currencies=usd%2Cbtc&include_24hr_vol=true").send().await?; val = serde_json::from_str(&result.text().await.unwrap()).unwrap(); @@ -170,7 +171,7 @@ pub async fn get_market(dashboard: Arc>) -> Result<(), Error> { data.soft_supply = format!("{:.2}", supply.to_string().parse::().unwrap() / 3150000000.0 * 100.0); - if CONFIG.coingecko_api == "on" && val != Value::Null { + if CONFIG.coingecko_api == "enabled" && val != Value::Null { // Check if CoingGecko API returned error if let Some(status) = val.get("status") { println!("{} {}.", "[ WARNING ]".yellow(), @@ -201,7 +202,7 @@ pub fn get_disk_usage(dashboard: Arc>) -> Result<(), Error> { let mut data = dashboard.lock().unwrap(); let chain_data; - if CONFIG.coingecko_api == "on" { + if CONFIG.coingecko_api == "enabled" { chain_data = format!("{}/main/chain_data", CONFIG.grin_dir); } else { chain_data = format!("{}/test/chain_data", CONFIG.grin_dir); @@ -250,7 +251,7 @@ pub async fn get_mining_stats(dashboard: Arc>) -> Result<(), an data.difficulty = net_diff.to_string(); - if CONFIG.coingecko_api == "on" { + if CONFIG.coingecko_api == "enabled" { // Calculating G1-mini production per hour let coins_per_hour = 1.2 / hashrate * 60.0 * 60.0; diff --git a/templates/base.html.tera b/templates/base.html.tera index e4da64b..f332790 100644 --- a/templates/base.html.tera +++ b/templates/base.html.tera @@ -219,7 +219,7 @@ - {% if cg_api == "on" %} + {% if cg_api == "enabled" %}
Powered by CoinGecko diff --git a/templates/index.html.tera b/templates/index.html.tera index ac1e8c0..6fd4d59 100644 --- a/templates/index.html.tera +++ b/templates/index.html.tera @@ -6,7 +6,7 @@ {# We have different UI to display if CoinGecko API is disabled by user #} -{% if cg_api == "on" %} +{% if cg_api == "enabled" %} {# CoinGecko API is enabled #}
From b59f50a615661026ad30d0ff6a58666c95c4c1de Mon Sep 17 00:00:00 2001 From: aglkm <39521015+aglkm@users.noreply.github.com> Date: Sun, 2 Jun 2024 15:48:13 +0300 Subject: [PATCH 04/13] prettify UI --- templates/base.html.tera | 20 +++-- templates/block_details.html.tera | 12 +-- templates/block_list.html.tera | 118 +++++++++++++++--------------- templates/error.html.tera | 2 - templates/index.html.tera | 40 +++++----- templates/kernel.html.tera | 7 +- templates/search.html.tera | 6 +- 7 files changed, 101 insertions(+), 104 deletions(-) diff --git a/templates/base.html.tera b/templates/base.html.tera index f332790..b0db59d 100644 --- a/templates/base.html.tera +++ b/templates/base.html.tera @@ -21,7 +21,7 @@ -