pub mod handlers;
pub mod ui;
pub use handlers::{admin_routes, AdminStats, SystemInfo};
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::OnceLock;
use std::time::Instant;
#[derive(Debug, Clone)]
pub struct AdminConfig {
pub secret_key: Option<String>,
pub base_path: String,
pub app_name: String,
pub app_version: String,
}
impl Default for AdminConfig {
fn default() -> Self {
Self {
secret_key: None,
base_path: "/admin".to_string(),
app_name: "rapid-rs App".to_string(),
app_version: env!("CARGO_PKG_VERSION").to_string(),
}
}
}
impl AdminConfig {
pub fn new() -> Self {
Self::default()
}
pub fn with_secret_key(mut self, key: impl Into<String>) -> Self {
self.secret_key = Some(key.into());
self
}
pub fn with_base_path(mut self, path: impl Into<String>) -> Self {
self.base_path = path.into();
self
}
pub fn with_app_name(mut self, name: impl Into<String>) -> Self {
self.app_name = name.into();
self
}
pub fn with_app_version(mut self, version: impl Into<String>) -> Self {
self.app_version = version.into();
self
}
}
static REQUEST_COUNT: AtomicU64 = AtomicU64::new(0);
static ERROR_COUNT: AtomicU64 = AtomicU64::new(0);
static START_TIME: OnceLock<Instant> = OnceLock::new();
fn start_time() -> &'static Instant {
START_TIME.get_or_init(Instant::now)
}
pub fn increment_request_count() {
REQUEST_COUNT.fetch_add(1, Ordering::Relaxed);
}
pub fn increment_error_count() {
ERROR_COUNT.fetch_add(1, Ordering::Relaxed);
}
pub fn get_request_count() -> u64 {
REQUEST_COUNT.load(Ordering::Relaxed)
}
pub fn get_error_count() -> u64 {
ERROR_COUNT.load(Ordering::Relaxed)
}
pub fn get_uptime_seconds() -> u64 {
start_time().elapsed().as_secs()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_admin_config_defaults() {
let config = AdminConfig::default();
assert_eq!(config.base_path, "/admin");
assert!(config.secret_key.is_none());
}
#[test]
fn test_admin_config_builder() {
let config = AdminConfig::new()
.with_secret_key("my-secret")
.with_base_path("/management")
.with_app_name("My API");
assert_eq!(config.secret_key, Some("my-secret".to_string()));
assert_eq!(config.base_path, "/management");
assert_eq!(config.app_name, "My API");
}
#[test]
fn test_counters() {
let initial = get_request_count();
increment_request_count();
assert_eq!(get_request_count(), initial + 1);
let initial_err = get_error_count();
increment_error_count();
assert_eq!(get_error_count(), initial_err + 1);
}
}