change to clap args and use url::Url to parse args

This commit is contained in:
Mark Sinclair
2025-11-11 19:36:17 +00:00
parent 51b6741f3e
commit 9517beecfa
15 changed files with 64 additions and 54 deletions
+1
View File
@@ -38,6 +38,7 @@ tokio-util = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true, features = ["env-filter"] }
tower-http = { workspace = true, features = ["cors", "trace"] }
url = { workspace = true }
utoipa = { workspace = true, features = ["axum_extras", "time"] }
utoipa-swagger-ui = { workspace = true, features = ["axum"] }
utoipauto = { workspace = true }
+14 -34
View File
@@ -1,8 +1,5 @@
use crate::cli::commands::run::Args;
use crate::db::DbPool;
use crate::env::vars::{
NYXD_SCRAPER_START_HEIGHT, NYXD_SCRAPER_UNSAFE_NUKE_DB,
NYXD_SCRAPER_USE_BEST_EFFORT_START_HEIGHT,
};
use nyxd_scraper_psql::{PostgresNyxdScraper, PruningOptions};
use std::fs;
use tracing::{info, warn};
@@ -10,48 +7,31 @@ use tracing::{info, warn};
pub(crate) mod webhook;
pub(crate) async fn run_chain_scraper(
args: Args,
config: &crate::config::Config,
connection_pool: DbPool,
) -> anyhow::Result<PostgresNyxdScraper> {
let websocket_url = std::env::var("NYXD_WS").expect("NYXD_WS not defined");
let use_best_effort_start_height = args.start_block_height.is_some();
let rpc_url = std::env::var("NYXD").expect("NYXD not defined");
let websocket_url = reqwest::Url::parse(&websocket_url)?;
let rpc_url = reqwest::Url::parse(&rpc_url)?;
// why are those not part of CLI? : (
let start_block_height = match std::env::var(NYXD_SCRAPER_START_HEIGHT).ok() {
None => None,
// blow up if passed malformed env value
Some(raw) => Some(raw.parse()?),
};
let use_best_effort_start_height =
match std::env::var(NYXD_SCRAPER_USE_BEST_EFFORT_START_HEIGHT).ok() {
None => false,
// blow up if passed malformed env value
Some(raw) => raw.parse()?,
};
let nuke_db: bool = match std::env::var(NYXD_SCRAPER_UNSAFE_NUKE_DB).ok() {
None => false,
// blow up if passed malformed env value
Some(raw) => raw.parse()?,
};
if nuke_db {
if args.nuke_db {
warn!("☢️☢️☢️ NUKING THE SCRAPER DATABASE");
fs::remove_file(config.chain_scraper_connection_string())?;
}
let database_storage = config
.chain_scraper_connection_string
.clone()
.and(args.db_connection_string)
.expect("no database connection string set in config");
let scraper = PostgresNyxdScraper::builder(nyxd_scraper_psql::Config {
websocket_url,
rpc_url,
database_storage: config.chain_scraper_connection_string.clone(),
websocket_url: args.websocket_url,
rpc_url: args.rpc_url,
database_storage,
pruning_options: PruningOptions::nothing(),
store_precommits: false,
start_block: nyxd_scraper_psql::StartingBlockOpts {
start_block_height,
start_block_height: args.start_block_height,
use_best_effort_start_height,
},
})
@@ -28,7 +28,7 @@ pub(crate) async fn execute(args: Args) -> Result<(), NymDataObservatoryError> {
.with_data_observatory_config(DataObservatoryConfig {
webhooks: vec![WebhookConfig {
id: DEFAULT_NYM_DATA_OBSERVATORY_ID.to_string(),
webhook_url: "https://webhook.site".to_string(),
webhook_url: url::Url::parse("https://webhook.site")?,
authentication: Some(AuthorizationBearerToken {
token: "1234".to_string(),
}),
@@ -2,9 +2,22 @@
// SPDX-License-Identifier: GPL-3.0-only
use crate::env::vars::*;
use url::Url;
#[derive(clap::Args, Debug)]
#[derive(clap::Args, Debug, Clone)]
pub(crate) struct Args {
#[arg(long, env = NYXD_WS, alias = "nyxd_ws")]
pub(crate) websocket_url: Url,
#[arg(long, env = NYXD, alias = "nyxd")]
pub(crate) rpc_url: Url,
#[arg(long, env = NYXD_SCRAPER_START_HEIGHT)]
pub(crate) start_block_height: Option<u32>,
#[arg(long, env = NYXD_SCRAPER_UNSAFE_NUKE_DB, default_value = "false")]
pub(crate) nuke_db: bool,
/// (Override) Postgres connection string for chain scraper history
#[arg(long, env = NYM_DATA_OBSERVATORY_DB_URL, alias = "db_url")]
pub(crate) db_connection_string: Option<String>,
@@ -22,7 +35,7 @@ pub(crate) struct Args {
long,
env = NYM_DATA_OBSERVATORY_WEBHOOK_URL
)]
pub webhook_url: Option<String>,
pub webhook_url: Option<Url>,
/// (Override) Optionally, authenticate with the webhook
#[clap(
+1 -1
View File
@@ -8,7 +8,7 @@ use clap::{Parser, Subcommand};
use nym_bin_common::bin_info;
use std::sync::OnceLock;
mod commands;
pub(crate) mod commands;
pub const DEFAULT_NYM_DATA_OBSERVATORY_ID: &str = "default-nym-data-observatory";
@@ -9,7 +9,7 @@ pub struct DataObservatoryConfig {
pub struct WebhookConfig {
pub id: String,
pub description: Option<String>,
pub webhook_url: String,
pub webhook_url: url::Url,
pub watch_for_chain_message_types: Vec<String>,
pub authentication: Option<HttpAuthenticationOptions>,
}
+5 -3
View File
@@ -81,7 +81,7 @@ impl ConfigBuilder {
save_path: Some(self.config_path),
data_observatory_config: self.data_observatory_config.unwrap_or_default(),
data_dir: self.data_dir,
chain_scraper_connection_string: self.chain_scraper_connection_string,
chain_scraper_connection_string: Some(self.chain_scraper_connection_string),
}
}
}
@@ -96,7 +96,7 @@ pub struct Config {
#[serde(skip)]
pub(crate) data_dir: PathBuf,
pub chain_scraper_connection_string: String,
pub chain_scraper_connection_string: Option<String>,
#[serde(default)]
pub data_observatory_config: DataObservatoryConfig,
@@ -182,7 +182,9 @@ impl Config {
}
pub fn chain_scraper_connection_string(&self) -> String {
self.chain_scraper_connection_string.clone()
self.chain_scraper_connection_string
.clone()
.expect("database connection string not set")
}
// simple wrapper that reads config file and assigns path location
+3
View File
@@ -3,6 +3,9 @@
#[allow(unused)]
pub mod vars {
pub const NYXD_WS: &str = "NYXD_WS";
pub const NYXD: &str = "NYXD";
pub const NYM_DATA_OBSERVATORY_NO_BANNER_ARG: &str = "NYM_DATA_OBSERVATORY_NO_BANNER";
pub const NYM_DATA_OBSERVATORY_CONFIG_ENV_FILE_ARG: &str =
"NYM_DATA_OBSERVATORY_CONFIG_ENV_FILE_ARG";
+3
View File
@@ -42,4 +42,7 @@ pub enum NymDataObservatoryError {
#[error(transparent)]
NymConfigTomlE(#[from] nym_config::error::NymConfigTomlError),
#[error(transparent)]
UrlParseFailure(#[from] url::ParseError),
}
+3 -1
View File
@@ -8,6 +8,7 @@ pub mod status {
use crate::db::models::CoingeckoPriceResponse;
use serde::{Deserialize, Serialize};
use time::OffsetDateTime;
use url::Url;
use utoipa::ToSchema;
#[derive(Clone, Copy, Debug, Serialize, Deserialize, schemars::JsonSchema, ToSchema)]
@@ -31,7 +32,8 @@ pub mod status {
pub struct Webhook {
pub id: String,
pub description: String,
pub webhook_url: String,
#[schema(value_type = String)]
pub webhook_url: Url,
pub watched_message_types: Vec<String>,
}
@@ -24,7 +24,7 @@ pub(crate) async fn execute(args: Args) -> Result<(), NymRewarderError> {
let config =
try_load_current_config(&args.custom_config_path)?.with_override(args.config_override);
SqliteNyxdScraper::new(config.scraper_config())
SqliteNyxdScraper::new(config.scraper_config()?)
.await?
.unsafe_process_single_block(args.height)
.await?;
@@ -37,7 +37,7 @@ pub(crate) async fn execute(args: Args) -> Result<(), NymRewarderError> {
let config =
try_load_current_config(&args.custom_config_path)?.with_override(args.config_override);
SqliteNyxdScraper::new(config.scraper_config())
SqliteNyxdScraper::new(config.scraper_config()?)
.await?
.unsafe_process_block_range(args.start_height, args.stop_height)
.await?;
+9 -4
View File
@@ -119,18 +119,23 @@ impl Config {
}
}
pub fn scraper_config(&self) -> nyxd_scraper_sqlite::Config {
nyxd_scraper_sqlite::Config {
pub fn scraper_config(&self) -> Result<nyxd_scraper_sqlite::Config, NymRewarderError> {
let database_storage = self.storage_paths.nyxd_scraper.as_path();
let database_storage = database_storage
.to_str()
.ok_or(NymRewarderError::ConfigError)?
.to_string();
Ok(nyxd_scraper_sqlite::Config {
websocket_url: self.nyxd_scraper.websocket_url.clone(),
rpc_url: self.base.upstream_nyxd.clone(),
database_storage: self.storage_paths.nyxd_scraper.clone(),
database_storage,
pruning_options: self.nyxd_scraper.pruning,
store_precommits: self.nyxd_scraper.store_precommits,
start_block: StartingBlockOpts {
start_block_height: None,
use_best_effort_start_height: true,
},
}
})
}
pub fn verification_config(&self) -> ticketbook_issuance::VerificationConfig {
@@ -15,7 +15,7 @@ pub const DEFAULT_ED25519_PUBLIC_IDENTITY_KEY_FILENAME: &str = "ed25519_identity
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ValidatorRewarderPaths {
pub nyxd_scraper: String,
pub nyxd_scraper: PathBuf,
pub reward_history: PathBuf,
@@ -47,9 +47,7 @@ impl Default for ValidatorRewarderPaths {
fn default() -> Self {
ValidatorRewarderPaths {
// validator rewarder uses sqlite
nyxd_scraper: (default_data_directory().join(DEFAULT_SCRAPER_DB_FILENAME))
.to_string_lossy()
.to_string(),
nyxd_scraper: default_data_directory().join(DEFAULT_SCRAPER_DB_FILENAME),
reward_history: default_data_directory().join(DEFAULT_REWARD_HISTORY_DB_FILENAME),
private_ed25519_identity_key_file: default_data_directory()
.join(DEFAULT_ED25519_PRIVATE_IDENTITY_KEY_FILENAME),
+4 -1
View File
@@ -11,7 +11,7 @@ use nym_validator_client::nyxd::tx::ErrorReport;
use nym_validator_client::nyxd::{AccountId, Coin};
use nyxd_scraper_sqlite::error::SqliteScraperError;
use std::io;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use thiserror::Error;
#[derive(Debug, Error)]
@@ -25,6 +25,9 @@ pub enum NymRewarderError {
#[error("failed to perform startup SQL migration: {0}")]
StartupMigrationFailure(#[from] sqlx::migrate::MigrateError),
#[error("config error: database storage path invalid")]
ConfigError,
#[error(
"failed to load config file using path '{}'. detailed message: {source}", path.display()
)]