Skip to content

Commit

Permalink
Merge pull request #28 from G8XSU/file-config
Browse files Browse the repository at this point in the history
Add file based Config support.
  • Loading branch information
G8XSU authored Dec 4, 2024
2 parents eed8ba5 + e14923c commit ecfe4cc
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 47 deletions.
22 changes: 22 additions & 0 deletions ldk-server/ldk-server.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
// The addresses on which the lightning node will listen for incoming connections.
"listening_address": "localhost:3001",

// The Bitcoin network to use.
"network": "regtest",

// The address on which LDK Server will accept incoming requests.
"rest_service_address": "127.0.0.1:3002",

// The path where the underlying LDK and BDK persist their data.
"storage_dir_path": "/tmp",

// Bitcoin Core's RPC endpoint.
"bitcoind_rpc_address": "127.0.0.1:8332",

// Bitcoin Core's RPC user.
"bitcoind_rpc_user": "bitcoind-testuser",

// Bitcoin Core's RPC password.
"bitcoind_rpc_password": "bitcoind-testpassword"
}
64 changes: 17 additions & 47 deletions ldk-server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ mod util;

use crate::service::NodeService;

use ldk_node::bitcoin::Network;
use ldk_node::lightning::ln::msgs::SocketAddress;
use ldk_node::{Builder, Event, LogLevel};

use tokio::net::TcpListener;
Expand All @@ -15,65 +13,36 @@ use tokio::signal::unix::SignalKind;
use hyper::server::conn::http1;
use hyper_util::rt::TokioIo;

use crate::util::config::load_config;
use ldk_node::config::Config;
use std::net::SocketAddr;
use std::str::FromStr;
use std::path::Path;
use std::sync::Arc;

