From e0ab2557300ab01354433ab0e138bce163750037 Mon Sep 17 00:00:00 2001 From: Chocolate Pie <106949016+chocolate-pie@users.noreply.github.com> Date: Sun, 14 Apr 2024 20:00:59 +0900 Subject: [PATCH 1/7] chore: Add support for retrieving system metrics --- .cargo/config.toml | 14 +- .npmignore | 13 - .nvmrc | 1 - .zed/settings.json | 20 + Cargo.toml | 7 + Cross.toml | 6 + Makefile.toml | 107 ++++ build.rs | 2 +- crates/slacc-system-metrics/Cargo.toml | 34 + crates/slacc-system-metrics/build.rs | 5 + crates/slacc-system-metrics/src/freebsd.rs | 157 +++++ crates/slacc-system-metrics/src/imp.rs | 300 +++++++++ crates/slacc-system-metrics/src/lib.rs | 74 +++ crates/slacc-system-metrics/src/linux.rs | 150 +++++ crates/slacc-system-metrics/src/macos.rs | 344 ++++++++++ crates/slacc-system-metrics/src/main.rs | 64 ++ crates/slacc-system-metrics/src/windows.rs | 116 ++++ index.d.ts | 33 + index.js | 55 +- package.json | 9 +- patches/fix-build-failed-on-freebsd.patch | 18 + patches/systeminformation+5.22.0.patch | 18 + pnpm-lock.yaml | 711 ++++++++++++--------- rustfmt.toml | 2 - src/aho_corasick.rs | 26 +- src/lib.rs | 1 + src/zip.rs | 66 +- 27 files changed, 1986 insertions(+), 367 deletions(-) delete mode 100644 .npmignore delete mode 100644 .nvmrc create mode 100644 .zed/settings.json create mode 100644 Cross.toml create mode 100644 Makefile.toml create mode 100644 crates/slacc-system-metrics/Cargo.toml create mode 100644 crates/slacc-system-metrics/build.rs create mode 100644 crates/slacc-system-metrics/src/freebsd.rs create mode 100644 crates/slacc-system-metrics/src/imp.rs create mode 100644 crates/slacc-system-metrics/src/lib.rs create mode 100644 crates/slacc-system-metrics/src/linux.rs create mode 100644 crates/slacc-system-metrics/src/macos.rs create mode 100644 crates/slacc-system-metrics/src/main.rs create mode 100644 crates/slacc-system-metrics/src/windows.rs create mode 100644 patches/fix-build-failed-on-freebsd.patch create mode 100644 patches/systeminformation+5.22.0.patch delete mode 100644 rustfmt.toml diff --git a/.cargo/config.toml b/.cargo/config.toml index 7ede30e..059562d 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,3 +1,15 @@ +[unstable] +unstable-options = true +build-std = ["std", "core", "alloc"] + +[build] +target = [ + "aarch64-apple-darwin", + "x86_64-pc-windows-gnu", + "x86_64-unknown-freebsd", + "aarch64-unknown-linux-gnu", +] + [target.aarch64-unknown-linux-musl] linker = "aarch64-linux-musl-gcc" -rustflags = ["-C", "target-feature=-crt-static"] \ No newline at end of file +rustflags = ["-C", "target-feature=-crt-static"] diff --git a/.npmignore b/.npmignore deleted file mode 100644 index ec144db..0000000 --- a/.npmignore +++ /dev/null @@ -1,13 +0,0 @@ -target -Cargo.lock -.cargo -.github -npm -.eslintrc -.prettierignore -rustfmt.toml -yarn.lock -*.node -.yarn -__test__ -renovate.json diff --git a/.nvmrc b/.nvmrc deleted file mode 100644 index 3c03207..0000000 --- a/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -18 diff --git a/.zed/settings.json b/.zed/settings.json new file mode 100644 index 0000000..82b3ddb --- /dev/null +++ b/.zed/settings.json @@ -0,0 +1,20 @@ +// Folder-specific settings +// +// For a full list of overridable settings, and general information on folder-specific settings, +// see the documentation: https://zed.dev/docs/configuring-zed#folder-specific-settings +{ + "lsp": { + "rust-analyzer": { + "initialization_settings": { + "check": { + "targets": [ + "aarch64-apple-darwin", + "x86_64-pc-windows-gnu", + "aarch64-unknown-linux-gnu" + ] + }, + "cargo": { "target": null } + } + } + } +} diff --git a/Cargo.toml b/Cargo.toml index 10ad4ef..6fb52c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,12 +6,19 @@ version = "0.0.10" [lib] crate-type = ["cdylib"] +[workspace] +members = [".", "crates/*"] + [dependencies] aho-corasick = "1.0.1" # Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix napi = { version = "2.12.0", default-features = false, features = ["napi4"] } napi-derive = "2.12.2" zip = { version = "0.6.4" } +slacc-system-metrics = { version = "0.0.10", path = "./crates/slacc-system-metrics", features = [ + "napi", + "nonblocking", +] } [build-dependencies] napi-build = "2.0.1" diff --git a/Cross.toml b/Cross.toml new file mode 100644 index 0000000..92eb664 --- /dev/null +++ b/Cross.toml @@ -0,0 +1,6 @@ +[target.x86_64-unknown-freebsd] +image = "x/x86_64-unknown-freebsd-cross:latest" + +[target.aarch64-unknown-freebsd] +build-std = true +image = "x/aarch64-unknown-freebsd-cross:latest" diff --git a/Makefile.toml b/Makefile.toml new file mode 100644 index 0000000..5ebe1c9 --- /dev/null +++ b/Makefile.toml @@ -0,0 +1,107 @@ +[tasks.build-darwin] +command = "cargo" +args = [ + "build", + "--bins", + "--package=slacc-system-metrics", + "--target=aarch64-apple-darwin", +] + +[tasks.build-windows] +command = "cargo" +args = [ + "build", + "--bins", + "--package=slacc-system-metrics", + "--target=x86_64-pc-windows-gnu", +] + +[tasks.build-linux] +command = "cargo" +args = [ + "build", + "--bins", + "--package=slacc-system-metrics", + "--target=aarch64-unknown-linux-gnu", +] + +[tasks.build-freebsd-amd] +command = "cross" +env = { CROSS_CONTAINER_OPTS = "--platform linux/amd64" } +args = [ + "build", + "--bins", + "--package=slacc-system-metrics", + "--target=x86_64-unknown-freebsd", +] + +[tasks.build-freebsd-arm] +command = "cross" +env = { CROSS_CONTAINER_OPTS = "--platform linux/amd64" } +args = [ + "build", + "--bins", + "--package=slacc-system-metrics", + "--target=aarch64-unknown-freebsd", +] + +[tasks.build-darwin-napi] +command = "napi" +args = ["build", "--platform", "--release", "--target=aarch64-apple-darwin"] + +[tasks.build-windows-napi] +command = "napi" +args = ["build", "--platform", "--release", "--target=x86_64-pc-windows-gnu"] + +[tasks.build-windows-msvc-napi] +env = { CARGO = "cargo-xwin" } +command = "napi" +args = ["build", "--platform", "--release", "--target=x86_64-pc-windows-msvc"] + +[tasks.build-linux-napi] +command = "napi" +args = [ + "build", + "--platform", + "--release", + "--target=aarch64-unknown-linux-gnu", +] + +[tasks.build-freebsd-napi-amd] +command = "napi" +env = { CROSS_CONTAINER_OPTS = "--platform linux/amd64", CARGO = "cross" } +args = ["build", "--platform", "--release", "--target=x86_64-unknown-freebsd"] + +[tasks.build-freebsd-napi-arm] +command = "napi" +env = { CROSS_CONTAINER_OPTS = "--platform linux/amd64", CARGO = "cross" } +args = ["build", "--platform", "--release", "--target=aarch64-unknown-freebsd"] + +[tasks.build-napi] +clear = true +command = "cargo" +args = ["check"] +dependencies = [ + "clean", + "build-linux-napi", + "build-darwin-napi", + "build-windows-msvc-napi", + "build-freebsd-napi-amd", + "build-freebsd-napi-arm", +] + +[tasks.build] +clear = true +command = "cargo" +args = ["check"] +dependencies = [ + "clean", + "build-linux", + "build-darwin", + "build-windows", + "build-freebsd-amd", + "build-freebsd-arm", +] + +[config] +default_to_workspace = false diff --git a/build.rs b/build.rs index 1f866b6..9fc2367 100644 --- a/build.rs +++ b/build.rs @@ -1,5 +1,5 @@ extern crate napi_build; fn main() { - napi_build::setup(); + napi_build::setup(); } diff --git a/crates/slacc-system-metrics/Cargo.toml b/crates/slacc-system-metrics/Cargo.toml new file mode 100644 index 0000000..168da41 --- /dev/null +++ b/crates/slacc-system-metrics/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "slacc-system-metrics" +version = "0.0.10" +edition = "2021" + +[dependencies] +num = "0.4.1" +napi = { version = "2.12.2", default-features = false, optional = true } +napi-derive = { version = "2.12.2", optional = true } +clap = { version = "4.5.0", features = ["derive"] } +core-foundation-sys = "0.8.6" +errno = "0.3.8" +libc = "0.2" +thiserror = "1.0.56" +miette = { version = "7.1.0", features = ["fancy"] } + +[features] +napi = ["napi/napi4", "napi-derive"] +nonblocking = ["napi"] + +[target.'cfg(windows)'.dependencies] +windows = { version = "0.54.0", features = [ + "Win32_Security", + "Win32_System_IO", + "Win32_Foundation", + "Win32_System_Ioctl", + "Win32_Storage_FileSystem", + "Win32_NetworkManagement_Ndis", + "Win32_NetworkManagement_IpHelper", +] } + +[[bin]] +name = "slacc-system-metrics" +path = "src/main.rs" diff --git a/crates/slacc-system-metrics/build.rs b/crates/slacc-system-metrics/build.rs new file mode 100644 index 0000000..996632b --- /dev/null +++ b/crates/slacc-system-metrics/build.rs @@ -0,0 +1,5 @@ +fn main() { + if std::env::var("TARGET").unwrap().contains("darwin") { + println!("cargo:rustc-link-lib=framework=IOKit"); + } +} diff --git a/crates/slacc-system-metrics/src/freebsd.rs b/crates/slacc-system-metrics/src/freebsd.rs new file mode 100644 index 0000000..f84120c --- /dev/null +++ b/crates/slacc-system-metrics/src/freebsd.rs @@ -0,0 +1,157 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright (c) 2024 Misskey and chocolate-pie */ + +use crate::{ErrnoExt, SlaccStatsError}; +use libc::devstat_trans_flags; + +// https://github.com/ziglang/zig/blob/13a9d94a8038727469cf11b72273ce4ea6d89faa/lib/std/Target.zig#L2489-L2502 +// https://github.com/ziglang/zig/blob/13a9d94a8038727469cf11b72273ce4ea6d89faa/lib/std/Target.zig#L2226-L2276 +// https://github.com/llvm/llvm-project/blob/7ac7d418ac2b16fd44789dcf48e2b5d73de3e715/clang/lib/Basic/Targets/X86.h#L444-L445 +// https://github.com/llvm/llvm-project/blob/7ac7d418ac2b16fd44789dcf48e2b5d73de3e715/clang/lib/Basic/Targets/X86.h#L724-L725 +// https://github.com/llvm/llvm-project/blob/7ac7d418ac2b16fd44789dcf48e2b5d73de3e715/clang/lib/Basic/Targets/AArch64.cpp#L161 +#[repr(C, align(16))] +#[allow(non_camel_case_types)] +pub(crate) struct f128([u8; 16]); + +#[repr(C)] +#[allow(non_camel_case_types)] +pub(crate) struct statinfo { + cp_time: [::libc::c_long; 5], + tk_nin: ::libc::c_long, + tk_nout: ::libc::c_long, + dinfo: *mut ::libc::devinfo, + snap_time: f128, +} + +#[derive(Debug, Clone)] +pub(crate) struct DiskInformation { + pub(crate) read_count: u64, + pub(crate) write_count: u64, +} + +#[derive(Debug, Clone)] +pub(crate) struct NetworkInformation { + pub(crate) read_bytes: u64, + pub(crate) write_bytes: u64, +} + +#[derive(Debug, Clone)] +pub(crate) struct MemoryInformation { + pub(crate) used_count: u64, + pub(crate) total_count: u64, + pub(crate) active_count: u64, +} + +macro_rules! sysctlbyname { + ($system: literal, $output: ident, $ty: ty) => {{ + let command = ::std::ffi::CString::new($system).unwrap(); + libc::sysctlbyname( + command.as_ptr(), + &raw mut $output as *mut ::libc::c_void, + &mut std::mem::size_of::<$ty>(), + std::ptr::null_mut(), + 0, + ) + }}; +} + +#[link(name = "devstat")] +extern "C" { + pub(crate) static devstat_errbuf: [::libc::c_char; 2048]; + pub(crate) fn devstat_getdevs(kd: *mut ::libc::kvm_t, stats: *mut statinfo) -> ::libc::c_int; +} + +pub(crate) unsafe fn get_disk_io() -> Result { + let mut read_total: u64 = 0; + let mut write_total: u64 = 0; + let mut devinfo = std::mem::zeroed::<::libc::devinfo>(); + let mut statistic = std::mem::zeroed::(); + statistic.dinfo = &mut devinfo; + devstat_getdevs(std::ptr::null_mut(), &mut statistic) + .into_error_with(|input| input >= 0) + .map_err(|_| SlaccStatsError::from_ptr(devstat_errbuf.as_ptr()))?; + let devices = std::slice::from_raw_parts(devinfo.devices, devinfo.numdevs as _); + for device in devices { + let read_count = device.operations[devstat_trans_flags::DEVSTAT_READ as usize]; + let write_count = device.operations[devstat_trans_flags::DEVSTAT_WRITE as usize]; + read_total = read_total.saturating_add(read_count); + write_total = write_total.saturating_add(write_count); + } + libc::free(devinfo.mem_ptr as *mut _); + Ok(DiskInformation { + read_count: read_total, + write_count: write_total, + }) +} + +pub(crate) unsafe fn get_network_info() -> Result { + let mut interface_count: ::libc::c_int = 0; + let mut read_total: u64 = 0; + let mut write_total: u64 = 0; + let command = [ + libc::CTL_NET, + libc::PF_LINK, + libc::NETLINK_GENERIC, + libc::IFMIB_SYSTEM, + libc::IFMIB_IFCOUNT, + ]; + + libc::sysctl( + command.as_ptr(), + command.len() as ::libc::c_uint, + &raw mut interface_count as *mut ::libc::c_void, + &mut std::mem::size_of::<::libc::c_int>(), + std::ptr::null_mut(), + 0, + ) + .into_errno()?; + + for index in 1..=interface_count { + let mut data = std::mem::zeroed::<::libc::ifmibdata>(); + let command = [ + libc::CTL_NET, + libc::PF_LINK, + libc::NETLINK_GENERIC, + libc::IFMIB_IFDATA, + index, + libc::IFDATA_GENERAL, + ]; + libc::sysctl( + command.as_ptr(), + command.len() as ::libc::c_uint, + &raw mut data as *mut ::libc::c_void, + &mut std::mem::size_of::<::libc::ifmibdata>(), + std::ptr::null_mut(), + 0, + ) + .into_errno()?; + let read_count = data.ifmd_data.ifi_ibytes; + let write_count = data.ifmd_data.ifi_obytes; + read_total = read_total.saturating_add(read_count); + write_total = write_total.saturating_add(write_count); + } + + Ok(NetworkInformation { + read_bytes: read_total, + write_bytes: write_total, + }) +} + +pub(crate) unsafe fn get_memory_info() -> Result { + let mut page_size: u64 = 0; + let mut free_memory: u64 = 0; + let mut total_memory: u64 = 0; + let mut active_memory: u64 = 0; + sysctlbyname!("hw.realmem", total_memory, u64).into_errno()?; + sysctlbyname!("vm.stats.vm.v_page_size", page_size, u64).into_errno()?; + sysctlbyname!("vm.stats.vm.v_free_count", free_memory, u64).into_errno()?; + sysctlbyname!("vm.stats.vm.v_active_count", active_memory, u64).into_errno()?; + let free_memory = free_memory.saturating_mul(page_size); + let active_memory = active_memory.saturating_mul(page_size); + let used_memory = total_memory.saturating_sub(free_memory); + Ok(MemoryInformation { + used_count: used_memory, + active_count: active_memory, + total_count: total_memory, + }) +} diff --git a/crates/slacc-system-metrics/src/imp.rs b/crates/slacc-system-metrics/src/imp.rs new file mode 100644 index 0000000..72dd1ea --- /dev/null +++ b/crates/slacc-system-metrics/src/imp.rs @@ -0,0 +1,300 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright (c) 2024 Misskey and chocolate-pie */ + +use miette::Diagnostic; +#[cfg(feature = "nonblocking")] +use napi::bindgen_prelude::{ToNapiValue, TypeName}; +#[cfg(feature = "nonblocking")] +use napi::{Error, Task}; +#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "linux"))] +use num::cast::AsPrimitive; +#[cfg(target_os = "freebsd")] +use std::ffi::CStr; +#[cfg(feature = "nonblocking")] +use std::panic::AssertUnwindSafe; +use thiserror::Error; + +#[derive(Debug, Clone, Error, Diagnostic)] +pub enum SlaccStatsError { + #[error("{0} (kind: {1:?})")] + #[diagnostic(code(misskey_stats::raw_error))] + RawError(String, Option), + /// Error was throwned from `windows` crate. + #[cfg(windows)] + #[error(transparent)] + #[diagnostic(code(misskey_stats::windows_error))] + WindowsError(#[from] ::windows::core::Error), + /// Null pointer was returned by external function. + #[error("Null pointer was returned by external function")] + NullPointerReturnedError, + #[error("Operation is not supported on this platform")] + #[diagnostic(code(misskey_stats::not_supported))] + NotSupportedError, + #[diagnostic(code(misskey_stats::specified_key_notfound))] + #[error("Specified key cannot found in this dictionary (provided key: {0})")] + SpecifiedKeyNotFoundError(String), + #[diagnostic(code(misskey_stats::netlink_failed))] + #[error("Something went wrong when retrieving network information")] + NetlinkFailed, + #[diagnostic(code(misskey_stats::try_from_int_error))] + #[error(transparent)] + TryFromIntError(#[from] std::num::TryFromIntError), +} + +impl SlaccStatsError { + #[cfg(target_os = "freebsd")] + pub(crate) unsafe fn from_ptr(pointer: *const ::libc::c_char) -> Self { + let message = CStr::from_ptr(pointer).to_string_lossy().into_owned(); + SlaccStatsError::RawError(message, None) + } +} + +#[cfg(feature = "napi")] +impl From for napi::JsError { + fn from(value: SlaccStatsError) -> Self { + napi::Error::new(napi::Status::GenericFailure, value.to_string()).into() + } +} + +#[cfg(feature = "nonblocking")] +pub trait AsyncTaskValue: Send + ToNapiValue + TypeName + 'static {} +#[cfg(feature = "nonblocking")] +impl AsyncTaskValue for T {} +#[cfg(feature = "nonblocking")] +pub struct AsyncTask(Box Result>); + +#[cfg(feature = "nonblocking")] +impl AsyncTask { + pub(crate) fn new(inner: impl Send + Fn() -> Result + 'static) -> Self { + Self(Box::new(inner)) + } +} + +#[cfg(feature = "nonblocking")] +impl Task for AsyncTask { + type JsValue = T; + type Output = Result; + + fn compute(&mut self) -> napi::Result { + match std::panic::catch_unwind(AssertUnwindSafe(move || match (self.0)() { + Ok(output) => Ok(output), + Err(error) => Err(napi::Error::from_reason(error.to_string())), + })) { + Ok(output) => Ok(output), + Err(_) => Err(Error::from_reason("Uncaught panic was occurred")), + } + } + + #[inline(always)] + fn resolve(&mut self, _env: napi::Env, output: Self::Output) -> napi::Result { + output + } +} + +#[cfg(feature = "napi")] +type Number = i64; +#[cfg(not(feature = "napi"))] +type Number = u64; + +#[derive(Debug, Clone)] +#[cfg_attr(feature = "napi", napi(object))] +pub struct MemoryInformation { + pub used_count: Number, + pub total_count: Number, + pub active_count: Number, +} + +#[derive(Debug, Clone)] +#[cfg_attr(feature = "napi", napi(object))] +pub struct DiskInformation { + pub read_count: Number, + pub write_count: Number, +} + +#[derive(Debug, Clone)] +#[cfg_attr(feature = "napi", napi(object))] +pub struct NetworkInformation { + pub read_bytes: Number, + pub write_bytes: Number, +} + +#[derive(Debug, Clone)] +#[cfg_attr(feature = "napi", napi(object))] +pub struct DiskSpaceInformation { + pub free_bytes: Number, + pub total_bytes: Number, +} + +#[allow(dead_code)] +#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "linux"))] +pub(crate) trait ErrnoExt: AsPrimitive { + unsafe fn into_errno(self) -> Result<(), SlaccStatsError>; + #[cfg(target_os = "linux")] + unsafe fn into_errno2(self) -> Result; + unsafe fn into_error_with(self, func: impl FnMut(i32) -> bool) -> Result<(), SlaccStatsError>; + unsafe fn into_error_release(self, mut func: impl FnMut()) -> Result<(), SlaccStatsError> { + self.into_errno().inspect_err(|_| { + func(); + }) + } +} + +#[cfg(target_os = "linux")] +pub(crate) trait CheckValidFd: AsPrimitive { + fn valid_fd(self) -> Result; +} + +#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "linux"))] +impl> ErrnoExt for T { + unsafe fn into_errno(self) -> Result<(), SlaccStatsError> { + if self.as_() != 0 { + let raw = errno::errno(); + Err(SlaccStatsError::RawError(raw.to_string(), Some(raw.0))) + } else { + Ok(()) + } + } + + #[cfg(target_os = "linux")] + unsafe fn into_errno2(self) -> Result { + if self.as_() < 0 { + let raw = errno::errno(); + Err(SlaccStatsError::RawError(raw.to_string(), Some(raw.0))) + } else { + Ok(self.as_()) + } + } + + unsafe fn into_error_with( + self, + mut func: impl FnMut(i32) -> bool, + ) -> Result<(), SlaccStatsError> { + if !func(self.as_()) { + let raw = errno::errno(); + Err(SlaccStatsError::RawError(raw.to_string(), Some(raw.0))) + } else { + Ok(()) + } + } +} + +#[cfg(target_os = "linux")] +impl> CheckValidFd for T { + fn valid_fd(self) -> Result { + match self.as_() >= 0 { + true => Ok(self), + false => Err(SlaccStatsError::NetlinkFailed), + } + } +} + +/// Retrieving disk information. +pub(crate) fn get_disk_io() -> Result { + #[cfg(target_os = "macos")] + unsafe { + let statistic = crate::macos::get_disk_io()?; + Ok(DiskInformation { + read_count: statistic.read_count as _, + write_count: statistic.write_count as _, + }) + } + #[cfg(target_os = "windows")] + unsafe { + let statistic = crate::windows::get_disk_io()?; + Ok(DiskInformation { + read_count: statistic.read_count as _, + write_count: statistic.write_count as _, + }) + } + #[cfg(target_os = "freebsd")] + unsafe { + let statistic = crate::freebsd::get_disk_io()?; + Ok(DiskInformation { + read_count: statistic.read_count as _, + write_count: statistic.write_count as _, + }) + } + #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "freebsd")))] + Err(SlaccStatsError::NotSupportedError) +} + +/// Retrieving disk space information. +pub(crate) fn get_disk_space() -> Result { + #[cfg(target_os = "windows")] + unsafe { + let statistic = crate::windows::get_disk_space()?; + Ok(DiskSpaceInformation { + free_bytes: statistic.free_bytes as _, + total_bytes: statistic.total_bytes as _, + }) + } + #[cfg(not(target_os = "windows"))] + Err(SlaccStatsError::NotSupportedError) +} + +/// Retrieving memory information. +pub(crate) fn get_memory_info() -> Result { + #[cfg(target_os = "macos")] + unsafe { + let statistic = crate::macos::get_memory_info()?; + Ok(MemoryInformation { + used_count: statistic.used_count as _, + total_count: statistic.total_count as _, + active_count: statistic.active_count as _, + }) + } + #[cfg(target_os = "freebsd")] + unsafe { + let statistic = crate::freebsd::get_memory_info()?; + Ok(MemoryInformation { + used_count: statistic.used_count as _, + total_count: statistic.total_count as _, + active_count: statistic.active_count as _, + }) + } + #[cfg(not(any(target_os = "macos", target_os = "freebsd")))] + Err(SlaccStatsError::NotSupportedError) +} + +/// Retrieving network information. +pub(crate) fn get_network_info() -> Result { + #[cfg(target_os = "windows")] + unsafe { + let statistic = crate::windows::get_network_info()?; + Ok(NetworkInformation { + read_bytes: statistic.read_bytes as _, + write_bytes: statistic.write_bytes as _, + }) + } + #[cfg(target_os = "macos")] + unsafe { + let statistic = crate::macos::get_network_info()?; + Ok(NetworkInformation { + read_bytes: statistic.read_bytes as _, + write_bytes: statistic.write_bytes as _, + }) + } + #[cfg(target_os = "freebsd")] + unsafe { + let statistic = crate::freebsd::get_network_info()?; + Ok(NetworkInformation { + read_bytes: statistic.read_bytes as _, + write_bytes: statistic.write_bytes as _, + }) + } + #[cfg(target_os = "linux")] + unsafe { + let statistic = crate::linux::get_network_info()?; + Ok(NetworkInformation { + read_bytes: statistic.read_bytes as _, + write_bytes: statistic.write_bytes as _, + }) + } + #[cfg(not(any( + target_os = "windows", + target_os = "macos", + target_os = "freebsd", + target_os = "linux" + )))] + Err(SlaccStatsError::NotSupportedError) +} diff --git a/crates/slacc-system-metrics/src/lib.rs b/crates/slacc-system-metrics/src/lib.rs new file mode 100644 index 0000000..f58dced --- /dev/null +++ b/crates/slacc-system-metrics/src/lib.rs @@ -0,0 +1,74 @@ +#![feature(raw_ref_op)] +#![allow(clippy::unit_arg)] +#![allow(unsafe_op_in_unsafe_fn)] + +#[cfg(feature = "napi")] +#[macro_use] +extern crate napi_derive; +#[cfg(target_os = "freebsd")] +mod freebsd; +mod imp; +#[cfg(target_os = "linux")] +mod linux; +#[cfg(target_os = "macos")] +mod macos; +#[cfg(target_os = "windows")] +mod windows; +pub use imp::*; +#[cfg(feature = "napi")] +pub use napi::bindgen_prelude::AsyncTask; + +/// Retrieving disk information. +#[cfg_attr(feature = "napi", napi)] +#[cfg(feature = "nonblocking")] +pub fn get_disk_io_nonblocking() -> AsyncTask> { + AsyncTask::new(imp::AsyncTask::new(imp::get_disk_io)) +} + +/// Retrieving disk information. +#[cfg_attr(feature = "napi", napi)] +pub fn get_disk_io() -> Result { + crate::imp::get_disk_io() +} + +/// Retrieving disk space information. +#[cfg_attr(feature = "napi", napi)] +#[cfg(feature = "nonblocking")] +pub fn get_disk_space_nonblocking( +) -> AsyncTask> { + AsyncTask::new(imp::AsyncTask::new(imp::get_disk_space)) +} + +/// Retrieving disk space information. +#[cfg_attr(feature = "napi", napi)] +pub fn get_disk_space() -> Result { + crate::imp::get_disk_space() +} + +/// Retrieving memory information. +#[cfg_attr(feature = "napi", napi)] +#[cfg(feature = "nonblocking")] +pub fn get_memory_info_nonblocking() -> AsyncTask> +{ + AsyncTask::new(imp::AsyncTask::new(imp::get_memory_info)) +} + +/// Retrieving memory information. +#[cfg_attr(feature = "napi", napi)] +pub fn get_memory_info() -> Result { + crate::imp::get_memory_info() +} + +/// Retrieving network information. +#[cfg_attr(feature = "napi", napi)] +#[cfg(feature = "nonblocking")] +pub fn get_network_info_nonblocking( +) -> AsyncTask> { + AsyncTask::new(imp::AsyncTask::new(imp::get_network_info)) +} + +/// Retrieving network information. +#[cfg_attr(feature = "napi", napi)] +pub fn get_network_info() -> Result { + crate::imp::get_network_info() +} diff --git a/crates/slacc-system-metrics/src/linux.rs b/crates/slacc-system-metrics/src/linux.rs new file mode 100644 index 0000000..3801efa --- /dev/null +++ b/crates/slacc-system-metrics/src/linux.rs @@ -0,0 +1,150 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright (c) 2024 Misskey and chocolate-pie */ + +use crate::{CheckValidFd, ErrnoExt, SlaccStatsError}; +use libc::{MSG_DONTWAIT, NETLINK_ROUTE, PF_NETLINK, SOCK_CLOEXEC, SOCK_RAW}; +use std::os::fd::{AsRawFd, FromRawFd, OwnedFd}; +use std::os::raw::c_ulonglong; + +#[repr(C)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct rtnl_link_stats64 { + rx_packets: c_ulonglong, + tx_packets: c_ulonglong, + rx_bytes: c_ulonglong, + tx_bytes: c_ulonglong, + rx_errors: c_ulonglong, + tx_errors: c_ulonglong, + rx_dropped: c_ulonglong, + tx_dropped: c_ulonglong, + multicast: c_ulonglong, + collisions: c_ulonglong, + rx_length_errors: c_ulonglong, + rx_over_errors: c_ulonglong, + rx_crc_errors: c_ulonglong, + rx_frame_errors: c_ulonglong, + rx_fifo_errors: c_ulonglong, + rx_missed_errors: c_ulonglong, + tx_aborted_errors: c_ulonglong, + tx_carrier_errors: c_ulonglong, + tx_fifo_errors: c_ulonglong, + tx_heartbeat_errors: c_ulonglong, + tx_window_errors: c_ulonglong, + rx_compressed: c_ulonglong, + tx_compressed: c_ulonglong, + rx_nohandler: c_ulonglong, +} + +#[derive(Debug, Clone, Default)] +pub(crate) struct NetworkInformation { + pub(crate) read_bytes: u64, + pub(crate) write_bytes: u64, +} + +#[repr(C)] +#[allow(non_camel_case_types)] +struct rtgenmsg { + rtgen_family: libc::c_uchar, +} + +#[repr(C)] +#[allow(non_camel_case_types)] +struct rtattr { + rta_len: libc::c_ushort, + rta_type: libc::c_ushort, +} + +#[repr(C)] +#[allow(non_camel_case_types)] +struct ifinfomsg { + ifi_family: libc::c_uchar, + __ifi_pad: libc::c_uchar, + ifi_type: libc::c_ushort, + ifi_index: libc::c_int, + ifi_flags: libc::c_uint, + ifi_change: libc::c_uint, +} + +#[repr(C)] +struct NetlinkRequest { + message: libc::nlmsghdr, + generation: rtgenmsg, +} + +pub(crate) unsafe fn get_network_info() -> Result { + let mut buffer = Vec::::with_capacity(8192 /* NLMSG_GOODSIZE */); + let socket = libc::socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE).valid_fd()?; + let socket = OwnedFd::from_raw_fd(socket); + let mut request = std::mem::zeroed::(); + request.message.nlmsg_len = std::mem::size_of::() as u32; + request.message.nlmsg_type = libc::RTM_GETLINK; + request.message.nlmsg_flags = (libc::NLM_F_DUMP | libc::NLM_F_REQUEST) as u16; + request.generation.rtgen_family = libc::AF_UNSPEC as u8; + let socket_fd = socket.as_raw_fd(); + let request_ptr = &raw const request as *const ::libc::c_void; + let request_size = std::mem::size_of::(); + libc::send(socket_fd, request_ptr, request_size, 0).into_errno2()?; + let mut network = NetworkInformation::default(); + + loop { + let mut offset: i32 = 0; + let mut message_ptr = buffer.as_ptr(); + let received = libc::recv( + socket_fd, + buffer.as_ptr() as *mut ::libc::c_void, + 8192, /* NLMSG_GOODSIZE */ + MSG_DONTWAIT, + ) + .into_errno2()?; + buffer.set_len(received.try_into()?); + while (received - offset) >= std::mem::size_of::() as i32 { + let message = &*(message_ptr as *const ::libc::nlmsghdr); + match message { + message if (message.nlmsg_flags & libc::NLM_F_DUMP_INTR as u16) != 0 => { + return Err(SlaccStatsError::NetlinkFailed) + } + message if message.nlmsg_type == libc::NLMSG_DONE as u16 => return Ok(network), + message if message.nlmsg_type == libc::NLMSG_ERROR as u16 => { + return Err(SlaccStatsError::NetlinkFailed) + } + message if offset + message.nlmsg_len as i32 > received => { + return Err(SlaccStatsError::NetlinkFailed) + } + message if message.nlmsg_type == libc::RTM_NEWLINK => { + let message_offset = std::mem::size_of::(); + let ifinfo_size = std::mem::size_of::(); + let rtattr_size = std::mem::size_of::(); + let mut message_offset = message_offset + ((ifinfo_size + 3) & !3); + while message_offset + rtattr_size <= message.nlmsg_len as usize { + let rtattr_message = message_ptr.add(message_offset); + let rtattr_message = &*(rtattr_message as *const rtattr); + let rtattr_needs_offset = message_offset + rtattr_message.rta_len as usize; + if rtattr_needs_offset <= message.nlmsg_len as usize { + if rtattr_message.rta_type == libc::IFLA_STATS64 { + let rta_data_offset = message_offset + rtattr_size; + let rta_data_message = message_ptr.add(rta_data_offset); + let rta_data_length = rtattr_message.rta_len as usize - rtattr_size; + let mut statistics = std::mem::zeroed::(); + let rta_data_length = + std::mem::size_of::().min(rta_data_length); + std::ptr::copy_nonoverlapping::( + rta_data_message, + &raw mut statistics as *mut u8, + rta_data_length, + ); + network.read_bytes += statistics.rx_bytes; + network.write_bytes += statistics.tx_bytes; + } + } + message_offset += ((rtattr_message.rta_len as usize) + 3) & !3; + } + } + _ => {} + } + let message_length = (message.nlmsg_len + 3) & !3; + offset += message_length as i32; + message_ptr = message_ptr.wrapping_offset(message_length as isize); + } + } +} diff --git a/crates/slacc-system-metrics/src/macos.rs b/crates/slacc-system-metrics/src/macos.rs new file mode 100644 index 0000000..eeeaf35 --- /dev/null +++ b/crates/slacc-system-metrics/src/macos.rs @@ -0,0 +1,344 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright (c) 2024 Misskey and chocolate-pie */ + +use core_foundation_sys::base::{kCFAllocatorDefault, kCFAllocatorNull, CFAllocatorRef, CFRelease}; +use core_foundation_sys::dictionary::{ + CFDictionaryGetValueIfPresent, CFDictionaryRef, CFMutableDictionaryRef, +}; +use core_foundation_sys::number::{kCFNumberSInt64Type, CFNumberGetValue, CFNumberRef}; +use core_foundation_sys::string::{ + kCFStringEncodingUTF8, CFStringCreateWithCStringNoCopy, CFStringRef, +}; +use std::ffi::CStr; +use std::marker::PhantomData; +use std::mem::MaybeUninit; + +use crate::{ErrnoExt, SlaccStatsError}; + +// Based on +// https://github.com/apple-oss-distributions/IOStorageFamily/blob/0993ad6b36e85774fb0bc280e7d795f6dcbc641c/IOMedia.h#L41 +// https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/iokit/IOKit/IOKitKeys.h#L49 +// https://github.com/apple-oss-distributions/IOStorageFamily/blob/0993ad6b36e85774fb0bc280e7d795f6dcbc641c/IOBlockStorageDriver.h#L35-L222 +#[rustfmt::skip] +#[allow(non_upper_case_globals, dead_code)] +mod constants { + const fn create_cstring(input: &[u8]) -> &std::ffi::CStr { + unsafe { std::ffi::CStr::from_bytes_with_nul_unchecked(input) } + } + pub(crate) const kIOMediaClass: &std::ffi::CStr = create_cstring(b"IOMedia\0"); + pub(crate) const kIOServicePlane: &std::ffi::CStr = create_cstring(b"IOService\0"); + pub(crate) const kIOBlockStorageDriverClass: &std::ffi::CStr = create_cstring(b"IOBlockStorageDriver\0"); + pub(crate) const kIOBlockStorageDriverStatisticsKey: &std::ffi::CStr = create_cstring(b"Statistics\0"); + pub(crate) const kIOBlockStorageDriverStatisticsBytesReadKey: &std::ffi::CStr = create_cstring(b"Bytes (Read)\0"); + pub(crate) const kIOBlockStorageDriverStatisticsBytesWrittenKey: &std::ffi::CStr = create_cstring(b"Bytes (Write)\0"); + pub(crate) const kIOBlockStorageDriverStatisticsReadErrorsKey: &std::ffi::CStr = create_cstring(b"Errors (Read)\0"); + pub(crate) const kIOBlockStorageDriverStatisticsWriteErrorsKey: &std::ffi::CStr = create_cstring(b"Errors (Write)\0"); + pub(crate) const kIOBlockStorageDriverStatisticsLatentReadTimeKey: &std::ffi::CStr = create_cstring(b"Latency Time (Read)\0"); + pub(crate) const kIOBlockStorageDriverStatisticsLatentWriteTimeKey: &std::ffi::CStr = create_cstring(b"Latency Time (Write)\0"); + pub(crate) const kIOBlockStorageDriverStatisticsReadsKey: &std::ffi::CStr = create_cstring(b"Operations (Read)\0"); + pub(crate) const kIOBlockStorageDriverStatisticsWritesKey: &std::ffi::CStr = create_cstring(b"Operations (Write)\0"); + pub(crate) const kIOBlockStorageDriverStatisticsReadRetriesKey: &std::ffi::CStr = create_cstring(b"Retries (Read)\0"); + pub(crate) const kIOBlockStorageDriverStatisticsWriteRetriesKey: &std::ffi::CStr = create_cstring(b"Retries (Write)\0"); + pub(crate) const kIOBlockStorageDriverStatisticsTotalReadTimeKey: &std::ffi::CStr = create_cstring(b"Total Time (Read)\0"); + pub(crate) const kIOBlockStorageDriverStatisticsTotalWriteTimeKey: &std::ffi::CStr = create_cstring(b"Total Time (Write)\0"); +} + +#[link(name = "IOKit", kind = "framework")] +extern "C" { + pub(crate) static kIOMasterPortDefault: ::libc::c_uint; + pub(crate) fn IOServiceMatching(name: *const ::libc::c_char) -> CFMutableDictionaryRef; + pub(crate) fn IOServiceGetMatchingServices( + master: ::libc::c_uint, + dictionary: CFDictionaryRef, + existing: *mut ::libc::c_uint, + ) -> ::libc::c_int; + pub(crate) fn IORegistryEntryGetParentEntry( + entry: ::libc::c_uint, + plane: *const ::libc::c_char, + parent: *mut ::libc::c_uint, + ) -> ::libc::c_int; + pub(crate) fn IORegistryEntryCreateCFProperties( + entry: ::libc::c_uint, + properties: *mut CFMutableDictionaryRef, + allocator: CFAllocatorRef, + options: ::libc::c_uint, + ) -> ::libc::c_int; + pub(crate) fn IOObjectConformsTo( + object: ::libc::c_uint, + name: *const ::libc::c_char, + ) -> ::libc::c_uint; + pub(crate) fn IOObjectRelease(object: ::libc::c_uint) -> ::libc::c_int; + pub(crate) fn IOIteratorNext(iterator: ::libc::c_uint) -> ::libc::c_uint; +} + +#[derive(Debug, Clone)] +pub(crate) struct DiskInformation { + pub(crate) read_count: i64, + pub(crate) write_count: i64, +} + +#[derive(Debug, Clone)] +pub(crate) struct NetworkInformation { + pub(crate) read_bytes: u64, + pub(crate) write_bytes: u64, +} + +#[derive(Debug, Clone, Default)] +pub(crate) struct MemoryInformation { + pub(crate) used_count: u64, + pub(crate) total_count: u64, + pub(crate) active_count: u64, +} + +#[derive(Debug)] +pub(crate) struct CFString<'a> { + inner: CFStringRef, + phantom: PhantomData<&'a CStr>, +} + +impl<'a> TryFrom<&'a CStr> for CFString<'a> { + type Error = SlaccStatsError; + + fn try_from(value: &'a CStr) -> Result { + unsafe { + match CFStringCreateWithCStringNoCopy( + kCFAllocatorDefault, + value.as_ptr(), + kCFStringEncodingUTF8, + kCFAllocatorNull, + ) { + output if !output.is_null() => Ok(Self { + inner: output, + phantom: PhantomData, + }), + _ => Err(SlaccStatsError::NullPointerReturnedError), + } + } + } +} + +impl<'a> Drop for CFString<'a> { + fn drop(&mut self) { + unsafe { CFRelease(self.inner as *const ::libc::c_void) }; + } +} + +macro_rules! release_io { + ($($item: expr),+) => {{ + $(IOObjectRelease($item);)+ + }}; + ($($item: expr),+ ; $($cfitem: expr),+) => {{ + $(IOObjectRelease($item);)+ + $(CFRelease($cfitem);)+ + }} +} + +pub(crate) unsafe fn get_disk_io() -> Result { + unsafe fn take_value_as_dictionary_from_dictionary( + key: &CStr, + dictionary: CFDictionaryRef, + ) -> Result { + let dictionary_key = CFString::try_from(key)?; + let mut dictionary_value = MaybeUninit::::uninit(); + + if CFDictionaryGetValueIfPresent( + dictionary, + dictionary_key.inner as *const ::libc::c_void, + dictionary_value.as_mut_ptr() as *mut *const ::libc::c_void, + ) == 0 + { + Err(SlaccStatsError::SpecifiedKeyNotFoundError( + key.to_string_lossy().into_owned(), + )) + } else { + Ok(dictionary_value.assume_init()) + } + } + + unsafe fn take_value_as_number_from_dictionary( + key: &CStr, + dictionary: CFDictionaryRef, + ) -> Result { + let dictionary_key = CFString::try_from(key)?; + let mut dictionary_value = MaybeUninit::::uninit(); + + if CFDictionaryGetValueIfPresent( + dictionary, + dictionary_key.inner as *const ::libc::c_void, + dictionary_value.as_mut_ptr() as *mut *const ::libc::c_void, + ) == 0 + { + Err(SlaccStatsError::SpecifiedKeyNotFoundError( + key.to_string_lossy().into_owned(), + )) + } else { + let mut number: i64 = 0; + let cf_number = dictionary_value.assume_init(); + CFNumberGetValue( + cf_number, + kCFNumberSInt64Type, + &raw mut number as *mut ::libc::c_void, + ); + Ok(number) + } + } + + let storage_driver_klass = constants::kIOBlockStorageDriverClass.as_ptr(); + let statistics_key = constants::kIOBlockStorageDriverStatisticsKey; + let reads_key = constants::kIOBlockStorageDriverStatisticsReadsKey; + let write_key = constants::kIOBlockStorageDriverStatisticsWritesKey; + let mut iterator = MaybeUninit::<::libc::c_uint>::uninit(); + let keyword_dict = IOServiceMatching(constants::kIOMediaClass.as_ptr()); + IOServiceGetMatchingServices(kIOMasterPortDefault, keyword_dict, iterator.as_mut_ptr()) + .into_errno()?; + let iterator = iterator.assume_init(); + let mut item = IOIteratorNext(iterator); + let mut read_total: i64 = 0; + let mut write_total: i64 = 0; + + while item != 0 { + let mut parent: ::libc::c_uint = 0; + let mut props_dictionary = MaybeUninit::::uninit(); + IORegistryEntryGetParentEntry(item, constants::kIOServicePlane.as_ptr(), &mut parent) + .into_error_release(|| release_io!(item, iterator))?; + + if IOObjectConformsTo(parent, storage_driver_klass) == 0 { + IOObjectRelease(parent); + IOObjectRelease(item); + item = IOIteratorNext(iterator); + continue; + } + + IORegistryEntryCreateCFProperties( + parent, + props_dictionary.as_mut_ptr(), + kCFAllocatorDefault, + 0, + ) + .into_error_release(|| release_io!(parent, item, iterator))?; + + let props_dictionary = props_dictionary.assume_init(); + let statistics_dictionary = + take_value_as_dictionary_from_dictionary(statistics_key, props_dictionary) + .inspect_err(|_| release_io!(parent,item,iterator;props_dictionary as *const _))?; + let read_count = take_value_as_number_from_dictionary(reads_key, statistics_dictionary) + .inspect_err(|_| release_io!(parent,item,iterator;props_dictionary as *const _))?; + let write_count = take_value_as_number_from_dictionary(write_key, statistics_dictionary) + .inspect_err(|_| release_io!(parent,item,iterator;props_dictionary as *const _))?; + + read_total = read_total.saturating_add(read_count); + write_total = write_total.saturating_add(write_count); + + IOObjectRelease(parent); + IOObjectRelease(item); + CFRelease(props_dictionary as *const _ as *const ::libc::c_void); + item = IOIteratorNext(iterator); + } + + IOObjectRelease(iterator); + Ok(DiskInformation { + read_count: read_total, + write_count: write_total, + }) +} + +pub(crate) unsafe fn get_memory_info() -> Result { + let mut page_size: u64 = 0; + let mut memory_size: u64 = 0; + let mut command = [libc::CTL_HW, libc::HW_PAGESIZE]; + let host_port = libc::mach_host_self(); + let mut statistic = MaybeUninit::<::libc::vm_statistics64>::uninit(); + let mut statistic_count = libc::HOST_VM_INFO64_COUNT; + + libc::host_statistics64( + host_port, + libc::HOST_VM_INFO64, + statistic.as_mut_ptr() as *mut i32, + &mut statistic_count, + ) + .into_errno()?; + + libc::sysctl( + command.as_mut_ptr(), + command.len() as ::libc::c_uint, + &raw mut page_size as *mut ::libc::c_void, + &mut std::mem::size_of::<::libc::c_ulong>(), + std::ptr::null_mut(), + 0, + ) + .into_errno()?; + + command = [libc::CTL_HW, libc::HW_MEMSIZE]; + let statistic = statistic.assume_init(); + + libc::sysctl( + command.as_mut_ptr(), + command.len() as ::libc::c_uint, + &raw mut memory_size as *mut ::libc::c_void, + &mut std::mem::size_of::<::libc::c_ulong>(), + std::ptr::null_mut(), + 0, + ) + .into_errno()?; + + let used_count = statistic + .active_count + .saturating_add(statistic.wire_count) + .saturating_add(statistic.speculative_count) + .saturating_add(statistic.compressor_page_count); + + Ok(MemoryInformation { + total_count: memory_size, + used_count: (used_count as u64).saturating_mul(page_size), + active_count: (statistic.active_count as u64).saturating_mul(page_size), + }) +} + +pub(crate) unsafe fn get_network_info() -> Result { + let mut length: ::libc::size_t = 0; + let mut read_bytes: u64 = 0; + let mut write_bytes: u64 = 0; + let mut command = [libc::CTL_NET, libc::PF_ROUTE, 0, 0, libc::NET_RT_IFLIST2, 0]; + + libc::sysctl( + command.as_mut_ptr(), + command.len() as ::libc::c_uint, + std::ptr::null_mut(), + &mut length, + std::ptr::null_mut(), + 0, + ) + .into_errno()?; + + let mut networks = Vec::with_capacity(length); + + libc::sysctl( + command.as_mut_ptr(), + command.len() as ::libc::c_uint, + networks.as_mut_ptr(), + &mut length, + std::ptr::null_mut(), + 0, + ) + .into_errno()?; + + #[allow(clippy::uninit_vec)] + networks.set_len(length); + let mut networks_addr = networks.as_ptr(); + let limit = networks_addr.add(length); + + while networks_addr < limit { + let network = &*(networks_addr as *const ::libc::if_msghdr); + if network.ifm_type == libc::RTM_IFINFO2 as u8 { + let network = &*(networks_addr as *const ::libc::if_msghdr2); + read_bytes = read_bytes.saturating_add(network.ifm_data.ifi_ibytes); + write_bytes = write_bytes.saturating_add(network.ifm_data.ifi_obytes); + } + networks_addr = networks_addr.offset(network.ifm_msglen as isize); + } + + Ok(NetworkInformation { + read_bytes, + write_bytes, + }) +} diff --git a/crates/slacc-system-metrics/src/main.rs b/crates/slacc-system-metrics/src/main.rs new file mode 100644 index 0000000..0054969 --- /dev/null +++ b/crates/slacc-system-metrics/src/main.rs @@ -0,0 +1,64 @@ +use clap::Parser; +use miette::Result; +use slacc_system_metrics::*; + +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +pub struct MisskeyStatsArguments { + /// Display information about disk. + #[arg(long, default_value_t = false)] + disk_io: bool, + /// Display information about memory. + #[arg(long, default_value_t = false)] + memory_info: bool, + /// Display information about network. + #[arg(long, default_value_t = false)] + network_info: bool, + /// Display information about disk space. + #[arg(long, default_value_t = false)] + disk_space_info: bool, +} + +fn main() -> Result<()> { + let args = MisskeyStatsArguments::parse(); + + if args.disk_io { + let DiskInformation { + read_count, + write_count, + } = get_disk_io()?; + println!("Operations (Read): {}", read_count); + println!("Operations (Write): {}", write_count); + } + + if args.memory_info { + let MemoryInformation { + used_count, + active_count, + total_count, + } = get_memory_info()?; + println!("Memory (Used): {}", used_count); + println!("Memory (Total): {}", total_count); + println!("Memory (Active): {}", active_count); + } + + if args.network_info { + let NetworkInformation { + read_bytes, + write_bytes, + } = get_network_info()?; + println!("Network (Read): {}", read_bytes); + println!("Network (Write): {}", write_bytes); + } + + if args.disk_space_info { + let DiskSpaceInformation { + free_bytes, + total_bytes, + } = get_disk_space()?; + println!("Disk (Free): {}", free_bytes); + println!("Disk (Total): {}", total_bytes); + } + + Ok(()) +} diff --git a/crates/slacc-system-metrics/src/windows.rs b/crates/slacc-system-metrics/src/windows.rs new file mode 100644 index 0000000..5db976d --- /dev/null +++ b/crates/slacc-system-metrics/src/windows.rs @@ -0,0 +1,116 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright (c) 2024 Misskey and chocolate-pie */ + +use crate::SlaccStatsError; +use windows::core::{HSTRING, PCWSTR}; +use windows::Win32::Foundation::CloseHandle; +use windows::Win32::NetworkManagement::IpHelper::{FreeMibTable, GetIfTable2, MIB_IF_TABLE2}; +use windows::Win32::Storage::FileSystem::{ + CreateFileW, GetDiskFreeSpaceExW, FILE_FLAGS_AND_ATTRIBUTES, FILE_SHARE_READ, FILE_SHARE_WRITE, + OPEN_EXISTING, +}; +use windows::Win32::System::Ioctl::{DISK_PERFORMANCE, IOCTL_DISK_PERFORMANCE}; +use windows::Win32::System::IO::DeviceIoControl; + +#[derive(Debug, Clone)] +pub(crate) struct NetworkInformation { + pub(crate) read_bytes: u64, + pub(crate) write_bytes: u64, +} + +#[derive(Debug, Clone)] +pub(crate) struct DiskInformation { + pub(crate) read_count: u64, + pub(crate) write_count: u64, +} + +#[derive(Debug, Clone)] +pub(crate) struct DiskSpaceInformation { + pub(crate) free_bytes: u64, + pub(crate) total_bytes: u64, +} + +pub(crate) unsafe fn get_network_info() -> Result { + let mut table = std::ptr::null_mut::(); + GetIfTable2(&mut table).ok()?; + let tables = std::slice::from_raw_parts((*table).Table.as_ptr(), (*table).NumEntries as usize); + let read_bytes = tables + .iter() + .fold(0u64, |acc, table| acc.saturating_add(table.InOctets)); + let write_bytes = tables + .iter() + .fold(0u64, |acc, table| acc.saturating_add(table.OutOctets)); + FreeMibTable(table as *const ::libc::c_void); + + Ok(NetworkInformation { + read_bytes, + write_bytes, + }) +} + +pub(crate) unsafe fn get_disk_space() -> Result { + let mut free_count: u64 = 0; + let mut total_count: u64 = 0; + GetDiskFreeSpaceExW( + PCWSTR::null(), + None, + Some(&mut total_count), + Some(&mut free_count), + )?; + Ok(DiskSpaceInformation { + free_bytes: free_count, + total_bytes: total_count, + }) +} + +pub(crate) unsafe fn get_disk_io() -> Result { + let mut read_count: u64 = 0; + let mut write_count: u64 = 0; + let mut drive_count = 0; + + loop { + let mut size: u32 = 0; + let mut performance_data = std::mem::zeroed::(); + let device_name = format!(r"\\.\PhysicalDrive{}", drive_count); + let device_name = HSTRING::from(device_name); + let device_name_wide = PCWSTR(device_name.as_wide().as_ptr()); + let device = CreateFileW( + device_name_wide, + 0, + FILE_SHARE_READ | FILE_SHARE_WRITE, + None, + OPEN_EXISTING, + FILE_FLAGS_AND_ATTRIBUTES(0), + None, + ); + + let device = match device { + Ok(device) => device, + Err(_) => break, + }; + + DeviceIoControl( + device, + IOCTL_DISK_PERFORMANCE, + None, + 0, + Some(&raw mut performance_data as *mut ::libc::c_void), + std::mem::size_of::() as u32, + Some(&mut size), + None, + ) + .inspect_err(|_| { + let _ = CloseHandle(device); + })?; + + read_count = read_count.saturating_add(performance_data.ReadCount as u64); + write_count = write_count.saturating_add(performance_data.WriteCount as u64); + drive_count += 1; + CloseHandle(device)?; + } + + Ok(DiskInformation { + read_count, + write_count, + }) +} diff --git a/index.d.ts b/index.d.ts index 20ffeb2..e8840be 100644 --- a/index.d.ts +++ b/index.d.ts @@ -3,6 +3,39 @@ /* auto-generated by NAPI-RS */ +export interface MemoryInformation { + usedCount: number + totalCount: number + activeCount: number +} +export interface DiskInformation { + readCount: number + writeCount: number +} +export interface NetworkInformation { + readBytes: number + writeBytes: number +} +export interface DiskSpaceInformation { + freeBytes: number + totalBytes: number +} +/** Retrieving disk information. */ +export function getDiskIoNonblocking(): Promise +/** Retrieving disk information. */ +export function getDiskIo(): DiskInformation +/** Retrieving disk space information. */ +export function getDiskSpaceNonblocking(): Promise +/** Retrieving disk space information. */ +export function getDiskSpace(): DiskSpaceInformation +/** Retrieving memory information. */ +export function getMemoryInfoNonblocking(): Promise +/** Retrieving memory information. */ +export function getMemoryInfo(): MemoryInformation +/** Retrieving network information. */ +export function getNetworkInfoNonblocking(): Promise +/** Retrieving network information. */ +export function getNetworkInfo(): NetworkInformation export type JsAhoCorasick = AhoCorasick export class AhoCorasick { static withPatterns(patterns: Array): JsAhoCorasick diff --git a/index.js b/index.js index 53b0fff..2d3d085 100644 --- a/index.js +++ b/index.js @@ -17,7 +17,7 @@ function isMusl() { // For Node 10 if (!process.report || typeof process.report.getReport !== 'function') { try { - const lddPath = require('child_process').execSync('which ldd').toString().trim(); + const lddPath = require('child_process').execSync('which ldd').toString().trim() return readFileSync(lddPath, 'utf8').includes('musl') } catch (e) { return true @@ -237,6 +237,49 @@ switch (platform) { loadError = e } break + case 'riscv64': + if (isMusl()) { + localFileExisted = existsSync( + join(__dirname, 'slacc.linux-riscv64-musl.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./slacc.linux-riscv64-musl.node') + } else { + nativeBinding = require('slacc-linux-riscv64-musl') + } + } catch (e) { + loadError = e + } + } else { + localFileExisted = existsSync( + join(__dirname, 'slacc.linux-riscv64-gnu.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./slacc.linux-riscv64-gnu.node') + } else { + nativeBinding = require('slacc-linux-riscv64-gnu') + } + } catch (e) { + loadError = e + } + } + break + case 's390x': + localFileExisted = existsSync( + join(__dirname, 'slacc.linux-s390x-gnu.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./slacc.linux-s390x-gnu.node') + } else { + nativeBinding = require('slacc-linux-s390x-gnu') + } + } catch (e) { + loadError = e + } + break default: throw new Error(`Unsupported architecture on Linux: ${arch}`) } @@ -252,7 +295,15 @@ if (!nativeBinding) { throw new Error(`Failed to load native binding`) } -const { AhoCorasick, ZipReader } = nativeBinding +const { getDiskIoNonblocking, getDiskIo, getDiskSpaceNonblocking, getDiskSpace, getMemoryInfoNonblocking, getMemoryInfo, getNetworkInfoNonblocking, getNetworkInfo, AhoCorasick, ZipReader } = nativeBinding +module.exports.getDiskIoNonblocking = getDiskIoNonblocking +module.exports.getDiskIo = getDiskIo +module.exports.getDiskSpaceNonblocking = getDiskSpaceNonblocking +module.exports.getDiskSpace = getDiskSpace +module.exports.getMemoryInfoNonblocking = getMemoryInfoNonblocking +module.exports.getMemoryInfo = getMemoryInfo +module.exports.getNetworkInfoNonblocking = getNetworkInfoNonblocking +module.exports.getNetworkInfo = getNetworkInfo module.exports.AhoCorasick = AhoCorasick module.exports.ZipReader = ZipReader diff --git a/package.json b/package.json index 8984ed2..3f8ad3c 100644 --- a/package.json +++ b/package.json @@ -21,16 +21,11 @@ } }, "license": "MIT", - "files": [ - "index.d.ts", - "index.js", - "LICENSE", - "README.md" - ], + "files": ["index.d.ts", "index.js", "LICENSE", "README.md"], "devDependencies": { "@napi-rs/cli": "^2.15.2", "@vitest/ui": "^0.30.1", - "re2": "^1.18.0", + "re2": "^1.20.10", "vitest": "^0.30.1" }, "ava": { diff --git a/patches/fix-build-failed-on-freebsd.patch b/patches/fix-build-failed-on-freebsd.patch new file mode 100644 index 0000000..ea70528 --- /dev/null +++ b/patches/fix-build-failed-on-freebsd.patch @@ -0,0 +1,18 @@ +diff --git a/docker/freebsd.sh b/docker/freebsd.sh +index e144f40..27bdb1e 100755 +--- a/docker/freebsd.sh ++++ b/docker/freebsd.sh +@@ -189,11 +189,12 @@ main() { + cp "${td}/freebsd/usr/lib/libc++.a" "${destdir}/lib" + cp "${td}/freebsd/usr/lib/libcxxrt.a" "${destdir}/lib" + cp "${td}/freebsd/usr/lib/libcompiler_rt.a" "${destdir}/lib" +- cp "${td}/freebsd/usr/lib"/lib{c,util,m,ssp_nonshared,memstat}.a "${destdir}/lib" ++ cp "${td}/freebsd/usr/lib"/lib{c,util,m,ssp_nonshared,memstat,elf}.a "${destdir}/lib" + cp "${td}/freebsd/usr/lib"/lib{rt,execinfo,procstat}.so.1 "${destdir}/lib" + cp "${td}/freebsd/usr/lib"/libmemstat.so.3 "${destdir}/lib" + cp "${td}/freebsd/usr/lib"/{crt1,Scrt1,crti,crtn}.o "${destdir}/lib" + cp "${td}/freebsd/usr/lib"/libkvm.a "${destdir}/lib" ++ cp "${td}/freebsd/usr/lib"/libelf.so "${destdir}/lib" + + local lib= + local base= diff --git a/patches/systeminformation+5.22.0.patch b/patches/systeminformation+5.22.0.patch new file mode 100644 index 0000000..8ffc5b2 --- /dev/null +++ b/patches/systeminformation+5.22.0.patch @@ -0,0 +1,18 @@ +diff --git a/node_modules/systeminformation/.DS_Store b/node_modules/systeminformation/.DS_Store +new file mode 100644 +index 0000000..b7f8ca5 +Binary files /dev/null and b/node_modules/systeminformation/.DS_Store differ +diff --git a/node_modules/systeminformation/lib/filesystem.js b/node_modules/systeminformation/lib/filesystem.js +index 1128fa0..d99f8fe 100644 +--- a/node_modules/systeminformation/lib/filesystem.js ++++ b/node_modules/systeminformation/lib/filesystem.js +@@ -924,8 +924,7 @@ function disksIO(callback) { + let rWaitTime = 0; + let wWaitTime = 0; + let tWaitTime = 0; +- +- if ((_disk_io && !_disk_io.ms) || (_disk_io && _disk_io.ms && Date.now() - _disk_io.ms >= 500)) { ++ if (true) { + if (_linux || _freebsd || _openbsd || _netbsd) { + // prints Block layer statistics for all mounted volumes + // var cmd = "for mount in `lsblk | grep / | sed -r 's/│ └─//' | cut -d ' ' -f 1`; do cat /sys/block/$mount/stat | sed -r 's/ +/;/g' | sed -r 's/^;//'; done"; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c69867e..3247742 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,5 +1,50 @@ lockfileVersion: '6.0' +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +optionalDependencies: + slacc-android-arm-eabi: + specifier: 0.0.10 + version: 0.0.10 + slacc-android-arm64: + specifier: 0.0.10 + version: 0.0.10 + slacc-darwin-arm64: + specifier: 0.0.10 + version: 0.0.10 + slacc-darwin-universal: + specifier: 0.0.10 + version: 0.0.10 + slacc-darwin-x64: + specifier: 0.0.10 + version: 0.0.10 + slacc-freebsd-x64: + specifier: 0.0.10 + version: 0.0.10 + slacc-linux-arm-gnueabihf: + specifier: 0.0.10 + version: 0.0.10 + slacc-linux-arm64-gnu: + specifier: 0.0.10 + version: 0.0.10 + slacc-linux-arm64-musl: + specifier: 0.0.10 + version: 0.0.10 + slacc-linux-x64-gnu: + specifier: 0.0.10 + version: 0.0.10 + slacc-linux-x64-musl: + specifier: 0.0.10 + version: 0.0.10 + slacc-win32-arm64-msvc: + specifier: 0.0.10 + version: 0.0.10 + slacc-win32-x64-msvc: + specifier: 0.0.10 + version: 0.0.10 + devDependencies: '@napi-rs/cli': specifier: ^2.15.2 @@ -8,8 +53,8 @@ devDependencies: specifier: ^0.30.1 version: 0.30.1 re2: - specifier: ^1.18.0 - version: 1.18.0 + specifier: ^1.20.10 + version: 1.20.10 vitest: specifier: ^0.30.1 version: 0.30.1(@vitest/ui@0.30.1) @@ -214,8 +259,16 @@ packages: dev: true optional: true - /@gar/promisify@1.1.3: - resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} + /@isaacs/cliui@8.0.2: + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + dependencies: + string-width: 5.1.2 + string-width-cjs: /string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: /strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: /wrap-ansi@7.0.0 dev: true /@jridgewell/sourcemap-codec@1.4.15: @@ -249,30 +302,35 @@ packages: fastq: 1.15.0 dev: true - /@npmcli/fs@2.1.2: - resolution: {integrity: sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + /@npmcli/agent@2.2.2: + resolution: {integrity: sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==} + engines: {node: ^16.14.0 || >=18.0.0} dependencies: - '@gar/promisify': 1.1.3 - semver: 7.5.0 + agent-base: 7.1.1 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.4 + lru-cache: 10.2.0 + socks-proxy-agent: 8.0.3 + transitivePeerDependencies: + - supports-color dev: true - /@npmcli/move-file@2.0.1: - resolution: {integrity: sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - deprecated: This functionality has been moved to @npmcli/fs + /@npmcli/fs@3.1.0: + resolution: {integrity: sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} dependencies: - mkdirp: 1.0.4 - rimraf: 3.0.2 + semver: 7.5.0 dev: true - /@polka/url@1.0.0-next.21: - resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==} + /@pkgjs/parseargs@0.11.0: + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + requiresBuild: true dev: true + optional: true - /@tootallnate/once@2.0.0: - resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} - engines: {node: '>= 10'} + /@polka/url@1.0.0-next.21: + resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==} dev: true /@types/chai-subset@1.3.3: @@ -340,8 +398,9 @@ packages: pretty-format: 27.5.1 dev: true - /abbrev@1.1.1: - resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + /abbrev@2.0.0: + resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} dev: true /acorn-walk@8.2.0: @@ -355,22 +414,11 @@ packages: hasBin: true dev: true - /agent-base@6.0.2: - resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} - engines: {node: '>= 6.0.0'} - dependencies: - debug: 4.3.4 - transitivePeerDependencies: - - supports-color - dev: true - - /agentkeepalive@4.3.0: - resolution: {integrity: sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==} - engines: {node: '>= 8.0.0'} + /agent-base@7.1.1: + resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==} + engines: {node: '>= 14'} dependencies: debug: 4.3.4 - depd: 2.0.0 - humanize-ms: 1.2.1 transitivePeerDependencies: - supports-color dev: true @@ -388,21 +436,26 @@ packages: engines: {node: '>=8'} dev: true + /ansi-regex@6.0.1: + resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + engines: {node: '>=12'} + dev: true + + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: true + /ansi-styles@5.2.0: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} dev: true - /aproba@2.0.0: - resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} - dev: true - - /are-we-there-yet@3.0.1: - resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - dependencies: - delegates: 1.0.0 - readable-stream: 3.6.2 + /ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} dev: true /assertion-error@1.1.0: @@ -417,13 +470,6 @@ packages: resolution: {integrity: sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==} dev: true - /brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - dev: true - /brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} dependencies: @@ -442,30 +488,22 @@ packages: engines: {node: '>=8'} dev: true - /cacache@16.1.3: - resolution: {integrity: sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + /cacache@18.0.2: + resolution: {integrity: sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw==} + engines: {node: ^16.14.0 || >=18.0.0} dependencies: - '@npmcli/fs': 2.1.2 - '@npmcli/move-file': 2.0.1 - chownr: 2.0.0 - fs-minipass: 2.1.0 - glob: 8.1.0 - infer-owner: 1.0.4 - lru-cache: 7.18.3 - minipass: 3.3.6 - minipass-collect: 1.0.2 + '@npmcli/fs': 3.1.0 + fs-minipass: 3.0.3 + glob: 10.3.12 + lru-cache: 10.2.0 + minipass: 7.0.4 + minipass-collect: 2.0.1 minipass-flush: 1.0.5 minipass-pipeline: 1.2.4 - mkdirp: 1.0.4 p-map: 4.0.0 - promise-inflight: 1.0.1 - rimraf: 3.0.2 - ssri: 9.0.1 + ssri: 10.0.5 tar: 6.1.13 - unique-filename: 2.0.1 - transitivePeerDependencies: - - bluebird + unique-filename: 3.0.0 dev: true /chai@4.3.7: @@ -495,13 +533,15 @@ packages: engines: {node: '>=6'} dev: true - /color-support@1.1.3: - resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} - hasBin: true + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 dev: true - /concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} dev: true /concordance@5.0.4: @@ -518,8 +558,13 @@ packages: well-known-symbols: 2.0.0 dev: true - /console-control-strings@1.1.0: - resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} + /cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 dev: true /date-time@3.1.0: @@ -548,19 +593,18 @@ packages: type-detect: 4.0.8 dev: true - /delegates@1.0.0: - resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} - dev: true - - /depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} + /eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} dev: true /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} dev: true + /emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: true + /encoding@0.1.13: resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} requiresBuild: true @@ -613,6 +657,10 @@ packages: engines: {node: '>=0.10.0'} dev: true + /exponential-backoff@3.1.1: + resolution: {integrity: sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==} + dev: true + /fast-diff@1.2.0: resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==} dev: true @@ -649,6 +697,14 @@ packages: resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} dev: true + /foreground-child@3.1.1: + resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} + engines: {node: '>=14'} + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + dev: true + /fs-minipass@2.1.0: resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} engines: {node: '>= 8'} @@ -656,8 +712,11 @@ packages: minipass: 3.3.6 dev: true - /fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + /fs-minipass@3.0.3: + resolution: {integrity: sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + minipass: 7.0.4 dev: true /fsevents@2.3.2: @@ -668,20 +727,6 @@ packages: dev: true optional: true - /gauge@4.0.4: - resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - dependencies: - aproba: 2.0.0 - color-support: 1.1.3 - console-control-strings: 1.1.0 - has-unicode: 2.0.1 - signal-exit: 3.0.7 - string-width: 4.2.3 - strip-ansi: 6.0.1 - wide-align: 1.1.5 - dev: true - /get-func-name@2.0.0: resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} dev: true @@ -693,67 +738,46 @@ packages: is-glob: 4.0.3 dev: true - /glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: true - - /glob@8.1.0: - resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} - engines: {node: '>=12'} + /glob@10.3.12: + resolution: {integrity: sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 5.1.6 - once: 1.4.0 + foreground-child: 3.1.1 + jackspeak: 2.3.6 + minimatch: 9.0.4 + minipass: 7.0.4 + path-scurry: 1.10.2 dev: true /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} dev: true - /has-unicode@2.0.1: - resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} - dev: true - /http-cache-semantics@4.1.1: resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} dev: true - /http-proxy-agent@5.0.0: - resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} - engines: {node: '>= 6'} + /http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} dependencies: - '@tootallnate/once': 2.0.0 - agent-base: 6.0.2 + agent-base: 7.1.1 debug: 4.3.4 transitivePeerDependencies: - supports-color dev: true - /https-proxy-agent@5.0.1: - resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} - engines: {node: '>= 6'} + /https-proxy-agent@7.0.4: + resolution: {integrity: sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==} + engines: {node: '>= 14'} dependencies: - agent-base: 6.0.2 + agent-base: 7.1.1 debug: 4.3.4 transitivePeerDependencies: - supports-color dev: true - /humanize-ms@1.2.1: - resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} - dependencies: - ms: 2.1.2 - dev: true - /iconv-lite@0.6.3: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} @@ -772,23 +796,8 @@ packages: engines: {node: '>=8'} dev: true - /infer-owner@1.0.4: - resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==} - dev: true - - /inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - dev: true - - /inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - dev: true - - /install-artifact-from-github@1.3.2: - resolution: {integrity: sha512-yCFcLvqk0yQdxx0uJz4t9Z3adDMLAYrcGYv546uRXCSvxE+GqNYhhz/KmrGcUKGI/gVLR9n/e/zM9jX/+ASMJQ==} + /install-artifact-from-github@1.3.5: + resolution: {integrity: sha512-gZHC7f/cJgXz7MXlHFBxPVMsvIbev1OQN1uKQYKVJDydGNm9oYf9JstbU4Atnh/eSvk41WtEovoRm+8IF686xg==} hasBin: true dev: true @@ -826,6 +835,20 @@ packages: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} dev: true + /isexe@3.1.1: + resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==} + engines: {node: '>=16'} + dev: true + + /jackspeak@2.3.6: + resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} + engines: {node: '>=14'} + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + dev: true + /js-string-escape@1.0.1: resolution: {integrity: sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==} engines: {node: '>= 0.8'} @@ -850,6 +873,11 @@ packages: get-func-name: 2.0.0 dev: true + /lru-cache@10.2.0: + resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} + engines: {node: 14 || >=16.14} + dev: true + /lru-cache@6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} @@ -857,11 +885,6 @@ packages: yallist: 4.0.0 dev: true - /lru-cache@7.18.3: - resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} - engines: {node: '>=12'} - dev: true - /magic-string@0.30.0: resolution: {integrity: sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==} engines: {node: '>=12'} @@ -869,28 +892,22 @@ packages: '@jridgewell/sourcemap-codec': 1.4.15 dev: true - /make-fetch-happen@10.2.1: - resolution: {integrity: sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + /make-fetch-happen@13.0.0: + resolution: {integrity: sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==} + engines: {node: ^16.14.0 || >=18.0.0} dependencies: - agentkeepalive: 4.3.0 - cacache: 16.1.3 + '@npmcli/agent': 2.2.2 + cacache: 18.0.2 http-cache-semantics: 4.1.1 - http-proxy-agent: 5.0.0 - https-proxy-agent: 5.0.1 is-lambda: 1.0.1 - lru-cache: 7.18.3 - minipass: 3.3.6 - minipass-collect: 1.0.2 - minipass-fetch: 2.1.2 + minipass: 7.0.4 + minipass-fetch: 3.0.4 minipass-flush: 1.0.5 minipass-pipeline: 1.2.4 negotiator: 0.6.3 promise-retry: 2.0.1 - socks-proxy-agent: 7.0.0 - ssri: 9.0.1 + ssri: 10.0.5 transitivePeerDependencies: - - bluebird - supports-color dev: true @@ -914,31 +931,25 @@ packages: picomatch: 2.3.1 dev: true - /minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - dependencies: - brace-expansion: 1.1.11 - dev: true - - /minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} - engines: {node: '>=10'} + /minimatch@9.0.4: + resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==} + engines: {node: '>=16 || 14 >=14.17'} dependencies: brace-expansion: 2.0.1 dev: true - /minipass-collect@1.0.2: - resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==} - engines: {node: '>= 8'} + /minipass-collect@2.0.1: + resolution: {integrity: sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==} + engines: {node: '>=16 || 14 >=14.17'} dependencies: - minipass: 3.3.6 + minipass: 7.0.4 dev: true - /minipass-fetch@2.1.2: - resolution: {integrity: sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + /minipass-fetch@3.0.4: + resolution: {integrity: sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} dependencies: - minipass: 3.3.6 + minipass: 7.0.4 minipass-sized: 1.0.3 minizlib: 2.1.2 optionalDependencies: @@ -978,6 +989,11 @@ packages: engines: {node: '>=8'} dev: true + /minipass@7.0.4: + resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} + engines: {node: '>=16 || 14 >=14.17'} + dev: true + /minizlib@2.1.2: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} engines: {node: '>= 8'} @@ -1010,8 +1026,8 @@ packages: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} dev: true - /nan@2.17.0: - resolution: {integrity: sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==} + /nan@2.19.0: + resolution: {integrity: sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==} dev: true /nanoid@3.3.6: @@ -1025,48 +1041,31 @@ packages: engines: {node: '>= 0.6'} dev: true - /node-gyp@9.3.1: - resolution: {integrity: sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==} - engines: {node: ^12.13 || ^14.13 || >=16} + /node-gyp@10.1.0: + resolution: {integrity: sha512-B4J5M1cABxPc5PwfjhbV5hoy2DP9p8lFXASnEN6hugXOa61416tnTZ29x9sSwAd0o99XNIcpvDDy1swAExsVKA==} + engines: {node: ^16.14.0 || >=18.0.0} hasBin: true dependencies: env-paths: 2.2.1 - glob: 7.2.3 + exponential-backoff: 3.1.1 + glob: 10.3.12 graceful-fs: 4.2.11 - make-fetch-happen: 10.2.1 - nopt: 6.0.0 - npmlog: 6.0.2 - rimraf: 3.0.2 + make-fetch-happen: 13.0.0 + nopt: 7.2.0 + proc-log: 3.0.0 semver: 7.5.0 tar: 6.1.13 - which: 2.0.2 + which: 4.0.0 transitivePeerDependencies: - - bluebird - supports-color dev: true - /nopt@6.0.0: - resolution: {integrity: sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + /nopt@7.2.0: + resolution: {integrity: sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} hasBin: true dependencies: - abbrev: 1.1.1 - dev: true - - /npmlog@6.0.2: - resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - dependencies: - are-we-there-yet: 3.0.1 - console-control-strings: 1.1.0 - gauge: 4.0.4 - set-blocking: 2.0.0 - dev: true - - /once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - dependencies: - wrappy: 1.0.2 + abbrev: 2.0.0 dev: true /p-limit@4.0.0: @@ -1083,9 +1082,17 @@ packages: aggregate-error: 3.1.0 dev: true - /path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} + /path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + dev: true + + /path-scurry@1.10.2: + resolution: {integrity: sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + lru-cache: 10.2.0 + minipass: 7.0.4 dev: true /pathe@1.1.0: @@ -1131,13 +1138,9 @@ packages: react-is: 17.0.2 dev: true - /promise-inflight@1.0.1: - resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} - peerDependencies: - bluebird: '*' - peerDependenciesMeta: - bluebird: - optional: true + /proc-log@3.0.0: + resolution: {integrity: sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} dev: true /promise-retry@2.0.1: @@ -1152,15 +1155,14 @@ packages: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true - /re2@1.18.0: - resolution: {integrity: sha512-MoCYZlJ9YUgksND9asyNF2/x532daXU/ARp1UeJbQ5flMY6ryKNEhrWt85aw3YluzOJlC3vXpGgK2a1jb0b4GA==} + /re2@1.20.10: + resolution: {integrity: sha512-/5JjSPXobSDaKFL6rD5Gb4qD4CVBITQb7NAxfQ/NA7o0HER3SJAPV3lPO2kvzw0/PN1pVJNVATEUk4y9j7oIIA==} requiresBuild: true dependencies: - install-artifact-from-github: 1.3.2 - nan: 2.17.0 - node-gyp: 9.3.1 + install-artifact-from-github: 1.3.5 + nan: 2.19.0 + node-gyp: 10.1.0 transitivePeerDependencies: - - bluebird - supports-color dev: true @@ -1168,15 +1170,6 @@ packages: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} dev: true - /readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} - dependencies: - inherits: 2.0.4 - string_decoder: 1.3.0 - util-deprecate: 1.0.2 - dev: true - /retry@0.12.0: resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} engines: {node: '>= 4'} @@ -1187,13 +1180,6 @@ packages: engines: {iojs: '>=1.0.0', node: '>=0.10.0'} dev: true - /rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - hasBin: true - dependencies: - glob: 7.2.3 - dev: true - /rollup@3.21.0: resolution: {integrity: sha512-ANPhVcyeHvYdQMUyCbczy33nbLzI7RzrBje4uvNiTDJGIMtlKoOStmympwr9OtS1LZxiDmE2wvxHyVhoLtf1KQ==} engines: {node: '>=14.18.0', npm: '>=8.0.0'} @@ -1208,10 +1194,6 @@ packages: queue-microtask: 1.2.3 dev: true - /safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - dev: true - /safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} dev: true @@ -1225,16 +1207,25 @@ packages: lru-cache: 6.0.0 dev: true - /set-blocking@2.0.0: - resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + /shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + dev: true + + /shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} dev: true /siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} dev: true - /signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} dev: true /sirv@2.0.3: @@ -1246,16 +1237,132 @@ packages: totalist: 3.0.1 dev: true + /slacc-android-arm-eabi@0.0.10: + resolution: {integrity: sha512-U3dVBuM1m8rT1D/w6S4knJ/uscNwsCR+MKxSQFbgDJEh8Atv+ovuC+FMGuaBT4iOQjpMj5dWSsN3ZPjVeo3hgA==} + engines: {node: '>= 10'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: false + optional: true + + /slacc-android-arm64@0.0.10: + resolution: {integrity: sha512-guVp88sW+4j1clTSXMzyDJHG8ondVnd8/FMKXIOfzKCEwSwX3uBxsuyHqtGvXkEwyZAGsBUy13Ei/PZAwElwYA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: false + optional: true + + /slacc-darwin-arm64@0.0.10: + resolution: {integrity: sha512-633qnOMTP7egvd5IeljAOku0tnxlBXSoCRu7HiT0yeXxN9y5Tbg2X2/FaRzstI36lClfIJ0Lavne4mOw/90z9A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /slacc-darwin-universal@0.0.10: + resolution: {integrity: sha512-x5kEqRMTEQTi3NCufPEukWvaWqcOL+7EkP18ZCCiajcWH83jWnT8DOSGOmmLYdrXd0B7ZZcbd8GyLp3i5zu8PA==} + engines: {node: '>= 10'} + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /slacc-darwin-x64@0.0.10: + resolution: {integrity: sha512-5gQYboy/4T6Bj3sVXiCpM3EvF1sK/Zx1Nq5YBMUuYb2GzrIwywghHbCD6bK4JYGvNsLN7r4PC45ZUB4gVkU8yA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /slacc-freebsd-x64@0.0.10: + resolution: {integrity: sha512-Jmi5YszELef/aCzYto+LwiNGhCk5mrlJfTJU/pOI91HBbrZlV+aRyIsPCcxAMg5yPsPQuyRljrDouVYrPzNmjw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: false + optional: true + + /slacc-linux-arm-gnueabihf@0.0.10: + resolution: {integrity: sha512-9lTM3DGtISQlZYSKrMuQyKCiUnHYRcy04mY6HF1ywYcQ2sqfv3bKEnrypVewepIFUtytlIGzkgpiUAk/ghYGoA==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /slacc-linux-arm64-gnu@0.0.10: + resolution: {integrity: sha512-qXrNWSINXOjHRO3c9idGm8DeOAjAjG1xHY8WiplCoHWgsZf3E7V+sPhWqRUaGQEvftsJg40+cFYREBaLQhpAVQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /slacc-linux-arm64-musl@0.0.10: + resolution: {integrity: sha512-3lUX7752f6Okn54aONioaA+9M5TvifqXBAart+u2lNXEdWmmh003cVSU2Vcwg7nJ9lLHtju2DkDmKKfJjFuShA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /slacc-linux-x64-gnu@0.0.10: + resolution: {integrity: sha512-BxxvylF9zlOLRLCpiyMvKTIUpdLlpetNBJ+DSMDh5+Ggq+AmQz2NUGawmcBJw58F8nMCj9TpWLlGNWc2AuY+JQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /slacc-linux-x64-musl@0.0.10: + resolution: {integrity: sha512-TYJi8LOtJiTFcZvka4du7bMjF9Bz1RHRwyLnScr5E5yjjgoLRrsvgSu7bxp87xH+rgJ3CdEwE3w3Ux8EiewHpA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /slacc-win32-arm64-msvc@0.0.10: + resolution: {integrity: sha512-1CHPLiDB4exzFyT5ndtJDsRRhBxNg8mGz6I6eJEMjelGkJR2KZPT9LZuby/1bS/bcVOr7zuJvGNfbEGBeHRwPQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /slacc-win32-x64-msvc@0.0.10: + resolution: {integrity: sha512-wAXBy5yKCAzfYWjVlyPpu6PscD+j4QhCQEy0wZaVuzNyx60HpXWcTZxxVnMR730Y7tfc7cBxSI8NtRb8RguSgg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + /smart-buffer@4.2.0: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} dev: true - /socks-proxy-agent@7.0.0: - resolution: {integrity: sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==} - engines: {node: '>= 10'} + /socks-proxy-agent@8.0.3: + resolution: {integrity: sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==} + engines: {node: '>= 14'} dependencies: - agent-base: 6.0.2 + agent-base: 7.1.1 debug: 4.3.4 socks: 2.7.1 transitivePeerDependencies: @@ -1280,11 +1387,11 @@ packages: engines: {node: '>=0.10.0'} dev: true - /ssri@9.0.1: - resolution: {integrity: sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + /ssri@10.0.5: + resolution: {integrity: sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} dependencies: - minipass: 3.3.6 + minipass: 7.0.4 dev: true /stackback@0.0.2: @@ -1304,10 +1411,13 @@ packages: strip-ansi: 6.0.1 dev: true - /string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + /string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} dependencies: - safe-buffer: 5.2.1 + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 dev: true /strip-ansi@6.0.1: @@ -1317,6 +1427,13 @@ packages: ansi-regex: 5.0.1 dev: true + /strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + dependencies: + ansi-regex: 6.0.1 + dev: true + /strip-literal@1.0.1: resolution: {integrity: sha512-QZTsipNpa2Ppr6v1AmJHESqJ3Uz247MUS0OjrnnZjFAvEoWqxuyFuXn2xLgMtRnijJShAa1HL0gtJyUs7u7n3Q==} dependencies: @@ -1375,24 +1492,20 @@ packages: resolution: {integrity: sha512-MvlCc4GHrmZdAllBc0iUDowff36Q9Ndw/UzqmEKyrfSzokTd9ZCy1i+IIk5hrYKkjoYVQyNbrw7/F8XJ2rEwTg==} dev: true - /unique-filename@2.0.1: - resolution: {integrity: sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + /unique-filename@3.0.0: + resolution: {integrity: sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} dependencies: - unique-slug: 3.0.0 + unique-slug: 4.0.0 dev: true - /unique-slug@3.0.0: - resolution: {integrity: sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + /unique-slug@4.0.0: + resolution: {integrity: sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} dependencies: imurmurhash: 0.1.4 dev: true - /util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - dev: true - /vite-node@0.30.1(@types/node@18.16.0): resolution: {integrity: sha512-vTikpU/J7e6LU/8iM3dzBo8ZhEiKZEKRznEMm+mJh95XhWaPrJQraT/QsT2NWmuEf+zgAoMe64PKT7hfZ1Njmg==} engines: {node: '>=v14.18.0'} @@ -1527,6 +1640,14 @@ packages: isexe: 2.0.0 dev: true + /which@4.0.0: + resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==} + engines: {node: ^16.13.0 || >=18.0.0} + hasBin: true + dependencies: + isexe: 3.1.1 + dev: true + /why-is-node-running@2.2.2: resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==} engines: {node: '>=8'} @@ -1536,14 +1657,22 @@ packages: stackback: 0.0.2 dev: true - /wide-align@1.1.5: - resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} + /wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} dependencies: + ansi-styles: 4.3.0 string-width: 4.2.3 + strip-ansi: 6.0.1 dev: true - /wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + /wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 dev: true /yallist@4.0.0: diff --git a/rustfmt.toml b/rustfmt.toml deleted file mode 100644 index cab5731..0000000 --- a/rustfmt.toml +++ /dev/null @@ -1,2 +0,0 @@ -tab_spaces = 2 -edition = "2021" diff --git a/src/aho_corasick.rs b/src/aho_corasick.rs index 246f4df..de76d43 100644 --- a/src/aho_corasick.rs +++ b/src/aho_corasick.rs @@ -1,26 +1,24 @@ -use aho_corasick; - pub struct AhoCorasick { - inner: aho_corasick::AhoCorasick, + inner: aho_corasick::AhoCorasick, } #[napi(js_name = "AhoCorasick")] pub struct JsAhoCorasick { - aho_corasick: AhoCorasick, + aho_corasick: AhoCorasick, } #[napi] impl JsAhoCorasick { - #[napi(factory)] - pub fn with_patterns(patterns: Vec) -> Self { - let inner = aho_corasick::AhoCorasick::new(patterns).unwrap(); - Self { - aho_corasick: AhoCorasick { inner }, + #[napi(factory)] + pub fn with_patterns(patterns: Vec) -> Self { + let inner = aho_corasick::AhoCorasick::new(patterns).unwrap(); + Self { + aho_corasick: AhoCorasick { inner }, + } } - } - #[napi] - pub fn is_match(&self, input: String) -> bool { - self.aho_corasick.inner.is_match(&input) - } + #[napi] + pub fn is_match(&self, input: String) -> bool { + self.aho_corasick.inner.is_match(&input) + } } diff --git a/src/lib.rs b/src/lib.rs index b243d6f..67e59c4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,5 +3,6 @@ #[macro_use] extern crate napi_derive; +pub use slacc_system_metrics::*; pub mod aho_corasick; pub mod zip; diff --git a/src/zip.rs b/src/zip.rs index 7979421..17728ad 100644 --- a/src/zip.rs +++ b/src/zip.rs @@ -1,53 +1,49 @@ -use std::{ - io::Cursor, - path::{Path, PathBuf}, -}; - use napi::bindgen_prelude::*; -use zip; +use std::io::Cursor; +use std::path::{Path, PathBuf}; pub struct ZipReader {} #[napi(js_name = "ZipReader")] pub struct JsZipReader { - destination: DestinationType, + destination: DestinationType, } enum DestinationType { - Path(Box), + Path(Box), } #[napi] impl JsZipReader { - #[napi(factory)] - pub fn with_destination_path(path: String) -> Self { - Self { - destination: DestinationType::Path(PathBuf::from(&path).into_boxed_path()), + #[napi(factory)] + pub fn with_destination_path(path: String) -> Self { + Self { + destination: DestinationType::Path(PathBuf::from(&path).into_boxed_path()), + } } - } - - #[napi] - pub fn via_buffer(&self, buffer: Buffer) -> Result<()> { - let mut zip = zip::ZipArchive::new(Cursor::new(buffer.as_ref())).or_else(|err| { - Err(Error::new( - Status::InvalidArg, - format!("Failed to open zip archive: {}", err), - )) - })?; - self.extract(&mut zip) - } - fn extract(&self, zip: &mut zip::ZipArchive>) -> Result<()> { - match &self.destination { - DestinationType::Path(path) => { - zip.extract(path).or_else(|err| { - Err(Error::new( - Status::InvalidArg, - format!("Failed to extract zip archive: {}", err), - )) + #[napi] + pub fn via_buffer(&self, buffer: Buffer) -> Result<()> { + let mut zip = zip::ZipArchive::new(Cursor::new(buffer.as_ref())).or_else(|err| { + Err(Error::new( + Status::InvalidArg, + format!("Failed to open zip archive: {}", err), + )) })?; - } + self.extract(&mut zip) + } + + fn extract(&self, zip: &mut zip::ZipArchive>) -> Result<()> { + match &self.destination { + DestinationType::Path(path) => { + zip.extract(path).or_else(|err| { + Err(Error::new( + Status::InvalidArg, + format!("Failed to extract zip archive: {}", err), + )) + })?; + } + } + Ok(()) } - Ok(()) - } } From 903b531b79d1b4ebb9bcadca7ef2e978d52104c0 Mon Sep 17 00:00:00 2001 From: Chocolate Pie <106949016+chocolate-pie@users.noreply.github.com> Date: Sat, 20 Apr 2024 14:38:01 +0900 Subject: [PATCH 2/7] chore: Fix `linux::get_network_info` causes undefined behaviour --- crates/slacc-system-metrics/src/linux.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/slacc-system-metrics/src/linux.rs b/crates/slacc-system-metrics/src/linux.rs index 3801efa..4b44314 100644 --- a/crates/slacc-system-metrics/src/linux.rs +++ b/crates/slacc-system-metrics/src/linux.rs @@ -92,7 +92,7 @@ pub(crate) unsafe fn get_network_info() -> Result Date: Sat, 20 Apr 2024 20:57:49 +0900 Subject: [PATCH 3/7] chore: Fix `macos::get_memory_info` may access to uninitialized memory --- crates/slacc-system-metrics/src/macos.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/crates/slacc-system-metrics/src/macos.rs b/crates/slacc-system-metrics/src/macos.rs index eeeaf35..c8eb69c 100644 --- a/crates/slacc-system-metrics/src/macos.rs +++ b/crates/slacc-system-metrics/src/macos.rs @@ -231,7 +231,7 @@ pub(crate) unsafe fn get_disk_io() -> Result { IOObjectRelease(parent); IOObjectRelease(item); - CFRelease(props_dictionary as *const _ as *const ::libc::c_void); + CFRelease(props_dictionary as *const _); item = IOIteratorNext(iterator); } @@ -247,13 +247,13 @@ pub(crate) unsafe fn get_memory_info() -> Result::uninit(); + let mut statistic = std::mem::zeroed::<::libc::vm_statistics64>(); let mut statistic_count = libc::HOST_VM_INFO64_COUNT; libc::host_statistics64( host_port, libc::HOST_VM_INFO64, - statistic.as_mut_ptr() as *mut i32, + &raw mut statistic as *mut i32, &mut statistic_count, ) .into_errno()?; @@ -269,7 +269,6 @@ pub(crate) unsafe fn get_memory_info() -> Result Date: Sat, 20 Apr 2024 21:25:31 +0900 Subject: [PATCH 4/7] refactor: improve readability --- crates/slacc-system-metrics/src/macos.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/slacc-system-metrics/src/macos.rs b/crates/slacc-system-metrics/src/macos.rs index c8eb69c..6ddec6d 100644 --- a/crates/slacc-system-metrics/src/macos.rs +++ b/crates/slacc-system-metrics/src/macos.rs @@ -262,7 +262,7 @@ pub(crate) unsafe fn get_memory_info() -> Result(), + &mut std::mem::size_of::(), std::ptr::null_mut(), 0, ) @@ -274,7 +274,7 @@ pub(crate) unsafe fn get_memory_info() -> Result(), + &mut std::mem::size_of::(), std::ptr::null_mut(), 0, ) From cae9888a7f9d1f9f496712273d62ad4e812c4df0 Mon Sep 17 00:00:00 2001 From: Chocolate Pie <106949016+chocolate-pie@users.noreply.github.com> Date: Sat, 27 Apr 2024 16:47:50 +0900 Subject: [PATCH 5/7] =?UTF-8?q?refactor(darwin):=20Use=20`c"=E2=80=A6"`=20?= =?UTF-8?q?string=20literals=20in=20`src/macos.rs`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/rust-lang/rfcs/pull/3348 https://github.com/rust-lang/rust/issues/105723 https://github.com/rust-lang/rust/pull/117472 --- crates/slacc-system-metrics/src/macos.rs | 35 +++++++++++------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/crates/slacc-system-metrics/src/macos.rs b/crates/slacc-system-metrics/src/macos.rs index 6ddec6d..33ca94d 100644 --- a/crates/slacc-system-metrics/src/macos.rs +++ b/crates/slacc-system-metrics/src/macos.rs @@ -22,25 +22,22 @@ use crate::{ErrnoExt, SlaccStatsError}; #[rustfmt::skip] #[allow(non_upper_case_globals, dead_code)] mod constants { - const fn create_cstring(input: &[u8]) -> &std::ffi::CStr { - unsafe { std::ffi::CStr::from_bytes_with_nul_unchecked(input) } - } - pub(crate) const kIOMediaClass: &std::ffi::CStr = create_cstring(b"IOMedia\0"); - pub(crate) const kIOServicePlane: &std::ffi::CStr = create_cstring(b"IOService\0"); - pub(crate) const kIOBlockStorageDriverClass: &std::ffi::CStr = create_cstring(b"IOBlockStorageDriver\0"); - pub(crate) const kIOBlockStorageDriverStatisticsKey: &std::ffi::CStr = create_cstring(b"Statistics\0"); - pub(crate) const kIOBlockStorageDriverStatisticsBytesReadKey: &std::ffi::CStr = create_cstring(b"Bytes (Read)\0"); - pub(crate) const kIOBlockStorageDriverStatisticsBytesWrittenKey: &std::ffi::CStr = create_cstring(b"Bytes (Write)\0"); - pub(crate) const kIOBlockStorageDriverStatisticsReadErrorsKey: &std::ffi::CStr = create_cstring(b"Errors (Read)\0"); - pub(crate) const kIOBlockStorageDriverStatisticsWriteErrorsKey: &std::ffi::CStr = create_cstring(b"Errors (Write)\0"); - pub(crate) const kIOBlockStorageDriverStatisticsLatentReadTimeKey: &std::ffi::CStr = create_cstring(b"Latency Time (Read)\0"); - pub(crate) const kIOBlockStorageDriverStatisticsLatentWriteTimeKey: &std::ffi::CStr = create_cstring(b"Latency Time (Write)\0"); - pub(crate) const kIOBlockStorageDriverStatisticsReadsKey: &std::ffi::CStr = create_cstring(b"Operations (Read)\0"); - pub(crate) const kIOBlockStorageDriverStatisticsWritesKey: &std::ffi::CStr = create_cstring(b"Operations (Write)\0"); - pub(crate) const kIOBlockStorageDriverStatisticsReadRetriesKey: &std::ffi::CStr = create_cstring(b"Retries (Read)\0"); - pub(crate) const kIOBlockStorageDriverStatisticsWriteRetriesKey: &std::ffi::CStr = create_cstring(b"Retries (Write)\0"); - pub(crate) const kIOBlockStorageDriverStatisticsTotalReadTimeKey: &std::ffi::CStr = create_cstring(b"Total Time (Read)\0"); - pub(crate) const kIOBlockStorageDriverStatisticsTotalWriteTimeKey: &std::ffi::CStr = create_cstring(b"Total Time (Write)\0"); + pub(crate) const kIOMediaClass: &std::ffi::CStr = c"IOMedia"; + pub(crate) const kIOServicePlane: &std::ffi::CStr = c"IOService"; + pub(crate) const kIOBlockStorageDriverClass: &std::ffi::CStr = c"IOBlockStorageDriver"; + pub(crate) const kIOBlockStorageDriverStatisticsKey: &std::ffi::CStr = c"Statistics"; + pub(crate) const kIOBlockStorageDriverStatisticsBytesReadKey: &std::ffi::CStr = c"Bytes (Read)"; + pub(crate) const kIOBlockStorageDriverStatisticsBytesWrittenKey: &std::ffi::CStr = c"Bytes (Write)"; + pub(crate) const kIOBlockStorageDriverStatisticsReadErrorsKey: &std::ffi::CStr = c"Errors (Read)"; + pub(crate) const kIOBlockStorageDriverStatisticsWriteErrorsKey: &std::ffi::CStr = c"Errors (Write)"; + pub(crate) const kIOBlockStorageDriverStatisticsLatentReadTimeKey: &std::ffi::CStr = c"Latency Time (Read)"; + pub(crate) const kIOBlockStorageDriverStatisticsLatentWriteTimeKey: &std::ffi::CStr = c"Latency Time (Write)"; + pub(crate) const kIOBlockStorageDriverStatisticsReadsKey: &std::ffi::CStr = c"Operations (Read)"; + pub(crate) const kIOBlockStorageDriverStatisticsWritesKey: &std::ffi::CStr = c"Operations (Write)"; + pub(crate) const kIOBlockStorageDriverStatisticsReadRetriesKey: &std::ffi::CStr = c"Retries (Read)"; + pub(crate) const kIOBlockStorageDriverStatisticsWriteRetriesKey: &std::ffi::CStr = c"Retries (Write)"; + pub(crate) const kIOBlockStorageDriverStatisticsTotalReadTimeKey: &std::ffi::CStr = c"Total Time (Read)"; + pub(crate) const kIOBlockStorageDriverStatisticsTotalWriteTimeKey: &std::ffi::CStr = c"Total Time (Write)"; } #[link(name = "IOKit", kind = "framework")] From c3eba8d649cdfdcf24d39820bbf263b5077d112d Mon Sep 17 00:00:00 2001 From: Chocolate Pie <106949016+chocolate-pie@users.noreply.github.com> Date: Mon, 29 Apr 2024 12:07:53 +0900 Subject: [PATCH 6/7] chore(safety): Add safety comments --- crates/slacc-system-metrics/src/lib.rs | 2 +- crates/slacc-system-metrics/src/linux.rs | 10 ++++++++++ crates/slacc-system-metrics/src/macos.rs | 12 +++++++++--- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/crates/slacc-system-metrics/src/lib.rs b/crates/slacc-system-metrics/src/lib.rs index f58dced..2129471 100644 --- a/crates/slacc-system-metrics/src/lib.rs +++ b/crates/slacc-system-metrics/src/lib.rs @@ -68,7 +68,7 @@ pub fn get_network_info_nonblocking( } /// Retrieving network information. -#[cfg_attr(feature = "napi", napi)] +#[cfg_attr(feature = "napi", napi(catch_unwind))] pub fn get_network_info() -> Result { crate::imp::get_network_info() } diff --git a/crates/slacc-system-metrics/src/linux.rs b/crates/slacc-system-metrics/src/linux.rs index 4b44314..7255409 100644 --- a/crates/slacc-system-metrics/src/linux.rs +++ b/crates/slacc-system-metrics/src/linux.rs @@ -72,6 +72,10 @@ struct NetlinkRequest { generation: rtgenmsg, } +const _: () = assert!(std::mem::align_of::() == 8); +const _: () = assert!(std::mem::align_of::() == 4); +const _: () = assert!(std::mem::align_of::() == 2); + pub(crate) unsafe fn get_network_info() -> Result { let mut buffer = Vec::::with_capacity(8192 /* NLMSG_GOODSIZE */); let socket = libc::socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE).valid_fd()?; @@ -99,6 +103,8 @@ pub(crate) unsafe fn get_network_info() -> Result= std::mem::size_of::() as i32 { + // Safety: `message_ptr` is rounded up to power of four and + // has padding, so always access to aligned pointer. let message = &*(message_ptr as *const ::libc::nlmsghdr); match message { message if (message.nlmsg_flags & libc::NLM_F_DUMP_INTR as u16) != 0 => { @@ -118,6 +124,8 @@ pub(crate) unsafe fn get_network_info() -> Result Result(); let rta_data_length = std::mem::size_of::().min(rta_data_length); + // Safety: We cannot guarantee `rtattr_message` is rounded up + // to power of eighth, so copy memory block using `memcpy()`. std::ptr::copy_nonoverlapping::( rta_data_message, &raw mut statistics as *mut u8, diff --git a/crates/slacc-system-metrics/src/macos.rs b/crates/slacc-system-metrics/src/macos.rs index 33ca94d..b6518c9 100644 --- a/crates/slacc-system-metrics/src/macos.rs +++ b/crates/slacc-system-metrics/src/macos.rs @@ -130,6 +130,9 @@ macro_rules! release_io { }} } +const _: () = assert!(std::mem::align_of::() == 4); +const _: () = assert!(std::mem::align_of::() == 4); + pub(crate) unsafe fn get_disk_io() -> Result { unsafe fn take_value_as_dictionary_from_dictionary( key: &CStr, @@ -324,13 +327,16 @@ pub(crate) unsafe fn get_network_info() -> Result Date: Mon, 20 May 2024 10:49:52 +0900 Subject: [PATCH 7/7] fix: Fix alignment check is incorrect --- crates/slacc-system-metrics/src/macos.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/slacc-system-metrics/src/macos.rs b/crates/slacc-system-metrics/src/macos.rs index b6518c9..24c6786 100644 --- a/crates/slacc-system-metrics/src/macos.rs +++ b/crates/slacc-system-metrics/src/macos.rs @@ -335,7 +335,7 @@ pub(crate) unsafe fn get_network_info() -> Result