keyfork/crates/daemon/keyforkd/src/lib.rs

118 lines
3.5 KiB
Rust

#![doc = include_str!("../README.md")]
use std::{
collections::HashMap,
path::{Path, PathBuf},
};
pub use keyfork_mnemonic::Mnemonic;
pub use tower::ServiceBuilder;
#[cfg(feature = "tracing")]
use tracing::debug;
#[cfg(feature = "tracing")]
use tracing_subscriber::{
filter::{EnvFilter, LevelFilter},
fmt::{format::FmtSpan, layer},
prelude::*,
registry,
};
/// Errors occurring while starting Keyforkd.
pub mod error;
/// Middleware used by Keyforkd.
pub mod middleware;
pub mod server;
pub mod service;
pub use error::Keyforkd as KeyforkdError;
pub use server::UnixServer;
pub use service::Keyforkd;
pub mod test_util;
/// Set up a Tracing subscriber, defaulting to debug mode.
#[cfg(feature = "tracing")]
pub fn setup_registry() {
let envfilter = EnvFilter::builder()
.with_default_directive(LevelFilter::DEBUG.into())
.from_env_lossy();
registry()
.with(envfilter)
.with(layer().with_span_events(FmtSpan::CLOSE))
.with(tracing_error::ErrorLayer::default())
.init();
}
/// Start and run a server on a given socket path.
///
/// # Errors
/// The function may return an error if a socket can't be bound, if the service can't be created,
/// or if the server encounters an unrecoverable error while running.
pub async fn start_and_run_server_on(
mnemonic: Mnemonic,
socket_path: &Path,
) -> Result<(), Box<dyn std::error::Error>> {
let service = ServiceBuilder::new()
.layer(middleware::BincodeLayer::new())
// TODO: passphrase support and/or store passphrase with mnemonic
.service(Keyforkd::new(mnemonic.generate_seed(None).to_vec()));
let mut server = match UnixServer::bind(socket_path) {
Ok(s) => s,
Err(e) => {
#[cfg(feature = "tracing")]
debug!(%e, "Encountered error attempting to bind socket: {}", socket_path.display());
return Err(e.into());
}
};
match server.run(service).await {
#[allow(clippy::ignored_unit_patterns)]
Ok(_) => (),
Err(e) => {
#[cfg(feature = "tracing")]
debug!(%e, "Encountered error while running");
}
}
Ok(())
}
/// Start and run the server using a discovered socket location.
///
/// # Errors
/// The function may return an error if the socket location could not be guessed, if a socket can't
/// be bound, if the service can't be created, or if the server encounters an unrecoverable error
/// while running.
pub async fn start_and_run_server(mnemonic: Mnemonic) -> Result<(), Box<dyn std::error::Error>> {
let runtime_vars = std::env::vars()
.filter(|(key, _)| ["XDG_RUNTIME_DIR", "KEYFORKD_SOCKET_PATH"].contains(&key.as_str()))
.collect::<HashMap<String, String>>();
let runtime_path = if let Some(occupied) = runtime_vars.get("KEYFORKD_SOCKET_PATH") {
PathBuf::from(occupied)
} else {
let mut runtime_path = PathBuf::from(
runtime_vars
.get("XDG_RUNTIME_DIR")
.ok_or(KeyforkdError::NoSocketPath)?,
);
runtime_path.push("keyforkd");
#[cfg(feature = "tracing")]
debug!("ensuring directory exists: {}", runtime_path.display());
if !runtime_path.is_dir() {
tokio::fs::create_dir(&runtime_path).await?;
}
runtime_path.push("keyforkd.sock");
runtime_path
};
#[cfg(feature = "tracing")]
debug!(
"binding UNIX socket in runtime dir: {}",
runtime_path.display()
);
start_and_run_server_on(mnemonic, &runtime_path).await
}