|
@@ -1,44 +1,47 @@
|
|
|
-use std::{net::SocketAddr, sync::atomic::Ordering};
|
|
|
|
|
-
|
|
|
|
|
-use async_channel::{Receiver, Sender};
|
|
|
|
|
-use async_executor::Executor;
|
|
|
|
|
use async_std::{
|
|
use async_std::{
|
|
|
net::{TcpListener, TcpStream},
|
|
net::{TcpListener, TcpStream},
|
|
|
sync::{Arc, Mutex},
|
|
sync::{Arc, Mutex},
|
|
|
};
|
|
};
|
|
|
|
|
+use std::{net::SocketAddr, sync::atomic::Ordering};
|
|
|
|
|
+
|
|
|
|
|
+use async_channel::Receiver;
|
|
|
|
|
+use async_executor::Executor;
|
|
|
|
|
+
|
|
|
use futures::{io::BufReader, AsyncBufReadExt, AsyncReadExt, FutureExt};
|
|
use futures::{io::BufReader, AsyncBufReadExt, AsyncReadExt, FutureExt};
|
|
|
use fxhash::FxHashMap;
|
|
use fxhash::FxHashMap;
|
|
|
use log::{debug, error, info, warn};
|
|
use log::{debug, error, info, warn};
|
|
|
use rand::rngs::OsRng;
|
|
use rand::rngs::OsRng;
|
|
|
|
|
+use ringbuffer::RingBufferWrite;
|
|
|
use smol::future;
|
|
use smol::future;
|
|
|
use structopt_toml::StructOptToml;
|
|
use structopt_toml::StructOptToml;
|
|
|
|
|
|
|
|
use darkfi::{
|
|
use darkfi::{
|
|
|
async_daemonize, net,
|
|
async_daemonize, net,
|
|
|
- raft::{NetMsg, ProtocolRaft, Raft},
|
|
|
|
|
rpc::server::listen_and_serve,
|
|
rpc::server::listen_and_serve,
|
|
|
util::{
|
|
util::{
|
|
|
cli::{get_log_config, get_log_level, spawn_config},
|
|
cli::{get_log_config, get_log_level, spawn_config},
|
|
|
- path::{expand_path, get_config_path},
|
|
|
|
|
|
|
+ path::get_config_path,
|
|
|
},
|
|
},
|
|
|
Error, Result,
|
|
Error, Result,
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
pub mod crypto;
|
|
pub mod crypto;
|
|
|
pub mod privmsg;
|
|
pub mod privmsg;
|
|
|
|
|
+pub mod protocol_privmsg;
|
|
|
pub mod rpc;
|
|
pub mod rpc;
|
|
|
pub mod server;
|
|
pub mod server;
|
|
|
pub mod settings;
|
|
pub mod settings;
|
|
|
|
|
|
|
|
use crate::{
|
|
use crate::{
|
|
|
crypto::try_decrypt_message,
|
|
crypto::try_decrypt_message,
|
|
|
- privmsg::Privmsg,
|
|
|
|
|
|
|
+ privmsg::{Privmsg, PrivmsgsBuffer, SeenMsgIds},
|
|
|
|
|
+ protocol_privmsg::ProtocolPrivmsg,
|
|
|
rpc::JsonRpcInterface,
|
|
rpc::JsonRpcInterface,
|
|
|
server::IrcServerConnection,
|
|
server::IrcServerConnection,
|
|
|
settings::{parse_configured_channels, Args, ChannelInfo, CONFIG_FILE, CONFIG_FILE_CONTENTS},
|
|
settings::{parse_configured_channels, Args, ChannelInfo, CONFIG_FILE, CONFIG_FILE_CONTENTS},
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-pub type SeenMsgIds = Arc<Mutex<Vec<u32>>>;
|
|
|
|
|
|
|
+const SIZE_OF_MSGS_BUFFER: usize = 4096;
|
|
|
|
|
|
|
|
fn build_irc_msg(msg: &Privmsg) -> String {
|
|
fn build_irc_msg(msg: &Privmsg) -> String {
|
|
|
debug!("ABOUT TO SEND: {:?}", msg);
|
|
debug!("ABOUT TO SEND: {:?}", msg);
|
|
@@ -65,90 +68,113 @@ fn clean_input(mut line: String, peer_addr: &SocketAddr) -> Result<String> {
|
|
|
Ok(line)
|
|
Ok(line)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-async fn broadcast_msg(
|
|
|
|
|
- irc_msg: String,
|
|
|
|
|
- peer_addr: SocketAddr,
|
|
|
|
|
- conn: &mut IrcServerConnection,
|
|
|
|
|
-) -> Result<()> {
|
|
|
|
|
- info!("Send msg to IRC client '{}' from {}", irc_msg, peer_addr);
|
|
|
|
|
|
|
+struct Ircd {
|
|
|
|
|
+ // msgs
|
|
|
|
|
+ seen_msg_ids: SeenMsgIds,
|
|
|
|
|
+ privmsgs_buffer: PrivmsgsBuffer,
|
|
|
|
|
+ // channels
|
|
|
|
|
+ autojoin_chans: Vec<String>,
|
|
|
|
|
+ configured_chans: FxHashMap<String, ChannelInfo>,
|
|
|
|
|
+ // p2p
|
|
|
|
|
+ p2p: net::P2pPtr,
|
|
|
|
|
+ p2p_receiver: Receiver<Privmsg>,
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- if let Err(e) = conn.update(irc_msg).await {
|
|
|
|
|
- warn!("Connection error: {} for {}", e, peer_addr);
|
|
|
|
|
- return Err(Error::ChannelStopped)
|
|
|
|
|
|
|
+impl Ircd {
|
|
|
|
|
+ fn new(
|
|
|
|
|
+ seen_msg_ids: SeenMsgIds,
|
|
|
|
|
+ autojoin_chans: Vec<String>,
|
|
|
|
|
+ configured_chans: FxHashMap<String, ChannelInfo>,
|
|
|
|
|
+ p2p: net::P2pPtr,
|
|
|
|
|
+ p2p_receiver: Receiver<Privmsg>,
|
|
|
|
|
+ ) -> Self {
|
|
|
|
|
+ let privmsgs_buffer: PrivmsgsBuffer =
|
|
|
|
|
+ Arc::new(Mutex::new(ringbuffer::AllocRingBuffer::with_capacity(SIZE_OF_MSGS_BUFFER)));
|
|
|
|
|
+
|
|
|
|
|
+ Self { seen_msg_ids, privmsgs_buffer, autojoin_chans, configured_chans, p2p, p2p_receiver }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- Ok(())
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ async fn process(
|
|
|
|
|
+ &self,
|
|
|
|
|
+ executor: Arc<Executor<'_>>,
|
|
|
|
|
+ stream: TcpStream,
|
|
|
|
|
+ peer_addr: SocketAddr,
|
|
|
|
|
+ ) -> Result<()> {
|
|
|
|
|
+ let (reader, writer) = stream.split();
|
|
|
|
|
+
|
|
|
|
|
+ let mut reader = BufReader::new(reader);
|
|
|
|
|
+ let mut conn = IrcServerConnection::new(
|
|
|
|
|
+ writer,
|
|
|
|
|
+ self.seen_msg_ids.clone(),
|
|
|
|
|
+ self.privmsgs_buffer.clone(),
|
|
|
|
|
+ self.autojoin_chans.clone(),
|
|
|
|
|
+ self.configured_chans.clone(),
|
|
|
|
|
+ self.p2p.clone(),
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ let p2p_receiver = self.p2p_receiver.clone();
|
|
|
|
|
+ let privmsgs_buffer = self.privmsgs_buffer.clone();
|
|
|
|
|
+
|
|
|
|
|
+ executor.spawn(async move {
|
|
|
|
|
+ loop {
|
|
|
|
|
+ let mut line = String::new();
|
|
|
|
|
+ futures::select! {
|
|
|
|
|
+ privmsg = p2p_receiver.recv().fuse() => {
|
|
|
|
|
+ let mut msg = privmsg?;
|
|
|
|
|
+ info!("Received msg from P2p network: {:?}", msg);
|
|
|
|
|
+
|
|
|
|
|
+ // Try to potentially decrypt the incoming message.
|
|
|
|
|
+ if conn.configured_chans.contains_key(&msg.channel) {
|
|
|
|
|
+ let chan_info = conn.configured_chans.get(&msg.channel).unwrap();
|
|
|
|
|
+ if !chan_info.joined.load(Ordering::Relaxed) {
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+ if let Some(salt_box) = &chan_info.salt_box {
|
|
|
|
|
+ if let Some(decrypted_msg) = try_decrypt_message(salt_box, &msg.message) {
|
|
|
|
|
+ msg.message = decrypted_msg;
|
|
|
|
|
+ info!("Decrypted received message: {:?}", msg);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
-async fn process(
|
|
|
|
|
- raft_receiver: Receiver<Privmsg>,
|
|
|
|
|
- stream: TcpStream,
|
|
|
|
|
- peer_addr: SocketAddr,
|
|
|
|
|
- raft_sender: Sender<Privmsg>,
|
|
|
|
|
- seen_msg_id: SeenMsgIds,
|
|
|
|
|
- autojoin_chans: Vec<String>,
|
|
|
|
|
- configured_chans: FxHashMap<String, ChannelInfo>,
|
|
|
|
|
-) -> Result<()> {
|
|
|
|
|
- let (reader, writer) = stream.split();
|
|
|
|
|
-
|
|
|
|
|
- let mut reader = BufReader::new(reader);
|
|
|
|
|
- let mut conn = IrcServerConnection::new(
|
|
|
|
|
- writer,
|
|
|
|
|
- seen_msg_id.clone(),
|
|
|
|
|
- raft_sender,
|
|
|
|
|
- autojoin_chans,
|
|
|
|
|
- configured_chans,
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- loop {
|
|
|
|
|
- let mut line = String::new();
|
|
|
|
|
- futures::select! {
|
|
|
|
|
- privmsg = raft_receiver.recv().fuse() => {
|
|
|
|
|
- let mut msg = privmsg?;
|
|
|
|
|
- info!("Received msg from Raft: {:?}", msg);
|
|
|
|
|
-
|
|
|
|
|
- let mut smi = seen_msg_id.lock().await;
|
|
|
|
|
- if smi.contains(&msg.id) {
|
|
|
|
|
- continue
|
|
|
|
|
- }
|
|
|
|
|
- smi.push(msg.id);
|
|
|
|
|
- drop(smi);
|
|
|
|
|
-
|
|
|
|
|
- // Try to potentially decrypt the incoming message.
|
|
|
|
|
- if conn.configured_chans.contains_key(&msg.channel) {
|
|
|
|
|
- let chan_info = conn.configured_chans.get(&msg.channel).unwrap();
|
|
|
|
|
- if !chan_info.joined.load(Ordering::Relaxed) {
|
|
|
|
|
- continue
|
|
|
|
|
- }
|
|
|
|
|
- if let Some(salt_box) = &chan_info.salt_box {
|
|
|
|
|
- if let Some(decrypted_msg) = try_decrypt_message(salt_box, &msg.message) {
|
|
|
|
|
- msg.message = decrypted_msg;
|
|
|
|
|
- info!("Decrypted received message: {:?}", msg);
|
|
|
|
|
|
|
+ // add the msg to buffer
|
|
|
|
|
+ {
|
|
|
|
|
+ (*privmsgs_buffer.lock().await).push(msg.clone());
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ let irc_msg = build_irc_msg(&msg);
|
|
|
|
|
+ conn.reply(&irc_msg).await?;
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
|
|
+ err = reader.read_line(&mut line).fuse() => {
|
|
|
|
|
+ if let Err(e) = err {
|
|
|
|
|
+ warn!("Read line error. Closing stream for {}: {}", peer_addr, e);
|
|
|
|
|
+ return Ok(())
|
|
|
|
|
+ }
|
|
|
|
|
+ info!("Received msg from IRC client: {:?}", line);
|
|
|
|
|
+ let irc_msg = match clean_input(line, &peer_addr) {
|
|
|
|
|
+ Ok(m) => m,
|
|
|
|
|
+ Err(e) => return Err(e)
|
|
|
|
|
+ };
|
|
|
|
|
|
|
|
- let irc_msg = build_irc_msg(&msg);
|
|
|
|
|
- conn.reply(&irc_msg).await?;
|
|
|
|
|
- }
|
|
|
|
|
- err = reader.read_line(&mut line).fuse() => {
|
|
|
|
|
- if let Err(e) = err {
|
|
|
|
|
- warn!("Read line error. Closing stream for {}: {}", peer_addr, e);
|
|
|
|
|
- return Ok(())
|
|
|
|
|
- }
|
|
|
|
|
- info!("Received msg from IRC client: {:?}", line);
|
|
|
|
|
- let irc_msg = match clean_input(line, &peer_addr) {
|
|
|
|
|
- Ok(m) => m,
|
|
|
|
|
- Err(e) => return Err(e)
|
|
|
|
|
|
|
+ info!("Send msg to IRC client '{}' from {}", irc_msg, peer_addr);
|
|
|
|
|
+
|
|
|
|
|
+ if let Err(e) = conn.update(irc_msg).await {
|
|
|
|
|
+ warn!("Connection error: {} for {}", e, peer_addr);
|
|
|
|
|
+ return Err(Error::ChannelStopped)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
};
|
|
};
|
|
|
- broadcast_msg(irc_msg, peer_addr,&mut conn).await?;
|
|
|
|
|
}
|
|
}
|
|
|
- };
|
|
|
|
|
|
|
+ }).detach();
|
|
|
|
|
+
|
|
|
|
|
+ Ok(())
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
async_daemonize!(realmain);
|
|
async_daemonize!(realmain);
|
|
|
async fn realmain(settings: Args, executor: Arc<Executor<'_>>) -> Result<()> {
|
|
async fn realmain(settings: Args, executor: Arc<Executor<'_>>) -> Result<()> {
|
|
|
|
|
+ let seen_msg_ids = Arc::new(Mutex::new(vec![]));
|
|
|
|
|
+
|
|
|
if settings.gen_secret {
|
|
if settings.gen_secret {
|
|
|
let secret_key = crypto_box::SecretKey::generate(&mut OsRng);
|
|
let secret_key = crypto_box::SecretKey::generate(&mut OsRng);
|
|
|
let encoded = bs58::encode(secret_key.as_bytes());
|
|
let encoded = bs58::encode(secret_key.as_bytes());
|
|
@@ -156,47 +182,34 @@ async fn realmain(settings: Args, executor: Arc<Executor<'_>>) -> Result<()> {
|
|
|
return Ok(())
|
|
return Ok(())
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- let seen_msg_id: SeenMsgIds = Arc::new(Mutex::new(vec![]));
|
|
|
|
|
-
|
|
|
|
|
// Pick up channel settings from the TOML configuration
|
|
// Pick up channel settings from the TOML configuration
|
|
|
let cfg_path = get_config_path(settings.config, CONFIG_FILE)?;
|
|
let cfg_path = get_config_path(settings.config, CONFIG_FILE)?;
|
|
|
let configured_chans = parse_configured_channels(&cfg_path)?;
|
|
let configured_chans = parse_configured_channels(&cfg_path)?;
|
|
|
|
|
|
|
|
//
|
|
//
|
|
|
- //Raft
|
|
|
|
|
|
|
+ // P2p setup
|
|
|
//
|
|
//
|
|
|
- let datastore_path = expand_path(&settings.datastore)?;
|
|
|
|
|
let net_settings = settings.net;
|
|
let net_settings = settings.net;
|
|
|
- let datastore_raft = datastore_path.join("ircd.db");
|
|
|
|
|
- let mut raft = Raft::<Privmsg>::new(net_settings.inbound.clone(), datastore_raft)?;
|
|
|
|
|
- let raft_sender = raft.get_broadcast();
|
|
|
|
|
- let raft_receiver = raft.get_commits();
|
|
|
|
|
-
|
|
|
|
|
- // P2p setup
|
|
|
|
|
- let (p2p_send_channel, p2p_recv_channel) = async_channel::unbounded::<NetMsg>();
|
|
|
|
|
|
|
+ let (p2p_send_channel, p2p_recv_channel) = async_channel::unbounded::<Privmsg>();
|
|
|
|
|
|
|
|
let p2p = net::P2p::new(net_settings.into()).await;
|
|
let p2p = net::P2p::new(net_settings.into()).await;
|
|
|
let p2p = p2p.clone();
|
|
let p2p = p2p.clone();
|
|
|
|
|
|
|
|
let registry = p2p.protocol_registry();
|
|
let registry = p2p.protocol_registry();
|
|
|
|
|
|
|
|
- let seen_net_msg = Arc::new(Mutex::new(vec![]));
|
|
|
|
|
- let raft_node_id = raft.id.clone();
|
|
|
|
|
|
|
+ let seen_msg_ids_cloned = seen_msg_ids.clone();
|
|
|
registry
|
|
registry
|
|
|
.register(net::SESSION_ALL, move |channel, p2p| {
|
|
.register(net::SESSION_ALL, move |channel, p2p| {
|
|
|
- let raft_node_id = raft_node_id.clone();
|
|
|
|
|
let sender = p2p_send_channel.clone();
|
|
let sender = p2p_send_channel.clone();
|
|
|
- let seen_net_msg_cloned = seen_net_msg.clone();
|
|
|
|
|
- async move {
|
|
|
|
|
- ProtocolRaft::init(raft_node_id, channel, sender, p2p, seen_net_msg_cloned).await
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ let seen_msg_ids_cloned = seen_msg_ids_cloned.clone();
|
|
|
|
|
+ async move { ProtocolPrivmsg::init(channel, sender, p2p, seen_msg_ids_cloned).await }
|
|
|
})
|
|
})
|
|
|
.await;
|
|
.await;
|
|
|
|
|
|
|
|
p2p.clone().start(executor.clone()).await?;
|
|
p2p.clone().start(executor.clone()).await?;
|
|
|
|
|
|
|
|
let executor_cloned = executor.clone();
|
|
let executor_cloned = executor.clone();
|
|
|
- let p2p_run_task = executor_cloned.spawn(p2p.clone().run(executor.clone()));
|
|
|
|
|
|
|
+ executor_cloned.spawn(p2p.clone().run(executor.clone())).detach();
|
|
|
|
|
|
|
|
//
|
|
//
|
|
|
// RPC interface
|
|
// RPC interface
|
|
@@ -204,8 +217,7 @@ async fn realmain(settings: Args, executor: Arc<Executor<'_>>) -> Result<()> {
|
|
|
let rpc_listen_addr = settings.rpc_listen.clone();
|
|
let rpc_listen_addr = settings.rpc_listen.clone();
|
|
|
let rpc_interface =
|
|
let rpc_interface =
|
|
|
Arc::new(JsonRpcInterface { addr: rpc_listen_addr.clone(), p2p: p2p.clone() });
|
|
Arc::new(JsonRpcInterface { addr: rpc_listen_addr.clone(), p2p: p2p.clone() });
|
|
|
- let rpc_task =
|
|
|
|
|
- executor.spawn(async move { listen_and_serve(rpc_listen_addr, rpc_interface).await });
|
|
|
|
|
|
|
+ executor.spawn(async move { listen_and_serve(rpc_listen_addr, rpc_interface).await }).detach();
|
|
|
|
|
|
|
|
//
|
|
//
|
|
|
// IRC instance
|
|
// IRC instance
|
|
@@ -214,33 +226,38 @@ async fn realmain(settings: Args, executor: Arc<Executor<'_>>) -> Result<()> {
|
|
|
let listener = TcpListener::bind(irc_listen_addr).await?;
|
|
let listener = TcpListener::bind(irc_listen_addr).await?;
|
|
|
let local_addr = listener.local_addr()?;
|
|
let local_addr = listener.local_addr()?;
|
|
|
info!("IRC listening on {}", local_addr);
|
|
info!("IRC listening on {}", local_addr);
|
|
|
|
|
+
|
|
|
let executor_cloned = executor.clone();
|
|
let executor_cloned = executor.clone();
|
|
|
- let raft_receiver_cloned = raft_receiver.clone();
|
|
|
|
|
- let irc_task: smol::Task<Result<()>> = executor.spawn(async move {
|
|
|
|
|
- loop {
|
|
|
|
|
- let (stream, peer_addr) = match listener.accept().await {
|
|
|
|
|
- Ok((s, a)) => (s, a),
|
|
|
|
|
- Err(e) => {
|
|
|
|
|
- error!("Failed listening for connections: {}", e);
|
|
|
|
|
- return Err(Error::ServiceStopped)
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- info!("IRC Accepted client: {}", peer_addr);
|
|
|
|
|
-
|
|
|
|
|
- executor_cloned
|
|
|
|
|
- .spawn(process(
|
|
|
|
|
- raft_receiver_cloned.clone(),
|
|
|
|
|
- stream,
|
|
|
|
|
- peer_addr,
|
|
|
|
|
- raft_sender.clone(),
|
|
|
|
|
- seen_msg_id.clone(),
|
|
|
|
|
- settings.autojoin.clone(),
|
|
|
|
|
- configured_chans.clone(),
|
|
|
|
|
- ))
|
|
|
|
|
- .detach();
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ executor
|
|
|
|
|
+ .spawn(async move {
|
|
|
|
|
+ let ircd = Ircd::new(
|
|
|
|
|
+ seen_msg_ids.clone(),
|
|
|
|
|
+ settings.autojoin.clone(),
|
|
|
|
|
+ configured_chans.clone(),
|
|
|
|
|
+ p2p.clone(),
|
|
|
|
|
+ p2p_recv_channel.clone(),
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ loop {
|
|
|
|
|
+ let (stream, peer_addr) = match listener.accept().await {
|
|
|
|
|
+ Ok((s, a)) => (s, a),
|
|
|
|
|
+ Err(e) => {
|
|
|
|
|
+ error!("failed accepting new connections: {}", e);
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ let result = ircd.process(executor_cloned.clone(), stream, peer_addr).await;
|
|
|
|
|
+
|
|
|
|
|
+ if let Err(e) = result {
|
|
|
|
|
+ error!("failed process the {} connections: {}", peer_addr, e);
|
|
|
|
|
+ continue
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ info!("IRC Accepted new client: {}", peer_addr);
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ .detach();
|
|
|
|
|
|
|
|
// Run once receive exit signal
|
|
// Run once receive exit signal
|
|
|
let (signal, shutdown) = async_channel::bounded::<()>(1);
|
|
let (signal, shutdown) = async_channel::bounded::<()>(1);
|
|
@@ -248,14 +265,13 @@ async fn realmain(settings: Args, executor: Arc<Executor<'_>>) -> Result<()> {
|
|
|
warn!(target: "ircd", "ircd start Exit Signal");
|
|
warn!(target: "ircd", "ircd start Exit Signal");
|
|
|
// cleaning up tasks running in the background
|
|
// cleaning up tasks running in the background
|
|
|
signal.send(()).await.unwrap();
|
|
signal.send(()).await.unwrap();
|
|
|
- rpc_task.cancel().await;
|
|
|
|
|
- irc_task.cancel().await;
|
|
|
|
|
- p2p_run_task.cancel().await;
|
|
|
|
|
})
|
|
})
|
|
|
.unwrap();
|
|
.unwrap();
|
|
|
|
|
|
|
|
- // blocking
|
|
|
|
|
- raft.start(p2p.clone(), p2p_recv_channel.clone(), executor.clone(), shutdown.clone()).await?;
|
|
|
|
|
|
|
+ // Wait for SIGINT
|
|
|
|
|
+ shutdown.recv().await?;
|
|
|
|
|
+ print!("\r");
|
|
|
|
|
+ info!("Caught termination signal, cleaning up and exiting...");
|
|
|
|
|
|
|
|
Ok(())
|
|
Ok(())
|
|
|
}
|
|
}
|