cli: Implement `rad node start` with support for deamonizing

Signed-off-by: xphoniex <dj.2dixx@gmail.com>
This commit is contained in:
xphoniex 2023-04-28 11:36:05 +00:00 committed by Alexis Sellier
parent 362f26a0c8
commit ac12a4deee
No known key found for this signature in database
3 changed files with 70 additions and 35 deletions

View File

@ -22,12 +22,14 @@ pub const HELP: Help = Help {
Usage
rad node status [<option>...]
rad node start [<option>...]
rad node start [--daemon|-d] [<option>...] [-- <node-option>...]
rad node stop [<option>...]
rad node connect <nid> <addr> [<option>...]
rad node routing [<option>...]
rad node tracking [--repos|--nodes] [<option>...]
For `<node-option>` see `radicle-node --help`.
Options
--help Print help
@ -41,12 +43,20 @@ pub struct Options {
}
pub enum Operation {
Connect { nid: NodeId, addr: Address },
Connect {
nid: NodeId,
addr: Address,
},
Routing,
Start,
Start {
daemon: bool,
options: Vec<OsString>,
},
Status,
Stop,
Tracking { mode: TrackingMode },
Tracking {
mode: TrackingMode,
},
}
#[derive(Default)]
@ -71,6 +81,8 @@ impl Args for Options {
fn from_args(args: Vec<OsString>) -> anyhow::Result<(Self, Vec<OsString>)> {
use lexopt::prelude::*;
let mut daemon = false;
let mut options = vec![];
let mut parser = lexopt::Parser::from_args(args);
let mut op: Option<OperationName> = None;
let mut tracking_mode = TrackingMode::default();
@ -111,6 +123,12 @@ impl Args for Options {
Long("nodes") if matches!(op, Some(OperationName::Tracking)) => {
tracking_mode = TrackingMode::Nodes
}
Long("daemon") | Short('d') if matches!(op, Some(OperationName::Start)) => {
daemon = true;
}
Value(val) if matches!(op, Some(OperationName::Start)) => {
options.push(val);
}
_ => return Err(anyhow!(arg.unexpected())),
}
}
@ -121,7 +139,7 @@ impl Args for Options {
addr: addr.ok_or_else(|| anyhow!("an address must be provided"))?,
},
OperationName::Routing => Operation::Routing,
OperationName::Start => Operation::Start,
OperationName::Start => Operation::Start { daemon, options },
OperationName::Status => Operation::Status,
OperationName::Stop => Operation::Stop,
OperationName::Tracking => Operation::Tracking {
@ -145,7 +163,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
radicle::node::routing::Table::reader(profile.home.node().join(ROUTING_DB_FILE))?;
routing::run(&store)?;
}
Operation::Start => control::start()?,
Operation::Start { daemon, options } => control::start(daemon, options)?,
Operation::Status => {
let node = Node::new(profile.socket());
control::status(&node);

View File

@ -1,10 +1,34 @@
use std::ffi::OsString;
use std::fs::OpenOptions;
use std::process;
use radicle::node::{Address, Handle as _, NodeId};
use radicle::Node;
use crate::terminal as term;
pub fn start() -> anyhow::Result<()> {
todo!()
pub fn start(daemon: bool, options: Vec<OsString>) -> anyhow::Result<()> {
if daemon {
let home = radicle::profile::home()?;
let log = OpenOptions::new()
.append(true)
.create(true)
.open(home.node().join("node.log"))?;
process::Command::new("radicle-node")
.args(options)
.stdin(process::Stdio::null())
.stdout(process::Stdio::from(log))
.stderr(process::Stdio::null())
.spawn()?;
} else {
let mut child = process::Command::new("radicle-node")
.args(options)
.spawn()?;
child.wait()?;
}
Ok(())
}
pub fn stop(node: Node) -> anyhow::Result<()> {

View File

@ -1,5 +1,5 @@
//! Logging module.
use std::io;
use std::io::{self, Write};
use chrono::prelude::*;
use colored::*;
@ -18,35 +18,28 @@ impl Log for Logger {
if self.enabled(record.metadata()) {
let target = record.target();
if record.level() == Level::Error {
write(record, target, io::stderr());
} else {
write(record, target, io::stdout());
}
let message = format!(
"{:<5} {:<8} {}",
record.level(),
target.cyan(),
record.args()
);
fn write(record: &log::Record, target: &str, mut stream: impl io::Write) {
let message = format!(
"{:<5} {:<8} {}",
record.level(),
target.cyan(),
record.args()
);
let message = format!(
"{} {}",
Local::now().to_rfc3339_opts(SecondsFormat::Millis, true),
message,
);
let message = format!(
"{} {}",
Local::now().to_rfc3339_opts(SecondsFormat::Millis, true),
message,
);
let message = match record.level() {
Level::Error => message.red(),
Level::Warn => message.yellow(),
Level::Info => message.normal(),
Level::Debug => message.dimmed(),
Level::Trace => message.white().dimmed(),
};
let message = match record.level() {
Level::Error => message.red(),
Level::Warn => message.yellow(),
Level::Info => message.normal(),
Level::Debug => message.dimmed(),
Level::Trace => message.white().dimmed(),
};
writeln!(stream, "{message}").expect("write shouldn't fail");
}
writeln!(io::stdout(), "{message}").expect("write shouldn't fail");
}
}