feat(mobile): start & stop mycelium.

Start & stop implemented by adding a global channel.

Upon startup `Node` listens to ctrl-c and channel receiver.
On stop, we send message to that channel and Node can exit..
This commit is contained in:
Iwan BK
2024-05-07 16:01:32 +02:00
committed by Lee Smet
parent 776f01a34c
commit ceeef0fa5e
3 changed files with 39 additions and 11 deletions
Generated
+1
View File
@@ -1047,6 +1047,7 @@ dependencies = [
"android_logger",
"log",
"mycelium",
"once_cell",
"tokio",
]
+2 -1
View File
@@ -6,12 +6,13 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
mycelium = { path = "../mycelium"}
mycelium = { path = "../mycelium", features = ["vendored-openssl"]}
tokio = { version = "1.37.0", features = [
"signal",
"rt-multi-thread",
] }
log = "0.4.21"
once_cell = "1.19.0"
[target.'cfg(target_os = "android")'.dependencies]
android_logger = "0.13.3"
+36 -10
View File
@@ -1,7 +1,7 @@
use std::convert::TryFrom;
use std::io;
use log::info;
use log::{error, info};
use metrics::Metrics;
use mycelium::endpoint::Endpoint;
@@ -10,19 +10,30 @@ use mycelium::{crypto, metrics, Config, Node};
#[cfg(target_os = "android")]
fn setup_the_logger() {
use log::LevelFilter;
android_logger::init_once(android_logger::Config::default().with_max_level(LevelFilter::Trace));
android_logger::init_once(android_logger::Config::default().with_max_level(LevelFilter::Info));
}
use once_cell::sync::Lazy;
use std::sync::Mutex;
use tokio::sync::mpsc;
// Declare the channel globally so we can use it on the start & stop mycelium functions
static CHANNEL: Lazy<(Mutex<mpsc::Sender<()>>, Mutex<mpsc::Receiver<()>>)> = Lazy::new(|| {
let (tx, rx) = mpsc::channel::<()>(1);
(Mutex::new(tx), Mutex::new(rx))
});
#[tokio::main]
#[allow(unused_variables)] // because tun_fd is only used in android and ios
pub async fn start_mycelium(peers: Vec<String>, tun_fd: i32, priv_key: Vec<u8>) {
#[cfg(target_os = "android")]
setup_the_logger();
info!("starting mycelium");
let endpoints: Vec<Endpoint> = peers
.into_iter()
.filter_map(|peer| peer.parse().ok())
.collect();
#[cfg(target_os = "android")]
setup_the_logger();
let secret_key = build_secret_key(priv_key).await.unwrap();
let config = Config {
@@ -45,14 +56,29 @@ pub async fn start_mycelium(peers: Vec<String>, tun_fd: i32, priv_key: Vec<u8>)
match _node {
Ok(_) => info!("node successfully created"),
// use info! here because error! is not printed
Err(err) => info!("failed to create stack: {err}"),
Err(err) => error!("failed to create mycelium node: {err}"),
};
// TODO: check what is the better way in Android and iOS
if let Err(e) = tokio::signal::ctrl_c().await {
log::error!("Failed to wait for SIGINT: {e}");
let mut rx = CHANNEL.1.lock().unwrap();
tokio::select! {
_ = tokio::signal::ctrl_c() => {
info!("Received SIGINT, stopping mycelium node");
}
_ = rx.recv() => {
info!("Received stop channel, stopping mycelium node");
}
}
info!("mycelium stopped");
}
#[tokio::main]
pub async fn stop_mycelium() {
info!("stopping mycelium by sending stop channel");
// TODO: check what happens if we send multiple times?
// it is currently OK to have this implementation because
// we prevent multiple calls to stop_mycelium from the UI side.
let tx = CHANNEL.0.lock().unwrap();
tx.send(()).await.unwrap();
}
#[derive(Clone)]