Skip to content

Commit

Permalink
feat(cli): add helpful CLI commands (#866)
Browse files Browse the repository at this point in the history
* Add helpful CLI commands

* Replace printlns with tracing

* PR suggestion

* only print hosts for mongo connection

* Flip `no_run` and add some docs
  • Loading branch information
Alexandcoats authored Nov 11, 2022
1 parent fdbcea6 commit 7e4ab39
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 38 deletions.
53 changes: 45 additions & 8 deletions src/bin/inx-chronicle/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ impl ClArgs {
/// Process subcommands and return whether the app should early exit.
#[allow(unused)]
#[allow(clippy::collapsible_match)]
pub async fn process_subcommands(&self, config: &ChronicleConfig) -> Result<bool, Error> {
pub async fn process_subcommands(&self, config: &ChronicleConfig) -> Result<PostCommand, Error> {
if let Some(subcommand) = &self.subcommand {
match subcommand {
#[cfg(feature = "api")]
Expand All @@ -195,20 +195,21 @@ impl ClArgs {
let exp_ts = time::OffsetDateTime::from_unix_timestamp(claims.exp.unwrap() as _).unwrap();
let jwt = auth_helper::jwt::JsonWebToken::new(claims, api_data.secret_key.as_ref())
.map_err(crate::api::ApiError::InvalidJwt)?;
println!("Bearer {}", jwt);
println!(
tracing::info!("Bearer {}", jwt);
tracing::info!(
"Expires: {} ({})",
exp_ts,
humantime::format_duration(api_data.jwt_expiration)
);
return Ok(true);
return Ok(PostCommand::Exit);
}
#[cfg(feature = "analytics")]
Subcommands::FillAnalytics {
start_milestone,
end_milestone,
num_tasks,
} => {
tracing::info!("Connecting to database using hosts: `{}`.", config.mongodb.hosts_str()?);
let db = chronicle::db::MongoDb::connect(&config.mongodb).await?;
let start_milestone = if let Some(index) = start_milestone {
*index
Expand Down Expand Up @@ -244,9 +245,9 @@ impl ClArgs {
{
let analytics = db.get_all_analytics(index).await?;
influx_db.insert_all_analytics(timestamp, index, analytics).await?;
println!("Finished analytics for milestone: {}", index);
tracing::info!("Finished analytics for milestone {}", index);
} else {
println!("No milestone in database for index {}", index);
tracing::info!("No milestone in database for index {}", index);
}
}
Result::<_, Error>::Ok(())
Expand All @@ -256,12 +257,29 @@ impl ClArgs {
// Panic: Acceptable risk
res.unwrap()?;
}
return Ok(true);
return Ok(PostCommand::Exit);
}
#[cfg(debug_assertions)]
Subcommands::ClearDatabase { run } => {
tracing::info!("Connecting to database using hosts: `{}`.", config.mongodb.hosts_str()?);
let db = chronicle::db::MongoDb::connect(&config.mongodb).await?;
db.clear().await?;
tracing::info!("Database cleared successfully.");
if !run {
return Ok(PostCommand::Exit);
}
}
Subcommands::BuildIndexes => {
tracing::info!("Connecting to database using hosts: `{}`.", config.mongodb.hosts_str()?);
let db = chronicle::db::MongoDb::connect(&config.mongodb).await?;
super::build_indexes(&db).await?;
tracing::info!("Indexes built successfully.");
return Ok(PostCommand::Exit);
}
_ => (),
}
}
Ok(false)
Ok(PostCommand::Start)
}
}

Expand All @@ -270,13 +288,32 @@ pub enum Subcommands {
/// Generate a JWT token using the available config.
#[cfg(feature = "api")]
GenerateJWT,
/// Manually fill the analytics database.
#[cfg(feature = "analytics")]
FillAnalytics {
/// The inclusive starting milestone index.
#[arg(short, long)]
start_milestone: Option<chronicle::types::tangle::MilestoneIndex>,
/// The exclusive ending milestone index.
#[arg(short, long)]
end_milestone: Option<chronicle::types::tangle::MilestoneIndex>,
/// The number of parallel tasks to use when filling the analytics.
#[arg(short, long)]
num_tasks: Option<usize>,
},
/// Clear the chronicle database.
#[cfg(debug_assertions)]
ClearDatabase {
/// Run the application after this command.
#[arg(short, long)]
run: bool,
},
/// Manually build indexes.
BuildIndexes,
}

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum PostCommand {
Start,
Exit,
}
61 changes: 34 additions & 27 deletions src/bin/inx-chronicle/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ use tokio::task::JoinSet;
use tracing::{debug, error, info};
use tracing_subscriber::{fmt::format::FmtSpan, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};

use crate::{cli::ClArgs, error::Error};
use self::{
cli::{ClArgs, PostCommand},
error::Error,
};

#[tokio::main]
async fn main() -> Result<(), Error> {
Expand All @@ -33,13 +36,13 @@ async fn main() -> Result<(), Error> {

let cl_args = ClArgs::parse();
let config = cl_args.get_config()?;
if cl_args.process_subcommands(&config).await? {
if cl_args.process_subcommands(&config).await? == PostCommand::Exit {
return Ok(());
}

set_up_logging(&config)?;

info!("Connecting to database at bind address `{}`.", config.mongodb.conn_str);
info!("Connecting to database using hosts: `{}`.", config.mongodb.hosts_str()?);
let db = MongoDb::connect(&config.mongodb).await?;
debug!("Available databases: `{:?}`", db.get_databases().await?);
info!(
Expand All @@ -49,30 +52,7 @@ async fn main() -> Result<(), Error> {
);

#[cfg(feature = "stardust")]
{
use chronicle::db::collections;
let start_indexes = db.get_index_names().await?;
db.create_indexes::<collections::OutputCollection>().await?;
db.create_indexes::<collections::BlockCollection>().await?;
db.create_indexes::<collections::LedgerUpdateCollection>().await?;
db.create_indexes::<collections::MilestoneCollection>().await?;
let end_indexes = db.get_index_names().await?;
for (collection, indexes) in end_indexes {
if let Some(old_indexes) = start_indexes.get(&collection) {
let num_created = indexes.difference(old_indexes).count();
if num_created > 0 {
info!("Created {} new indexes in {}", num_created, collection);
if tracing::enabled!(tracing::Level::DEBUG) {
for index in indexes.difference(old_indexes) {
debug!(" - {}", index);
}
}
}
} else {
info!("Created {} new indexes in {}", indexes.len(), collection);
}
}
}
build_indexes(&db).await?;

let mut tasks: JoinSet<Result<(), Error>> = JoinSet::new();

Expand Down Expand Up @@ -186,3 +166,30 @@ fn set_up_logging(#[allow(unused)] config: &ChronicleConfig) -> Result<(), Error
registry.init();
Ok(())
}

#[cfg(feature = "stardust")]
async fn build_indexes(db: &MongoDb) -> Result<(), Error> {
use chronicle::db::collections;
let start_indexes = db.get_index_names().await?;
db.create_indexes::<collections::OutputCollection>().await?;
db.create_indexes::<collections::BlockCollection>().await?;
db.create_indexes::<collections::LedgerUpdateCollection>().await?;
db.create_indexes::<collections::MilestoneCollection>().await?;
let end_indexes = db.get_index_names().await?;
for (collection, indexes) in end_indexes {
if let Some(old_indexes) = start_indexes.get(&collection) {
let num_created = indexes.difference(old_indexes).count();
if num_created > 0 {
info!("Created {} new indexes in {}", num_created, collection);
if tracing::enabled!(tracing::Level::DEBUG) {
for index in indexes.difference(old_indexes) {
debug!(" - {}", index);
}
}
}
} else {
info!("Created {} new indexes in {}", indexes.len(), collection);
}
}
Ok(())
}
18 changes: 15 additions & 3 deletions src/db/mongodb/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use std::collections::{HashMap, HashSet};
use mongodb::{
bson::{doc, Document},
error::Error,
options::{ClientOptions, Credential},
options::{ClientOptions, ConnectionString, Credential, HostInfo},
Client,
};
use serde::{Deserialize, Serialize};
Expand All @@ -28,7 +28,7 @@ pub struct MongoDb {

impl MongoDb {
const DEFAULT_NAME: &'static str = "chronicle";
const DEFAULT_CONNECT_URL: &'static str = "mongodb://localhost:27017";
const DEFAULT_CONNECT_STR: &'static str = "mongodb://localhost:27017";

/// Constructs a [`MongoDb`] by connecting to a MongoDB instance.
pub async fn connect(config: &MongoDbConfig) -> Result<Self, Error> {
Expand Down Expand Up @@ -149,10 +149,22 @@ pub struct MongoDbConfig {
pub min_pool_size: Option<u32>,
}

impl MongoDbConfig {
/// Get the hosts portion of the connection string.
pub fn hosts_str(&self) -> Result<String, Error> {
let hosts = ConnectionString::parse(&self.conn_str)?.host_info;
Ok(match hosts {
HostInfo::HostIdentifiers(hosts) => hosts.iter().map(ToString::to_string).collect::<Vec<_>>().join(","),
HostInfo::DnsRecord(hostname) => hostname,
_ => unreachable!(),
})
}
}

impl Default for MongoDbConfig {
fn default() -> Self {
Self {
conn_str: MongoDb::DEFAULT_CONNECT_URL.to_string(),
conn_str: MongoDb::DEFAULT_CONNECT_STR.to_string(),
username: None,
password: None,
database_name: MongoDb::DEFAULT_NAME.to_string(),
Expand Down

0 comments on commit 7e4ab39

Please sign in to comment.