Skip to content

Commit e8c38c3

Browse files
authored
Merge pull request lightningdevkit#96 from benthecarman/default-data-dir
Create default data directory at ~/.ldk-server
2 parents 86563e4 + 901902d commit e8c38c3

7 files changed

Lines changed: 276 additions & 57 deletions

File tree

ldk-server/Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ldk-server/ldk-server-cli/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ edition = "2021"
66
[dependencies]
77
ldk-server-client = { path = "../ldk-server-client", features = ["serde"] }
88
clap = { version = "4.0.5", default-features = false, features = ["derive", "std", "error-context", "suggestions", "help"] }
9+
hex-conservative = { version = "0.2", default-features = false, features = ["std"] }
910
tokio = { version = "1.38.0", default-features = false, features = ["rt-multi-thread", "macros"] }
1011
serde = "1.0"
1112
serde_json = "1.0"
13+
toml = { version = "0.8", default-features = false, features = ["parse"] }
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// This file is Copyright its original authors, visible in version control
2+
// history.
3+
//
4+
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
5+
// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
7+
// You may not use this file except in accordance with one or both of these
8+
// licenses.
9+
10+
use serde::{Deserialize, Serialize};
11+
use std::path::PathBuf;
12+
13+
const DEFAULT_CONFIG_FILE: &str = "config.toml";
14+
const DEFAULT_CERT_FILE: &str = "tls.crt";
15+
const API_KEY_FILE: &str = "api_key";
16+
17+
pub fn get_default_data_dir() -> Option<PathBuf> {
18+
#[cfg(target_os = "macos")]
19+
{
20+
#[allow(deprecated)] // todo can remove once we update MSRV to 1.87+
21+
std::env::home_dir().map(|home| home.join("Library/Application Support/ldk-server"))
22+
}
23+
#[cfg(target_os = "windows")]
24+
{
25+
std::env::var("APPDATA").ok().map(|appdata| PathBuf::from(appdata).join("ldk-server"))
26+
}
27+
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
28+
{
29+
#[allow(deprecated)] // todo can remove once we update MSRV to 1.87+
30+
std::env::home_dir().map(|home| home.join(".ldk-server"))
31+
}
32+
}
33+
34+
pub fn get_default_config_path() -> Option<PathBuf> {
35+
get_default_data_dir().map(|dir| dir.join(DEFAULT_CONFIG_FILE))
36+
}
37+
38+
pub fn get_default_cert_path() -> Option<PathBuf> {
39+
get_default_data_dir().map(|path| path.join(DEFAULT_CERT_FILE))
40+
}
41+
42+
pub fn get_default_api_key_path(network: &str) -> Option<PathBuf> {
43+
get_default_data_dir().map(|path| path.join(network).join(API_KEY_FILE))
44+
}
45+
46+
#[derive(Debug, Deserialize)]
47+
pub struct Config {
48+
pub node: NodeConfig,
49+
pub tls: Option<TlsConfig>,
50+
}
51+
52+
#[derive(Debug, Deserialize, Serialize)]
53+
pub struct TlsConfig {
54+
pub cert_path: Option<String>,
55+
}
56+
57+
#[derive(Debug, Deserialize)]
58+
pub struct NodeConfig {
59+
pub rest_service_address: String,
60+
network: String,
61+
}
62+
63+
impl Config {
64+
pub fn network(&self) -> Result<String, String> {
65+
match self.node.network.as_str() {
66+
"bitcoin" | "mainnet" => Ok("bitcoin".to_string()),
67+
"testnet" => Ok("testnet".to_string()),
68+
"testnet4" => Ok("testnet4".to_string()),
69+
"signet" => Ok("signet".to_string()),
70+
"regtest" => Ok("regtest".to_string()),
71+
other => Err(format!("Unsupported network: {other}")),
72+
}
73+
}
74+
}
75+
76+
pub fn load_config(path: &PathBuf) -> Result<Config, String> {
77+
let contents = std::fs::read_to_string(path)
78+
.map_err(|e| format!("Failed to read config file '{}': {}", path.display(), e))?;
79+
toml::from_str(&contents)
80+
.map_err(|e| format!("Failed to parse config file '{}': {}", path.display(), e))
81+
}

ldk-server/ldk-server-cli/src/main.rs

Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
// licenses.
99

1010
use clap::{Parser, Subcommand};
11+
use config::{
12+
get_default_api_key_path, get_default_cert_path, get_default_config_path, load_config,
13+
};
14+
use hex_conservative::DisplayHex;
1115
use ldk_server_client::client::LdkServerClient;
1216
use ldk_server_client::error::LdkServerError;
1317
use ldk_server_client::error::LdkServerErrorCode::{
@@ -28,8 +32,10 @@ use ldk_server_client::ldk_server_protos::types::{
2832
RouteParametersConfig,
2933
};
3034
use serde::Serialize;
35+
use std::path::PathBuf;
3136
use types::CliListPaymentsResponse;
3237

38+
mod config;
3339
mod types;
3440

3541
// Having these default values as constants in the Proto file and
@@ -43,19 +49,25 @@ const DEFAULT_EXPIRY_SECS: u32 = 86_400;
4349
#[derive(Parser, Debug)]
4450
#[command(version, about, long_about = None)]
4551
struct Cli {
46-
#[arg(short, long, default_value = "localhost:3000")]
47-
base_url: String,
52+
#[arg(short, long, help = "Base URL of the server. If not provided, reads from config file")]
53+
base_url: Option<String>,
4854

49-
#[arg(short, long, required(true))]
50-
api_key: String,
55+
#[arg(
56+
short,
57+
long,
58+
help = "API key for authentication. Defaults by reading ~/.ldk-server/[network]/api_key"
59+
)]
60+
api_key: Option<String>,
5161

