Skip to content

Commit 0494dba

Browse files
committed
sim-cli: source simulation file from data directory
Adds a simln data-dir cli param, but maintains the default value to cwd Sources the simulation file from this data dir Prompts the user to select a simulatin file if the default/configured file is not found
1 parent 3416e02 commit 0494dba

File tree

5 files changed

+183
-37
lines changed

5 files changed

+183
-37
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ sim.json
55
package-lock.json
66
activity-generator/releases/*
77
.DS_Store
8-
*simulation_*.csv
8+
/results

Cargo.lock

+77-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sim-cli/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Instantly simulate real-world Lightning network activity
1111
[dependencies]
1212
anyhow = { version = "1.0.69", features = ["backtrace"] }
1313
clap = { version = "4.1.6", features = ["derive", "env", "std", "help", "usage", "error-context", "suggestions"], default-features = false }
14+
dialoguer = "0.11.0"
1415
log = "0.4.20"
1516
serde = "1.0.183"
1617
serde_json = "1.0.104"

sim-cli/src/main.rs

+76-5
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,16 @@ use clap::Parser;
1010
use log::LevelFilter;
1111
use sim_lib::{
1212
cln::ClnNode, lnd::LndNode, ActivityDefinition, LightningError, LightningNode, NodeConnection,
13-
NodeId, SimParams, Simulation,
13+
NodeId, SimParams, Simulation, WriteResults,
1414
};
1515
use simple_logger::SimpleLogger;
1616

17+
/// The default directory where the simulation files are stored and where the results will be written to.
18+
pub const DEFAULT_DATA_DIR: &str = ".";
19+
20+
/// The default simulation file to be used by the simulator.
21+
pub const DEFAULT_SIM_FILE: &str = "sim.json";
22+
1723
/// The default expected payment amount for the simulation, around ~$10 at the time of writing.
1824
pub const EXPECTED_PAYMENT_AMOUNT: u64 = 3_800_000;
1925

@@ -42,8 +48,12 @@ fn deserialize_f64_greater_than_zero(x: String) -> Result<f64, String> {
4248
#[derive(Parser)]
4349
#[command(version, about)]
4450
struct Cli {
51+
/// Path to a directory containing simulation files, and where simulation results will be stored
52+
#[clap(long, short, default_value = DEFAULT_DATA_DIR)]
53+
data_dir: PathBuf,
4554
/// Path to the simulation file to be used by the simulator
46-
#[clap(index = 1)]
55+
/// This can either be an absolute path, or relative path with respect to data_dir
56+
#[clap(long, short, default_value = DEFAULT_SIM_FILE)]
4757
sim_file: PathBuf,
4858
/// Total time the simulator will be running
4959
#[clap(long, short)]
@@ -77,8 +87,9 @@ async fn main() -> anyhow::Result<()> {
7787
.init()
7888
.unwrap();
7989

90+
let sim_path = read_sim_path(cli.data_dir.clone(), cli.sim_file).await?;
8091
let SimParams { nodes, activity } =
81-
serde_json::from_str(&std::fs::read_to_string(cli.sim_file)?)
92+
serde_json::from_str(&std::fs::read_to_string(sim_path)?)
8293
.map_err(|e| anyhow!("Could not deserialize node connection data or activity description from simulation file (line {}, col {}).", e.line(), e.column()))?;
8394

8495
let mut clients: HashMap<PublicKey, Arc<Mutex<dyn LightningNode + Send>>> = HashMap::new();
@@ -179,14 +190,22 @@ async fn main() -> anyhow::Result<()> {
179190
});
180191
}
181192

193+
let write_results = if !cli.no_results {
194+
Some(WriteResults {
195+
results_dir: mkdir(cli.data_dir.join("results")).await?,
196+
batch_size: cli.print_batch_size,
197+
})
198+
} else {
199+
None
200+
};
201+
182202
let sim = Simulation::new(
183203
clients,
184204
validated_activities,
185205
cli.total_time,
186-
cli.print_batch_size,
187206
cli.expected_pmt_amt,
188207
cli.capacity_multiplier,
189-
cli.no_results,
208+
write_results,
190209
);
191210
let sim2 = sim.clone();
192211

@@ -199,3 +218,55 @@ async fn main() -> anyhow::Result<()> {
199218

200219
Ok(())
201220
}
221+
222+
async fn read_sim_path(data_dir: PathBuf, sim_file: PathBuf) -> anyhow::Result<PathBuf> {
223+
let sim_path = if sim_file.is_relative() {
224+
data_dir.join(sim_file)
225+
} else {
226+
sim_file
227+
};
228+
229+
if sim_path.exists() {
230+
Ok(sim_path)
231+
} else {
232+
log::info!("Simulation file '{}' does not exist.", sim_path.display());
233+
select_sim_file(data_dir).await
234+
}
235+
}
236+
237+
async fn select_sim_file(data_dir: PathBuf) -> anyhow::Result<PathBuf> {
238+
let sim_files = std::fs::read_dir(data_dir.clone())?
239+
.filter_map(|f| {
240+
f.ok().and_then(|f| {
241+
if f.path().extension()?.to_str()? == "json" {
242+
f.file_name().into_string().ok()
243+
} else {
244+
None
245+
}
246+
})
247+
})
248+
.collect::<Vec<_>>();
249+
250+
if sim_files.is_empty() {
251+
anyhow::bail!(
252+
"no simulation files found in {}",
253+
data_dir.canonicalize()?.display()
254+
);
255+
}
256+
257+
let selection = dialoguer::Select::new()
258+
.with_prompt(format!(
259+
"Select a simulation file. Found these in {}",
260+
data_dir.canonicalize()?.display()
261+
))
262+
.items(&sim_files)
263+
.default(0)
264+
.interact()?;
265+
266+
Ok(data_dir.join(sim_files[selection].clone()))
267+
}
268+
269+
async fn mkdir(dir: PathBuf) -> anyhow::Result<PathBuf> {
270+
tokio::fs::create_dir_all(&dir).await?;
271+
Ok(dir)
272+
}

0 commit comments

Comments
 (0)