From 0ec2e808ca7e47191a2d7c2668d5d3015867eebb Mon Sep 17 00:00:00 2001
From: Matthew Rheaume <mhr@lightspark.com>
Date: Fri, 25 Oct 2024 17:11:09 -0700
Subject: [PATCH 1/3] Added data_dir configuration options.

In certain deployment scenarios, we may not want (or be able) to write
to the default ~/.lndk data directory. For example, the home directory
may be mounted as read-only, or mounted using ephemeral storage.

This change adds a new `data_dir` configuration option to specify where
LNDK should store data. If this option isn't specified, then falls back
to the default ~/.lndk.
---
 config_spec.toml |  5 +++++
 src/main.rs      | 14 +++++++++-----
 2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/config_spec.toml b/config_spec.toml
index 4613925..560474a 100644
--- a/config_spec.toml
+++ b/config_spec.toml
@@ -37,6 +37,11 @@ type = "String"
 optional = true
 doc = "The hex encoded macaroon to pass directly into LNDK"
 
+[[param]]
+name = "data_dir"
+type = "String"
+doc = "The path to the lndk data directory. By default this is stored in ~/.lndk"
+
 [[param]]
 name = "log_dir"
 type = "String"
diff --git a/src/main.rs b/src/main.rs
index 8490e6b..f1938f7 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -37,8 +37,8 @@ async fn main() -> Result<(), ()> {
         .unwrap_or_exit()
         .0;
 
-    let data_dir =
-        create_data_dir().map_err(|e| println!("Error creating LNDK's data dir {e:?}"))?;
+    let data_dir = create_data_dir(config.data_dir)
+        .map_err(|e| println!("Error creating LNDK's data dir {e:?}"))?;
     setup_logger(config.log_level, config.log_dir)?;
 
     let creds = validate_lnd_creds(
@@ -156,9 +156,13 @@ async fn main() -> Result<(), ()> {
     Ok(())
 }
 
-// Creates lndk's data directory at ~/.lndk.
-fn create_data_dir() -> Result<PathBuf, std::io::Error> {
-    let path = home_dir().unwrap().join(DEFAULT_DATA_DIR);
+// Creates lndk's data directory at the specified directory, or ~/.lndk if not specified.
+fn create_data_dir(data_dir: Option<String>) -> Result<PathBuf, std::io::Error> {
+    let path = match data_dir {
+        Some(dir) => PathBuf::from(&dir),
+        None => home_dir().unwrap().join(DEFAULT_DATA_DIR),
+    };
+
     create_dir_all(&path)?;
 
     Ok(path)

From a47a2ff5a96ab9be13234e95fe9dbca5171e16d0 Mon Sep 17 00:00:00 2001
From: Matthew Rheaume <mhr@lightspark.com>
Date: Mon, 11 Nov 2024 10:25:53 -0800
Subject: [PATCH 2/3] Renamed `log_dir` configuration to `log_file`.

This is expected to be passed in as a file, not a directory, so change
the name to reflect that fact.
---
 config_spec.toml           | 2 +-
 src/main.rs                | 2 +-
 tests/common/mod.rs        | 4 ++--
 tests/integration_tests.rs | 8 ++++----
 4 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/config_spec.toml b/config_spec.toml
index 560474a..a7aa006 100644
--- a/config_spec.toml
+++ b/config_spec.toml
@@ -43,7 +43,7 @@ type = "String"
 doc = "The path to the lndk data directory. By default this is stored in ~/.lndk"
 
 [[param]]
-name = "log_dir"
+name = "log_file"
 type = "String"
 doc = "The path to the lndk log file. By default this is stored in ~/.lndk"
 
diff --git a/src/main.rs b/src/main.rs
index f1938f7..a85f15e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -39,7 +39,7 @@ async fn main() -> Result<(), ()> {
 
     let data_dir = create_data_dir(config.data_dir)
         .map_err(|e| println!("Error creating LNDK's data dir {e:?}"))?;
-    setup_logger(config.log_level, config.log_dir)?;
+    setup_logger(config.log_level, config.log_file)?;
 
     let creds = validate_lnd_creds(
         config.cert_path,
diff --git a/tests/common/mod.rs b/tests/common/mod.rs
index cab5531..c0d8635 100644
--- a/tests/common/mod.rs
+++ b/tests/common/mod.rs
@@ -193,14 +193,14 @@ pub async fn setup_lndk(
     let handler = Arc::new(lndk::OfferHandler::default());
     let messenger = lndk::LndkOnionMessenger::new();
 
-    let log_dir = Some(
+    let log_file = Some(
         lndk_dir
             .join(format!("lndk-logs.txt"))
             .to_str()
             .unwrap()
             .to_string(),
     );
-    setup_logger(None, log_dir).unwrap();
+    setup_logger(None, log_file).unwrap();
 
     return (lndk_cfg, handler, messenger, shutdown);
 }
diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs
index 511391a..00f7073 100644
--- a/tests/integration_tests.rs
+++ b/tests/integration_tests.rs
@@ -209,14 +209,14 @@ async fn test_lndk_send_invoice_request() {
         }
     }
 
-    let log_dir = Some(
+    let log_file = Some(
         lndk_dir
             .join(format!("lndk-logs.txt"))
             .to_str()
             .unwrap()
             .to_string(),
     );
-    setup_logger(None, log_dir).unwrap();
+    setup_logger(None, log_file).unwrap();
 
     // Make sure lndk successfully sends the invoice_request.
     let handler = Arc::new(lndk::OfferHandler::default());
@@ -266,14 +266,14 @@ async fn test_lndk_send_invoice_request() {
         rate_limit_period_secs: 1,
     };
 
-    let log_dir = Some(
+    let log_file = Some(
         lndk_dir
             .join(format!("lndk-logs.txt"))
             .to_str()
             .unwrap()
             .to_string(),
     );
-    setup_logger(None, log_dir).unwrap();
+    setup_logger(None, log_file).unwrap();
 
     let handler = Arc::new(lndk::OfferHandler::default());
     let messenger = lndk::LndkOnionMessenger::new();

From 7335927af57cb0bae4635154757097935177237f Mon Sep 17 00:00:00 2001
From: Matthew Rheaume <mhr@lightspark.com>
Date: Sun, 3 Nov 2024 10:39:43 -0800
Subject: [PATCH 3/3] Fall back to `data_dir` if `log_file` is unspecified.

---
 config_spec.toml           |  2 +-
 src/lib.rs                 | 16 +++++++---------
 src/main.rs                | 13 +++++++++----
 tests/common/mod.rs        |  8 +-------
 tests/integration_tests.rs | 16 ++--------------
 5 files changed, 20 insertions(+), 35 deletions(-)

diff --git a/config_spec.toml b/config_spec.toml
index a7aa006..1f65c78 100644
--- a/config_spec.toml
+++ b/config_spec.toml
@@ -45,7 +45,7 @@ doc = "The path to the lndk data directory. By default this is stored in ~/.lndk
 [[param]]
 name = "log_file"
 type = "String"
-doc = "The path to the lndk log file. By default this is stored in ~/.lndk"
+doc = "The path to the lndk log file. If not specified, defaults to `<data_dir>/lndk.log`."
 
 [[param]]
 name = "log_level"
diff --git a/src/lib.rs b/src/lib.rs
index fa8a7bf..7b3b5b1 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -42,6 +42,7 @@ use log4rs::config::{Appender, Config as LogConfig, Logger, Root};
 use log4rs::encode::pattern::PatternEncoder;
 use rate_limit::RateLimiterCfg;
 use std::collections::HashMap;
+use std::path::PathBuf;
 use std::str::FromStr;
 use std::sync::{Arc, Mutex, Once};
 use tokio::time::{sleep, timeout, Duration};
@@ -62,13 +63,14 @@ pub const DEFAULT_SERVER_HOST: &str = "127.0.0.1";
 pub const DEFAULT_SERVER_PORT: u16 = 7000;
 pub const LDK_LOGGER_NAME: &str = "ldk";
 pub const DEFAULT_DATA_DIR: &str = ".lndk";
+pub const DEFAULT_LOG_FILE: &str = "lndk.log";
 
 pub const TLS_CERT_FILENAME: &str = "tls-cert.pem";
 pub const TLS_KEY_FILENAME: &str = "tls-key.pem";
 pub const DEFAULT_RESPONSE_INVOICE_TIMEOUT: u32 = 15;
 
 #[allow(clippy::result_unit_err)]
-pub fn setup_logger(log_level: Option<String>, log_dir: Option<String>) -> Result<(), ()> {
+pub fn setup_logger(log_level: Option<String>, log_file: Option<PathBuf>) -> Result<(), ()> {
     let log_level = match log_level {
         Some(level_str) => match LevelFilter::from_str(&level_str) {
             Ok(level) => level,
@@ -85,22 +87,18 @@ pub fn setup_logger(log_level: Option<String>, log_dir: Option<String>) -> Resul
         None => LevelFilter::Trace,
     };
 
-    let log_dir = log_dir.unwrap_or_else(|| {
+    let log_file = log_file.unwrap_or_else(|| {
         home_dir()
             .unwrap()
-            .join(".lndk")
-            .join("lndk.log")
-            .as_path()
-            .to_str()
-            .unwrap()
-            .to_string()
+            .join(DEFAULT_DATA_DIR)
+            .join(DEFAULT_LOG_FILE)
     });
 
     // Log both to stdout and a log file.
     let stdout = ConsoleAppender::builder().build();
     let lndk_logs = FileAppender::builder()
         .encoder(Box::new(PatternEncoder::new("{d} - {m}{n}")))
-        .build(log_dir)
+        .build(log_file)
         .unwrap();
 
     let config = LogConfig::builder()
diff --git a/src/main.rs b/src/main.rs
index a85f15e..36bd98c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -15,7 +15,7 @@ use lndk::lnd::{get_lnd_client, validate_lnd_creds, LndCfg};
 use lndk::server::{generate_tls_creds, read_tls, LNDKServer};
 use lndk::{
     lndkrpc, setup_logger, Cfg, LifecycleSignals, LndkOnionMessenger, OfferHandler,
-    DEFAULT_DATA_DIR, DEFAULT_SERVER_HOST, DEFAULT_SERVER_PORT,
+    DEFAULT_DATA_DIR, DEFAULT_LOG_FILE, DEFAULT_SERVER_HOST, DEFAULT_SERVER_PORT,
 };
 use lndkrpc::offers_server::OffersServer;
 use log::{error, info};
@@ -37,9 +37,14 @@ async fn main() -> Result<(), ()> {
         .unwrap_or_exit()
         .0;
 
-    let data_dir = create_data_dir(config.data_dir)
+    let data_dir = create_data_dir(&config.data_dir)
         .map_err(|e| println!("Error creating LNDK's data dir {e:?}"))?;
-    setup_logger(config.log_level, config.log_file)?;
+
+    let log_file = config.log_file.map(PathBuf::from).or(config
+        .data_dir
+        .map(|data_dir| PathBuf::from(data_dir).join(DEFAULT_LOG_FILE)));
+
+    setup_logger(config.log_level, log_file)?;
 
     let creds = validate_lnd_creds(
         config.cert_path,
@@ -157,7 +162,7 @@ async fn main() -> Result<(), ()> {
 }
 
 // Creates lndk's data directory at the specified directory, or ~/.lndk if not specified.
-fn create_data_dir(data_dir: Option<String>) -> Result<PathBuf, std::io::Error> {
+fn create_data_dir(data_dir: &Option<String>) -> Result<PathBuf, std::io::Error> {
     let path = match data_dir {
         Some(dir) => PathBuf::from(&dir),
         None => home_dir().unwrap().join(DEFAULT_DATA_DIR),
diff --git a/tests/common/mod.rs b/tests/common/mod.rs
index c0d8635..a331d89 100644
--- a/tests/common/mod.rs
+++ b/tests/common/mod.rs
@@ -193,13 +193,7 @@ pub async fn setup_lndk(
     let handler = Arc::new(lndk::OfferHandler::default());
     let messenger = lndk::LndkOnionMessenger::new();
 
-    let log_file = Some(
-        lndk_dir
-            .join(format!("lndk-logs.txt"))
-            .to_str()
-            .unwrap()
-            .to_string(),
-    );
+    let log_file = Some(lndk_dir.join(format!("lndk-logs.txt")));
     setup_logger(None, log_file).unwrap();
 
     return (lndk_cfg, handler, messenger, shutdown);
diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs
index 00f7073..ec64402 100644
--- a/tests/integration_tests.rs
+++ b/tests/integration_tests.rs
@@ -209,13 +209,7 @@ async fn test_lndk_send_invoice_request() {
         }
     }
 
-    let log_file = Some(
-        lndk_dir
-            .join(format!("lndk-logs.txt"))
-            .to_str()
-            .unwrap()
-            .to_string(),
-    );
+    let log_file = Some(lndk_dir.join(format!("lndk-logs.txt")));
     setup_logger(None, log_file).unwrap();
 
     // Make sure lndk successfully sends the invoice_request.
@@ -266,13 +260,7 @@ async fn test_lndk_send_invoice_request() {
         rate_limit_period_secs: 1,
     };
 
-    let log_file = Some(
-        lndk_dir
-            .join(format!("lndk-logs.txt"))
-            .to_str()
-            .unwrap()
-            .to_string(),
-    );
+    let log_file = Some(lndk_dir.join(format!("lndk-logs.txt")));
     setup_logger(None, log_file).unwrap();
 
     let handler = Arc::new(lndk::OfferHandler::default());