use serde_yaml;
use std::collections::HashMap;
use toml;
use crate::models::{ProxyGroupConfig, RegexMatchConfig, RulesetConfig};
use crate::settings::Settings;
use crate::utils::file::load_content_async;
use super::ini_external::IniExternalSettings;
use super::toml_external::TomlExternalSettings;
use super::yaml_external::YamlExternalSettings;
#[derive(Debug, Clone, Default)]
pub struct ExternalSettings {
pub clash_rule_base: String,
pub surge_rule_base: String,
pub surfboard_rule_base: String,
pub mellow_rule_base: String,
pub quan_rule_base: String,
pub quanx_rule_base: String,
pub loon_rule_base: String,
pub sssub_rule_base: String,
pub singbox_rule_base: String,
pub enable_rule_generator: Option<bool>,
pub overwrite_original_rules: Option<bool>,
pub add_emoji: Option<bool>,
pub remove_old_emoji: Option<bool>,
pub emojis: Vec<RegexMatchConfig>,
pub include_remarks: Vec<String>,
pub exclude_remarks: Vec<String>,
pub custom_rulesets: Vec<RulesetConfig>,
pub custom_proxy_groups: Vec<ProxyGroupConfig>,
pub rename_nodes: Vec<RegexMatchConfig>,
pub tpl_args: Option<HashMap<String, String>>,
}
impl ExternalSettings {
pub fn new() -> Self {
Self::default()
}
pub async fn load_from_file(path: &str) -> Result<Self, Box<dyn std::error::Error>> {
let _content = load_content_async(path).await?;
Self::parse_content(&_content).await
}
async fn parse_content(content: &str) -> Result<Self, Box<dyn std::error::Error>> {
if content.contains("custom:") {
let mut yaml_settings: YamlExternalSettings = serde_yaml::from_str(content)?;
yaml_settings.process_imports().await?;
let config = Self::from(yaml_settings);
return Ok(config);
}
if toml::from_str::<toml::Value>(content).is_ok() {
let mut toml_settings: TomlExternalSettings = toml::from_str(content)?;
toml_settings.process_imports().await?;
let config = Self::from(toml_settings);
return Ok(config);
}
let mut ini_settings = IniExternalSettings::new();
match ini_settings.load_from_ini(content) {
Ok(_) => {
ini_settings.process_imports().await?;
let config = Self::from(ini_settings);
return Ok(config);
}
Err(e) => Err(format!("Failed to parse external config as INI: {}", e).into()),
}
}
pub fn validate_rulesets(&self) -> Result<(), Box<dyn std::error::Error>> {
let settings = Settings::current();
if settings.max_allowed_rulesets > 0
&& self.custom_rulesets.len() > settings.max_allowed_rulesets
{
return Err("Ruleset count in external config has exceeded limit.".into());
}
Ok(())
}
}