Skip to content

Commit

Permalink
Refactoring main.rs moving to lib.rs before tests part 1/2
Browse files Browse the repository at this point in the history
  • Loading branch information
Vovke committed Sep 22, 2024
1 parent 1c72c05 commit 45d135a
Show file tree
Hide file tree
Showing 7 changed files with 485 additions and 514 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ shadow-rs = { version = "0.28", default-features = false, features = ["git2"] }

[dev-dependencies]
reqwest = { version = "0.12", features = ["json"] }
http = "1.1.0"
lazy_static = "1"
indoc = "2"

Expand Down
166 changes: 166 additions & 0 deletions src/arguments.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
use crate::{
definitions::{api_v2::Timestamp, Chain},
error::SeedEnvError,
logger, Error,
};
use ahash::AHashMap;
use clap::{Arg, ArgAction, Parser};
use serde::Deserialize;
use std::{
env, fs,
net::{IpAddr, Ipv4Addr, SocketAddr},
str,
};
use toml_edit::de;

shadow_rs::shadow!(shadow);

use shadow::{BUILD_TIME_3339, RUST_VERSION, SHORT_COMMIT};

macro_rules! env_var_prefix {
($var:literal) => {
concat!("KALATORI_", $var)
};
}

pub const SEED: &str = env_var_prefix!("SEED");
pub const OLD_SEED: &str = env_var_prefix!("OLD_SEED_");

const SOCKET_DEFAULT: SocketAddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 16726);
pub const DATABASE_DEFAULT: &str = "kalatori.db";

#[derive(Parser)]
#[command(
about,
disable_help_flag(true),
arg(
Arg::new("help")
.short('h')
.long("help")
.action(ArgAction::Help)
.help("Print this text.")
),
after_help(concat!(
"`SEED` is a required environment variable.\n\nMore documentation can be found at ",
env!("CARGO_PKG_REPOSITORY"),
".\n\nCopyright (C) 2024 ",
clap::crate_authors!()
)),
disable_version_flag(true),
version,
arg(
Arg::new("version")
.short('V')
.long("version")
.action(ArgAction::Version)
.help("Print the daemon version (and its build metadata).")
),
long_version(shadow_rs::formatcp!(
"{} ({SHORT_COMMIT})\n\nBuilt on {}\nwith {RUST_VERSION}.",
clap::crate_version!(),
shadow_rs::str_splice!(BUILD_TIME_3339, BUILD_TIME_3339.len().saturating_sub(6).., "Z").output,
)),
)]
pub struct CliArgs {
#[arg(
short,
long,
env(env_var_prefix!("CONFIG")),
value_name("PATH"),
default_value("configs/polkadot.toml")
)]
pub config: String,

#[arg(
short,
long,
env(env_var_prefix!("LOG")),
value_name("DIRECTIVES"),
default_value(logger::default_filter()),
default_missing_value(""),
num_args(0..=1),
require_equals(true),
)]
pub log: String,

#[arg(long, env(env_var_prefix!("REMARK")), visible_alias("rmrk"), value_name("STRING"))]
pub remark: Option<String>,

#[arg(short, long, env(env_var_prefix!("RECIPIENT")), value_name("HEX/SS58 ADDRESS"))]
pub recipient: String,
}

pub struct SeedEnvVars {
pub seed: String,
pub old_seeds: AHashMap<String, String>,
}

impl SeedEnvVars {
pub fn parse() -> Result<Self, SeedEnvError> {
const SEED_BYTES: &[u8] = SEED.as_bytes();

let mut seed_option = None;
let mut old_seeds = AHashMap::new();

for (raw_key, raw_value) in env::vars_os() {
match raw_key.as_encoded_bytes() {
SEED_BYTES => {
env::remove_var(raw_key);

seed_option = {
Some(
raw_value
.into_string()
.map_err(|_| SeedEnvError::InvalidUnicodeValue(SEED.into()))?,
)
};
}
raw_key_bytes => {
if let Some(stripped_raw_key) = raw_key_bytes.strip_prefix(OLD_SEED.as_bytes()) {
env::remove_var(&raw_key);

let key = str::from_utf8(stripped_raw_key)
.map_err(|_| SeedEnvError::InvalidUnicodeOldSeedKey)?;
let value = raw_value.to_str().ok_or(SeedEnvError::InvalidUnicodeValue(
format!("{OLD_SEED}{key}").into(),
))?;

old_seeds.insert(key.into(), value.into());
}
}
}
}

Ok(Self {
seed: seed_option.ok_or(SeedEnvError::SeedNotPresent)?,
old_seeds,
})
}
}

/// User-supplied settings through the config file.
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct Config {
pub account_lifetime: Timestamp,
#[serde(default = "default_host")]
pub host: SocketAddr,
pub database: Option<String>,
pub debug: Option<bool>,
#[serde(default)]
pub in_memory_db: bool,
pub chain: Vec<Chain>,
}

impl Config {
pub fn parse(path: String) -> Result<Self, Error> {
let unparsed_config =
fs::read_to_string(&path).map_err(|e| Error::ConfigFileRead(path, e))?;

de::from_str(&unparsed_config).map_err(Into::into)
}
}

fn default_host() -> SocketAddr {
SOCKET_DEFAULT
}
71 changes: 71 additions & 0 deletions src/logger.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use crate::{callback, chain, database, server, Error};
use tracing_subscriber::{fmt::time::UtcTime, EnvFilter};

const TARGETS: &[&str] = &[
callback::MODULE,
database::MODULE,
chain::MODULE,
server::MODULE,
env!("CARGO_PKG_NAME"),
];
const COMMA: &str = ",";
const INFO: &str = "=info";
const OFF: &str = "off";

pub fn initialize(directives: String) -> Result<(), Error> {
let filter =
EnvFilter::try_new(&directives).map_err(|e| Error::LoggerDirectives(directives, e))?;

tracing_subscriber::fmt()
.with_timer(UtcTime::rfc_3339())
.with_env_filter(filter)
.init();

Ok(())
}

fn default_filter_capacity() -> usize {
OFF.len().saturating_add(
TARGETS
.iter()
.map(|module| {
COMMA
.len()
.saturating_add(module.len())
.saturating_add(INFO.len())
})
.sum(),
)
}

pub fn default_filter() -> String {
let mut filter = String::with_capacity(default_filter_capacity());

filter.push_str(OFF);

for target in TARGETS {
filter.push_str(COMMA);
filter.push_str(target);
filter.push_str(INFO);
}

filter
}

#[cfg(test)]
mod tests {
use tracing_subscriber::EnvFilter;

#[test]
fn default_filter_capacity() {
assert_eq!(
super::default_filter().len(),
super::default_filter_capacity()
);
}

#[test]
fn default_filter_is_valid() {
assert!(EnvFilter::try_new(super::default_filter()).is_ok());
}
}
Loading

0 comments on commit 45d135a

Please sign in to comment.