radicle_cli/commands/node/
args.rs1use std::ffi::OsString;
2use std::fmt::Debug;
3use std::path::PathBuf;
4use std::str::FromStr;
5
6use thiserror::Error;
7
8use clap::{Parser, Subcommand};
9
10use radicle::crypto::{PublicKey, PublicKeyError};
11use radicle::node::{Address, NodeId, PeerAddr, PeerAddrParseError};
12use radicle::prelude::RepoId;
13
14const ABOUT: &str = "Control and query the Radicle Node";
15
16#[derive(Parser, Debug)]
17#[command(about = ABOUT, long_about, disable_version_flag = true)]
18pub struct Args {
19 #[command(subcommand)]
20 pub(super) command: Option<Command>,
21}
22
23#[derive(Clone, Debug)]
25pub(super) enum Addr {
26 Peer(PeerAddr<NodeId, Address>),
28 Node(NodeId),
30}
31
32#[derive(Error, Debug)]
33pub(super) enum AddrParseError {
34 #[error("{0}, expected <NID> or <NID>@<ADDR>")]
35 PeerAddr(#[from] PeerAddrParseError<PublicKey>),
36 #[error(transparent)]
37 NodeId(#[from] PublicKeyError),
38}
39
40impl FromStr for Addr {
41 type Err = AddrParseError;
42
43 fn from_str(s: &str) -> Result<Self, Self::Err> {
44 if s.contains("@") {
45 PeerAddr::from_str(s)
46 .map(Self::Peer)
47 .map_err(AddrParseError::PeerAddr)
48 } else {
49 NodeId::from_str(s)
50 .map(Self::Node)
51 .map_err(AddrParseError::NodeId)
52 }
53 }
54}
55
56#[derive(Clone, Debug)]
57pub enum Only {
58 Nid,
59}
60
61#[derive(Error, Debug)]
62#[error("could not parse value `{0}`")]
63pub struct OnlyParseError(String);
64
65impl FromStr for Only {
66 type Err = OnlyParseError;
67
68 fn from_str(value: &str) -> Result<Self, Self::Err> {
69 match value {
70 "nid" => Ok(Only::Nid),
71 _ => Err(OnlyParseError(value.to_string())),
72 }
73 }
74}
75
76#[derive(Clone, Debug)]
77struct OnlyParser;
78
79impl clap::builder::TypedValueParser for OnlyParser {
80 type Value = Only;
81
82 fn parse_ref(
83 &self,
84 cmd: &clap::Command,
85 arg: Option<&clap::Arg>,
86 value: &std::ffi::OsStr,
87 ) -> Result<Self::Value, clap::Error> {
88 <Only as std::str::FromStr>::from_str.parse_ref(cmd, arg, value)
89 }
90
91 fn possible_values(
92 &self,
93 ) -> Option<Box<dyn Iterator<Item = clap::builder::PossibleValue> + '_>> {
94 use clap::builder::PossibleValue;
95 Some(Box::new([PossibleValue::new("nid")].into_iter()))
96 }
97}
98
99#[derive(Subcommand, Debug)]
100pub(super) enum Command {
101 Connect {
103 #[arg(value_name = "NID[@ADDR]")]
105 addr: Addr,
106
107 #[arg(long, value_parser = humantime::parse_duration)]
111 timeout: Option<std::time::Duration>,
112 },
113
114 Config {
116 #[arg(long)]
118 addresses: bool,
119 },
120
121 #[command(subcommand, hide = true)]
123 Db(DbOperation),
124
125 Events {
132 #[arg(long, value_parser = humantime::parse_duration)]
136 timeout: Option<std::time::Duration>,
137
138 #[arg(long, short = 'n')]
140 count: Option<usize>,
141 },
142
143 Routing {
145 #[arg(long)]
147 json: bool,
148
149 #[arg(long)]
151 rid: Option<RepoId>,
152
153 #[arg(long)]
155 nid: Option<NodeId>,
156 },
157
158 Start {
160 #[arg(long)]
162 foreground: bool,
163
164 #[arg(long, short)]
166 verbose: bool,
167
168 #[arg(long, default_value = "radicle-node")]
170 path: PathBuf,
171
172 #[arg(value_name = "NODE_OPTIONS", last = true, num_args = 1..)]
176 options: Vec<OsString>,
177 },
178
179 Logs {
181 #[arg(long, value_name = "COUNT", default_value_t = 60)]
183 lines: usize,
184 },
185
186 Status {
188 #[arg(long, value_parser = OnlyParser)]
190 only: Option<Only>,
191 },
192
193 Inventory {
195 #[arg(long)]
197 nid: Option<NodeId>,
198 },
199
200 Debug,
204
205 #[command(hide = true)]
209 Sessions,
210
211 Stop,
213}
214
215impl Default for Command {
216 fn default() -> Self {
217 Command::Status { only: None }
218 }
219}
220
221#[derive(Debug, Subcommand)]
223pub(super) enum DbOperation {
224 Exec {
232 #[arg(value_name = "SQL")]
233 query: String,
234 },
235}