Skip to content

Commit

Permalink
refactor: error handling via anyhow
Browse files Browse the repository at this point in the history
  • Loading branch information
spencerwooo committed Dec 29, 2023
1 parent 6eeb911 commit 7685864
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 148 deletions.
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
[package]
name = "mihoro"
description = "Mihomo CLI client on Linux."
version = "0.2.7"
version = "0.3.0"
edition = "2021"
readme = "README.md"
license = "MIT"
authors = ["spencerwooo <spencer.woo@outlook.com>"]
homepage = "https://github.com/spencerwooo/mihoro"
repository = "https://github.com/spencerwooo/mihoro"
keywords = ["cli", "clash", "network", "linux"]
keywords = ["cli", "clash", "network", "linux", "mihomo"]
categories = ["command-line-utilities"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand All @@ -29,3 +29,4 @@ futures-util = "0.3"
indicatif = "0.17"
tokio = { version = "1.34", features = ["full"] }
truncatable = "0.1"
anyhow = "1.0.77"
2 changes: 1 addition & 1 deletion src/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub enum Commands {
Restart,
#[command(about = "Check mihomo.service logs with journalctl")]
Log,
#[command(about = "Proxy export commands, `mihoro proxy --help` to see more")]
#[command(about = "Proxy export commands, `mihoro proxy --help` for details")]
Proxy {
#[command(subcommand)]
proxy: Option<ProxyCommands>,
Expand Down
89 changes: 39 additions & 50 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ use std::collections::HashMap;
use std::fs;
use std::path::Path;

use anyhow::bail;
use anyhow::Result;
use colored::Colorize;
use serde::Deserialize;
use serde::Serialize;

use crate::utils::create_parent_dir;

/// `mihoro` configurations.
#[derive(Serialize, Deserialize, Debug)]
pub struct Config {
Expand Down Expand Up @@ -91,72 +95,56 @@ impl Config {
/// however the error message always shows the line and column number as `line 1 column 1`,
/// which is because the function `fs::read_to_string` preserves newline characters as `\n`,
/// resulting in a single-lined string.
pub fn setup_from(path: &str) -> Result<Config, toml::de::Error> {
let raw_config = fs::read_to_string(path).unwrap();
toml::from_str(&raw_config)
pub fn setup_from(path: &str) -> Result<Config> {
let raw_config = fs::read_to_string(path)?;
let config: Config = toml::from_str(&raw_config)?;
Ok(config)
}

pub fn write(&mut self, path: &Path) {
let serialized_config = toml::to_string(&self).unwrap();
fs::write(path, serialized_config).unwrap();
pub fn write(&mut self, path: &Path) -> Result<()> {
let serialized_config = toml::to_string(&self)?;
fs::write(path, serialized_config)?;
Ok(())
}
}

#[derive(Debug)]
pub enum ConfigError {
FileMissing,
ParseError,
}

/// Tries to parse mihoro config as toml from path.
///
/// * If config file does not exist, creates default config file to path and returns error.
/// * If found, tries to parse the file and returns error if parse fails or fields found undefined.
pub fn parse_config(path: &str, prefix: &str) -> Result<Config, ConfigError> {
pub fn parse_config(path: &str, prefix: &str) -> Result<Config> {
// Create `~/.config` directory if not exists
let parent_dir = Path::new(path).parent().unwrap();
if !parent_dir.exists() {
fs::create_dir_all(parent_dir).unwrap();
}
create_parent_dir(path)?;

// Create mihoro default config if not exists
let config_path = Path::new(path);
if !config_path.exists() {
Config::new().write(config_path);
println!(
"{prefix} Created default config at {path}, edit as needed\n{prefix} Run again to finish setup",
Config::new().write(config_path)?;
bail!(
"{prefix} Created default config at `{path}`, edit as needed\n{prefix} Run again to finish setup",
prefix = prefix.yellow(),
path = path.underline()
);
return Err(ConfigError::FileMissing);
}

// Parse config file and validate if urls are defined
// println!("{} Reading config from {}", prefix.cyan(), path.underline());
match Config::setup_from(path) {
Ok(config) => {
let required_urls = [
("remote_config_url", &config.remote_config_url),
("remote_mmdb_url", &config.remote_mmdb_url),
("mihomo_binary_path", &config.mihomo_binary_path),
("mihomo_config_root", &config.mihomo_config_root),
("user_systemd_root", &config.user_systemd_root),
];

for (field, value) in required_urls.iter() {
if value.is_empty() {
println!("{} `{}` undefined", "error:".red(), field);
return Err(ConfigError::ParseError);
}
}

Ok(config)
}
Err(error) => {
println!("{} {}", "error:".red(), error);
Err(ConfigError::ParseError)
// Parse config file
let config = Config::setup_from(path)?;
let required_urls = [
("remote_config_url", &config.remote_config_url),
("remote_mmdb_url", &config.remote_mmdb_url),
("mihomo_binary_path", &config.mihomo_binary_path),
("mihomo_config_root", &config.mihomo_config_root),
("user_systemd_root", &config.user_systemd_root),
];

// Validate if urls are defined
for (field, value) in required_urls.iter() {
if value.is_empty() {
bail!("`{}` undefined", field)
}
}

Ok(config)
}

/// `mihomoYamlConfig` is defined to support serde serialization and deserialization of arbitrary
Expand Down Expand Up @@ -208,9 +196,9 @@ pub struct MihomoYamlConfig {
/// * Fields defined in `mihoro.toml` will override the downloaded remote `config.yaml`.
/// * Fields undefined will be removed from the downloaded `config.yaml`.
/// * Fields not supported by `mihoro` will be kept as is.
pub fn apply_mihomo_override(path: &str, override_config: &MihomoConfig) {
let raw_mihomo_yaml = fs::read_to_string(path).unwrap();
let mut mihomo_yaml: MihomoYamlConfig = serde_yaml::from_str(&raw_mihomo_yaml).unwrap();
pub fn apply_mihomo_override(path: &str, override_config: &MihomoConfig) -> Result<()> {
let raw_mihomo_yaml = fs::read_to_string(path)?;
let mut mihomo_yaml: MihomoYamlConfig = serde_yaml::from_str(&raw_mihomo_yaml)?;

// Apply config overrides
mihomo_yaml.port = Some(override_config.port);
Expand All @@ -225,6 +213,7 @@ pub fn apply_mihomo_override(path: &str, override_config: &MihomoConfig) {
mihomo_yaml.secret = override_config.secret.clone();

// Write to file
let serialized_mihomo_yaml = serde_yaml::to_string(&mihomo_yaml).unwrap();
fs::write(path, serialized_mihomo_yaml).unwrap();
let serialized_mihomo_yaml = serde_yaml::to_string(&mihomo_yaml)?;
fs::write(path, serialized_mihomo_yaml)?;
Ok(())
}
Loading

0 comments on commit 7685864

Please sign in to comment.