dev_kit/command/
mod.rs

1use anyhow::anyhow;
2use std::ops::Deref;
3use std::str::FromStr;
4
5#[derive(clap::Subcommand)]
6pub enum Commands {
7    #[clap(about = "uri tools", alias = "url")]
8    Uri {
9        #[clap(subcommand)]
10        command: uri::UriCommand,
11    },
12    #[clap(about = "json tools")]
13    Json {
14        #[clap(subcommand)]
15        command: json::JsonCommand,
16    },
17    #[clap(about = "time tools")]
18    Time {
19        #[clap(subcommand)]
20        command: time::TimeCommand,
21    },
22    #[clap(name = "qrcode", about = "qrcode generator tools, alias 'qr'", alias = "qr")]
23    QrCode(qrcode::QrCodeArgs),
24    #[clap(about = "base64 tools, alias 'b64'", alias = "b64")]
25    Base64 {
26        #[clap(subcommand)]
27        command: base64::Base64Command,
28    },
29}
30
31pub trait Command {
32    fn run(&self) -> crate::Result<()>;
33}
34
35impl Command for Commands {
36    fn run(&self) -> crate::Result<()> {
37        match self {
38            Commands::Uri { command } => command.run(),
39            Commands::Json { command } => command.run(),
40            Commands::Time { command } => command.run(),
41            Commands::QrCode(args) => args.run(),
42            Commands::Base64 { command } => command.run(),
43        }
44    }
45}
46
47pub mod base64;
48mod http_parser;
49pub mod json;
50pub mod qrcode;
51pub mod time;
52pub mod uri;
53
54#[cfg(feature = "read_stdin")]
55fn read_stdin() -> Option<String> {
56    use std::io::{BufRead, IsTerminal};
57    let stdin = std::io::stdin().lock();
58    if stdin.is_terminal() {
59        None
60    } else {
61        let mut lines = vec![];
62        for line in stdin.lines() {
63            match line {
64                Ok(line) => {
65                    let _ = lines.push(line);
66                }
67                Err(err) => {
68                    log::error!("read from stdin failed, {}", err);
69                    break;
70                }
71            }
72        }
73        let string = lines.join("\n");
74        Some(string)
75    }
76}
77
78#[derive(Debug, Clone)]
79pub struct StringInput(String);
80
81impl Deref for StringInput {
82    type Target = str;
83    fn deref(&self) -> &Self::Target {
84        &self.0
85    }
86}
87
88impl FromStr for StringInput {
89    type Err = anyhow::Error;
90    fn from_str(value: &str) -> Result<Self, Self::Err> {
91        if value.is_empty()
92            && let Some(string) = read_stdin()
93        {
94            if !string.is_empty() {
95                return Ok(Self::from_str(&string)?);
96            }
97        }
98        if value.is_empty() {
99            Err(anyhow!("Invalid input"))
100        } else {
101            Ok(Self(value.to_string()))
102        }
103    }
104}
105
106#[cfg(not(feature = "read_stdin"))]
107fn read_stdin() -> Option<String> {
108    None
109}