diff --git a/CHANGELOG.md b/CHANGELOG.md index a69f97549..e50479e56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ # Changelog +# 2.1.1 (2025-01-xx) +- added new path `/status` which is an alias to `healthcheck` +- added memory usage to `/status` + # 2.1.0 (2025-01-17) - Watch files are now moved inside the `target` folder. Move them manually from `watch__.bin` to `/watch_.bin` - No error log for xtream api when content is skipped with options `xtream_skip_[live|vod|series]` diff --git a/Cargo.lock b/Cargo.lock index d2edd980b..4a7ee83c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1791,6 +1791,7 @@ dependencies = [ "flate2", "futures", "jsonwebtoken", + "libc", "log", "mime", "openssl", @@ -1815,6 +1816,7 @@ dependencies = [ "tokio-stream", "unidecode", "url", + "winapi", ] [[package]] @@ -3265,6 +3267,28 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-core" version = "0.52.0" diff --git a/Cargo.toml b/Cargo.toml index 13761f4a4..d0d982b2b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,5 +57,9 @@ paste = "1.0" tempfile = "3.15" ruzstd = "0" async-broadcast = "0" +#[cfg(target_os = "macos")] +libc = "0" +#[cfg(target_os = "windows")] +winapi = "0" # [target.'cfg(not(target_env = "msvc"))'.dependencies] # tikv-jemallocator = { version = "*", features = ["profiling", "unprefixed_malloc_on_supported_platforms"] } diff --git a/src/api/main_api.rs b/src/api/main_api.rs index 67d88fdaa..932dba462 100644 --- a/src/api/main_api.rs +++ b/src/api/main_api.rs @@ -21,6 +21,8 @@ use crate::model::config::{validate_targets, Config, ProcessTargets, ScheduleCon use crate::model::healthcheck::Healthcheck; use crate::processing::playlist_processor; use crate::utils::lru_cache::{LRUResourceCache}; +use crate::utils::size_utils::human_readable_byte_size; +use crate::utils::sys; use crate::VERSION; fn get_web_dir_path(web_ui_enabled: bool, web_root: &str) -> Result { @@ -39,6 +41,7 @@ async fn healthcheck() -> HttpResponse { status: "ok".to_string(), version: VERSION.to_string(), time: ts, + mem: sys::get_memory_usage().map_or(String::from("?"), human_readable_byte_size) }) } @@ -167,6 +170,7 @@ pub async fn start_server(cfg: Arc, targets: Arc) -> fut srvcfg.configure(v1_api_register(web_auth_enabled)); } srvcfg.service(web::resource("/healthcheck").route(web::get().to(healthcheck))); + srvcfg.service(web::resource("/status").route(web::get().to(healthcheck))); }) .configure(xtream_api_register) .configure(m3u_api_register) diff --git a/src/model/healthcheck.rs b/src/model/healthcheck.rs index 0531013ad..a74337708 100644 --- a/src/model/healthcheck.rs +++ b/src/model/healthcheck.rs @@ -3,4 +3,5 @@ pub struct Healthcheck { pub status: String, pub version: String, pub time: String, + pub mem: String, } \ No newline at end of file diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 008496d82..99032a9d4 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -12,6 +12,7 @@ mod compression_utils; pub mod directed_graph; pub mod lru_cache; pub mod size_utils; +pub mod sys; #[macro_export] macro_rules! debug_if_enabled { diff --git a/src/utils/sys.rs b/src/utils/sys.rs new file mode 100644 index 000000000..a1dc2ecdd --- /dev/null +++ b/src/utils/sys.rs @@ -0,0 +1,70 @@ +#[cfg(target_os = "linux")] +fn get_memory_usage_linux() -> std::io::Result { + use std::fs::File; + use std::io::{BufReader, Read}; + + let path = "/proc/self/status"; + let file = File::open(path)?; + let mut reader = BufReader::new(file); + + let mut contents = String::new(); + reader.read_to_string(&mut contents)?; + + let re = regex::Regex::new(r"VmRSS:\s+(\d+) kB").unwrap(); + if let Some(captures) = re.captures(&contents) { + let memory_kb: u64 = captures[1].parse().unwrap(); + Ok(memory_kb * 1024) + } else { + Err(std::io::Error::new(std::io::ErrorKind::NotFound, "VmRSS not found")) + } +} + +#[cfg(target_os = "windows")] +fn get_memory_usage_windows() -> u64 { + use winapi::um::psapi::{GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS}; + use winapi::um::processenv::GetCurrentProcess; + use winapi::shared::minwindef::DWORD; + + unsafe { + let mut counters: PROCESS_MEMORY_COUNTERS = std::mem::zeroed(); + let process = GetCurrentProcess(); + GetProcessMemoryInfo(process, &mut counters, std::mem::size_of::() as DWORD); + counters.WorkingSetSize as u64 + } +} + +#[cfg(target_os = "macos")] +fn get_memory_usage_macos() -> u64 { + use libc::{sysctl, CTL_KERN, KERN_PROC, KERN_PROC_PID}; + use std::ptr; + + unsafe { + let mut mib = [CTL_KERN, KERN_PROC, KERN_PROC_PID, 0]; + mib[3] = libc::getpid(); + let mut info: libc::rusage = std::mem::zeroed(); + let mut len = std::mem::size_of::(); + + sysctl(mib.as_mut_ptr(), mib.len() as libc::c_uint, &mut info as *mut _ as *mut _, &mut len, ptr::null_mut(), 0); + + info.ru_maxrss as u64 * 1024 + } +} + +#[cfg(not(any(target_os = "linux", target_os = "windows", target_os = "macos")))] +fn get_memory_usage_other() -> Option { + None +} + +pub fn get_memory_usage() -> Option { + #[cfg(target_os = "linux")] + return get_memory_usage_linux().ok(); + + #[cfg(target_os = "windows")] + return get_memory_usage_windows(); + + #[cfg(target_os = "macos")] + return get_memory_usage_macos(); + + #[cfg(not(any(target_os = "linux", target_os = "windows", target_os = "macos")))] + return get_memory_usage_other(); +}