diff --git a/hyperswarm-bootstrap/Cargo.toml b/hyperswarm-bootstrap/Cargo.toml
index c49799c..d80d2ff 100644
--- a/hyperswarm-bootstrap/Cargo.toml
+++ b/hyperswarm-bootstrap/Cargo.toml
@@ -10,4 +10,6 @@ edition = "2018"
hyperswarm = { path = "..", default-features = false }
async-std = { version = "1.9.0", features = ["unstable"] }
env_logger = "0.8.3"
-clap = "3.0.0-beta.2"
+log = "0.4.14"
+anyhow = "1.0.39"
+clap = { version = "3.1.7", features = ["derive"] }
diff --git a/hyperswarm-bootstrap/README.md b/hyperswarm-bootstrap/README.md
new file mode 100644
index 0000000..477b8ee
--- /dev/null
+++ b/hyperswarm-bootstrap/README.md
@@ -0,0 +1,17 @@
+# hyperswarm-bootstrap
+
+Simple binary to run a bootstrap node.
+
+```
+$ cargo run -- --help
+hyperswarm-bootstrap
+Run a Hyperswarm bootstrap node
+
+USAGE:
+ hyperswarm-bootstrap [OPTIONS]
+
+OPTIONS:
+ -a, --address
Local address to bind bootstrap node on [default: 0.0.0.0:49737]
+ -b, --bootstrap Bootstrap addresses
+ -h, --help Print help information
+```
diff --git a/hyperswarm-bootstrap/src/main.rs b/hyperswarm-bootstrap/src/main.rs
index c61fa53..7724963 100644
--- a/hyperswarm-bootstrap/src/main.rs
+++ b/hyperswarm-bootstrap/src/main.rs
@@ -1,31 +1,80 @@
+use anyhow::Context;
use async_std::task;
-use clap::Clap;
+use clap::Parser;
+use log::*;
use std::io;
-use std::net::SocketAddr;
+use std::net::{SocketAddr, ToSocketAddrs};
-use hyperswarm::run_bootstrap_node;
+use hyperswarm::{BootstrapNode, DhtConfig};
-/// Options for the storage daemon
-#[derive(Clap, Debug)]
+/// Run a Hyperswarm bootstrap node.
+#[derive(Parser, Debug)]
struct Options {
/// Local address to bind bootstrap node on.
- #[clap(short, long)]
- address: Option,
+ #[clap(short, long, default_value = "0.0.0.0:49737")]
+ address: SocketAddr,
/// Bootstrap addresses
#[clap(short, long)]
- bootstrap: Vec,
+ bootstrap: Vec,
}
fn main() -> io::Result<()> {
env_logger::init();
- task::block_on(async_main())
+ match task::block_on(async_main()) {
+ Err(e) => {
+ debug!("{:?}", e);
+ eprintln!("Error: {}", e);
+ std::process::exit(1);
+ }
+ Ok(()) => Ok(()),
+ }
}
-async fn async_main() -> io::Result<()> {
+async fn async_main() -> anyhow::Result<()> {
let opts: Options = Options::parse();
- let (addr, task) = run_bootstrap_node(opts.address).await?;
- println!("listening on {}", addr);
+
+ let config = DhtConfig::default()
+ .set_bootstrap_nodes(&opts.bootstrap[..])
+ .set_ephemeral(false);
+
+ let mut config = if opts.bootstrap.len() > 0 {
+ let mut addrs = vec![];
+ for addr in opts.bootstrap.iter() {
+ for addr in addr
+ .to_socket_addrs()
+ .with_context(|| format!("Invalid socket address \"{}\"", addr))?
+ {
+ if addr.is_ipv4() {
+ addrs.push(addr);
+ }
+ }
+ }
+ config.set_bootstrap_nodes(&addrs[..])
+ } else {
+ config
+ };
+
+ let bootstrap_addrs: Vec = config
+ .bootstrap_nodes()
+ .map(|v| v.clone().iter().map(|s| s.to_string()).collect())
+ .unwrap_or_else(|| {
+ hyperswarm::DEFAULT_BOOTSTRAP
+ .to_vec()
+ .iter()
+ .map(|s| s.to_string())
+ .collect()
+ });
+
+ let node = BootstrapNode::new(config, Some(opts.address));
+ let (addr, task) = node.run().await?;
+
+ println!("DHT listening on {}", addr);
+ debug!(
+ "Bootstrapping DHT via nodes: {}",
+ bootstrap_addrs.join(", ")
+ );
+
task.await?;
Ok(())
}