1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-23 15:49:44 -05:00

feat(unstable): Add "Deno.osUptime()" API (#17179)

This PR adds support for `Deno.osUptime` which reports number of seconds
since os was booted. It will allow us to be compatible with Node's `os.uptime` -
https://nodejs.org/api/os.html#osuptime

Partially based on
https://docs.rs/uptime_lib/latest/src/uptime_lib/lib.rs.html
This commit is contained in:
Kamil Ogórek 2022-12-27 00:16:12 +01:00 committed by Bartek Iwańczuk
parent 1e857bc03c
commit 3baf1a4bd3
No known key found for this signature in database
GPG key ID: 0C6BCDDC3B3AD750
10 changed files with 110 additions and 1 deletions

View file

@ -239,6 +239,18 @@ Deno.test({ permissions: { sys: false } }, function releasePerm() {
}, Deno.errors.PermissionDenied);
});
Deno.test({ permissions: { sys: ["osUptime"] } }, function osUptime() {
const uptime = Deno.osUptime();
assert(typeof uptime === "number");
assert(uptime > 0);
});
Deno.test({ permissions: { sys: false } }, function osUptimePerm() {
assertThrows(() => {
Deno.osUptime();
}, Deno.errors.PermissionDenied);
});
Deno.test(
{ permissions: { sys: ["systemMemoryInfo"] } },
function systemMemoryInfo() {

View file

@ -22,6 +22,7 @@ Deno.test(async function permissionNetInvalidHost() {
Deno.test(async function permissionSysValidKind() {
await Deno.permissions.query({ name: "sys", kind: "loadavg" });
await Deno.permissions.query({ name: "sys", kind: "osRelease" });
await Deno.permissions.query({ name: "sys", kind: "osUptime" });
await Deno.permissions.query({ name: "sys", kind: "networkInterfaces" });
await Deno.permissions.query({ name: "sys", kind: "systemMemoryInfo" });
await Deno.permissions.query({ name: "sys", kind: "hostname" });

View file

@ -46,6 +46,7 @@ const UNSTABLE_DENO_PROPS: &[&str] = &[
"ServeInit",
"ServeTlsInit",
"Handler",
"osUptime",
];
static MSG_MISSING_PROPERTY_DENO: Lazy<Regex> = Lazy::new(|| {

View file

@ -4120,6 +4120,7 @@ declare namespace Deno {
| "systemMemoryInfo"
| "networkInterfaces"
| "osRelease"
| "osUptime"
| "uid"
| "gid";
}

View file

@ -1691,6 +1691,21 @@ declare namespace Deno {
/** The buffered output from the child process' `stderr`. */
readonly stderr: Uint8Array;
}
/** **UNSTABLE**: New API, yet to be vetted.
*
* Returns the Operating System uptime in number of seconds.
*
* ```ts
* console.log(Deno.osUptime());
* ```
*
* Requires `allow-sys` permission.
*
* @tags allow-sys
* @category Runtime Environment
*/
export function osUptime(): number;
}
/** **UNSTABLE**: New API, yet to be vetted.

View file

@ -25,6 +25,10 @@
return ops.op_os_release();
}
function osUptime() {
return ops.op_os_uptime();
}
function systemMemoryInfo() {
return ops.op_system_memory_info();
}
@ -106,6 +110,7 @@
loadavg,
networkInterfaces,
osRelease,
osUptime,
setExitHandler,
systemMemoryInfo,
uid,

View file

@ -119,6 +119,7 @@
refTimer: __bootstrap.timers.refTimer,
unrefTimer: __bootstrap.timers.unrefTimer,
osRelease: __bootstrap.os.osRelease,
osUptime: __bootstrap.os.osUptime,
hostname: __bootstrap.os.hostname,
systemMemoryInfo: __bootstrap.os.systemMemoryInfo,
networkInterfaces: __bootstrap.os.networkInterfaces,

View file

@ -29,6 +29,7 @@ fn init_ops(builder: &mut ExtensionBuilder) -> &mut ExtensionBuilder {
op_loadavg::decl(),
op_network_interfaces::decl(),
op_os_release::decl(),
op_os_uptime::decl(),
op_set_env::decl(),
op_set_exit_code::decl(),
op_system_memory_info::decl(),
@ -423,3 +424,13 @@ fn rss() -> usize {
}
}
}
#[op]
fn op_os_uptime(state: &mut OpState) -> Result<u64, AnyError> {
super::check_unstable(state, "Deno.osUptime");
state
.borrow_mut::<Permissions>()
.sys
.check("osUptime", Some("Deno.osUptime()"))?;
Ok(sys_info::os_uptime())
}

View file

@ -300,3 +300,65 @@ pub fn mem_info() -> Option<MemInfo> {
Some(mem_info)
}
pub fn os_uptime() -> u64 {
#[cfg(target_os = "linux")]
{
let mut info = std::mem::MaybeUninit::uninit();
// SAFETY: `info` is a valid pointer to a `libc::sysinfo` struct.
let res = unsafe { libc::sysinfo(info.as_mut_ptr()) };
if res == 0 {
// SAFETY: `sysinfo` initializes the struct.
let info = unsafe { info.assume_init() };
return info.uptime as u64;
}
}
#[cfg(any(
target_vendor = "apple",
target_os = "freebsd",
target_os = "openbsd"
))]
{
use std::mem;
use std::time::Duration;
use std::time::SystemTime;
let mut request = [libc::CTL_KERN, libc::KERN_BOOTTIME];
// SAFETY: `boottime` is only accessed if sysctl() succeeds
// and agrees with the `size` set by sysctl().
let mut boottime: libc::timeval = unsafe { mem::zeroed() };
let mut size: libc::size_t = mem::size_of_val(&boottime) as libc::size_t;
// SAFETY: `sysctl` is thread-safe.
let res = unsafe {
libc::sysctl(
&mut request[0],
2,
&mut boottime as *mut libc::timeval as *mut libc::c_void,
&mut size,
std::ptr::null_mut(),
0,
)
};
if res == 0 {
return SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.map(|d| {
(d - Duration::new(
boottime.tv_sec as u64,
boottime.tv_usec as u32 * 1000,
))
.as_secs()
})
.unwrap_or_default();
}
}
#[cfg(target_family = "windows")]
unsafe {
// Windows is the only one that returns `uptime` in milisecond precision,
// so we need to get the seconds out of it to be in sync with other envs.
return unsafe { winapi::um::sysinfoapi::GetTickCount64() as u64 / 1000 };
}
0
}

View file

@ -309,7 +309,7 @@ pub struct SysDescriptor(pub String);
pub fn parse_sys_kind(kind: &str) -> Result<&str, AnyError> {
match kind {
"hostname" | "osRelease" | "loadavg" | "networkInterfaces"
"hostname" | "osRelease" | "osUptime" | "loadavg" | "networkInterfaces"
| "systemMemoryInfo" | "uid" | "gid" => Ok(kind),
_ => Err(type_error(format!("unknown system info kind \"{}\"", kind))),
}