Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
cli: Implement `rad node start` with support for deamonizing
xphoniex committed 3 years ago
commit ac12a4deeeeb7522335ff0bf1c0a4a5c256c1722
parent 362f26a0c8bfe08ca3711a2f85603c6d279bf78a
3 files changed +73 -38
modified radicle-cli/src/commands/node.rs
@@ -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);
modified radicle-cli/src/commands/node/control.rs
@@ -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<()> {
modified radicle-node/src/logger.rs
@@ -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());
-
            }
-

-
            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 = 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");
-
            }
+
            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 = 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!(io::stdout(), "{message}").expect("write shouldn't fail");
        }
    }