Skip to main content

gmsol_cli/
lib.rs

1/// Configuration.
2pub mod config;
3
4/// Utils for wallet.
5pub mod wallet;
6
7/// Commands.
8pub mod commands;
9
10use std::{ops::Deref, path::PathBuf};
11
12use clap::Parser;
13use commands::{Command, CommandClient, Commands, Context};
14use config::Config;
15use eyre::OptionExt;
16use figment::{
17    providers::{Env, Format, Serialized, Toml},
18    Figment,
19};
20
21const ENV_PREFIX: &str = "GMSOL_";
22const CONFIG_DIR: &str = "gmsol";
23
24/// We use `__` in the name of environment variable as an alias of `.`.
25///
26/// See [`Env`] for more infomation.
27const DOT_ALIAS: &str = "__";
28
29/// Command-line interface for GMX-Solana.
30#[derive(Debug)]
31pub struct Cli(Inner);
32
33impl Cli {
34    /// Creates from the command line arguments.
35    pub fn init() -> eyre::Result<Self> {
36        let cli = Inner::parse();
37
38        let config_path = cli.find_config()?;
39        let Inner {
40            config,
41            command,
42            verbose,
43            ..
44        } = cli;
45
46        let config = Figment::new()
47            .merge(Serialized::defaults(config))
48            .join(Env::prefixed(ENV_PREFIX).split(DOT_ALIAS))
49            .join(Toml::file(config_path.clone()))
50            .extract()?;
51
52        Ok(Self(Inner {
53            config_path: Some(config_path),
54            config,
55            command,
56            verbose,
57        }))
58    }
59}
60
61impl Deref for Cli {
62    type Target = Inner;
63
64    fn deref(&self) -> &Self::Target {
65        &self.0
66    }
67}
68
69/// Command-line interface for GMX-Solana.
70#[derive(Debug, Parser)]
71#[command(
72    version = concat!(
73        env!("CARGO_PKG_VERSION"), " (",
74        env!("VERGEN_BUILD_DATE"), ")"
75    ),
76    long_version = concat!(
77        env!("CARGO_PKG_VERSION"), "\n",
78        "Built: ", env!("VERGEN_BUILD_TIMESTAMP"), "\n",
79        "Git commit: ", env!("VERGEN_GIT_SHA"), "\n",
80        "Rustc version: ", env!("VERGEN_RUSTC_SEMVER"), "\n",
81        "Enabled features: ", env!("VERGEN_CARGO_FEATURES"), "\n",
82        "Debug: ", env!("VERGEN_CARGO_DEBUG"),
83    ),
84    about = None,
85    long_about = None,
86)]
87pub struct Inner {
88    /// Path to the config file.
89    #[clap(long = "config", short)]
90    config_path: Option<PathBuf>,
91    /// Enable detailed output.
92    #[clap(long, short, global = true)]
93    verbose: bool,
94    /// Config.
95    #[command(flatten)]
96    config: Config,
97    /// Commands.
98    #[command(subcommand)]
99    command: Commands,
100}
101
102impl Inner {
103    fn find_config(&self) -> eyre::Result<PathBuf> {
104        use etcetera::{choose_base_strategy, BaseStrategy};
105
106        match self.config_path.as_ref() {
107            Some(path) => Ok(path.clone()),
108            None => {
109                let strategy = choose_base_strategy()?;
110                Ok(strategy.config_dir().join(CONFIG_DIR).join("config.toml"))
111            }
112        }
113    }
114
115    /// Execute command.
116    pub async fn execute(&self) -> eyre::Result<()> {
117        let config_path = self
118            .config_path
119            .as_ref()
120            .ok_or_eyre("config path is not set")?;
121        #[cfg(feature = "remote-wallet")]
122        let mut wallet_manager = None;
123        let client = if self.command.is_client_required() {
124            cfg_if::cfg_if! {
125                if #[cfg(feature = "remote-wallet")] {
126                    Some(CommandClient::new(&self.config, &mut wallet_manager, self.verbose)?)
127                } else {
128                    Some(CommandClient::new(&self.config, self.verbose)?)
129                }
130            }
131        } else {
132            None
133        };
134        let store = self.config.store_address();
135        self.command
136            .execute(Context::new(
137                store,
138                config_path,
139                &self.config,
140                client.as_ref(),
141                self.verbose,
142            ))
143            .await
144    }
145}