diff --git a/Cargo.lock b/Cargo.lock index 01850ab4f756..722787f1fa35 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2017,6 +2017,15 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "directories" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f51c5d4ddabd36886dd3e1438cb358cdcb0d7c499cb99cb4ac2e38e18b5cb210" +dependencies = [ + "dirs-sys", +] + [[package]] name = "dirs" version = "2.0.2" @@ -2741,6 +2750,7 @@ dependencies = [ "chain", "chain_sync", "ctrlc", + "directories", "fil_types", "forest_address", "forest_bigint", diff --git a/README.md b/README.md index ca06eba6b38c..22c26163e815 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,12 @@ bootstrap_peers = [""] Example of a [multiaddress](https://github.com/multiformats/multiaddr): `"/ip4/54.186.82.90/tcp/1347/p2p/12D3K1oWKNF7vNFEhnvB45E9mw2B5z6t419W3ziZPLdUDVnLLKGs"` +Forest will look for config files in the following order and priority: + * Paths passed to the command line via the `--config` flag. + * The environment variable `FOREST_CONFIG_PATH`, if no config was passed through command line arguments. + * If none of the above are found, Forest will look in the systems default configuration directory (`$XDG_CONFIG_HOME` on Linux systems). + * After all locations are exhausted and a config file is not found, a default configuration is assumed and used. + ### Logging The Forest logger uses [Rust's log filtering options](https://doc.rust-lang.org/1.1.0/log/index.html#filtering-results) with the `RUST_LOG` environment variable. diff --git a/forest/Cargo.toml b/forest/Cargo.toml index 458c19b6598c..277498ed846c 100644 --- a/forest/Cargo.toml +++ b/forest/Cargo.toml @@ -60,6 +60,7 @@ ticker = "0.1" byte-unit = "4.0" rug = "1.13" toml = "0.5" +directories = "4.0.1" [dependencies.jsonrpc-v2] version = "0.10" diff --git a/forest/src/cli/mod.rs b/forest/src/cli/mod.rs index 2cd6666131ad..e1ed442d941d 100644 --- a/forest/src/cli/mod.rs +++ b/forest/src/cli/mod.rs @@ -25,8 +25,10 @@ pub(super) use self::sync_cmd::SyncCommands; pub(super) use self::wallet_cmd::WalletCommands; use byte_unit::Byte; +use directories::ProjectDirs; use fil_types::FILECOIN_PRECISION; use jsonrpc_v2::Error as JsonRpcError; +use log::{info, warn}; use num_bigint::BigInt; use rug::float::ParseFloatError; use rug::Float; @@ -158,17 +160,7 @@ impl CliOpts { // Parse and return the configuration file read_toml(&toml)? } - None => { - // Check ENV VAR for config file - if let Ok(config_file) = std::env::var("FOREST_CONFIG_PATH") { - // Read from config file - let toml = read_file_to_string(&PathBuf::from(&config_file))?; - // Parse and return the configuration file - read_toml(&toml)? - } else { - Config::default() - } - } + None => find_default_config().unwrap_or_default(), }; if let Some(genesis_file) = &self.genesis { cfg.genesis_file = Some(genesis_file.to_owned()); @@ -224,6 +216,53 @@ impl CliOpts { } } +fn find_default_config() -> Option { + if let Ok(config_file) = std::env::var("FOREST_CONFIG_PATH") { + info!( + "FOREST_CONFIG_PATH is set! Using configuration at {}", + config_file + ); + let path = PathBuf::from(config_file); + if path.exists() { + return read_config_or_none(path); + } + }; + + if let Some(dir) = ProjectDirs::from("com", "ChainSafe", "Forest") { + let mut config_dir = dir.config_dir().to_path_buf(); + config_dir.push("config.toml"); + if config_dir.exists() { + info!("Found config file at {}", config_dir.display()); + return read_config_or_none(config_dir); + } + } + + warn!("No configuration found! Using default"); + + None +} + +fn read_config_or_none(path: PathBuf) -> Option { + let toml = match read_file_to_string(&path) { + Ok(t) => t, + Err(e) => { + warn!("An error occured while reading configuration file at {}. Resorting to default configuration. Error was {}", path.display(), e); + return None; + } + }; + + match read_toml(&toml) { + Ok(cfg) => Some(cfg), + Err(e) => { + warn!( + "Error reading configuration, opting to default. Error was {} ", + e + ); + None + } + } +} + /// Blocks current thread until ctrl-c is received pub async fn block_until_sigint() { let (ctrlc_send, ctrlc_oneshot) = futures::channel::oneshot::channel();