Files
sbrs/src/config.rs
2025-06-29 10:53:21 +03:00

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(())
}
}