use crate::app::App;
use anyhow::{Context, Result};
use clap::Parser;
use colored::Colorize;
use gsdk::Api;
use serde::{Deserialize, Serialize};
use std::{fs, path::PathBuf, str::FromStr};
use url::Url;
const CONFIG_PATH: &str = "gear-gcli/config.toml";
#[derive(Clone, Debug, Parser)]
pub struct Config {
#[clap(subcommand)]
action: Action,
}
impl Config {
pub fn exec(self, app: &mut App) -> Result<()> {
let mut config = app.config()?;
match self.action {
Action::Set(option) => {
config.set(option);
config
.write()
.context("failed to write new configuration")?;
println!("Successfully updated the configuration");
println!();
config.pretty_print();
}
Action::Get => {
app.config()?.pretty_print();
}
Action::Reset => {
config = ConfigSettings::default();
config
.write()
.context("failed to write new configuration")?;
println!("Successfully reset the configuration");
println!();
config.pretty_print();
}
}
Ok(())
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Default)]
pub struct ConfigSettings {
#[serde(alias = "url")]
pub endpoint: Endpoint,
}
#[derive(Debug, Clone, Parser)]
enum ConfigOption {
Endpoint {
endpoint: Endpoint,
},
}
impl ConfigSettings {
fn config_path() -> Result<PathBuf> {
Ok(std::env::var_os("GCLI_CONFIG_DIR")
.map_or_else(
|| dirs::config_dir().context("failed to get config directory"),
|dir| Ok(PathBuf::from(dir)),
)?
.join(CONFIG_PATH))
}
pub fn read() -> Result<ConfigSettings> {
let path = Self::config_path()?;
if path.exists() {
let contents = fs::read_to_string(path)?;
Ok(toml::from_str(&contents)?)
} else {
Ok(Self::default())
}
}
fn set(&mut self, option: ConfigOption) {
match option {
ConfigOption::Endpoint { endpoint } => self.endpoint = endpoint,
}
}
pub fn write(&self) -> Result<()> {
let path = Self::config_path()?;
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)?;
}
let contents = toml::to_string_pretty(self)?;
Ok(fs::write(path, contents)?)
}
pub fn pretty_print(&self) {
println!("{} {}", "RPC URL:".bold(), self.endpoint.as_str())
}
}
#[derive(Clone, Debug, Parser)]
enum Action {
#[clap(subcommand)]
Set(ConfigOption),
Get,
Reset,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Endpoint {
#[default]
Mainnet,
Testnet,
Localhost,
Custom(Url),
}
impl Endpoint {
pub fn as_str(&self) -> &str {
match self {
Self::Mainnet => Api::VARA_ENDPOINT,
Self::Testnet => Api::VARA_TESTNET_ENDPOINT,
Self::Localhost => Api::DEV_ENDPOINT,
Self::Custom(url) => url.as_str(),
}
}
}
impl FromStr for Endpoint {
type Err = url::ParseError;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
Ok(match s {
"mainnet" => Self::Mainnet,
"testnet" => Self::Testnet,
"localhost" => Self::Localhost,
input => Self::Custom(Url::parse(input)?),
})
}
}