summaryrefslogtreecommitdiffstats
path: root/src/main.rs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-10-25 12:55:27 +0100
committertv <tv@krebsco.de>2026-10-25 12:55:27 +0100
commitd6620dc266b593e9ed269bcb7e65d3d8c9710d27 (patch)
tree15d86e3fa2e0ef3b2cea6907c7b778a8ee6ed2b4 /src/main.rs
parent9845a07960fa083db0b0c7e2312f98706e9684cb (diff)
add possibility to start with a document
The --recover-from option allows a node start with a given document.
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs48
1 files changed, 39 insertions, 9 deletions
diff --git a/src/main.rs b/src/main.rs
index 4cfae66..d6773eb 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -116,12 +116,21 @@ async fn main() -> Result<()> {
let (change_tx, _) = watch::channel(0_u64);
let (change_events, _) = broadcast::channel(256);
- let initial_epoch = match args.debug_epoch {
- Some(generation) => Epoch {
+ let recovered = match &args.recover_from {
+ Some(path) => Some(bootstrap::load_backup(path)?),
+ None => None,
+ };
+ let (initial_doc, recovered_epoch, recovered_swarm) = match recovered {
+ Some((doc, epoch, swarm_id)) => (doc, Some(epoch), Some(swarm_id)),
+ None => (AutoCommit::new(), None, None),
+ };
+ let initial_epoch = match (recovered_epoch, args.debug_epoch) {
+ (Some(epoch), _) => epoch,
+ (None, Some(generation)) => Epoch {
generation,
id: [0xee; 32],
},
- None => Epoch::GENESIS,
+ (None, None) => Epoch::GENESIS,
};
let (epoch_tx, _) = watch::channel(initial_epoch);
debug!(epoch = %initial_epoch, "Local epoch");
@@ -133,7 +142,7 @@ async fn main() -> Result<()> {
debug!(local_id = mycelium_transport.local_id(), "Transport ready");
let state = AppState {
- doc: Arc::new(RwLock::new(Replica::new(initial_epoch, AutoCommit::new()))),
+ doc: Arc::new(RwLock::new(Replica::new(initial_epoch, initial_doc))),
epoch_tx,
lifecycle: Arc::new(RwLock::new(NodeLifecycle::Joining {
discovered_swarm_id: None,
@@ -179,10 +188,31 @@ async fn main() -> Result<()> {
trace!("Application state initialized");
- // Join the remembered swarm and no other; HELLOs claim it.
- if let Some(remembered) = remembered {
- state.set_expected_swarm_id(remembered.swarm_id).await?;
- }
+ // Join the remembered swarm and no other; HELLOs claim it. A backup to recover from
+ // names its swarm itself, which wins.
+ let start = match recovered_swarm {
+ Some(swarm_id) => {
+ if let Some(remembered) = remembered.filter(|r| r.swarm_id != swarm_id) {
+ warn!(
+ backup = %swarm_id,
+ remembered = %remembered.swarm_id,
+ "The backup is of another swarm than the remembered one; recovering the backup's"
+ );
+ }
+ state.set_expected_swarm_id(swarm_id).await?;
+ bootstrap::Start::Recovered
+ }
+ None => {
+ if let Some(remembered) = remembered {
+ state.set_expected_swarm_id(remembered.swarm_id).await?;
+ }
+ if args.genesis {
+ bootstrap::Start::Genesis
+ } else {
+ bootstrap::Start::Join
+ }
+ }
+ };
let consumer_state = state.clone();
tokio::spawn(async move {
@@ -215,7 +245,7 @@ async fn main() -> Result<()> {
tokio::spawn(remake::run_worker(state.clone()));
trace!("Remake worker task spawned");
- let joining = bootstrap::bootstrap(&state, &seeds, args.genesis);
+ let joining = bootstrap::bootstrap(&state, &seeds, start);
tokio::select! {
joined = joining => joined.context("Joining swarm")?,
_ = stopped(stop.clone()) => {