1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//! commands
#![cfg(feature = "cli")]
use crate::{api::Api, result::Result};
use env_logger::{Builder, Env};
use log::LevelFilter;
use structopt::StructOpt;

pub mod claim;
pub mod create;
pub mod info;
pub mod key;
pub mod login;
pub mod meta;
pub mod new;
pub mod program;
pub mod reply;
pub mod send;
pub mod transfer;
pub mod update;
pub mod upload;

/// Commands of cli `gear`
#[derive(Debug, StructOpt)]
pub enum Command {
    Claim(claim::Claim),
    Create(create::Create),
    Info(info::Info),
    Key(key::Key),
    Login(login::Login),
    Meta(meta::Meta),
    New(new::New),
    Program(program::Program),
    Reply(reply::Reply),
    Send(send::Send),
    Upload(upload::Upload),
    Transfer(transfer::Transfer),
    Update(update::Update),
}

/// Entrypoint of cli `gear`
#[derive(Debug, StructOpt)]
#[structopt(name = "gear-program")]
pub struct Opt {
    /// Commands.
    #[structopt(subcommand)]
    pub command: Command,
    /// Enable verbose logs.
    #[structopt(short, long)]
    pub verbose: bool,
    /// Gear node rpc endpoint.
    #[structopt(short, long)]
    pub endpoint: Option<String>,
    /// Password of the signer account.
    #[structopt(short, long)]
    pub passwd: Option<String>,
}

impl Opt {
    /// setup logs
    fn setup_logs(&self) -> Result<()> {
        let mut builder = if self.verbose {
            Builder::from_env(Env::default().default_filter_or("debug"))
        } else {
            match &self.command {
                Command::Claim(_)
                | Command::Create(_)
                | Command::Reply(_)
                | Command::Send(_)
                | Command::Upload(_)
                | Command::Transfer(_) => {
                    let mut builder = Builder::from_env(Env::default().default_filter_or("info"));
                    builder
                        .format_target(false)
                        .format_module_path(false)
                        .format_timestamp(None)
                        .filter_level(LevelFilter::Info);

                    builder
                }
                _ => Builder::from_default_env(),
            }
        };

        builder.try_init()?;
        Ok(())
    }

    /// run program
    pub async fn run() -> Result<()> {
        let opt = Opt::from_args();

        opt.setup_logs()?;
        opt.exec().await?;
        Ok(())
    }

    /// Create api client from endpoint
    async fn api(&self) -> Result<Api> {
        Api::new(self.endpoint.as_deref()).await
    }

    /// Execute command.
    pub async fn exec(&self) -> Result<()> {
        match &self.command {
            Command::Key(key) => key.exec(self.passwd.as_deref())?,
            Command::Login(login) => login.exec()?,
            Command::Meta(meta) => meta.exec()?,
            Command::New(new) => new.exec().await?,
            Command::Program(program) => program.exec(self.api().await?).await?,
            Command::Update(update) => update.exec().await?,
            sub => {
                let signer = Api::new(self.endpoint.as_deref())
                    .await?
                    .try_signer(self.passwd.as_deref())?;

                match sub {
                    Command::Claim(claim) => claim.exec(signer).await?,
                    Command::Create(create) => create.exec(signer).await?,
                    Command::Info(info) => info.exec(signer).await?,
                    Command::Send(send) => send.exec(signer).await?,
                    Command::Upload(upload) => upload.exec(signer).await?,
                    Command::Transfer(transfer) => transfer.exec(signer).await?,
                    Command::Reply(reply) => reply.exec(signer).await?,
                    _ => unreachable!("Already matched"),
                }
            }
        }

        Ok(())
    }
}