fn main() {
let args: Vec<String> = std::env::args().collect();

if args.len() < 8 {
eprintln!(
"Usage: {} storage_path listening_addr rest_svc_addr network bitcoind_rpc_addr bitcoind_rpc_user bitcoind_rpc_password",
args[0]
);
if args.len() < 2 {
eprintln!("Usage: {} config_path", args[0]);
std::process::exit(-1);
}

let mut config = Config::default();
config.storage_dir_path = args[1].clone();
config.log_level = LogLevel::Trace;
let mut ldk_node_config = Config::default();
let config_file = load_config(Path::new(&args[1])).expect("Invalid configuration file.");

config.listening_addresses = match SocketAddress::from_str(&args[2]) {
Ok(addr) => Some(vec![addr]),
Err(_) => {
eprintln!("Failed to parse listening_addr: {}", args[2]);
std::process::exit(-1);
},
};

let rest_svc_addr = match SocketAddr::from_str(&args[3]) {
Ok(addr) => addr,
Err(_) => {
eprintln!("Failed to parse rest_svc_addr: {}", args[3]);
std::process::exit(-1);
},
};
ldk_node_config.log_level = LogLevel::Trace;
ldk_node_config.storage_dir_path = config_file.storage_dir_path;
ldk_node_config.listening_addresses = Some(vec![config_file.listening_addr]);
ldk_node_config.network = config_file.network;

config.network = match Network::from_str(&args[4]) {
Ok(network) => network,
Err(_) => {
eprintln!("Unsupported network: {}. Use 'bitcoin', 'testnet', 'regtest', 'signet', 'regtest'.", args[4]);
std::process::exit(-1);
},
};

let mut builder = Builder::from_config(config);
let mut builder = Builder::from_config(ldk_node_config);

let bitcoind_rpc_addr = match SocketAddr::from_str(&args[5]) {
Ok(addr) => addr,
Err(_) => {
eprintln!("Failed to parse bitcoind_rpc_addr: {}", args[3]);
std::process::exit(-1);
},
};
let bitcoind_rpc_addr = config_file.bitcoind_rpc_addr;

builder.set_chain_source_bitcoind_rpc(
bitcoind_rpc_addr.ip().to_string(),
bitcoind_rpc_addr.port(),
args[6].clone(),
args[7].clone(),
config_file.bitcoind_rpc_user,
config_file.bitcoind_rpc_password,
);

let runtime = match tokio::runtime::Builder::new_multi_thread().enable_all().build() {
Expand Down Expand Up @@ -116,8 +85,9 @@ fn main() {
},
};
let event_node = Arc::clone(&node);
let rest_svc_listener =
TcpListener::bind(rest_svc_addr).await.expect("Failed to bind listening port");
let rest_svc_listener = TcpListener::bind(config_file.rest_service_addr)
.await
.expect("Failed to bind listening port");
loop {
tokio::select! {
event = event_node.next_event_async() => {
Expand Down
136 changes: 136 additions & 0 deletions ldk-server/src/util/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
use ldk_node::bitcoin::Network;
use ldk_node::lightning::ln::msgs::SocketAddress;
use serde::{Deserialize, Serialize};
use std::net::SocketAddr;
use std::path::Path;
use std::str::FromStr;
use std::{fs, io};

/// Configuration for LDK Server.
#[derive(PartialEq, Eq, Debug)]
pub struct Config {
pub listening_addr: SocketAddress,
pub network: Network,
pub rest_service_addr: SocketAddr,
pub storage_dir_path: String,
pub bitcoind_rpc_addr: SocketAddr,
pub bitcoind_rpc_user: String,
pub bitcoind_rpc_password: String,
}

impl TryFrom<JsonConfig> for Config {
type Error = io::Error;

fn try_from(json_config: JsonConfig) -> io::Result<Self> {
let listening_addr =
SocketAddress::from_str(&json_config.listening_address).map_err(|e| {
io::Error::new(
io::ErrorKind::InvalidInput,
format!("Invalid listening address configured: {}", e),
)
})?;
let rest_service_addr =
SocketAddr::from_str(&json_config.rest_service_address).map_err(|e| {
io::Error::new(
io::ErrorKind::InvalidInput,
format!("Invalid rest service address configured: {}", e),
)
})?;

let bitcoind_rpc_addr =
SocketAddr::from_str(&json_config.bitcoind_rpc_address).map_err(|e| {
io::Error::new(
io::ErrorKind::InvalidInput,
format!("Invalid bitcoind RPC address configured: {}", e),
)
})?;

Ok(Config {
listening_addr,
network: json_config.network,
rest_service_addr,
storage_dir_path: json_config.storage_dir_path,
bitcoind_rpc_addr,
bitcoind_rpc_user: json_config.bitcoind_rpc_user,
bitcoind_rpc_password: json_config.bitcoind_rpc_password,
})
}
}

/// Configuration loaded from a JSON file.
#[derive(Deserialize, Serialize)]
pub struct JsonConfig {
listening_address: String,
network: Network,
rest_service_address: String,
storage_dir_path: String,
bitcoind_rpc_address: String,
bitcoind_rpc_user: String,
bitcoind_rpc_password: String,
}

/// Loads the configuration from a JSON file at the given path.
pub fn load_config<P: AsRef<Path>>(config_path: P) -> io::Result<Config> {
let file_contents = fs::read_to_string(config_path.as_ref()).map_err(|e| {
io::Error::new(
e.kind(),
format!("Failed to read config file '{}': {}", config_path.as_ref().display(), e),
)
})?;

let json_string = remove_json_comments(file_contents.as_str());
let json_config: JsonConfig = serde_json::from_str(&json_string).map_err(|e| {
io::Error::new(
io::ErrorKind::InvalidData,
format!("Config file contains invalid JSON format: {}", e),
)
})?;
Ok(Config::try_from(json_config)?)
}

fn remove_json_comments(s: &str) -> String {
s.lines()
.map(|line| if let Some(pos) = line.find("//") { &line[..pos] } else { line })
.collect::<Vec<&str>>()
.join("\n")
}

#[cfg(test)]
mod tests {
use super::*;
use ldk_node::{bitcoin::Network, lightning::ln::msgs::SocketAddress};
use std::str::FromStr;

#[test]
fn test_read_json_config_from_file() {
let storage_path = std::env::temp_dir();
let config_file_name = "config.json";

let json_config = r#"{
"listening_address": "localhost:3001",
"network": "regtest",
"rest_service_address": "127.0.0.1:3002",
"storage_dir_path": "/tmp",
"bitcoind_rpc_address":"127.0.0.1:8332", // comment-1
"bitcoind_rpc_user": "bitcoind-testuser",
"bitcoind_rpc_password": "bitcoind-testpassword",
"unknown_key": "random-value"
// comment-2
}"#;

fs::write(storage_path.join(config_file_name), json_config).unwrap();

assert_eq!(
load_config(storage_path.join(config_file_name)).unwrap(),
Config {
listening_addr: SocketAddress::from_str("localhost:3001").unwrap(),
network: Network::Regtest,
rest_service_addr: SocketAddr::from_str("127.0.0.1:3002").unwrap(),
storage_dir_path: "/tmp".to_string(),
bitcoind_rpc_addr: SocketAddr::from_str("127.0.0.1:8332").unwrap(),
bitcoind_rpc_user: "bitcoind-testuser".to_string(),
bitcoind_rpc_password: "bitcoind-testpassword".to_string(),
}
)
}
}
1 change: 1 addition & 0 deletions ldk-server/src/util/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub(crate) mod config;
pub(crate) mod proto_adapter;

0 comments on commit ecfe4cc

Please sign in to comment.