netget/utils/clock.rs
1//! The monotonic and wall clocks, on every target NetGet builds for.
2//!
3//! `std::time::Instant::now()` and `SystemTime::now()` **panic** on `wasm32-unknown-unknown`
4//! ("time not implemented on this platform"); the browser has clocks, std just does not know
5//! how to reach them. On that target `Instant` is the tokio shim's `performance.now()` clock
6//! and `SystemTime` is `web_time`'s `Date.now()`; on native both are std, so on native this
7//! module changes nothing but a path.
8//!
9//! Use `crate::utils::clock::{Instant, SystemTime, UNIX_EPOCH}` rather than `std::time::*` in
10//! anything the browser build compiles: `src/state`, `src/llm`, `src/protocol`, `src/cli`,
11//! `src/tui`, the shared server modules and the protocols enabled in `crates/netget-web`. A
12//! protocol that is only ever built natively can keep using std; the moment it is added to the
13//! web build, every `Instant::now()` it reaches is a panic on first connection, so run the
14//! rewrite in that direction rather than trusting it. `Duration` has no clock in it and stays
15//! `std::time::Duration` everywhere.
16
17#[cfg(not(target_arch = "wasm32"))]
18pub use std::time::{Instant, SystemTime, SystemTimeError, UNIX_EPOCH};
19
20// The monotonic clock is the tokio shim's (`crates/netget-tokio-wasm/src/time.rs`): the same
21// type `tokio::time::sleep_until` takes, and offset so `Instant::now() - window` cannot
22// underflow on a page that just loaded. The wall clock is `Date.now()` through `web-time`.
23#[cfg(target_arch = "wasm32")]
24pub use tokio::time::Instant;
25#[cfg(target_arch = "wasm32")]
26pub use web_time::{SystemTime, SystemTimeError, UNIX_EPOCH};
27
28/// The current process id, or `0` where there is no process (the browser).
29///
30/// `std::process::id()` panics on `wasm32-unknown-unknown`; it is used here only to make
31/// identifiers unique across NetGet processes, and there is one page per wasm instance.
32pub fn process_id() -> u32 {
33 #[cfg(not(target_arch = "wasm32"))]
34 {
35 std::process::id()
36 }
37 #[cfg(target_arch = "wasm32")]
38 {
39 0
40 }
41}
42
43/// A wall-clock time as a local `chrono` date-time.
44///
45/// `chrono` converts `std::time::SystemTime`; on wasm ours is `web_time`'s, so the conversion
46/// goes through the epoch offset, which is target-neutral arithmetic.
47pub fn to_local_datetime(t: SystemTime) -> chrono::DateTime<chrono::Local> {
48 let since_epoch = t.duration_since(UNIX_EPOCH).unwrap_or_default();
49 chrono::DateTime::<chrono::Local>::from(std::time::UNIX_EPOCH + since_epoch)
50}