summaryrefslogtreecommitdiff
path: root/ext/web/timers.rs
diff options
context:
space:
mode:
authorAndreu Botella <andreu@andreubotella.com>2022-02-15 12:17:30 +0100
committerGitHub <noreply@github.com>2022-02-15 12:17:30 +0100
commit760f4c9e2427e87815a8e59b0807693c8dcb623a (patch)
treecb04b2b42cfcf1fc46d74a3e4c7f86c73491d2b0 /ext/web/timers.rs
parent5e845442fade02cd12d13e74222b26e217c5971d (diff)
chore(ext/timers): move ext/timers to ext/web (#13665)
Diffstat (limited to 'ext/web/timers.rs')
-rw-r--r--ext/web/timers.rs103
1 files changed, 103 insertions, 0 deletions
diff --git a/ext/web/timers.rs b/ext/web/timers.rs
new file mode 100644
index 000000000..7f17aa969
--- /dev/null
+++ b/ext/web/timers.rs
@@ -0,0 +1,103 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+//! This module helps deno implement timers and performance APIs.
+
+use deno_core::error::AnyError;
+use deno_core::CancelFuture;
+use deno_core::CancelHandle;
+use deno_core::OpState;
+use deno_core::Resource;
+use deno_core::ResourceId;
+use std::borrow::Cow;
+use std::cell::RefCell;
+use std::rc::Rc;
+use std::time::Duration;
+use std::time::Instant;
+
+pub trait TimersPermission {
+ fn allow_hrtime(&mut self) -> bool;
+ fn check_unstable(&self, state: &OpState, api_name: &'static str);
+}
+
+pub type StartTime = Instant;
+
+// Returns a milliseconds and nanoseconds subsec
+// since the start time of the deno runtime.
+// If the High precision flag is not set, the
+// nanoseconds are rounded on 2ms.
+pub fn op_now<TP>(
+ state: &mut OpState,
+ _argument: (),
+ _: (),
+) -> Result<f64, AnyError>
+where
+ TP: TimersPermission + 'static,
+{
+ let start_time = state.borrow::<StartTime>();
+ let seconds = start_time.elapsed().as_secs();
+ let mut subsec_nanos = start_time.elapsed().subsec_nanos() as f64;
+ let reduced_time_precision = 2_000_000.0; // 2ms in nanoseconds
+
+ // If the permission is not enabled
+ // Round the nano result on 2 milliseconds
+ // see: https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp#Reduced_time_precision
+ if !state.borrow_mut::<TP>().allow_hrtime() {
+ subsec_nanos -= subsec_nanos % reduced_time_precision;
+ }
+
+ let result = (seconds * 1_000) as f64 + (subsec_nanos / 1_000_000.0);
+
+ Ok(result)
+}
+
+pub struct TimerHandle(Rc<CancelHandle>);
+
+impl Resource for TimerHandle {
+ fn name(&self) -> Cow<str> {
+ "timer".into()
+ }
+
+ fn close(self: Rc<Self>) {
+ self.0.cancel();
+ }
+}
+
+/// Creates a [`TimerHandle`] resource that can be used to cancel invocations of
+/// [`op_sleep`].
+pub fn op_timer_handle(
+ state: &mut OpState,
+ _: (),
+ _: (),
+) -> Result<ResourceId, AnyError> {
+ let rid = state
+ .resource_table
+ .add(TimerHandle(CancelHandle::new_rc()));
+ Ok(rid)
+}
+
+/// Waits asynchronously until either `millis` milliseconds have passed or the
+/// [`TimerHandle`] resource given by `rid` has been canceled.
+pub async fn op_sleep(
+ state: Rc<RefCell<OpState>>,
+ millis: u64,
+ rid: ResourceId,
+) -> Result<(), AnyError> {
+ let handle = state.borrow().resource_table.get::<TimerHandle>(rid)?;
+ tokio::time::sleep(Duration::from_millis(millis))
+ .or_cancel(handle.0.clone())
+ .await?;
+ Ok(())
+}
+
+pub fn op_sleep_sync<TP>(
+ state: &mut OpState,
+ millis: u64,
+ _: (),
+) -> Result<(), AnyError>
+where
+ TP: TimersPermission + 'static,
+{
+ state.borrow::<TP>().check_unstable(state, "Deno.sleepSync");
+ std::thread::sleep(Duration::from_millis(millis));
+ Ok(())
+}