Skip to content

refactor: use OS-specific config & data dirs, default iroh-store dir #218

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions iroh-ctl/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use iroh_ctl::{
store::{run_command as run_store_command, Store},
};
use iroh_rpc_client::Client;
use iroh_util::{iroh_home_path, make_config};
use iroh_util::{iroh_config_path, make_config};

use iroh_ctl::{
config::{Config, CONFIG_FILE_NAME, ENV_PREFIX},
Expand Down Expand Up @@ -53,7 +53,8 @@ enum Commands {
async fn main() -> anyhow::Result<()> {
let cli = Cli::parse();

let sources = vec![iroh_home_path(CONFIG_FILE_NAME), cli.cfg.clone()];
let cfg_path = iroh_config_path(CONFIG_FILE_NAME)?;
let sources = vec![Some(cfg_path), cli.cfg.clone()];
let config = make_config(
// default
Config::default(),
Expand Down
5 changes: 3 additions & 2 deletions iroh-gateway/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ use iroh_gateway::{
core::Core,
metrics,
};
use iroh_util::{iroh_home_path, make_config};
use iroh_util::{iroh_config_path, make_config};
use tokio::sync::RwLock;
use tracing::{debug, error};

#[tokio::main(flavor = "multi_thread")]
async fn main() -> Result<()> {
let args = Args::parse();

let sources = vec![iroh_home_path(CONFIG_FILE_NAME), args.cfg.clone()];
let cfg_path = iroh_config_path(CONFIG_FILE_NAME)?;
let sources = vec![Some(cfg_path), args.cfg.clone()];
let mut config = make_config(
// default
Config::default(),
Expand Down
5 changes: 3 additions & 2 deletions iroh-one/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use iroh_one::{
config::{Config, CONFIG_FILE_NAME, ENV_PREFIX},
};
use iroh_rpc_types::Addr;
use iroh_util::{iroh_home_path, make_config};
use iroh_util::{iroh_config_path, make_config};
#[cfg(feature = "uds-gateway")]
use tempdir::TempDir;
use tokio::sync::RwLock;
Expand All @@ -21,7 +21,8 @@ use tracing::{debug, error};
async fn main() -> Result<()> {
let args = Args::parse();

let sources = vec![iroh_home_path(CONFIG_FILE_NAME), args.cfg.clone()];
let cfg_path = iroh_config_path(CONFIG_FILE_NAME)?;
let sources = vec![Some(cfg_path), args.cfg.clone()];
let mut config = make_config(
// default
Config::default(),
Expand Down
6 changes: 3 additions & 3 deletions iroh-p2p/src/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::path::{Path, PathBuf};
use anyhow::{anyhow, Result};
use async_trait::async_trait;
use futures::{Stream, StreamExt, TryStreamExt};
use iroh_util::iroh_home_root;
use iroh_util::iroh_config_root;
use ssh_key::LineEnding;
use tokio::fs;
use tracing::warn;
Expand Down Expand Up @@ -113,9 +113,9 @@ impl Keychain<MemoryStorage> {
}

impl Keychain<DiskStorage> {
/// Creates a new on disk keychain, with the root defaulting to `.iroh`.
/// Creates a new on disk keychain, with the root defaulting to the iroh config directory
pub async fn new() -> Result<Self> {
let root = iroh_home_root().ok_or_else(|| anyhow!("missing home path"))?;
let root = iroh_config_root()?;
Self::with_root(root).await
}

Expand Down
5 changes: 3 additions & 2 deletions iroh-p2p/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use anyhow::anyhow;
use clap::Parser;
use iroh_p2p::config::{Config, CONFIG_FILE_NAME, ENV_PREFIX};
use iroh_p2p::{cli::Args, metrics, DiskStorage, Keychain, Node};
use iroh_util::{iroh_home_path, make_config};
use iroh_util::{iroh_config_path, make_config};
use tokio::task;
use tracing::{debug, error};

Expand All @@ -15,7 +15,8 @@ async fn main() -> anyhow::Result<()> {
let args = Args::parse();

// TODO: configurable network
let sources = vec![iroh_home_path(CONFIG_FILE_NAME), args.cfg.clone()];
let cfg_path = iroh_config_path(CONFIG_FILE_NAME)?;
let sources = vec![Some(cfg_path), args.cfg.clone()];
let network_config = make_config(
// default
Config::default_grpc(),
Expand Down
24 changes: 23 additions & 1 deletion iroh-store/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use iroh_rpc_types::{
store::{StoreClientAddr, StoreServerAddr},
Addr,
};
use iroh_util::insert_into_config_map;
use iroh_util::{insert_into_config_map, iroh_data_path};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;

Expand All @@ -17,6 +17,15 @@ pub const CONFIG_FILE_NAME: &str = "store.config.toml";
/// For example, `IROH_STORE_PATH=/path/to/config` would set the value of the `Config.path` field
pub const ENV_PREFIX: &str = "IROH_STORE";

/// the path to data directory. If arg_path is `None`, the default iroh_data_path()/store is used
/// iroh_data_path() returns an operating system-specific directory
pub fn config_data_path(arg_path: Option<PathBuf>) -> Result<PathBuf> {
match arg_path {
Some(p) => Ok(p),
None => iroh_data_path("store"),
}
Comment on lines +23 to +26
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm unclear on weather or not there's a more succinct way to express this

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think arg_path.map_or(iroh_data_path("store"), |v| Ok(v)) is equivalent - but not easier to read!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oooh I hadn't found map_or. Thanks for the tip @fabricedesre! I agree with you that the match is easier to read, and will leave it as is unless I'm overruled by dig 😄

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems fine and readable

}

/// The configuration for the store.
#[derive(PartialEq, Debug, Deserialize, Serialize, Clone)]
pub struct Config {
Expand Down Expand Up @@ -129,4 +138,17 @@ mod tests {

assert_eq!(expect, got);
}

#[test]
fn test_config_data_path() {
let path = PathBuf::new().join("arg_path");
let path_given = config_data_path(Some(path.clone())).expect("config data path error");
assert_eq!(path_given.display().to_string(), path.display().to_string());

let no_path_given = config_data_path(None)
.expect("config data path error")
.display()
.to_string();
assert!(no_path_given.ends_with("store"));
}
}
11 changes: 6 additions & 5 deletions iroh-store/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ use anyhow::anyhow;
use clap::Parser;
use iroh_store::{
cli::Args,
config::{CONFIG_FILE_NAME, ENV_PREFIX},
config::{config_data_path, CONFIG_FILE_NAME, ENV_PREFIX},
metrics, rpc, Config, Store,
};
use iroh_util::{block_until_sigint, iroh_home_path, make_config};
use std::path::PathBuf;
use iroh_util::{block_until_sigint, iroh_config_path, make_config};
use tracing::{debug, error, info};

#[tokio::main(flavor = "multi_thread")]
Expand All @@ -16,10 +15,12 @@ async fn main() -> anyhow::Result<()> {
let version = env!("CARGO_PKG_VERSION");
println!("Starting iroh-store, version {version}");

let sources = vec![iroh_home_path(CONFIG_FILE_NAME), args.cfg.clone()];
let config_path = iroh_config_path(CONFIG_FILE_NAME)?;
let sources = vec![Some(config_path), args.cfg.clone()];
let config_data_path = config_data_path(args.path.clone())?;
let config = make_config(
// default
Config::new_grpc(args.path.clone().unwrap_or_else(|| PathBuf::from(""))),
Config::new_grpc(config_data_path),
// potential config files
sources,
// env var prefix for this config
Expand Down
4 changes: 2 additions & 2 deletions iroh-util/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ futures = "0.3.21"
anyhow = "1.0.57"
toml = "0.5.9"
serde = { version = "1.0", features = ["derive"] }
dirs = "4.0.0"
config = "0.13.1"
tracing = "0.1.34"
temp-env = "0.2.0"
rlimit = "0.8.3"
rlimit = "0.8.3"
dirs-next = "2.0.0"
61 changes: 46 additions & 15 deletions iroh-util/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
use std::{
cell::RefCell,
collections::HashMap,
path::{Path, PathBuf},
path::PathBuf,
sync::{
atomic::{AtomicUsize, Ordering},
Arc,
},
};

use anyhow::Result;
use anyhow::{anyhow, Result};
use cid::{
multihash::{Code, MultihashDigest},
Cid,
};
use config::{Config, ConfigError, Environment, File, Map, Source, Value, ValueKind};
use dirs::home_dir;
use tracing::debug;

const IROH_DIR: &str = ".iroh";
/// name of directory that wraps all iroh files in a given application directory
const IROH_DIR: &str = "iroh";
const DEFAULT_NOFILE_LIMIT: u64 = 65536;
const MIN_NOFILE_LIMIT: u64 = 2048;

Expand All @@ -44,16 +44,47 @@ pub async fn block_until_sigint() {
ctrlc_oneshot.await.unwrap();
}

/// Path to the iroh home directory.
pub fn iroh_home_root() -> Option<PathBuf> {
let home = home_dir()?;
Some(Path::new(&home).join(IROH_DIR))
/// Returns the path to the user's iroh config directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// | Platform | Value | Example |
/// | -------- | ------------------------------------- | -------------------------------- |
/// | Linux | `$XDG_CONFIG_HOME` or `$HOME`/.config/iroh | /home/alice/.config/iroh |
/// | macOS | `$HOME`/Library/Application Support/iroh | /Users/Alice/Library/Application Support/iroh |
/// | Windows | `{FOLDERID_RoamingAppData}`/iroh | C:\Users\Alice\AppData\Roaming\iroh |
pub fn iroh_config_root() -> Result<PathBuf> {
let cfg = dirs_next::config_dir()
.ok_or_else(|| anyhow!("operating environment provides no directory for configuration"))?;
Ok(cfg.join(&IROH_DIR))
}

// Path that leads to a file in the iroh config directory.
pub fn iroh_config_path(file_name: &str) -> Result<PathBuf> {
let path = iroh_config_root()?.join(file_name);
Ok(path)
}

/// Returns the path to the user's iroh data directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// | Platform | Value | Example |
/// | -------- | --------------------------------------------- | ---------------------------------------- |
/// | Linux | `$XDG_DATA_HOME`/iroh or `$HOME`/.local/share/iroh | /home/alice/.local/share/iroh |
/// | macOS | `$HOME`/Library/Application Support/iroh | /Users/Alice/Library/Application Support/iroh |
/// | Windows | `{FOLDERID_RoamingAppData}/iroh` | C:\Users\Alice\AppData\Roaming\iroh |
pub fn iroh_data_root() -> Result<PathBuf> {
let path = dirs_next::data_dir().ok_or_else(|| {
anyhow!("operating environment provides no directory for application data")
})?;
Ok(path.join(&IROH_DIR))
}

/// Path that leads to a file in the iroh home directory.
pub fn iroh_home_path(file_name: &str) -> Option<PathBuf> {
let path = iroh_home_root()?.join(file_name);
Some(path)
/// Path that leads to a file in the iroh data directory.
pub fn iroh_data_path(file_name: &str) -> Result<PathBuf> {
let path = iroh_data_root()?.join(file_name);
Ok(path)
}

/// insert a value into a `config::Map`
Expand Down Expand Up @@ -174,9 +205,9 @@ pub fn increase_fd_limit() -> std::io::Result<u64> {
mod tests {
use super::*;
#[test]
fn test_iroh_home_path() {
let got = iroh_home_path("foo.bar").unwrap();
fn test_iroh_config_path() {
let got = iroh_config_path("foo.bar").unwrap();
let got = got.to_str().unwrap().to_string();
assert!(got.ends_with("/.iroh/foo.bar"));
assert!(got.ends_with("/iroh/foo.bar"));
}
}