mintrt 0.1.1

Security-featured runtime for lua.
//     <<*>> Revenge of snowflake.
//     -^v-  SASWE
//     @ This source code is licensed under a dual license model:
//       1. MPL-2.0 for non-commercial use only
//       2. Commercial License for commercial use
//       See LICENSE and LICENSE_COMMERCIAL files for details.

// 通义添加:日志频率限制器模块 - 使用 Arc<Mutex> 保证线程安全
use std::sync::{Arc, Mutex};
use std::time::{Instant, Duration};
use crate::config;

/// 日志频率限制器结构
struct LogRateLimiter {
    last_log: Instant,
    min_interval: Duration,
    dropped_count: u32,  // 被丢弃的日志数量
}

impl LogRateLimiter {
    // 通义添加:创建新的限制器
    fn new(interval_ms: u64) -> Self {
        LogRateLimiter {
            last_log: Instant::now() - Duration::from_millis(interval_ms), // 允许首次立即输出
            min_interval: Duration::from_millis(interval_ms),
            dropped_count: 0,
        }
    }

    // 通义添加:尝试记录日志,如果频率过高则返回 false
    fn try_log(&mut self) -> bool {
        let now = Instant::now();
        if now.duration_since(self.last_log) >= self.min_interval {
            self.last_log = now;
            true
        } else {
            self.dropped_count += 1;
            false
        }
    }

    // 通义添加:获取并重置丢弃计数
    fn take_dropped(&mut self) -> u32 {
        std::mem::take(&mut self.dropped_count)
    }
}

// 通义添加:全局日志限制器(每个日志级别独立)
static LOG_LIMITER_INFO: std::sync::OnceLock<Arc<Mutex<LogRateLimiter>>> = std::sync::OnceLock::new();
static LOG_LIMITER_ERROR: std::sync::OnceLock<Arc<Mutex<LogRateLimiter>>> = std::sync::OnceLock::new();
static LOG_LIMITER_TRACE: std::sync::OnceLock<Arc<Mutex<LogRateLimiter>>> = std::sync::OnceLock::new();
static LOG_LIMITER_WARN: std::sync::OnceLock<Arc<Mutex<LogRateLimiter>>> = std::sync::OnceLock::new();

// 通义添加:获取或创建日志限制器(懒初始化)
fn get_limiter(level: &str) -> Arc<Mutex<LogRateLimiter>> {
    match level {
        "info" => LOG_LIMITER_INFO.get_or_init(|| Arc::new(Mutex::new(LogRateLimiter::new(100)))).clone(),
        "error" => LOG_LIMITER_ERROR.get_or_init(|| Arc::new(Mutex::new(LogRateLimiter::new(200)))).clone(),
        "trace" => LOG_LIMITER_TRACE.get_or_init(|| Arc::new(Mutex::new(LogRateLimiter::new(50)))).clone(),
        "warn" => LOG_LIMITER_WARN.get_or_init(|| Arc::new(Mutex::new(LogRateLimiter::new(150)))).clone(),
        _ => Arc::new(Mutex::new(LogRateLimiter::new(100))),
    }
}

// 通义添加:日志函数返回值 - Lua nil 表示成功,string 表示错误
pub fn log_info(loginfo: String) -> Option<String> {
    if loginfo.len() >= config::LUA_LOG_LENGTH_LIMIT {
        return Some("Rejected by mint: info too long.".to_string());
    }
    
    let limiter = get_limiter("info");
    match limiter.lock() {
        Ok(mut guard) => {
            if guard.try_log() {
                let dropped = guard.take_dropped();
                if dropped > 0 {
                    log::info!("... ({} messages suppressed)", dropped);
                }
                drop(guard);  // 提前释放锁
                log::info!("{}", loginfo);
            }
            None  // 返回 nil 给 Lua,表示成功
        }
        Err(_) => Some("Mutex lock failed".to_string()),
    }
}

pub fn log_error(loginfo: String) -> Option<String> {
    if loginfo.len() >= config::LUA_LOG_LENGTH_LIMIT {
        return Some("Rejected by mint: error too long.".to_string());
    }
    
    let limiter = get_limiter("error");
    match limiter.lock() {
        Ok(mut guard) => {
            if guard.try_log() {
                let dropped = guard.take_dropped();
                if dropped > 0 {
                    log::error!("... ({} messages suppressed)", dropped);
                }
                drop(guard);
                log::error!("{}", loginfo);
            }
            None
        }
        Err(_) => Some("Mutex lock failed".to_string()),
    }
}

pub fn log_trace(loginfo: String) -> Option<String> {
    if loginfo.len() >= config::LUA_LOG_LENGTH_LIMIT {
        return Some("Rejected by mint: trace too long.".to_string());
    }
    
    let limiter = get_limiter("trace");
    match limiter.lock() {
        Ok(mut guard) => {
            if guard.try_log() {
                let dropped = guard.take_dropped();
                if dropped > 0 {
                    log::trace!("... ({} messages suppressed)", dropped);
                }
                drop(guard);
                log::trace!("{}", loginfo);
            }
            None
        }
        Err(_) => Some("Mutex lock failed".to_string()),
    }
}

pub fn log_warn(loginfo: String) -> Option<String> {
    if loginfo.len() >= config::LUA_LOG_LENGTH_LIMIT {
        return Some("Rejected by mint: warn too long.".to_string());
    }
    
    let limiter = get_limiter("warn");
    match limiter.lock() {
        Ok(mut guard) => {
            if guard.try_log() {
                let dropped = guard.take_dropped();
                if dropped > 0 {
                    log::warn!("... ({} messages suppressed)", dropped);
                }
                drop(guard);
                log::warn!("{}", loginfo);
            }
            None
        }
        Err(_) => Some("Mutex lock failed".to_string()),
    }
}