Rework page wait again

Further reducing bouncing between page and server for loop polling. If there is
a page, the page polls. If there isn't a page, the server polls. Simpler.
This commit is contained in:
Karl Seguin
2025-09-03 19:37:09 +08:00
parent e237e709b6
commit b6137b03cd
12 changed files with 185 additions and 179 deletions

View File

@@ -124,48 +124,58 @@ pub const Server = struct {
client.* = try Client.init(socket, self);
defer client.deinit();
var last_message = timestamp();
var http = &self.app.http;
http.monitorSocket(socket);
defer http.unmonitorSocket();
std.debug.assert(client.mode == .http);
while (true) {
if (http.poll(10) == .extra_socket) {
const n = posix.read(socket, client.readBuf()) catch |err| {
log.warn(.app, "CDP read", .{ .err = err });
return;
};
if (n == 0) {
log.info(.app, "CDP disconnect", .{});
return;
}
const more = client.processData(n) catch false;
if (!more) {
return;
}
last_message = timestamp();
} else if (timestamp() - last_message > timeout_ms) {
if (http.poll(timeout_ms) != .extra_socket) {
log.info(.app, "CDP timeout", .{});
return;
}
// We have 3 types of "events":
// - Incoming CDP messages
// - Network events from the browser
// - Timeouts from the browser
// The call to http.poll above handles the first two (which is why
// we pass the client socket to it). But browser timeouts aren't
// hooked into that. So we need to go to the browser page (if there
// is one), and ask it to process any pending events. That action
// doesn't starve #2 (Network events from the browser), because
// page.wait() handles that too. But it does starve #1 (Incoming CDP
// messages). The good news is that, while the Page is mostly
// unaware of CDP, it will only block if it actually has something to
// do AND it knows if we're waiting on an intercept request, and will
// eagerly return control here in those cases.
if (try client.readSocket() == false) {
return;
}
if (client.mode == .cdp) {
client.mode.cdp.pageWait();
break; // switch to our CDP loop
}
}
var cdp = &client.mode.cdp;
var last_message = timestamp();
var ms_remaining = timeout_ms;
while (true) {
switch (cdp.pageWait(ms_remaining)) {
.extra_socket => {
if (try client.readSocket() == false) {
return;
}
last_message = timestamp();
ms_remaining = timeout_ms;
},
.no_page => {
if (http.poll(ms_remaining) != .extra_socket) {
log.info(.app, "CDP timeout", .{});
return;
}
if (try client.readSocket() == false) {
return;
}
last_message = timestamp();
ms_remaining = timeout_ms;
},
.done => {
std.debug.print("ok\n", .{});
const elapsed = timestamp() - last_message;
if (elapsed > ms_remaining) {
log.info(.app, "CDP timeout", .{});
return;
}
ms_remaining -= @as(i32, @intCast(elapsed));
},
}
}
}
@@ -222,6 +232,20 @@ pub const Client = struct {
self.send_arena.deinit();
}
fn readSocket(self: *Client) !bool {
const n = posix.read(self.socket, self.readBuf()) catch |err| {
log.warn(.app, "CDP read", .{ .err = err });
return false;
};
if (n == 0) {
log.info(.app, "CDP disconnect", .{});
return false;
}
return self.processData(n) catch false;
}
fn readBuf(self: *Client) []u8 {
return self.reader.readBuf();
}