Skip to content
Open
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
1 change: 1 addition & 0 deletions Cargo-minimal.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2522,6 +2522,7 @@ dependencies = [
"tempfile",
"tokio",
"tokio-rustls",
"toml 0.5.11",
"tracing",
"tracing-subscriber",
"url",
Expand Down
1 change: 1 addition & 0 deletions Cargo-recent.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2522,6 +2522,7 @@ dependencies = [
"tempfile",
"tokio",
"tokio-rustls",
"toml 0.5.11",
"tracing",
"tracing-subscriber",
"url",
Expand Down
3 changes: 3 additions & 0 deletions payjoin-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,11 @@ url = { version = "2.5.4", features = ["serde"] }
dirs = "6.0.0"
tracing = "0.1.41"
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
toml = "0.5.11"

[dev-dependencies]
nix = { version = "0.30.1", features = ["aio", "process", "signal"] }
payjoin-test-utils = { version = "0.0.1" }
tempfile = "3.20.0"


2 changes: 2 additions & 0 deletions payjoin-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ Congratulations! You've completed a version 2 payjoin, which can be used for che

Config options can be passed from the command line, or manually edited in a `config.toml` file within the directory you run `payjoin-cli` from.

You can persist command-line flags into a configuration file. If a config file exists in the current working directory it will be used; otherwise, one in the default directory is used. This behavior is enabled via the `--set-config` flag.

See the
[example.config.toml](https://github.com/payjoin/rust-payjoin/blob/fde867b93ede767c9a50913432a73782a94ef40b/payjoin-cli/example.config.toml)
for inspiration.
Expand Down
78 changes: 78 additions & 0 deletions payjoin-cli/src/app/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,84 @@ impl Config {
Ok(config)
}

#[cfg(feature = "v2")]
pub fn save_config(cli: &Cli) -> Result<(), anyhow::Error> {
let version = Self::determine_version(cli)
.map_err(|e| anyhow::anyhow!("Failed to determine version: {e}"))?;

if version != Version::Two {
return Err(anyhow::anyhow!("--set-config is only available for bip77 (v2) mode"));
}

if cli.ohttp_relays.is_none() || cli.pj_directory.is_none() {
return Err(anyhow::anyhow!(
"--set-config requires ALL of: \
--pj-directory, --ohttp-relays"
));
}

let cookie_provided = cli.cookie_file.is_some();
let rpc_provided =
cli.rpcuser.is_some() && cli.rpcpassword.is_some() && cli.rpchost.is_some();

// Ensure all required parameters are present

if !(cookie_provided || rpc_provided) {
return Err(anyhow::anyhow!(
"--set-config requires ALL of: \
--rpcuser, --rpcpassword, --rpchost, or \
--cookie-file"
));
}

// Build the TOML map , this feels a bit hacky but it works
let mut toml_map = toml::map::Map::new();
let mut bitcoind_map = toml::map::Map::new();

bitcoind_map.insert("rpcuser".into(), toml::Value::String(cli.rpcuser.clone().unwrap()));
bitcoind_map
.insert("rpcpassword".into(), toml::Value::String(cli.rpcpassword.clone().unwrap()));
bitcoind_map.insert(
"rpchost".into(),
toml::Value::String(cli.rpchost.clone().unwrap().to_string()),
);
toml_map.insert("bitcoind".into(), toml::Value::Table(bitcoind_map));

let mut v2_map = toml::map::Map::new();
v2_map.insert(
"pj_directory".into(),
toml::Value::String(cli.pj_directory.as_ref().unwrap().to_string()),
);
let relay_list: Vec<toml::Value> = cli
.ohttp_relays
.as_ref()
.unwrap()
.iter()
.map(|url| toml::Value::String(url.to_string()))
.collect();
v2_map.insert("ohttp_relays".into(), toml::Value::Array(relay_list));
toml_map.insert("v2".into(), toml::Value::Table(v2_map));

let toml_content = toml::Value::Table(toml_map);
let toml_str = toml::to_string_pretty(&toml_content)?;

let config_path = std::env::current_dir()?.join("config.toml");
let final_path = if !config_path.exists() {
if let Some(config_dir) = dirs::config_dir() {
let global_dir = config_dir.join(CONFIG_DIR);
std::fs::create_dir_all(&global_dir)?;
global_dir.join("config.toml")
} else {
config_path
}
} else {
config_path
};

std::fs::write(final_path, toml_str)?;
Ok(())
}

#[cfg(feature = "v1")]
pub fn v1(&self) -> Result<&V1Config, anyhow::Error> {
match &self.version {
Expand Down
4 changes: 4 additions & 0 deletions payjoin-cli/src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ pub struct Cli {
#[arg(long = "pj-directory", help = "The directory to store payjoin requests", value_parser = value_parser!(Url))]
pub pj_directory: Option<Url>,

#[cfg(feature = "v2")]
#[arg(long = "set-config", help = "Save current configuration parameters to config.toml", value_parser = value_parser!(bool))]
pub set_config: bool,

#[cfg(feature = "_manual-tls")]
#[arg(long = "root-certificate", help = "Specify a TLS certificate to be added as a root", value_parser = value_parser!(PathBuf))]
pub root_certificate: Option<PathBuf>,
Expand Down
5 changes: 5 additions & 0 deletions payjoin-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ async fn main() -> Result<()> {
tracing_subscriber::fmt().with_target(true).with_level(true).with_env_filter(env_filter).init();

let cli = Cli::parse();

#[cfg(feature = "v2")]
if cli.set_config {
Config::save_config(&cli)?;
}
let config = Config::new(&cli)?;

#[allow(clippy::if_same_then_else)]
Expand Down
Loading