Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 122 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion crates/jaunt-host/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ serde_json = "1"
rmp-serde = "1"
toml = "0.8"
hostname = "0.4"
nix = { version = "0.29", features = ["user"] }
nix = { version = "0.29", features = ["user", "signal", "process"] }
hmac = "0.12"
sha2 = "0.10"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
tracing-appender = "0.2"

[package.metadata.deb]
maintainer = "moukrea <contact@moukrea.dev>"
Expand Down
98 changes: 94 additions & 4 deletions crates/jaunt-host/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ mod config;
mod files;
mod node;
mod pairing_server;
mod pid;
mod profile;
mod snag;

use clap::{Parser, Subcommand};
use tracing::error;

#[derive(Parser)]
#[command(name = "jaunt-host", about = "Jaunt host daemon", version)]
Expand All @@ -17,15 +19,23 @@ struct Cli {

#[derive(Subcommand)]
enum Command {
/// Start the host daemon (default)
Serve,
/// Generate a pairing profile and wait for a peer to connect
/// Start the host daemon — accepts connections from paired devices
Serve {
/// Run as a background daemon
#[arg(short, long)]
daemon: bool,
},
/// Pair a new device — generates a PIN and waits for connection
Pair,
/// Manage paired devices
Devices {
#[command(subcommand)]
action: DeviceAction,
},
/// Stop a running daemon
Stop,
/// Show daemon status
Status,
}

#[derive(Subcommand)]
Expand All @@ -36,13 +46,91 @@ enum DeviceAction {
Revoke { peer_id: String },
}

fn init_logging(daemon: bool) {
use tracing_subscriber::{fmt, EnvFilter};

let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));

if daemon {
// Daemon mode: log to file
let log_dir = dirs_log();
std::fs::create_dir_all(&log_dir).ok();
let file_appender = tracing_appender::rolling::daily(&log_dir, "jaunt-host.log");
fmt()
.with_env_filter(filter)
.with_writer(file_appender)
.with_ansi(false)
.init();
} else {
// Foreground: log to stderr
fmt()
.with_env_filter(filter)
.with_writer(std::io::stderr)
.with_target(false)
.init();
}
}

fn dirs_log() -> std::path::PathBuf {
if let Ok(dir) = std::env::var("XDG_DATA_HOME") {
std::path::PathBuf::from(dir).join("jaunt")
} else if let Ok(home) = std::env::var("HOME") {
std::path::PathBuf::from(home)
.join(".local")
.join("share")
.join("jaunt")
} else {
std::path::PathBuf::from("/tmp/jaunt")
}
}

#[tokio::main(flavor = "current_thread")]
async fn main() {
let cli = Cli::parse();

// Commands that don't need logging or config
match &cli.command {
Some(Command::Stop) => {
pid::cmd_stop();
return;
}
Some(Command::Status) => {
pid::cmd_status();
return;
}
_ => {}
}

let config = config::JauntConfig::load();
let is_daemon = matches!(&cli.command, Some(Command::Serve { daemon: true }));

init_logging(is_daemon);

let result = match cli.command {
None | Some(Command::Serve) => node::run_host(config).await,
None | Some(Command::Serve { .. }) => {
// Check for existing instance
if let Err(msg) = pid::acquire() {
error!("{msg}");
eprintln!("error: {msg}");
std::process::exit(1);
}

// Daemonize if requested
if is_daemon {
if let Err(e) = nix::unistd::daemon(true, false) {
error!("Failed to daemonize: {e}");
eprintln!("error: failed to daemonize: {e}");
pid::release();
std::process::exit(1);
}
// Re-write PID after fork (PID changed)
pid::write_current();
}

let res = node::run_host(config).await;
pid::release();
res
}
Some(Command::Pair) => node::run_pair(config).await,
Some(Command::Devices { action }) => match action {
DeviceAction::List => {
Expand All @@ -63,9 +151,11 @@ async fn main() {
Ok(())
}
},
Some(Command::Stop) | Some(Command::Status) => unreachable!(),
};

if let Err(e) = result {
error!("{e}");
eprintln!("error: {e}");
std::process::exit(1);
}
Expand Down
Loading
Loading