Przeglądaj źródła

darkirc: monitor network disconnection and resync accordingly

dasman 1 rok temu
rodzic
commit
54b891c905
1 zmienionych plików z 76 dodań i 25 usunięć
  1. 76 25
      bin/darkirc/src/main.rs

+ 76 - 25
bin/darkirc/src/main.rs

@@ -26,7 +26,7 @@ use darkfi::{
         jsonrpc::JsonSubscriber,
         server::{listen_and_serve, RequestHandler},
     },
-    system::{sleep, StoppableTask, StoppableTaskPtr},
+    system::{sleep, StoppableTask, StoppableTaskPtr, Subscription},
     util::path::{expand_path, get_config_path},
     Error, Result,
 };
@@ -401,32 +401,22 @@ async fn realmain(args: Args, ex: Arc<Executor<'static>>) -> Result<()> {
     info!("Starting P2P network");
     p2p.clone().start().await?;
 
-    let comms_timeout = p2p.settings().read().await.outbound_connect_timeout;
+    // Initial DAG sync
+    sync_task(&p2p, &event_graph, args.skip_dag_sync).await?;
 
-    loop {
-        if p2p.is_connected() {
-            info!("Got peer connection");
-            // We'll attempt to sync for ever
-            if !args.skip_dag_sync {
-                info!("Syncing event DAG");
-                match event_graph.dag_sync().await {
-                    Ok(()) => break,
-                    Err(e) => {
-                        // TODO: Maybe at this point we should prune or something?
-                        // TODO: Or maybe just tell the user to delete the DAG from FS.
-                        error!("Failed syncing DAG ({}), retrying in {}s...", e, comms_timeout);
-                        sleep(comms_timeout).await;
-                    }
-                }
-            } else {
-                *event_graph.synced.write().await = true;
-                break
+    // Stoppable task to monitor network and resync on disconnect.
+    let sync_mon_task = StoppableTask::new();
+    sync_mon_task.clone().start(
+        sync_and_monitor(p2p.clone(), event_graph.clone(), args.skip_dag_sync),
+        |res| async move {
+            match res {
+                Ok(()) | Err(Error::DetachedTaskStopped) => { /* TODO: */ }
+                Err(e) => error!("Failed sync task: {}", e),
             }
-        } else {
-            info!("Waiting for some P2P connections...");
-            sleep(comms_timeout).await;
-        }
-    }
+        },
+        Error::DetachedTaskStopped,
+        ex.clone(),
+    );
 
     // Signal handling for graceful termination.
     let (signals_handler, signals_task) = SignalHandler::new(ex)?;
@@ -452,3 +442,64 @@ async fn realmain(args: Args, ex: Arc<Executor<'static>>) -> Result<()> {
     info!("Shut down successfully");
     Ok(())
 }
+
+/// Async task to monitor network disconnections.
+async fn monitor_network(subscription: &Subscription<Error>) -> Result<()> {
+    Err(subscription.receive().await)
+}
+
+/// Async task to endlessly try to sync DAG, returns Ok if done.
+async fn sync_task(p2p: &P2pPtr, event_graph: &EventGraphPtr, skip_dag_sync: bool) -> Result<()> {
+    let comms_timeout = p2p.settings().read().await.outbound_connect_timeout;
+
+    loop {
+        if p2p.is_connected() {
+            info!("Got peer connection");
+            // We'll attempt to sync for ever
+            if !skip_dag_sync {
+                info!("Syncing event DAG");
+                match event_graph.dag_sync().await {
+                    Ok(()) => break,
+                    Err(e) => {
+                        // TODO: Maybe at this point we should prune or something?
+                        // TODO: Or maybe just tell the user to delete the DAG from FS.
+                        error!("Failed syncing DAG ({}), retrying in {}s...", e, comms_timeout);
+                        sleep(comms_timeout).await;
+                    }
+                }
+            } else {
+                *event_graph.synced.write().await = true;
+                break;
+            }
+        } else {
+            info!("Waiting for some P2P connections...");
+            sleep(comms_timeout).await;
+        }
+    }
+
+    Ok(())
+}
+
+/// Async task to monitor the network and force resync on disconnections
+async fn sync_and_monitor(
+    p2p: P2pPtr,
+    event_graph: EventGraphPtr,
+    skip_dag_sync: bool,
+) -> Result<()> {
+    loop {
+        let net_subscription = p2p.hosts().subscribe_disconnect().await;
+        let result = monitor_network(&net_subscription).await;
+        net_subscription.unsubscribe().await;
+
+        match result {
+            Ok(_) => return Ok(()),
+            Err(Error::NetworkNotConnected) => {
+                // Sync node again
+                info!("Network disconnection detected, resyncing...");
+                *event_graph.synced.write().await = false;
+                sync_task(&p2p, &event_graph, skip_dag_sync).await?;
+            }
+            Err(e) => return Err(e),
+        }
+    }
+}