5262
#[arg(
5363
short,
5464
long,
55-
required(true),
56-
help = "Path to the server's TLS certificate file (PEM format). Found at <server_storage_dir>/tls.crt"
65+
help = "Path to the server's TLS certificate file (PEM format). Defaults to ~/.ldk-server/tls.crt"
5766
)]
58-
tls_cert: String,
67+
tls_cert: Option<String>,
68+
69+
#[arg(short, long, help = "Path to config file. Defaults to ~/.ldk-server/config.toml")]
70+
config: Option<String>,
5971

6072
#[command(subcommand)]
6173
command: Commands,
@@ -226,18 +238,54 @@ enum Commands {
226238
async fn main() {
227239
let cli = Cli::parse();
228240

229-
// Load server certificate for TLS verification
230-
let server_cert_pem = std::fs::read(&cli.tls_cert).unwrap_or_else(|e| {
231-
eprintln!("Failed to read server certificate file '{}': {}", cli.tls_cert, e);
232-
std::process::exit(1);
233-
});
241+
let config_path = cli.config.map(PathBuf::from).or_else(get_default_config_path);
242+
let config = config_path.as_ref().and_then(|p| load_config(p).ok());
234243

235-
let client =
236-
LdkServerClient::new(cli.base_url, cli.api_key, &server_cert_pem).unwrap_or_else(|e| {
237-
eprintln!("Failed to create client: {e}");
244+
// Get API key from argument, then from api_key file
245+
let api_key = cli
246+
.api_key
247+
.or_else(|| {
248+
// Try to read from api_key file based on network (file contains raw bytes)
249+
let network = config.as_ref().and_then(|c| c.network().ok()).unwrap_or("bitcoin".to_string());
250+
get_default_api_key_path(&network)
251+
.and_then(|path| std::fs::read(&path).ok())
252+
.map(|bytes| bytes.to_lower_hex_string())
253+
})
254+
.unwrap_or_else(|| {
255+
eprintln!("API key not provided. Use --api-key or ensure the api_key file exists at ~/.ldk-server/[network]/api_key");
238256
std::process::exit(1);
239257
});
240258

259+
// Get base URL from argument then from config file
260+
let base_url =
261+
cli.base_url.or_else(|| config.as_ref().map(|c| c.node.rest_service_address.clone()))
262+
.unwrap_or_else(|| {
263+
eprintln!("Base URL not provided. Use --base-url or ensure config file exists at ~/.ldk-server/config.toml");
264+
std::process::exit(1);
265+
});
266+
267+
// Get TLS cert path from argument, then from config file, then try default location
268+
let tls_cert_path = cli.tls_cert.map(PathBuf::from).or_else(|| {
269+
config
270+
.as_ref()
271+
.and_then(|c| c.tls.as_ref().and_then(|t| t.cert_path.as_ref().map(PathBuf::from)))
272+
.or_else(get_default_cert_path)
273+
})
274+
.unwrap_or_else(|| {
275+
eprintln!("TLS cert path not provided. Use --tls-cert or ensure config file exists at ~/.ldk-server/config.toml");
276+
std::process::exit(1);
277+
});
278+
279+
let server_cert_pem = std::fs::read(&tls_cert_path).unwrap_or_else(|e| {
280+
eprintln!("Failed to read server certificate file '{}': {}", tls_cert_path.display(), e);
281+
std::process::exit(1);
282+
});
283+
284+
let client = LdkServerClient::new(base_url, api_key, &server_cert_pem).unwrap_or_else(|e| {
285+
eprintln!("Failed to create client: {e}");
286+
std::process::exit(1);
287+
});
288+
241289
match cli.command {
242290
Commands::GetNodeInfo => {
243291
handle_response_result::<_, GetNodeInfoResponse>(

ldk-server/ldk-server/ldk-server-config.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@ network = "regtest" # Bitcoin network to use
44
listening_addresses = ["localhost:3001"] # Lightning node listening addresses
55
announcement_addresses = ["54.3.7.81:3001"] # Lightning node announcement addresses
66
rest_service_address = "127.0.0.1:3002" # LDK Server REST address
7-
api_key = "your-secret-api-key" # API key for authenticating REST requests
87

98
# Storage settings
109
[storage.disk]
11-
dir_path = "/tmp/ldk-server/" # Path for LDK and BDK data persistence
10+
dir_path = "/tmp/ldk-server/" # Path for LDK and BDK data persistence, optional, defaults to ~/.ldk-server/
1211

1312
[log]
1413
level = "Debug" # Log level (Error, Warn, Info, Debug, Trace)

0 commit comments

Comments
 (0)