quick_file_transfer/
config.rs1use anyhow::Result;
2use stderrlog::LogLevelNum;
3use transfer::{listen::ListenArgs, send::SendArgs};
4mod util;
5use util::*;
6
7pub mod compression;
8#[cfg(feature = "ssh")]
9pub mod ssh;
10pub mod transfer;
11
12pub const BIN_NAME: &str = "qft";
13
14#[cfg(feature = "evaluate-compression")]
15pub mod evaluate_compression;
16pub mod get_free_port;
17#[cfg(feature = "mdns")]
18pub mod mdns;
19pub mod misc;
20
21#[derive(Debug, Parser)]
22#[command(name = "Quick File Transfer", version, styles = misc::cli_styles())]
23#[command(bin_name = BIN_NAME)]
24pub struct Config {
25 #[clap(subcommand)]
27 pub command: Option<Command>,
28
29 #[arg(short, long, action = ArgAction::Count, default_value_t = 0, global = true)]
34 pub verbose: u8,
35
36 #[arg(short, long, action = ArgAction::SetTrue, conflicts_with("verbose"), global = true, env = "QFT_QUIET")]
38 pub quiet: bool,
39
40 #[arg(
41 long,
42 require_equals = true,
43 value_name = "WHEN",
44 default_value_t = clap::ColorChoice::Auto,
45 default_missing_value = "always",
46 value_enum,
47 global = true
48 )]
49 pub color: clap::ColorChoice,
50
51 #[arg(
54 long = "completions",
55 value_hint = clap::ValueHint::Other,
56 value_name = "SHELL"
57 )]
58 pub completions: Option<clap_complete::Shell>,
59}
60
61impl Config {
62 pub fn init() -> Result<Self> {
63 let cfg = Self::parse();
64
65 let log_level: LogLevelNum = match cfg.verbose {
66 0 => LogLevelNum::Info,
67 1 => LogLevelNum::Debug,
68 255 => LogLevelNum::Off,
69 _ => LogLevelNum::Trace,
70 };
71
72 let log_color_when: stderrlog::ColorChoice = match cfg.color {
73 clap::ColorChoice::Auto => stderrlog::ColorChoice::Auto,
74 clap::ColorChoice::Always => stderrlog::ColorChoice::Always,
75 clap::ColorChoice::Never => stderrlog::ColorChoice::Never,
76 };
77
78 set_tracing(&log_level);
79 stderrlog::new()
80 .verbosity(log_level)
81 .quiet(cfg.quiet)
82 .color(log_color_when)
83 .init()?;
84
85 Ok(cfg)
86 }
87
88 pub fn generate_completion_script(shell: clap_complete::Shell) {
90 use clap::CommandFactory;
91 clap_complete::generate(
92 shell,
93 &mut Config::command(),
94 BIN_NAME,
95 &mut std::io::stdout(),
96 );
97 }
98}
99
100#[allow(clippy::large_enum_variant)]
101#[derive(Debug, Subcommand)]
102pub enum Command {
103 Listen(ListenArgs),
105 Send(SendArgs),
107 #[cfg(feature = "mdns")]
109 Mdns(mdns::MdnsArgs),
110 #[cfg(feature = "evaluate-compression")]
112 EvaluateCompression(evaluate_compression::EvaluateCompressionArgs),
113 GetFreePort(get_free_port::GetFreePortArgs),
115 #[cfg(feature = "ssh")]
117 #[command(long_about("SCP-like transfer to a remote target that might not have qft actively listening.\n\
118 Authentication uses SSH (key based auth only) and while the transfer occurs over TCP, UNENCRYPTED!.\n\
119 Just like the rest of QTF, this is not suitable for transforring sensitive information."))]
120 Ssh(ssh::SendSshArgs),
121}
122
123fn set_tracing(_trace_level: &LogLevelNum) {
124 #[cfg(debug_assertions)]
125 set_dev_tracing(_trace_level);
126 #[cfg(not(debug_assertions))]
127 set_prod_tracing();
128}
129
130#[cfg(not(debug_assertions))]
131fn set_prod_tracing() {
132 let subscriber = tracing_subscriber::FmtSubscriber::builder()
133 .with_writer(std::io::stderr)
134 .with_max_level(tracing::Level::ERROR)
135 .with_file(false)
136 .without_time()
137 .compact()
138 .finish();
139 tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");
140}
141
142#[cfg(debug_assertions)]
143fn set_dev_tracing(trace_level: &LogLevelNum) {
144 use tracing::Level;
145 let log_level: Level = match trace_level {
146 LogLevelNum::Info => Level::INFO,
147 LogLevelNum::Debug => Level::DEBUG,
148 LogLevelNum::Trace => Level::TRACE,
149 LogLevelNum::Off => Level::ERROR,
150 _ => Level::ERROR,
151 };
152 let subscriber = tracing_subscriber::FmtSubscriber::builder()
153 .with_writer(std::io::stderr)
154 .with_max_level(log_level)
155 .with_line_number(true)
156 .with_thread_names(true)
157 .finish();
158
159 tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");
160}