Skip to main content

rush_sync_server/core/
helpers.rs

1use crate::core::prelude::*;
2use std::path::PathBuf;
3use std::sync::{OnceLock, RwLock, RwLockReadGuard, RwLockWriteGuard};
4
5/// Runtime-safe config loader
6pub fn get_config() -> Result<Config> {
7    tokio::task::block_in_place(|| tokio::runtime::Handle::current().block_on(Config::load()))
8}
9
10/// Safe read lock acquisition with context for error messages
11pub fn read_lock<'a, T>(lock: &'a RwLock<T>, context: &str) -> Result<RwLockReadGuard<'a, T>> {
12    lock.read().map_err(|e| {
13        log::error!("{} read lock poisoned: {}", context, e);
14        AppError::Validation(format!("{} lock poisoned", context))
15    })
16}
17
18static BASE_DIR: OnceLock<PathBuf> = OnceLock::new();
19
20/// Get the base directory (parent of the executable), cached via OnceLock
21pub fn get_base_dir() -> Result<PathBuf> {
22    Ok(BASE_DIR
23        .get_or_init(|| {
24            std::env::current_exe()
25                .ok()
26                .and_then(|p| p.parent().map(|p| p.to_path_buf()))
27                .unwrap_or_else(|| PathBuf::from("."))
28        })
29        .clone())
30}
31
32/// Safe write lock acquisition with context for error messages
33pub fn write_lock<'a, T>(lock: &'a RwLock<T>, context: &str) -> Result<RwLockWriteGuard<'a, T>> {
34    lock.write().map_err(|e| {
35        log::error!("{} write lock poisoned: {}", context, e);
36        AppError::Validation(format!("{} lock poisoned", context))
37    })
38}
39
40/// Escape HTML special characters to prevent XSS
41pub fn html_escape(input: &str) -> String {
42    input
43        .replace('&', "&amp;")
44        .replace('<', "&lt;")
45        .replace('>', "&gt;")
46        .replace('"', "&quot;")
47        .replace('\'', "&#x27;")
48}