mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-07-30 09:16:07 -04:00
Merge pull request #3061 from lightpanda-io/consistent-clocks
chore: make our use of clock/timestamp more consistent
This commit is contained in:
@@ -22,7 +22,6 @@ const lp = @import("lightpanda");
|
||||
const Env = @import("browser/js/Env.zig");
|
||||
|
||||
const log = lp.log;
|
||||
const milliTimestamp = @import("datetime.zig").milliTimestamp;
|
||||
|
||||
// How often the checker thread scans the entries.
|
||||
const CHECK_INTERVAL_NS = 1 * std.time.ns_per_s;
|
||||
@@ -107,7 +106,7 @@ fn run(self: *Watchdog) void {
|
||||
return;
|
||||
}
|
||||
|
||||
const now = milliTimestamp(.monotonic);
|
||||
const now = lp.datetime.milliTimestamp(.boot);
|
||||
var node = self.entries.first;
|
||||
while (node) |n| : (node = n.next) {
|
||||
const entry: *Entry = @fieldParentPtr("node", n);
|
||||
@@ -157,7 +156,7 @@ pub const Heartbeat = struct {
|
||||
last_activity: std.atomic.Value(u64) = .init(0),
|
||||
|
||||
pub fn touch(self: *Heartbeat) void {
|
||||
self.last_activity.store(milliTimestamp(.monotonic), .release);
|
||||
self.last_activity.store(lp.datetime.milliTimestamp(.boot), .release);
|
||||
}
|
||||
|
||||
pub fn disarm(self: *Heartbeat) void {
|
||||
|
||||
@@ -28,7 +28,7 @@ const braille = [_][]const u8{ "⡇", "⣆", "⣤", "⣰", "⢸", "⠹", "⠛",
|
||||
const interval_ns: u64 = 100 * std.time.ns_per_ms;
|
||||
/// Minimum dwell on a tool label so the user can read it. Slow tools exceed
|
||||
/// it naturally; fast ones (getUrl, getCookies) get padded.
|
||||
const min_tool_display_ns: u64 = 1500 * std.time.ns_per_ms;
|
||||
const min_tool_display_ms: u64 = 1500;
|
||||
const clear_eol = ansi.clear_eol;
|
||||
|
||||
const max_args_bytes: usize = 256;
|
||||
@@ -45,8 +45,8 @@ const ToolState = struct {
|
||||
name_len: usize = 0,
|
||||
args_buf: [max_args_bytes]u8 = undefined,
|
||||
args_len: usize = 0,
|
||||
/// Wall-clock at which `setTool` last fired; gates dwell-honoring.
|
||||
set_ns: i128 = 0,
|
||||
/// Time at which `setTool` last fired; gates dwell-honoring.
|
||||
set_ms: u64 = 0,
|
||||
/// Worker should flip back to thinking once dwell elapses. A fresh
|
||||
/// `setTool` clears it, overriding the dwell with a new label.
|
||||
dwell_pending: bool = false,
|
||||
@@ -76,7 +76,7 @@ frame: u8 = 0,
|
||||
paused: bool = false,
|
||||
|
||||
tool_calls: u32 = 0,
|
||||
turn_started_ns: i128 = 0,
|
||||
turn_started_ms: u64 = 0,
|
||||
|
||||
thread: ?std.Thread = null,
|
||||
should_exit: bool = false,
|
||||
@@ -112,7 +112,7 @@ pub fn start(self: *Spinner) void {
|
||||
self.paused = false;
|
||||
self.frame = 0;
|
||||
self.tool_calls = 0;
|
||||
self.turn_started_ns = std.Io.Clock.now(.real, lp.io).toNanoseconds();
|
||||
self.turn_started_ms = lp.datetime.milliTimestamp(.boot);
|
||||
self.ensureWorkerLocked();
|
||||
self.cv.signal(lp.io);
|
||||
}
|
||||
@@ -136,8 +136,8 @@ pub fn stop(self: *Spinner) void {
|
||||
self.mu.lockUncancelable(lp.io);
|
||||
defer self.mu.unlock(lp.io);
|
||||
if (self.state == .idle) return;
|
||||
const elapsed_ns = std.Io.Clock.now(.real, lp.io).toNanoseconds() - self.turn_started_ns;
|
||||
const elapsed_s = @as(f64, @floatFromInt(elapsed_ns)) / @as(f64, std.time.ns_per_s);
|
||||
const elapsed_ms = lp.datetime.milliTimestamp(.boot) - self.turn_started_ms;
|
||||
const elapsed_s = @as(f64, @floatFromInt(elapsed_ms)) / @as(f64, std.time.ms_per_s);
|
||||
|
||||
var buf: [frame_buf_bytes]u8 = undefined;
|
||||
const summary = std.fmt.bufPrint(
|
||||
@@ -192,7 +192,7 @@ pub fn setTool(self: *Spinner, name: []const u8, args: []const u8) void {
|
||||
self.paused = false;
|
||||
const manual = self.state == .idle;
|
||||
self.tool_calls += 1;
|
||||
var tool: ToolState = .{ .set_ns = std.Io.Clock.now(.real, lp.io).toNanoseconds(), .manual = manual };
|
||||
var tool: ToolState = .{ .set_ms = lp.datetime.milliTimestamp(.boot), .manual = manual };
|
||||
const name_prefix = truncateUtf8(name, tool.name_buf.len);
|
||||
tool.name_len = name_prefix.len;
|
||||
@memcpy(tool.name_buf[0..name_prefix.len], name_prefix);
|
||||
@@ -213,7 +213,7 @@ pub fn setTool(self: *Spinner, name: []const u8, args: []const u8) void {
|
||||
}
|
||||
|
||||
/// Request a transition back to the cycling "thinking" state. The worker
|
||||
/// honors `min_tool_display_ns`: if the current tool label has not been up
|
||||
/// honors `min_tool_display_ms`: if the current tool label has not been up
|
||||
/// long enough, the flip is deferred until it has.
|
||||
pub fn setThinking(self: *Spinner) void {
|
||||
if (!self.isEnabled()) return;
|
||||
@@ -254,10 +254,8 @@ fn workerLoop(self: *Spinner) void {
|
||||
switch (self.state) {
|
||||
.tool => {
|
||||
if (self.state.tool.dwell_pending) {
|
||||
// Signed compare: a backward clock jump (NTP slew, suspend/resume)
|
||||
// can make the delta negative; `@intCast` to u64 would panic.
|
||||
const delta: i128 = std.Io.Clock.now(.real, lp.io).toNanoseconds() - self.state.tool.set_ns;
|
||||
if (delta >= @as(i128, min_tool_display_ns)) {
|
||||
const delta = lp.datetime.milliTimestamp(.boot) - self.state.tool.set_ms;
|
||||
if (delta >= min_tool_display_ms) {
|
||||
self.state = .thinking;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,9 +74,6 @@ const AnimatedPreserveAspectRatio = @import("webapi/svg/AnimatedPreserveAspectRa
|
||||
const sys_url = @import("../sys/url.zig");
|
||||
const HttpClient = @import("../network/HttpClient.zig");
|
||||
|
||||
const timestamp = @import("../datetime.zig").timestamp;
|
||||
const milliTimestamp = @import("../datetime.zig").milliTimestamp;
|
||||
|
||||
const GlobalEventHandlersLookup = @import("webapi/global_event_handlers.zig").Lookup;
|
||||
|
||||
pub const parse = @import("frame/parse.zig");
|
||||
@@ -731,7 +728,7 @@ pub fn navigate(self: *Frame, request_url: [:0]const u8, opts: NavigateOpts) !vo
|
||||
.frame_id = self._frame_id,
|
||||
.loader_id = self._loader_id,
|
||||
.url = request_url,
|
||||
.timestamp = timestamp(.monotonic),
|
||||
.timestamp = lp.datetime.timestamp(.boot),
|
||||
});
|
||||
|
||||
self.recordNavigateTelemetry(false);
|
||||
@@ -746,7 +743,7 @@ pub fn navigate(self: *Frame, request_url: [:0]const u8, opts: NavigateOpts) !vo
|
||||
.method = opts.method,
|
||||
},
|
||||
.url = request_url,
|
||||
.timestamp = timestamp(.monotonic),
|
||||
.timestamp = lp.datetime.timestamp(.boot),
|
||||
});
|
||||
|
||||
if (self.parent == null) {
|
||||
@@ -829,7 +826,7 @@ pub fn navigate(self: *Frame, request_url: [:0]const u8, opts: NavigateOpts) !vo
|
||||
.req_id = transfer.id,
|
||||
.frame_id = self._frame_id,
|
||||
.loader_id = self._loader_id,
|
||||
.timestamp = timestamp(.monotonic),
|
||||
.timestamp = lp.datetime.timestamp(.boot),
|
||||
.is_pending_root = is_pending_root,
|
||||
});
|
||||
|
||||
@@ -1091,7 +1088,7 @@ pub fn _documentIsLoaded(self: *Frame) !void {
|
||||
.req_id = self._req_id,
|
||||
.frame_id = self._frame_id,
|
||||
.loader_id = self._loader_id,
|
||||
.timestamp = timestamp(.monotonic),
|
||||
.timestamp = lp.datetime.timestamp(.boot),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1201,7 +1198,7 @@ fn _documentIsComplete(self: *Frame) !void {
|
||||
.req_id = self._req_id,
|
||||
.frame_id = self._frame_id,
|
||||
.loader_id = self._loader_id,
|
||||
.timestamp = timestamp(.monotonic),
|
||||
.timestamp = lp.datetime.timestamp(.boot),
|
||||
});
|
||||
|
||||
if (self._event_manager.hasDirectListeners(window_target, "pageshow", self.window._on_pageshow)) {
|
||||
@@ -1298,7 +1295,7 @@ fn frameHeaderDoneCallback(transfer: *HttpClient.Transfer) !HttpClient.Transfer.
|
||||
.req_id = self._req_id,
|
||||
.frame_id = self._frame_id,
|
||||
.loader_id = self._loader_id,
|
||||
.timestamp = timestamp(.monotonic),
|
||||
.timestamp = lp.datetime.timestamp(.boot),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1713,7 +1710,7 @@ fn frameErrorCallback(ctx: *anyopaque, err: anyerror) void {
|
||||
self._session.notification.dispatch(.frame_navigate_failed, &.{
|
||||
.frame_id = self._frame_id,
|
||||
.loader_id = self._loader_id,
|
||||
.timestamp = timestamp(.monotonic),
|
||||
.timestamp = lp.datetime.timestamp(.boot),
|
||||
.url = self.url,
|
||||
.err = err,
|
||||
.opts = self._navigated_options orelse .{},
|
||||
@@ -1830,7 +1827,7 @@ pub fn iframeAddedCallback(self: *Frame, iframe: *IFrame) !void {
|
||||
.parent_id = self._frame_id,
|
||||
.frame_id = new_frame._frame_id,
|
||||
.loader_id = new_frame._loader_id,
|
||||
.timestamp = timestamp(.monotonic),
|
||||
.timestamp = lp.datetime.timestamp(.boot),
|
||||
});
|
||||
|
||||
const url = blk: {
|
||||
@@ -2346,7 +2343,7 @@ pub fn notifyNetworkIdle(self: *Frame) void {
|
||||
.req_id = self._req_id,
|
||||
.frame_id = self._frame_id,
|
||||
.loader_id = self._loader_id,
|
||||
.timestamp = timestamp(.monotonic),
|
||||
.timestamp = lp.datetime.timestamp(.boot),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2356,7 +2353,7 @@ pub fn notifyNetworkAlmostIdle(self: *Frame) void {
|
||||
.req_id = self._req_id,
|
||||
.frame_id = self._frame_id,
|
||||
.loader_id = self._loader_id,
|
||||
.timestamp = timestamp(.monotonic),
|
||||
.timestamp = lp.datetime.timestamp(.boot),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3062,13 +3059,13 @@ const IdleNotification = union(enum) {
|
||||
// the first time after being un-triggered). Record the time
|
||||
// so that if the condition holds for long enough, we can
|
||||
// send a notification.
|
||||
self.* = .{ .triggered = milliTimestamp(.monotonic) };
|
||||
self.* = .{ .triggered = lp.datetime.milliTimestamp(.boot) };
|
||||
},
|
||||
.triggered => |ms| {
|
||||
// The condition was already triggered and was triggered
|
||||
// again. When this condition holds for 500+ms, we'll send
|
||||
// a notification.
|
||||
if (milliTimestamp(.monotonic) - ms >= 500) {
|
||||
if (lp.datetime.milliTimestamp(.boot) - ms >= 500) {
|
||||
// This is the only place in this function where we can
|
||||
// return true. The only place where we can tell our caller
|
||||
// "send the notification!".
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
const std = @import("std");
|
||||
const lp = @import("lightpanda");
|
||||
const builtin = @import("builtin");
|
||||
const milliTimestamp = @import("../../datetime.zig").milliTimestamp;
|
||||
|
||||
const log = lp.log;
|
||||
const IS_DEBUG = builtin.mode == .Debug;
|
||||
@@ -85,7 +84,7 @@ pub fn add(self: *Scheduler, ctx: *anyopaque, cb: Callback, run_in_ms: u32, opts
|
||||
.sequence = seq,
|
||||
.name = opts.name,
|
||||
.finalizer = opts.finalizer,
|
||||
.run_at = milliTimestamp(.monotonic) + run_in_ms,
|
||||
.run_at = lp.datetime.milliTimestamp(.boot) + run_in_ms,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -95,13 +94,13 @@ pub fn run(self: *Scheduler) !void {
|
||||
}
|
||||
|
||||
pub fn hasReadyTasks(self: *Scheduler) bool {
|
||||
const now = milliTimestamp(.monotonic);
|
||||
const now = lp.datetime.milliTimestamp(.boot);
|
||||
return queueHasReadyTask(&self.low_priority, now) or queueHasReadyTask(&self.high_priority, now);
|
||||
}
|
||||
|
||||
pub fn msToNext(self: *Scheduler) ?u64 {
|
||||
var next: ?u64 = null;
|
||||
const now = milliTimestamp(.monotonic);
|
||||
const now = lp.datetime.milliTimestamp(.boot);
|
||||
for ([_]*Queue{ &self.high_priority, &self.low_priority }) |queue| {
|
||||
const task = queue.peek() orelse continue;
|
||||
const ms = if (task.run_at <= now) 0 else task.run_at - now;
|
||||
@@ -116,7 +115,7 @@ fn runQueue(self: *Scheduler, queue: *Queue) !void {
|
||||
if (queue.count() == 0) {
|
||||
return;
|
||||
}
|
||||
const start = milliTimestamp(.monotonic);
|
||||
const start = lp.datetime.milliTimestamp(.boot);
|
||||
var now = start;
|
||||
|
||||
while (queue.peek()) |*task_| {
|
||||
@@ -144,7 +143,7 @@ fn runQueue(self: *Scheduler, queue: *Queue) !void {
|
||||
try self.low_priority.push(self.allocator, task);
|
||||
}
|
||||
|
||||
now = milliTimestamp(.monotonic);
|
||||
now = lp.datetime.milliTimestamp(.boot);
|
||||
if (now - start > 500) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ const lp = @import("lightpanda");
|
||||
const js = @import("../js/js.zig");
|
||||
|
||||
const Notification = @import("../../Notification.zig");
|
||||
const datetime = @import("../../datetime.zig");
|
||||
|
||||
const logger = lp.log;
|
||||
|
||||
@@ -34,7 +33,7 @@ pub const init: Console = .{};
|
||||
|
||||
fn dispatchConsoleMessage(values: []js.Value, console_type: Notification.ConsoleMessageType, exec: *js.Execution) void {
|
||||
const notification = exec.session.notification;
|
||||
const ts = datetime.timestamp(.monotonic);
|
||||
const ts = lp.datetime.timestamp(.boot);
|
||||
|
||||
notification.dispatch(.console_message, &.{
|
||||
.source = .javascript,
|
||||
@@ -133,11 +132,11 @@ pub fn time(self: *Console, label_: ?[]const u8, exec: *js.Execution) !void {
|
||||
return;
|
||||
}
|
||||
gop.key_ptr.* = try exec.arena.dupe(u8, label);
|
||||
gop.value_ptr.* = timestamp();
|
||||
gop.value_ptr.* = lp.datetime.timestamp(.boot);
|
||||
}
|
||||
|
||||
pub fn timeLog(self: *Console, label_: ?[]const u8) void {
|
||||
const elapsed = timestamp();
|
||||
const elapsed = lp.datetime.timestamp(.boot);
|
||||
const label = label_ orelse "default";
|
||||
const start = self._timers.get(label) orelse {
|
||||
logger.info(.js, "console.timeLog", .{ .label = label, .err = "invalid timer" });
|
||||
@@ -147,7 +146,7 @@ pub fn timeLog(self: *Console, label_: ?[]const u8) void {
|
||||
}
|
||||
|
||||
pub fn timeEnd(self: *Console, label_: ?[]const u8) void {
|
||||
const elapsed = timestamp();
|
||||
const elapsed = lp.datetime.timestamp(.boot);
|
||||
const label = label_ orelse "default";
|
||||
const kv = self._timers.fetchRemove(label) orelse {
|
||||
logger.info(.js, "console.timeEnd", .{ .label = label, .err = "invalid timer" });
|
||||
@@ -166,11 +165,6 @@ pub fn groupCollapsed(_: *const Console, values: []js.Value) void {
|
||||
}
|
||||
|
||||
pub fn groupEnd(_: *const Console) void {}
|
||||
|
||||
fn timestamp() u64 {
|
||||
return @import("../../datetime.zig").timestamp(.monotonic);
|
||||
}
|
||||
|
||||
const ValueWriter = struct {
|
||||
values: []js.Value,
|
||||
stack: ?[]const u8 = null,
|
||||
|
||||
@@ -196,7 +196,8 @@ pub fn getLastModified(self: *const Document, frame: *Frame) ![]const u8 {
|
||||
}
|
||||
}
|
||||
}
|
||||
break :blk std.Io.Clock.now(.real, lp.io).toSeconds();
|
||||
// localTime is signed: a parsed Last-Modified can predate the epoch
|
||||
break :blk @as(i64, @intCast(lp.datetime.timestamp(.real)));
|
||||
};
|
||||
|
||||
const tm = try dt.localTime(timestamp);
|
||||
@@ -307,7 +308,7 @@ pub fn setCookie(self: *Document, cookie_str: []const u8, frame: *Frame) ![]cons
|
||||
c.deinit();
|
||||
return ""; // HttpOnly cookies cannot be set from JS
|
||||
}
|
||||
try frame._session.cookie_jar.add(c, std.Io.Clock.now(.real, lp.io).toSeconds(), false);
|
||||
try frame._session.cookie_jar.add(c, lp.datetime.timestamp(.real), false);
|
||||
return cookie_str;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ pub fn init(
|
||||
file.* = .{
|
||||
._proto = blob,
|
||||
._name = try blob._arena.dupe(u8, name),
|
||||
._last_modified = opts.lastModified orelse std.Io.Clock.now(.real, lp.io).toMilliseconds(),
|
||||
._last_modified = opts.lastModified orelse @intCast(lp.datetime.milliTimestamp(.real)),
|
||||
};
|
||||
blob._type = .{ .file = file };
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ const std = @import("std");
|
||||
const lp = @import("lightpanda");
|
||||
|
||||
const js = @import("../js/js.zig");
|
||||
const datetime = @import("../../datetime.zig");
|
||||
|
||||
const EventCounts = @import("EventCounts.zig");
|
||||
const PerformanceObserver = @import("PerformanceObserver.zig");
|
||||
@@ -48,7 +47,7 @@ _delivery_scheduled: bool = false,
|
||||
/// Get high-resolution timestamp in microseconds, rounded to 5μs increments
|
||||
/// to match browser behavior (prevents fingerprinting)
|
||||
pub fn highResTimestamp() u64 {
|
||||
const micros = datetime.microTimestamp(.monotonic);
|
||||
const micros = lp.datetime.microTimestamp(.boot);
|
||||
// Round to nearest 5 microseconds (like Firefox default)
|
||||
const rounded = @divTrunc(micros + 2, 5) * 5;
|
||||
return rounded;
|
||||
|
||||
@@ -215,7 +215,7 @@ fn fileFrom(source: *Blob, name: []const u8, page: *Page) !*File {
|
||||
file.* = .{
|
||||
._proto = blob,
|
||||
._name = try blob._arena.dupe(u8, name),
|
||||
._last_modified = std.Io.Clock.now(.real, lp.io).toMilliseconds(),
|
||||
._last_modified = @intCast(lp.datetime.milliTimestamp(.real)),
|
||||
};
|
||||
blob._type = .{ .file = file };
|
||||
blob.acquireRef();
|
||||
|
||||
@@ -179,7 +179,7 @@ pub fn parse(allocator: Allocator, url: [:0]const u8, str: []const u8) !Cookie {
|
||||
|
||||
var normalized_expires: ?f64 = null;
|
||||
if (max_age) |ma| {
|
||||
normalized_expires = @floatFromInt(std.Io.Clock.now(.real, lp.io).toSeconds() + ma);
|
||||
normalized_expires = @as(f64, @floatFromInt(lp.datetime.timestamp(.real))) + @as(f64, @floatFromInt(ma));
|
||||
} else {
|
||||
// max age takes priority over expires
|
||||
if (expires) |expires_| {
|
||||
@@ -484,7 +484,7 @@ pub const Jar = struct {
|
||||
pub fn add(
|
||||
self: *Jar,
|
||||
cookie: Cookie,
|
||||
request_time: i64,
|
||||
request_time: u64,
|
||||
/// Checks if addition comes from HTTP request or JS context.
|
||||
comptime is_http: bool,
|
||||
) !void {
|
||||
@@ -557,9 +557,9 @@ pub const Jar = struct {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn removeExpired(self: *Jar, request_time: ?i64) void {
|
||||
pub fn removeExpired(self: *Jar, request_time: ?u64) void {
|
||||
if (self.cookies.items.len == 0) return;
|
||||
const time = request_time orelse std.Io.Clock.now(.real, lp.io).toSeconds();
|
||||
const time = request_time orelse lp.datetime.timestamp(.real);
|
||||
var i: usize = self.cookies.items.len;
|
||||
while (i > 0) {
|
||||
i -= 1;
|
||||
@@ -572,7 +572,7 @@ pub const Jar = struct {
|
||||
|
||||
pub const LookupOpts = struct {
|
||||
is_http: bool,
|
||||
request_time: ?i64 = null,
|
||||
request_time: ?u64 = null,
|
||||
is_navigation: bool = true,
|
||||
prefix: ?[]const u8 = null,
|
||||
origin_url: ?[:0]const u8 = null,
|
||||
@@ -608,7 +608,7 @@ pub const Jar = struct {
|
||||
return;
|
||||
};
|
||||
|
||||
const now = std.Io.Clock.now(.real, lp.io).toSeconds();
|
||||
const now = lp.datetime.timestamp(.real);
|
||||
try self.add(c, now, true);
|
||||
}
|
||||
|
||||
@@ -623,7 +623,7 @@ pub const Jar = struct {
|
||||
}
|
||||
};
|
||||
|
||||
fn isCookieExpired(cookie: *const Cookie, now: i64) bool {
|
||||
fn isCookieExpired(cookie: *const Cookie, now: u64) bool {
|
||||
const ce = cookie.expires orelse return false;
|
||||
return ce <= @as(f64, @floatFromInt(now));
|
||||
}
|
||||
@@ -734,7 +734,7 @@ test "Jar: add" {
|
||||
}
|
||||
}.expect;
|
||||
|
||||
const now = std.Io.Clock.now(.real, lp.io).toSeconds();
|
||||
const now = lp.datetime.timestamp(.real);
|
||||
|
||||
var jar = Jar.init(testing.allocator, null);
|
||||
defer jar.deinit();
|
||||
@@ -766,7 +766,7 @@ test "Jar: add" {
|
||||
}
|
||||
|
||||
test "Jar: non-HTTP add must not replace or duplicate an HttpOnly cookie" {
|
||||
const now = std.Io.Clock.now(.real, lp.io).toSeconds();
|
||||
const now = lp.datetime.timestamp(.real);
|
||||
|
||||
var jar = Jar.init(testing.allocator, null);
|
||||
defer jar.deinit();
|
||||
@@ -788,7 +788,7 @@ test "Jar: add limit" {
|
||||
var jar = Jar.init(testing.allocator, null);
|
||||
defer jar.deinit();
|
||||
|
||||
const now = std.Io.Clock.now(.real, lp.io).toSeconds();
|
||||
const now = lp.datetime.timestamp(.real);
|
||||
|
||||
// add a too big cookie value.
|
||||
try testing.expectError(error.CookieSizeExceeded, jar.add(.{
|
||||
@@ -845,7 +845,7 @@ test "Jar: forRequest" {
|
||||
}
|
||||
}.expect;
|
||||
|
||||
const now = std.Io.Clock.now(.real, lp.io).toSeconds();
|
||||
const now = lp.datetime.timestamp(.real);
|
||||
|
||||
var jar = Jar.init(testing.allocator, null);
|
||||
defer jar.deinit();
|
||||
@@ -997,7 +997,7 @@ test "Jar: forRequest SameSite=Strict on cross-site navigation" {
|
||||
defer jar.deinit();
|
||||
|
||||
const victim_url: [:0]const u8 = "http://victim.example/";
|
||||
try jar.add(try Cookie.parse(testing.allocator, victim_url, "sid=STRICT_COOKIE; Path=/; SameSite=Strict"), std.Io.Clock.now(.real, lp.io).toSeconds(), true);
|
||||
try jar.add(try Cookie.parse(testing.allocator, victim_url, "sid=STRICT_COOKIE; Path=/; SameSite=Strict"), lp.datetime.timestamp(.real), true);
|
||||
|
||||
// Same-site navigation: cookie included.
|
||||
try expectCookies("sid=STRICT_COOKIE", &jar, "http://victim.example/transfer", .{
|
||||
@@ -1170,13 +1170,15 @@ test "Cookie: parse max-age" {
|
||||
try expectAttribute(.{ .expires = null }, null, "b;max-age=13.22");
|
||||
try expectAttribute(.{ .expires = null }, null, "b;max-age=13abc");
|
||||
|
||||
try expectAttribute(.{ .expires = std.Io.Clock.now(.real, lp.io).toSeconds() + 13 }, null, "b;max-age=13");
|
||||
try expectAttribute(.{ .expires = std.Io.Clock.now(.real, lp.io).toSeconds() + -22 }, null, "b;max-age=-22");
|
||||
try expectAttribute(.{ .expires = std.Io.Clock.now(.real, lp.io).toSeconds() + 4294967296 }, null, "b;max-age=4294967296");
|
||||
try expectAttribute(.{ .expires = std.Io.Clock.now(.real, lp.io).toSeconds() + -4294967296 }, null, "b;Max-Age= -4294967296");
|
||||
try expectAttribute(.{ .expires = std.Io.Clock.now(.real, lp.io).toSeconds() + 0 }, null, "b; Max-Age=0");
|
||||
try expectAttribute(.{ .expires = std.Io.Clock.now(.real, lp.io).toSeconds() + 500 }, null, "b; Max-Age = 500 ; Max-Age=invalid");
|
||||
try expectAttribute(.{ .expires = std.Io.Clock.now(.real, lp.io).toSeconds() + 1000 }, null, "b;max-age=600;max-age=0;max-age = 1000");
|
||||
// max-age can be negative, so the expected expiry has to be signed
|
||||
const now: i64 = @intCast(lp.datetime.timestamp(.real));
|
||||
try expectAttribute(.{ .expires = now + 13 }, null, "b;max-age=13");
|
||||
try expectAttribute(.{ .expires = now + -22 }, null, "b;max-age=-22");
|
||||
try expectAttribute(.{ .expires = now + 4294967296 }, null, "b;max-age=4294967296");
|
||||
try expectAttribute(.{ .expires = now + -4294967296 }, null, "b;Max-Age= -4294967296");
|
||||
try expectAttribute(.{ .expires = now + 0 }, null, "b; Max-Age=0");
|
||||
try expectAttribute(.{ .expires = now + 500 }, null, "b; Max-Age = 500 ; Max-Age=invalid");
|
||||
try expectAttribute(.{ .expires = now + 1000 }, null, "b;max-age=600;max-age=0;max-age = 1000");
|
||||
}
|
||||
|
||||
test "Cookie: parse expires" {
|
||||
@@ -1188,7 +1190,7 @@ test "Cookie: parse expires" {
|
||||
try expectAttribute(.{ .expires = 1918798080 }, null, "b;expires=Wed, 21 Oct 2030 07:28:00 GMT");
|
||||
try expectAttribute(.{ .expires = 1784275395 }, null, "b;expires=Fri, 17-Jul-2026 08:03:15 GMT");
|
||||
// max-age has priority over expires
|
||||
try expectAttribute(.{ .expires = std.Io.Clock.now(.real, lp.io).toSeconds() + 10 }, null, "b;Max-Age=10; expires=Wed, 21 Oct 2030 07:28:00 GMT");
|
||||
try expectAttribute(.{ .expires = lp.datetime.timestamp(.real) + 10 }, null, "b;Max-Age=10; expires=Wed, 21 Oct 2030 07:28:00 GMT");
|
||||
}
|
||||
|
||||
test "Cookie: parse all" {
|
||||
@@ -1206,7 +1208,7 @@ test "Cookie: parse all" {
|
||||
.http_only = true,
|
||||
.secure = true,
|
||||
.domain = ".lightpanda.io",
|
||||
.expires = @floatFromInt(std.Io.Clock.now(.real, lp.io).toSeconds() + 30),
|
||||
.expires = @floatFromInt(lp.datetime.timestamp(.real) + 30),
|
||||
}, "https://lightpanda.io/cms/users", "user-id=9000; HttpOnly; Max-Age=30; Secure; path=/; Domain=lightpanda.io");
|
||||
|
||||
try expectCookie(.{
|
||||
@@ -1217,7 +1219,7 @@ test "Cookie: parse all" {
|
||||
.secure = false,
|
||||
.domain = ".localhost",
|
||||
.same_site = .lax,
|
||||
.expires = @floatFromInt(std.Io.Clock.now(.real, lp.io).toSeconds() + 7200),
|
||||
.expires = @floatFromInt(lp.datetime.timestamp(.real) + 7200),
|
||||
}, "http://localhost:8000/login", "app_session=123; Max-Age=7200; path=/; domain=localhost; httponly; samesite=lax");
|
||||
}
|
||||
|
||||
|
||||
@@ -431,12 +431,12 @@ fn storeCookie(exec: *const Execution, init_: CookieInit, is_delete: bool) !void
|
||||
}
|
||||
// convert to absolute time, so the rest of the code is shared for
|
||||
// maxAge and expires.
|
||||
init.expires = (@as(f64, @floatFromInt(std.Io.Clock.now(.real, lp.io).toSeconds())) + max_age) * 1000.0;
|
||||
init.expires = (@as(f64, @floatFromInt(lp.datetime.timestamp(.real))) + max_age) * 1000.0;
|
||||
}
|
||||
|
||||
if (init.expires) |ms| {
|
||||
// 400 day expiry limit, per spec.
|
||||
const cap_ms = (@as(f64, @floatFromInt(std.Io.Clock.now(.real, lp.io).toSeconds())) + 400 * std.time.s_per_day) * 1000.0;
|
||||
const cap_ms = (@as(f64, @floatFromInt(lp.datetime.timestamp(.real))) + 400 * std.time.s_per_day) * 1000.0;
|
||||
init.expires = @min(ms, cap_ms);
|
||||
}
|
||||
|
||||
@@ -557,7 +557,7 @@ fn storeCookie(exec: *const Execution, init_: CookieInit, is_delete: bool) !void
|
||||
};
|
||||
|
||||
// CookieStore is a script API, so is_http = false.
|
||||
try session.cookie_jar.add(cookie, std.Io.Clock.now(.real, lp.io).toSeconds(), false);
|
||||
try session.cookie_jar.add(cookie, lp.datetime.timestamp(.real), false);
|
||||
}
|
||||
|
||||
// Control characters (U+0000–U+001F and U+007F DEL) and `;` cannot appear in
|
||||
|
||||
@@ -27,7 +27,6 @@ const Config = @import("../../Config.zig");
|
||||
const URL = @import("../../browser/URL.zig");
|
||||
const Mime = @import("../../browser/Mime.zig");
|
||||
const Notification = @import("../../Notification.zig");
|
||||
const timestamp = @import("../../datetime.zig").timestamp;
|
||||
|
||||
const HttpClient = @import("../../network/HttpClient.zig");
|
||||
const Cache = @import("../../network/cache/Cache.zig");
|
||||
@@ -328,7 +327,7 @@ pub fn httpRequestFail(bc: *CDP.BrowserContext, msg: *const Notification.Request
|
||||
// We're missing a bunch of fields, but, for now, this seems like enough
|
||||
try bc.cdp.sendEvent("Network.loadingFailed", .{
|
||||
.requestId = &id.toRequestId(msg.transfer),
|
||||
.timestamp = timestamp(.monotonic),
|
||||
.timestamp = lp.datetime.timestamp(.boot),
|
||||
// Seems to be what chrome answers with. I assume it depends on the type of error?
|
||||
.type = "Ping",
|
||||
.errorText = msg.err,
|
||||
@@ -365,8 +364,8 @@ pub fn httpRequestStart(bc: *CDP.BrowserContext, msg: *const Notification.Reques
|
||||
.initiator = .{ .type = "other" },
|
||||
.redirectHasExtraInfo = false, // TODO change after adding Network.requestWillBeSentExtraInfo
|
||||
.hasUserGesture = false,
|
||||
.timestamp = timestamp(.monotonic),
|
||||
.wallTime = timestamp(.clock),
|
||||
.timestamp = lp.datetime.timestamp(.boot),
|
||||
.wallTime = lp.datetime.timestamp(.real),
|
||||
}, .{ .session_id = session_id });
|
||||
}
|
||||
|
||||
@@ -383,7 +382,7 @@ pub fn httpResponseHeaderDone(arena: Allocator, bc: *CDP.BrowserContext, msg: *c
|
||||
.frameId = &id.toFrameId(req.document_frame_id orelse req.frame_id),
|
||||
.requestId = &id.toRequestId(transfer),
|
||||
.loaderId = &id.toLoaderId(req.loader_id),
|
||||
.timestamp = timestamp(.monotonic),
|
||||
.timestamp = lp.datetime.timestamp(.boot),
|
||||
.type = req.resource_type.string(),
|
||||
.response = ResponseWriter.init(arena, msg.transfer),
|
||||
.hasExtraInfo = false, // TODO change after adding Network.responseReceivedExtraInfo
|
||||
@@ -396,7 +395,7 @@ pub fn httpRequestDone(bc: *CDP.BrowserContext, msg: *const Notification.Request
|
||||
const session_id = bc.session_id orelse return;
|
||||
try bc.cdp.sendEvent("Network.loadingFinished", .{
|
||||
.requestId = &id.toRequestId(msg.transfer),
|
||||
.timestamp = timestamp(.monotonic),
|
||||
.timestamp = lp.datetime.timestamp(.boot),
|
||||
.encodedDataLength = msg.content_length,
|
||||
}, .{ .session_id = session_id });
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ const CDP = @import("../CDP.zig");
|
||||
const js = @import("../../browser/js/js.zig");
|
||||
const URL = @import("../../browser/URL.zig");
|
||||
const Frame = @import("../../browser/Frame.zig");
|
||||
const timestampF = @import("../../datetime.zig").timestamp;
|
||||
const Notification = @import("../../Notification.zig");
|
||||
|
||||
const log = lp.log;
|
||||
@@ -123,7 +122,7 @@ fn setLifecycleEventsEnabled(cmd: *CDP.Command) !void {
|
||||
const frame_id = &id.toFrameId(frame._frame_id);
|
||||
const loader_id = &id.toLoaderId(frame._loader_id);
|
||||
|
||||
const now = timestampF(.monotonic);
|
||||
const now = lp.datetime.timestamp(.boot);
|
||||
try sendPageLifecycle(bc, "DOMContentLoaded", now, frame_id, loader_id);
|
||||
try sendPageLifecycle(bc, "load", now, frame_id, loader_id);
|
||||
|
||||
|
||||
@@ -171,7 +171,7 @@ pub fn setCdpCookie(cookie_jar: *CookieJar, param: CdpCookie) !void {
|
||||
},
|
||||
};
|
||||
};
|
||||
try cookie_jar.add(cookie, std.Io.Clock.now(.real, lp.io).toSeconds(), true);
|
||||
try cookie_jar.add(cookie, lp.datetime.timestamp(.real), true);
|
||||
}
|
||||
|
||||
pub const CookieWriter = struct {
|
||||
|
||||
@@ -51,7 +51,7 @@ fn _loadFromFile(session: *Session, path: []const u8) !void {
|
||||
};
|
||||
|
||||
const jar = &session.cookie_jar;
|
||||
const now = std.Io.Clock.now(.real, lp.io).toSeconds();
|
||||
const now = lp.datetime.timestamp(.real);
|
||||
|
||||
var loaded: usize = 0;
|
||||
for (json_cookies) |jc| {
|
||||
|
||||
@@ -291,7 +291,7 @@ pub const DateTime = struct {
|
||||
|
||||
pub fn now() DateTime {
|
||||
return .{
|
||||
.micros = @intCast(microTimestamp(.clock)),
|
||||
.micros = @intCast(microTimestamp(.real)),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -522,30 +522,16 @@ pub const DateTime = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const TimestampMode = enum {
|
||||
clock,
|
||||
monotonic,
|
||||
|
||||
// .boot intends to keep counting across system suspend, matching the
|
||||
// old CLOCK_BOOTTIME / UPTIME_RAW choice.
|
||||
fn ioClock(comptime mode: TimestampMode) std.Io.Clock {
|
||||
return switch (mode) {
|
||||
.clock => .real,
|
||||
.monotonic => .boot,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub fn timestamp(comptime mode: TimestampMode) u64 {
|
||||
return @intCast(mode.ioClock().now(lp.io).toSeconds());
|
||||
pub fn timestamp(comptime clock: std.Io.Clock) u64 {
|
||||
return @intCast(clock.now(lp.io).toSeconds());
|
||||
}
|
||||
|
||||
pub fn milliTimestamp(comptime mode: TimestampMode) u64 {
|
||||
return @intCast(mode.ioClock().now(lp.io).toMilliseconds());
|
||||
pub fn milliTimestamp(comptime clock: std.Io.Clock) u64 {
|
||||
return @intCast(clock.now(lp.io).toMilliseconds());
|
||||
}
|
||||
|
||||
pub fn microTimestamp(comptime mode: TimestampMode) u64 {
|
||||
return @intCast(mode.ioClock().now(lp.io).toMicroseconds());
|
||||
pub fn microTimestamp(comptime clock: std.Io.Clock) u64 {
|
||||
return @intCast(clock.now(lp.io).toMicroseconds());
|
||||
}
|
||||
|
||||
fn writeDate(into: []u8, date: Date) u8 {
|
||||
@@ -1239,7 +1225,7 @@ test "DateTime: initUTC" {
|
||||
|
||||
test "DateTime: now" {
|
||||
const dt = DateTime.now();
|
||||
try testing.expectDelta(@as(i64, @intCast(microTimestamp(.clock))), dt.micros, 1000);
|
||||
try testing.expectDelta(@as(i64, @intCast(microTimestamp(.real))), dt.micros, 1000);
|
||||
}
|
||||
|
||||
test "DateTime: date" {
|
||||
|
||||
12
src/log.zig
12
src/log.zig
@@ -155,7 +155,7 @@ pub fn log(scope: Scope, level: Level, msg: []const u8, data: anytype) void {
|
||||
var buf: [4096]u8 = undefined;
|
||||
var w: std.Io.Writer = .fixed(&buf);
|
||||
logTo(scope, level, msg, data, &w) catch |log_err| {
|
||||
std.debug.print("$time={d} $level=fatal $scope={s} $msg=\"log err\" err={s} log_msg=\"{s}\"\n", .{ timestamp(.clock), @tagName(scope), @errorName(log_err), msg });
|
||||
std.debug.print("$time={d} $level=fatal $scope={s} $msg=\"log err\" err={s} log_msg=\"{s}\"\n", .{ timestamp(.real), @tagName(scope), @errorName(log_err), msg });
|
||||
return;
|
||||
};
|
||||
s(w.buffered());
|
||||
@@ -167,7 +167,7 @@ pub fn log(scope: Scope, level: Level, msg: []const u8, data: anytype) void {
|
||||
defer std.debug.unlockStderr();
|
||||
|
||||
logTo(scope, level, msg, data, &stderr.file_writer.interface) catch |log_err| {
|
||||
std.debug.print("$time={d} $level=fatal $scope={s} $msg=\"log err\" err={s} log_msg=\"{s}\"\n", .{ timestamp(.clock), @errorName(log_err), @tagName(scope), msg });
|
||||
std.debug.print("$time={d} $level=fatal $scope={s} $msg=\"log err\" err={s} log_msg=\"{s}\"\n", .{ timestamp(.real), @errorName(log_err), @tagName(scope), msg });
|
||||
};
|
||||
}
|
||||
|
||||
@@ -223,7 +223,7 @@ fn logLogfmt(scope: Scope, level: Level, msg: []const u8, kvs: []const KV, write
|
||||
|
||||
fn logLogFmtPrefix(scope: Scope, level: Level, msg: []const u8, writer: *std.Io.Writer) !void {
|
||||
try writer.writeAll("$time=");
|
||||
try writer.print("{d}", .{timestamp(.clock)});
|
||||
try writer.print("{d}", .{timestamp(.real)});
|
||||
|
||||
try writer.writeAll(" $scope=");
|
||||
try writer.writeAll(@tagName(scope));
|
||||
@@ -494,7 +494,7 @@ pub const LogFormatWriter = struct {
|
||||
|
||||
var first_log: std.atomic.Value(u64) = .init(0);
|
||||
fn elapsed() struct { time: f64, unit: []const u8 } {
|
||||
const now = timestamp(.monotonic);
|
||||
const now = timestamp(.boot);
|
||||
|
||||
var first = first_log.load(.monotonic);
|
||||
if (first == 0) {
|
||||
@@ -509,11 +509,11 @@ fn elapsed() struct { time: f64, unit: []const u8 } {
|
||||
}
|
||||
|
||||
const datetime = @import("datetime.zig");
|
||||
fn timestamp(comptime mode: datetime.TimestampMode) u64 {
|
||||
fn timestamp(comptime clock: std.Io.Clock) u64 {
|
||||
if (IS_TEST) {
|
||||
return 1739795092929;
|
||||
}
|
||||
return datetime.milliTimestamp(mode);
|
||||
return datetime.milliTimestamp(clock);
|
||||
}
|
||||
|
||||
const testing = @import("testing.zig");
|
||||
|
||||
@@ -23,7 +23,6 @@ const builtin = @import("builtin");
|
||||
const Inbox = @import("../Inbox.zig");
|
||||
const ArenaPool = @import("../ArenaPool.zig");
|
||||
const Notification = @import("../Notification.zig");
|
||||
const timestamp = @import("../datetime.zig").timestamp;
|
||||
|
||||
const CDP = @import("../cdp/CDP.zig");
|
||||
const Watchdog = @import("../Watchdog.zig");
|
||||
@@ -593,7 +592,7 @@ pub fn newRequest(self: *Client, req: Request, owner: ?*Owner) anyerror!*Transfe
|
||||
.client = self,
|
||||
.arena = arena,
|
||||
.id = self.incrReqId(),
|
||||
.start_time = timestamp(.monotonic),
|
||||
.start_time = lp.datetime.timestamp(.boot),
|
||||
// owner is set AFTER we've actually appended to the owner list,
|
||||
// so transfer.deinit's `if (self.owner)` branch only fires when
|
||||
// we're truly linked. Otherwise we'd try to remove a node from
|
||||
@@ -928,7 +927,7 @@ fn cacheLookup(self: *Client, transfer: *Transfer) !bool {
|
||||
|
||||
const cached = cache.get(arena, .{
|
||||
.url = req.url,
|
||||
.timestamp = std.Io.Clock.now(.real, lp.io).toSeconds(),
|
||||
.timestamp = lp.datetime.timestamp(.real),
|
||||
.request_headers = req_headers.items,
|
||||
}) orelse {
|
||||
lp.metrics.http_cache.incr(.miss);
|
||||
@@ -985,7 +984,7 @@ fn cacheRevalidated(self: *Client, transfer: *Transfer) !bool {
|
||||
|
||||
cache.renew(transfer.arena, .{
|
||||
.url = transfer._cache_key,
|
||||
.timestamp = std.Io.Clock.now(.real, lp.io).toSeconds(),
|
||||
.timestamp = lp.datetime.timestamp(.real),
|
||||
.headers = transfer.res.headers,
|
||||
}) catch |err| {
|
||||
log.warn(.cache, "renew failed", .{ .err = err });
|
||||
@@ -1023,7 +1022,7 @@ fn cacheStore(self: *Client, transfer: *Transfer) void {
|
||||
const vary = findHeader(headers, "vary");
|
||||
const maybe_cm = Cache.tryCache(
|
||||
arena,
|
||||
std.Io.Clock.now(.real, lp.io).toSeconds(),
|
||||
lp.datetime.timestamp(.real),
|
||||
transfer._cache_key,
|
||||
rh.status,
|
||||
rh.contentType(),
|
||||
|
||||
@@ -94,7 +94,7 @@ pub fn signRequest(
|
||||
headers: *Http.Headers,
|
||||
authority: []const u8,
|
||||
) !void {
|
||||
const now = std.Io.Clock.now(.real, lp.io).toSeconds();
|
||||
const now = lp.datetime.timestamp(.real);
|
||||
const expires = now + 60;
|
||||
|
||||
// build the signature-input value (without the sig1= label)
|
||||
|
||||
15
src/network/cache/Cache.zig
vendored
15
src/network/cache/Cache.zig
vendored
@@ -129,7 +129,7 @@ pub const CachedMetadata = struct {
|
||||
content_type: []const u8,
|
||||
|
||||
status: u16,
|
||||
stored_at: i64,
|
||||
stored_at: u64,
|
||||
age_at_store: u64,
|
||||
|
||||
cache_control: CacheControl,
|
||||
@@ -164,10 +164,11 @@ pub const CachedMetadata = struct {
|
||||
try writer.print("]", .{});
|
||||
}
|
||||
|
||||
pub fn isStale(self: CachedMetadata, timestamp: i64) bool {
|
||||
pub fn isStale(self: CachedMetadata, timestamp: u64) bool {
|
||||
if (self.cache_control.must_revalidate) return true;
|
||||
const age = (timestamp - self.stored_at) + @as(i64, @intCast(self.age_at_store));
|
||||
return age >= @as(i64, @intCast(self.cache_control.max_age));
|
||||
// saturating: a backwards wall-clock jump leaves the entry fresh
|
||||
const age = (timestamp -| self.stored_at) + self.age_at_store;
|
||||
return age >= self.cache_control.max_age;
|
||||
}
|
||||
|
||||
pub fn hasValidators(self: CachedMetadata) bool {
|
||||
@@ -197,13 +198,13 @@ pub const CachedMetadata = struct {
|
||||
|
||||
pub const CacheRequest = struct {
|
||||
url: []const u8,
|
||||
timestamp: i64,
|
||||
timestamp: u64,
|
||||
request_headers: []const Http.Header,
|
||||
};
|
||||
|
||||
pub const RenewResponse = struct {
|
||||
url: []const u8,
|
||||
timestamp: i64,
|
||||
timestamp: u64,
|
||||
headers: []const Http.Header,
|
||||
};
|
||||
|
||||
@@ -246,7 +247,7 @@ pub const CachedResponse = struct {
|
||||
|
||||
pub fn tryCache(
|
||||
arena: std.mem.Allocator,
|
||||
timestamp: i64,
|
||||
timestamp: u64,
|
||||
url: [:0]const u8,
|
||||
status: u16,
|
||||
content_type: ?[]const u8,
|
||||
|
||||
16
src/network/cache/FsCache.zig
vendored
16
src/network/cache/FsCache.zig
vendored
@@ -372,7 +372,7 @@ test "FsCache: basic put and get" {
|
||||
var arena = std.heap.ArenaAllocator.init(testing.allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
const now = std.Io.Clock.now(.real, lp.io).toSeconds();
|
||||
const now = lp.datetime.timestamp(.real);
|
||||
const meta = CachedMetadata{
|
||||
.url = "https://example.com",
|
||||
.content_type = "text/html",
|
||||
@@ -595,7 +595,7 @@ test "FsCache: vary hit and miss" {
|
||||
var arena = std.heap.ArenaAllocator.init(testing.allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
const now = std.Io.Clock.now(.real, lp.io).toSeconds();
|
||||
const now = lp.datetime.timestamp(.real);
|
||||
const meta = CachedMetadata{
|
||||
.url = "https://example.com",
|
||||
.content_type = "text/html",
|
||||
@@ -656,7 +656,7 @@ test "FsCache: vary multiple headers" {
|
||||
var arena = std.heap.ArenaAllocator.init(testing.allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
const now = std.Io.Clock.now(.real, lp.io).toSeconds();
|
||||
const now = lp.datetime.timestamp(.real);
|
||||
const meta = CachedMetadata{
|
||||
.url = "https://example.com",
|
||||
.content_type = "text/html",
|
||||
@@ -705,7 +705,7 @@ test "FsCache: clear removes all entries" {
|
||||
var arena = std.heap.ArenaAllocator.init(testing.allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
const now = std.Io.Clock.now(.real, lp.io).toSeconds();
|
||||
const now = lp.datetime.timestamp(.real);
|
||||
const base_meta_a = CachedMetadata{
|
||||
.url = "https://example.com/a",
|
||||
.status = 200,
|
||||
@@ -786,7 +786,7 @@ test "FsCache: put after clear works" {
|
||||
var arena = std.heap.ArenaAllocator.init(testing.allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
const now = std.Io.Clock.now(.real, lp.io).toSeconds();
|
||||
const now = lp.datetime.timestamp(.real);
|
||||
const meta = CachedMetadata{
|
||||
.url = "https://example.com",
|
||||
.content_type = "text/html",
|
||||
@@ -847,7 +847,7 @@ test "FsCache: evict removes entry" {
|
||||
var arena = std.heap.ArenaAllocator.init(testing.allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
const now = std.Io.Clock.now(.real, lp.io).toSeconds();
|
||||
const now = lp.datetime.timestamp(.real);
|
||||
const meta = CachedMetadata{
|
||||
.url = "https://example.com",
|
||||
.content_type = "text/html",
|
||||
@@ -895,7 +895,7 @@ test "FsCache: renew refreshes expiry" {
|
||||
var arena = std.heap.ArenaAllocator.init(testing.allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
const now: i64 = 5000;
|
||||
const now: u64 = 5000;
|
||||
const max_age: u64 = 1000;
|
||||
|
||||
const meta = CachedMetadata{
|
||||
@@ -958,7 +958,7 @@ test "FsCache: renew preserves body" {
|
||||
var arena = std.heap.ArenaAllocator.init(testing.allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
const now = std.Io.Clock.now(.real, lp.io).toSeconds();
|
||||
const now = lp.datetime.timestamp(.real);
|
||||
const meta = CachedMetadata{
|
||||
.url = "https://example.com",
|
||||
.content_type = "text/html",
|
||||
|
||||
Reference in New Issue
Block a user