main.rs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2025 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use log::{debug, error, info, warn};
  19. use sled_overlay::sled;
  20. use smol::{stream::StreamExt, Executor};
  21. use std::sync::Arc;
  22. use structopt_toml::StructOptToml;
  23. use darkfi::{
  24. async_daemonize,
  25. dht::DhtHandler,
  26. net::{session::SESSION_DEFAULT, P2p, Settings as NetSettings},
  27. rpc::{
  28. jsonrpc::JsonSubscriber,
  29. server::{listen_and_serve, RequestHandler},
  30. settings::RpcSettings,
  31. },
  32. system::{Publisher, StoppableTask},
  33. util::path::expand_path,
  34. Error, Result,
  35. };
  36. use fud::{
  37. proto::{FudFindNodesReply, ProtocolFud},
  38. rpc::JsonRpcInterface,
  39. settings::{Args, CONFIG_FILE, CONFIG_FILE_CONTENTS},
  40. tasks::{announce_seed_task, get_task, node_id_task},
  41. Fud,
  42. };
  43. async_daemonize!(realmain);
  44. async fn realmain(args: Args, ex: Arc<Executor<'static>>) -> Result<()> {
  45. // The working directory for this daemon and geode.
  46. let basedir = expand_path(&args.base_dir)?;
  47. // Cloned args
  48. let args_ = args.clone();
  49. // Sled database init
  50. info!(target: "fud", "Instantiating database");
  51. let sled_db = sled::open(basedir.join("db"))?;
  52. info!(target: "fud", "Instantiating P2P network");
  53. let net_settings: NetSettings = args.net.into();
  54. let p2p = P2p::new(net_settings.clone(), ex.clone()).await?;
  55. info!(target: "fud", "Starting dnet subs task");
  56. let dnet_sub = JsonSubscriber::new("dnet.subscribe_events");
  57. let dnet_sub_ = dnet_sub.clone();
  58. let p2p_ = p2p.clone();
  59. let dnet_task = StoppableTask::new();
  60. dnet_task.clone().start(
  61. async move {
  62. let dnet_sub = p2p_.dnet_subscribe().await;
  63. loop {
  64. let event = dnet_sub.receive().await;
  65. debug!("Got dnet event: {event:?}");
  66. dnet_sub_.notify(vec![event.into()].into()).await;
  67. }
  68. },
  69. |res| async {
  70. match res {
  71. Ok(()) | Err(Error::DetachedTaskStopped) => { /* Do nothing */ }
  72. Err(e) => panic!("{e}"),
  73. }
  74. },
  75. Error::DetachedTaskStopped,
  76. ex.clone(),
  77. );
  78. // Daemon instantiation
  79. let event_pub = Publisher::new();
  80. let fud: Arc<Fud> =
  81. Arc::new(Fud::new(args_, p2p.clone(), &sled_db, event_pub.clone(), ex.clone()).await?);
  82. info!(target: "fud", "Starting download subs task");
  83. let event_sub = JsonSubscriber::new("event");
  84. let event_sub_ = event_sub.clone();
  85. let event_task = StoppableTask::new();
  86. event_task.clone().start(
  87. async move {
  88. let event_sub = event_pub.clone().subscribe().await;
  89. loop {
  90. let event = event_sub.receive().await;
  91. debug!(target: "fud", "Got event: {event:?}");
  92. event_sub_.notify(event.into()).await;
  93. }
  94. },
  95. |res| async {
  96. match res {
  97. Ok(()) | Err(Error::DetachedTaskStopped) => { /* Do nothing */ }
  98. Err(e) => panic!("{e}"),
  99. }
  100. },
  101. Error::DetachedTaskStopped,
  102. ex.clone(),
  103. );
  104. info!(target: "fud", "Starting get task");
  105. let get_task_ = StoppableTask::new();
  106. get_task_.clone().start(
  107. get_task(fud.clone(), ex.clone()),
  108. |res| async {
  109. match res {
  110. Ok(()) | Err(Error::DetachedTaskStopped) => { /* Do nothing */ }
  111. Err(e) => error!(target: "fud", "Failed starting get task: {e}"),
  112. }
  113. },
  114. Error::DetachedTaskStopped,
  115. ex.clone(),
  116. );
  117. let rpc_settings: RpcSettings = args.rpc.into();
  118. info!(target: "fud", "Starting JSON-RPC server on {}", rpc_settings.listen);
  119. let rpc_interface = Arc::new(JsonRpcInterface::new(fud.clone(), dnet_sub, event_sub));
  120. let rpc_task = StoppableTask::new();
  121. let rpc_interface_ = rpc_interface.clone();
  122. rpc_task.clone().start(
  123. listen_and_serve(rpc_settings, rpc_interface, None, ex.clone()),
  124. |res| async move {
  125. match res {
  126. Ok(()) | Err(Error::RpcServerStopped) => rpc_interface_.stop_connections().await,
  127. Err(e) => error!(target: "fud", "Failed starting sync JSON-RPC server: {e}"),
  128. }
  129. },
  130. Error::RpcServerStopped,
  131. ex.clone(),
  132. );
  133. info!(target: "fud", "Starting P2P protocols");
  134. let registry = p2p.protocol_registry();
  135. let fud_ = fud.clone();
  136. registry
  137. .register(SESSION_DEFAULT, move |channel, p2p| {
  138. let fud_ = fud_.clone();
  139. async move { ProtocolFud::init(fud_, channel, p2p).await.unwrap() }
  140. })
  141. .await;
  142. p2p.clone().start().await?;
  143. let p2p_settings_lock = p2p.settings();
  144. let p2p_settings = p2p_settings_lock.read().await;
  145. if p2p_settings.external_addrs.is_empty() {
  146. warn!(target: "fud::realmain", "No external addresses, you won't be able to seed")
  147. }
  148. drop(p2p_settings);
  149. info!(target: "fud", "Starting DHT tasks");
  150. let dht_channel_task = StoppableTask::new();
  151. let fud_ = fud.clone();
  152. dht_channel_task.clone().start(
  153. async move { fud_.channel_task::<FudFindNodesReply>().await },
  154. |res| async {
  155. match res {
  156. Ok(()) | Err(Error::DetachedTaskStopped) => { /* Do nothing */ }
  157. Err(e) => error!(target: "fud", "Failed starting dht channel task: {e}"),
  158. }
  159. },
  160. Error::DetachedTaskStopped,
  161. ex.clone(),
  162. );
  163. let announce_task = StoppableTask::new();
  164. let fud_ = fud.clone();
  165. announce_task.clone().start(
  166. async move { announce_seed_task(fud_.clone()).await },
  167. |res| async {
  168. match res {
  169. Ok(()) | Err(Error::DetachedTaskStopped) => { /* Do nothing */ }
  170. Err(e) => error!(target: "fud", "Failed starting announce task: {e}"),
  171. }
  172. },
  173. Error::DetachedTaskStopped,
  174. ex.clone(),
  175. );
  176. info!(target: "fud", "Starting node ID task");
  177. let node_task = StoppableTask::new();
  178. let fud_ = fud.clone();
  179. node_task.clone().start(
  180. async move { node_id_task(fud_.clone()).await },
  181. |res| async {
  182. match res {
  183. Ok(()) | Err(Error::DetachedTaskStopped) => { /* Do nothing */ }
  184. Err(e) => error!(target: "fud", "Failed starting node ID task: {e}"),
  185. }
  186. },
  187. Error::DetachedTaskStopped,
  188. ex.clone(),
  189. );
  190. // Signal handling for graceful termination.
  191. let (signals_handler, signals_task) = SignalHandler::new(ex)?;
  192. signals_handler.wait_termination(signals_task).await?;
  193. info!(target: "fud", "Caught termination signal, cleaning up and exiting...");
  194. info!(target: "fud", "Stopping fetch tasks...");
  195. fud.stop().await;
  196. info!(target: "fud", "Stopping get task...");
  197. get_task_.stop().await;
  198. info!(target: "fud", "Stopping JSON-RPC server...");
  199. rpc_task.stop().await;
  200. info!(target: "fud", "Stopping P2P network...");
  201. p2p.stop().await;
  202. info!(target: "fud", "Stopping DHT tasks...");
  203. dht_channel_task.stop().await;
  204. announce_task.stop().await;
  205. info!(target: "fud", "Stopping node ID task...");
  206. node_task.stop().await;
  207. info!(target: "fud", "Flushing sled database...");
  208. let flushed_bytes = sled_db.flush_async().await?;
  209. info!(target: "fud", "Flushed {flushed_bytes} bytes");
  210. info!(target: "fud", "Shut down successfully");
  211. Ok(())
  212. }