daemon: introduce the DaemonHandle, which for now only creates a datadir

This code was mainly taken and adapted from revaultd at commit
7cd856d5a345319cebc815aa61f3b66cebb48b86.
This commit is contained in:
Antoine Poinsot 2022-07-20 21:06:11 +02:00
parent 1b35196448
commit 989a2cf8fd
No known key found for this signature in database
GPG Key ID: E13FC145CD3F4304
4 changed files with 193 additions and 1 deletions

67
Cargo.lock generated
View File

@ -2,6 +2,36 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "addr2line"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
dependencies = [
"gimli",
]
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "backtrace"
version = "0.3.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7"
dependencies = [
"addr2line",
"cc",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
]
[[package]]
name = "bech32"
version = "0.8.1"
@ -87,6 +117,12 @@ dependencies = [
"wasi",
]
[[package]]
name = "gimli"
version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
[[package]]
name = "itoa"
version = "1.0.2"
@ -108,10 +144,17 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "minisafed"
version = "0.0.1"
dependencies = [
"backtrace",
"dirs",
"fern",
"log",
@ -131,6 +174,24 @@ dependencies = [
"serde",
]
[[package]]
name = "miniz_oxide"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
dependencies = [
"adler",
]
[[package]]
name = "object"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
dependencies = [
"memchr",
]
[[package]]
name = "proc-macro2"
version = "1.0.40"
@ -169,6 +230,12 @@ dependencies = [
"thiserror",
]
[[package]]
name = "rustc-demangle"
version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
[[package]]
name = "ryu"
version = "1.0.10"

View File

@ -32,3 +32,8 @@ serde_json = { version = "1.0", features = ["raw_value"] }
# Logging stuff
log = "0.4"
fern = "0.6"
# In order to have a backtrace on panic, because the
# stdlib does not have a programmatic interface yet
# to work with our custom panic hook.
backtrace = "0.3"

View File

@ -5,7 +5,7 @@ use std::{
process, time,
};
use minisafed::config::Config;
use minisafed::{config::Config, DaemonHandle};
fn parse_args(args: Vec<String>) -> Option<PathBuf> {
if args.len() == 1 {
@ -58,6 +58,11 @@ fn main() {
process::exit(1);
});
let _ = DaemonHandle::start(config).unwrap_or_else(|e| {
// The panic hook will log::error
panic!("Starting Minisafe daemon: {}", e);
});
// We are always logging to stdout, should it be then piped to the log file (if self) or
// not. So just make sure that all messages were actually written.
io::stdout().flush().expect("Flushing stdout");

View File

@ -1 +1,116 @@
pub mod config;
use crate::config::{config_folder_path, Config};
use std::{error, fmt, fs, io, panic, path, process};
// A panic in any thread should stop the main thread, and print the panic.
fn setup_panic_hook() {
panic::set_hook(Box::new(move |panic_info| {
let file = panic_info
.location()
.map(|l| l.file())
.unwrap_or_else(|| "'unknown'");
let line = panic_info
.location()
.map(|l| l.line().to_string())
.unwrap_or_else(|| "'unknown'".to_string());
let bt = backtrace::Backtrace::new();
let info = panic_info
.payload()
.downcast_ref::<&str>()
.map(|s| s.to_string())
.or_else(|| panic_info.payload().downcast_ref::<String>().cloned());
log::error!(
"panic occurred at line {} of file {}: {:?}\n{:?}",
line,
file,
info,
bt
);
process::exit(1);
}));
}
#[derive(Debug)]
pub enum StartupError {
Io(io::Error),
DefaultDataDirNotFound,
DatadirCreation(path::PathBuf, io::Error),
}
impl fmt::Display for StartupError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Io(e) => write!(f, "{}", e),
Self::DefaultDataDirNotFound => write!(
f,
"Not data directory was specified and a default path could not be determined for this platform."
),
Self::DatadirCreation(dir_path, e) => write!(
f,
"Could not create data directory at '{}': '{}'", dir_path.display(), e
),
}
}
}
impl error::Error for StartupError {}
impl From<io::Error> for StartupError {
fn from(e: io::Error) -> Self {
Self::Io(e)
}
}
fn create_datadir(datadir_path: &path::Path) -> Result<(), StartupError> {
#[cfg(unix)]
return {
use fs::DirBuilder;
use std::os::unix::fs::DirBuilderExt;
let mut builder = DirBuilder::new();
builder
.mode(0o700)
.recursive(true)
.create(datadir_path)
.map_err(|e| StartupError::DatadirCreation(datadir_path.to_path_buf(), e))
};
// TODO: permissions on Windows..
#[cfg(not(unix))]
return {
fs::create_dir_all(datadir_path)
.map_err(|e| StartupError::DatadirCreation(datadir_path.to_path_buf(), e))
};
}
pub struct DaemonHandle {}
impl DaemonHandle {
/// This starts the Minisafe daemon. Call `shutdown` to shut it down.
///
/// **Note**: we internally use threads, and set a panic hook. A downstream application must
/// not overwrite this panic hook.
pub fn start(config: Config) -> Result<Self, StartupError> {
setup_panic_hook();
// First, check the data directory
let mut data_dir = config
.data_dir
.unwrap_or(config_folder_path().ok_or(StartupError::DefaultDataDirNotFound)?);
data_dir.push(config.bitcoind_config.network.to_string());
if !data_dir.as_path().exists() {
create_datadir(&data_dir)?;
log::info!("Created a new data directory at '{}'", data_dir.display());
}
Ok(Self {})
}
// NOTE: this moves out the data as it should not be reused after shutdown
/// Shut down the Minisafe daemon.
pub fn shutdown(self) {}
}