76 lines
2.5 KiB
Rust
76 lines
2.5 KiB
Rust
use anyhow::{Context, Result};
|
|
use serde::{Deserialize, Serialize};
|
|
use serde_json::Value;
|
|
use std::collections::BTreeMap;
|
|
use std::fs;
|
|
use std::path::Path;
|
|
|
|
/// Represents a single rule, capturing the URL, tag, and any other fields.
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
pub struct Rule {
|
|
pub url: String,
|
|
pub tag: String,
|
|
// Capture any other fields in the rule object
|
|
#[serde(flatten)]
|
|
pub other_fields: BTreeMap<String, Value>,
|
|
}
|
|
|
|
/// Represents the "route" object in the config.
|
|
#[derive(Serialize, Deserialize, Debug)]
|
|
struct Route {
|
|
#[serde(default, rename = "rule_set")]
|
|
rule_set: Vec<Rule>,
|
|
}
|
|
|
|
/// Represents the top-level structure of the configuration file.
|
|
#[derive(Serialize, Deserialize, Debug)]
|
|
pub struct Config {
|
|
route: Route,
|
|
// Capture any other top-level fields
|
|
#[serde(flatten)]
|
|
other_fields: BTreeMap<String, Value>,
|
|
}
|
|
|
|
impl Config {
|
|
/// Loads and parses the config file from a given path.
|
|
pub fn load(path: &Path) -> Result<Self> {
|
|
let content = fs::read_to_string(path)
|
|
.with_context(|| format!("Failed to read config file from '{}'", path.display()))?;
|
|
let config: Config = serde_json::from_str(&content)
|
|
.context("Failed to parse JSON. Please check the config file structure.")?;
|
|
Ok(config)
|
|
}
|
|
|
|
/// Saves the current config state back to a file, prettified.
|
|
pub fn save(&self, path: &Path) -> Result<()> {
|
|
let new_content = serde_json::to_string_pretty(self)
|
|
.context("Failed to serialize modified config to JSON.")?;
|
|
fs::write(path, new_content)?;
|
|
Ok(())
|
|
}
|
|
|
|
/// Extracts all URLs from the rule_set.
|
|
pub fn extract_urls(&self) -> Vec<String> {
|
|
self.route
|
|
.rule_set
|
|
.iter()
|
|
.map(|rule| rule.url.clone())
|
|
.collect()
|
|
}
|
|
|
|
/// Rewrites the URLs in the config based on the provided domain and path.
|
|
pub fn rewrite_urls(&mut self, domain: &str, rule_path: &str) -> Result<()> {
|
|
let clean_domain = domain.trim_matches('/');
|
|
let clean_rule_path = format!("/{}/", rule_path.trim_matches('/'));
|
|
|
|
for rule in &mut self.route.rule_set {
|
|
if let Some(filename) = rule.url.split('/').last().filter(|s| !s.is_empty()) {
|
|
let new_url = format!("https://{}{}{}", clean_domain, clean_rule_path, filename);
|
|
println!(" '{}' -> {}", rule.tag, new_url);
|
|
rule.url = new_url;
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|