diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 04a2153ff..a0ab47f9f 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1952,6 +1952,7 @@ dependencies = [ "ip_network", "ipconfig", "known-folders", + "libc", "mutants", "nix 0.28.0", "resolv-conf", @@ -1967,7 +1968,6 @@ dependencies = [ "tokio-util", "tracing", "tracing-subscriber", - "uptime_lib", "url", "uuid", "windows 0.57.0", @@ -6976,17 +6976,6 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" -[[package]] -name = "uptime_lib" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4e71ddbefed856d5881821d6ada4e606bbb91fd332296963ed596e2ad2100f3" -dependencies = [ - "libc", - "thiserror", - "windows 0.52.0", -] - [[package]] name = "url" version = "2.5.0" diff --git a/rust/headless-client/Cargo.toml b/rust/headless-client/Cargo.toml index fe4265e50..1d250bd25 100644 --- a/rust/headless-client/Cargo.toml +++ b/rust/headless-client/Cargo.toml @@ -28,7 +28,6 @@ tokio = { version = "1.38.0", features = ["macros", "signal"] } tokio-util = { version = "0.7.11", features = ["codec"] } tracing = { workspace = true } tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } -uptime_lib = "0.3.0" url = { version = "2.3.1", default-features = false } uuid = { version = "1.7", default-features = false, features = ["std", "v4", "serde"] } @@ -40,6 +39,7 @@ mutants = "0.0.3" # Needed to mark functions as exempt from `cargo-mutants` test [target.'cfg(target_os = "linux")'.dependencies] dirs = "5.0.1" +libc = "0.2.150" nix = { version = "0.28.0", features = ["fs", "user"] } resolv-conf = "0.7.0" rtnetlink = { workspace = true } @@ -65,8 +65,8 @@ features = [ "Win32_NetworkManagement_Ndis", "Win32_Networking_WinSock", - # For named pipe IPC - "Win32_Security", + "Win32_Security", # For named pipe IPC + "Win32_System_SystemInformation", # For uptime "Win32_System_SystemServices", "Win32_System_Pipes", ] diff --git a/rust/headless-client/src/heartbeat.rs b/rust/headless-client/src/heartbeat.rs index bee03a76b..c5a38dbc5 100644 --- a/rust/headless-client/src/heartbeat.rs +++ b/rust/headless-client/src/heartbeat.rs @@ -5,6 +5,7 @@ //! state, so this heartbeat allows us to estimate roughly how long each process stayed //! up when looking at user logs, using unlimited disk space per run of the app. +use crate::uptime; use std::time::Duration; use tokio::time::{sleep_until, Instant}; @@ -13,7 +14,7 @@ pub async fn heartbeat() { let mut hb = Heartbeat::default(); loop { sleep_until(hb.next_instant).await; - let system_uptime = uptime_lib::get().ok(); + let system_uptime = uptime::get(); tracing::info!(?system_uptime, "Heartbeat"); hb.tick(); } diff --git a/rust/headless-client/src/lib.rs b/rust/headless-client/src/lib.rs index 5a3963560..ad24febb7 100644 --- a/rust/headless-client/src/lib.rs +++ b/rust/headless-client/src/lib.rs @@ -33,6 +33,7 @@ pub mod heartbeat; mod ipc_service; pub mod known_dirs; mod standalone; +mod uptime; #[cfg(target_os = "linux")] #[path = "linux.rs"] diff --git a/rust/headless-client/src/uptime/README.md b/rust/headless-client/src/uptime/README.md new file mode 100644 index 000000000..9bad25eea --- /dev/null +++ b/rust/headless-client/src/uptime/README.md @@ -0,0 +1 @@ +Manually vendored from `uptime_lib` 0.3.0, https://github.com/itchyny/uptime-rs/tree/e6e31f4aa69b057d0610c20f8f2b5f8f0724decb diff --git a/rust/headless-client/src/uptime/mod.rs b/rust/headless-client/src/uptime/mod.rs new file mode 100644 index 000000000..8d848e1af --- /dev/null +++ b/rust/headless-client/src/uptime/mod.rs @@ -0,0 +1,54 @@ +// Manually vendored from https://github.com/itchyny/uptime-rs/blob/e6e31f4aa69b057d0610c20f8f2b5f8f0724decb/src/lib.rs and https://github.com/itchyny/uptime-rs/blob/e6e31f4aa69b057d0610c20f8f2b5f8f0724decb/tests/lib.rs + +/* +The MIT License (MIT) + +Copyright (c) 2017-2023 itchyny + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +use std::time::Duration; + +#[cfg(target_os = "linux")] +pub fn get() -> Option { + let mut info: libc::sysinfo = unsafe { std::mem::zeroed() }; + let ret = unsafe { libc::sysinfo(&mut info) }; + if ret == 0 { + Some(Duration::from_secs(info.uptime as u64)) + } else { + None + } +} + +#[cfg(target_os = "windows")] +// `Result` is needed to match other platforms' signatures +#[allow(clippy::unnecessary_wraps)] +pub fn get() -> Option { + let ret: u64 = unsafe { windows::Win32::System::SystemInformation::GetTickCount64() }; + Some(Duration::from_millis(ret)) +} + +#[cfg(test)] +mod tests { + #[test] + fn test_uptime_get() { + assert!(super::get().is_some()); + } +}