Handle CDP messages with different order

The 'method' still needs to be the first or the second key
(in this case after the 'id').

Signed-off-by: Francis Bouvier <francis@lightpanda.io>
This commit is contained in:
Francis Bouvier
2024-06-07 15:59:57 +02:00
parent 3ad19dffa1
commit dc1456f4e8
8 changed files with 255 additions and 211 deletions

View File

@@ -4,7 +4,7 @@ const server = @import("../server.zig");
const Ctx = server.Cmd; const Ctx = server.Cmd;
const cdp = @import("cdp.zig"); const cdp = @import("cdp.zig");
const result = cdp.result; const result = cdp.result;
const getParams = cdp.getParams; const getMsg = cdp.getMsg;
const BrowserMethods = enum { const BrowserMethods = enum {
getVersion, getVersion,
@@ -15,7 +15,7 @@ const BrowserMethods = enum {
pub fn browser( pub fn browser(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
action: []const u8, action: []const u8,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
ctx: *Ctx, ctx: *Ctx,
@@ -38,10 +38,12 @@ const JsVersion = "12.4.254.8";
fn browserGetVersion( fn browserGetVersion(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
_: *std.json.Scanner, scanner: *std.json.Scanner,
_: *Ctx, _: *Ctx,
) ![]const u8 { ) ![]const u8 {
const msg = try getMsg(alloc, void, scanner);
const Res = struct { const Res = struct {
protocolVersion: []const u8, protocolVersion: []const u8,
product: []const u8, product: []const u8,
@@ -57,12 +59,12 @@ fn browserGetVersion(
.userAgent = UserAgent, .userAgent = UserAgent,
.jsVersion = JsVersion, .jsVersion = JsVersion,
}; };
return result(alloc, id, Res, res, null); return result(alloc, id orelse msg.id.?, Res, res, null);
} }
fn browserSetDownloadBehavior( fn browserSetDownloadBehavior(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
_: *Ctx, _: *Ctx,
) ![]const u8 { ) ![]const u8 {
@@ -72,15 +74,15 @@ fn browserSetDownloadBehavior(
downloadPath: ?[]const u8 = null, downloadPath: ?[]const u8 = null,
eventsEnabled: ?bool = null, eventsEnabled: ?bool = null,
}; };
_ = try getParams(alloc, Params, scanner); const msg = try getMsg(alloc, Params, scanner);
return result(alloc, id, null, null, null); return result(alloc, id orelse msg.id.?, null, null, null);
} }
const DevToolsWindowID = 1923710101; const DevToolsWindowID = 1923710101;
fn getWindowForTarget( fn getWindowForTarget(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
_: *Ctx, _: *Ctx,
) ![]const u8 { ) ![]const u8 {
@@ -89,8 +91,8 @@ fn getWindowForTarget(
const Params = struct { const Params = struct {
targetId: ?[]const u8 = null, targetId: ?[]const u8 = null,
}; };
const content = try cdp.getContent(alloc, ?Params, scanner); const msg = try cdp.getMsg(alloc, ?Params, scanner);
std.debug.assert(content.sessionID != null); std.debug.assert(msg.sessionID != null);
// output // output
const Resp = struct { const Resp = struct {
@@ -103,16 +105,16 @@ fn getWindowForTarget(
windowState: []const u8 = "normal", windowState: []const u8 = "normal",
} = .{}, } = .{},
}; };
return result(alloc, id, Resp, Resp{}, content.sessionID.?); return result(alloc, id orelse msg.id.?, Resp, Resp{}, msg.sessionID.?);
} }
fn setWindowBounds( fn setWindowBounds(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
_: *Ctx, _: *Ctx,
) ![]const u8 { ) ![]const u8 {
// NOTE: noop // NOTE: noop
const content = try cdp.getContent(alloc, void, scanner); const msg = try cdp.getMsg(alloc, void, scanner);
return result(alloc, id, null, null, content.sessionID); return result(alloc, id orelse msg.id.?, null, null, msg.sessionID);
} }

View File

@@ -53,26 +53,22 @@ pub fn do(
// handle 2 possible orders: // handle 2 possible orders:
// - id, method <...> // - id, method <...>
// - method, id <...> // - method, id <...>
var id_key = (try scanner.next()).string;
var id_token = try scanner.next();
var method_key = (try scanner.next()).string; var method_key = (try scanner.next()).string;
var method_token = try scanner.next(); var method_token: std.json.Token = undefined;
var id: ?u16 = null;
// check swap order // check swap order
if (!std.mem.eql(u8, id_key, "id")) { if (std.mem.eql(u8, method_key, "id")) {
const swap_key = method_key; id = try getId(&scanner, method_key);
const swap_token = method_token; method_key = (try scanner.next()).string;
method_key = id_key; method_token = try scanner.next();
method_token = id_token; } else {
id_key = swap_key; method_token = try scanner.next();
id_token = swap_token;
} }
try checkKey(id_key, "id");
try checkKey(method_key, "method"); try checkKey(method_key, "method");
// retrieve id and method // retrieve method
const id = try std.fmt.parseUnsigned(u64, id_token.number, 10);
const method_name = method_token.string; const method_name = method_token.string;
std.log.debug("cmd: id {any}, method {s}", .{ id, method_name }); std.log.debug("cmd: method {s}, id {any}", .{ method_name, id });
// retrieve domain from method // retrieve domain from method
var iter = std.mem.splitScalar(u8, method_name, '.'); var iter = std.mem.splitScalar(u8, method_name, '.');
@@ -128,7 +124,7 @@ const resultNullSession = "{{\"id\": {d}, \"result\": {{}}, \"sessionId\": \"{s}
// caller owns the slice returned // caller owns the slice returned
pub fn result( pub fn result(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: u16,
comptime T: ?type, comptime T: ?type,
res: anytype, res: anytype,
sessionID: ?[]const u8, sessionID: ?[]const u8,
@@ -142,7 +138,7 @@ pub fn result(
} }
const Resp = struct { const Resp = struct {
id: u64, id: u16,
result: T.?, result: T.?,
sessionId: ?[]const u8, sessionId: ?[]const u8,
}; };
@@ -171,108 +167,94 @@ pub fn sendEvent(
try server.sendSync(ctx, event_msg); try server.sendSync(ctx, event_msg);
} }
pub fn getParams( fn getParams(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
comptime T: type, comptime T: type,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
key: []const u8,
) !?T { ) !?T {
// if next token is the end of the object, there is no "params" // check key key is "params"
const t = try scanner.next(); if (!std.mem.eql(u8, "params", key)) return null;
if (t == .object_end) return null;
// if next token is not "params" there is no "params" // skip "params" if not requested
if (!std.mem.eql(u8, "params", t.string)) return null; if (T == void) {
var finished: usize = 0;
while (true) {
switch (try scanner.next()) {
.object_begin => finished += 1,
.object_end => finished -= 1,
else => continue,
}
if (finished == 0) break;
}
return void{};
}
// parse "params" // parse "params"
const options = std.json.ParseOptions{ const options = std.json.ParseOptions{
.max_value_len = scanner.input.len, .max_value_len = scanner.input.len,
.allocate = .alloc_if_needed, .allocate = .alloc_if_needed,
}; };
const params = try std.json.innerParse(T, alloc, scanner, options); return try std.json.innerParse(T, alloc, scanner, options);
return params;
} }
pub fn getSessionID(scanner: *std.json.Scanner) !?[]const u8 { fn getId(scanner: *std.json.Scanner, key: []const u8) !?u16 {
// if next token is the end of the object, there is no "sessionId" // check key is "id"
const t = try scanner.next(); if (!std.mem.eql(u8, "id", key)) return null;
if (t == .object_end) return null;
var n = t.string; // parse "id"
return try std.fmt.parseUnsigned(u16, (try scanner.next()).number, 10);
}
// if next token is "params" ignore them fn getSessionId(scanner: *std.json.Scanner, key: []const u8) !?[]const u8 {
// NOTE: will panic if it's not an empty "params" object
// TODO: maybe we should return a custom error here
if (std.mem.eql(u8, n, "params")) {
// ignore empty params
_ = (try scanner.next()).object_begin;
_ = (try scanner.next()).object_end;
n = (try scanner.next()).string;
}
// if next token is not "sessionId" there is no "sessionId" // check key is "sessionId"
if (!std.mem.eql(u8, n, "sessionId")) return null; if (!std.mem.eql(u8, "sessionId", key)) return null;
// parse "sessionId" // parse "sessionId"
return (try scanner.next()).string; return (try scanner.next()).string;
} }
pub fn getContent( pub fn getMsg(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
comptime T: type, comptime params_T: type,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
) !struct { params: T, sessionID: ?[]const u8 } { ) !struct { id: ?u16, params: ?params_T, sessionID: ?[]const u8 } {
var id: ?u16 = null;
// if next token is the end of the object, error var params: ?params_T = null;
const t = try scanner.next();
if (t == .object_end) return error.CDPNoContent;
var params: T = undefined;
var sessionID: ?[]const u8 = null; var sessionID: ?[]const u8 = null;
var n = t.string; var t: std.json.Token = undefined;
// params while (true) {
if (std.mem.eql(u8, n, "params")) { t = try scanner.next();
if (T == void) { if (t == .object_end) break;
if (t != .string) {
// ignore params return error.CDPMsgWrong;
var finished: usize = 0; }
while (true) { if (id == null) {
switch (try scanner.next()) { id = try getId(scanner, t.string);
.object_begin => finished += 1, if (id != null) continue;
.object_end => finished -= 1, }
else => continue, if (params == null) {
} params = try getParams(alloc, params_T, scanner, t.string);
if (finished == 0) break; if (params != null) continue;
} }
params = void{}; if (sessionID == null) {
} else { sessionID = try getSessionId(scanner, t.string);
// parse "params"
const options = std.json.ParseOptions{
.max_value_len = scanner.input.len,
.allocate = .alloc_if_needed,
};
params = try std.json.innerParse(T, alloc, scanner, options);
} }
// go next
n = (try scanner.next()).string;
} else {
params = switch (@typeInfo(T)) {
.Void => void{},
.Optional => null,
else => return error.CDPNoParams,
};
} }
if (std.mem.eql(u8, n, "sessionId")) { // end
sessionID = (try scanner.next()).string; std.log.debug(
} "id {any}, params {any}, sessionID: {any}, token {any}",
.{ id, params, sessionID, t },
return .{ .params = params, .sessionID = sessionID }; );
t = try scanner.next();
if (t != .end_of_document) return error.CDPMsgEnd;
return .{ .id = id, .params = params, .sessionID = sessionID };
} }
// Common // Common

View File

@@ -4,7 +4,7 @@ const server = @import("../server.zig");
const Ctx = server.Cmd; const Ctx = server.Cmd;
const cdp = @import("cdp.zig"); const cdp = @import("cdp.zig");
const result = cdp.result; const result = cdp.result;
const getParams = cdp.getParams; const getMsg = cdp.getMsg;
const stringify = cdp.stringify; const stringify = cdp.stringify;
const EmulationMethods = enum { const EmulationMethods = enum {
@@ -15,7 +15,7 @@ const EmulationMethods = enum {
pub fn emulation( pub fn emulation(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
action: []const u8, action: []const u8,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
ctx: *Ctx, ctx: *Ctx,
@@ -36,26 +36,26 @@ const MediaFeature = struct {
fn setEmulatedMedia( fn setEmulatedMedia(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
_: *Ctx, _: *Ctx,
) ![]const u8 { ) ![]const u8 {
// input // input
const Params = struct { const Params = struct {
media: ?[]const u8 = null, media: ?[]const u8 = null,
features: ?[]MediaFeature = null, features: ?[]MediaFeature = null,
}; };
_ = try getParams(alloc, Params, scanner); const msg = try getMsg(alloc, Params, scanner);
const sessionID = try cdp.getSessionID(scanner);
// output // output
// TODO: dummy // TODO: dummy
return result(alloc, id, null, null, sessionID); return result(alloc, id orelse msg.id.?, null, null, msg.sessionID);
} }
fn setFocusEmulationEnabled( fn setFocusEmulationEnabled(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
_: *Ctx, _: *Ctx,
) ![]const u8 { ) ![]const u8 {
@@ -64,24 +64,23 @@ fn setFocusEmulationEnabled(
const Params = struct { const Params = struct {
enabled: bool, enabled: bool,
}; };
_ = try getParams(alloc, Params, scanner); const msg = try getMsg(alloc, Params, scanner);
const sessionID = try cdp.getSessionID(scanner);
// output // output
// TODO: dummy // TODO: dummy
return result(alloc, id, null, null, sessionID); return result(alloc, id orelse msg.id.?, null, null, msg.sessionID);
} }
fn setDeviceMetricsOverride( fn setDeviceMetricsOverride(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
_: *Ctx, _: *Ctx,
) ![]const u8 { ) ![]const u8 {
// input // input
const content = try cdp.getContent(alloc, void, scanner); const msg = try cdp.getMsg(alloc, void, scanner);
// output // output
return result(alloc, id, null, null, content.sessionID); return result(alloc, id orelse msg.id.?, null, null, msg.sessionID);
} }

View File

@@ -4,7 +4,7 @@ const server = @import("../server.zig");
const Ctx = server.Cmd; const Ctx = server.Cmd;
const cdp = @import("cdp.zig"); const cdp = @import("cdp.zig");
const result = cdp.result; const result = cdp.result;
const getParams = cdp.getParams; const getMsg = cdp.getMsg;
const stringify = cdp.stringify; const stringify = cdp.stringify;
const LogMethods = enum { const LogMethods = enum {
@@ -13,24 +13,26 @@ const LogMethods = enum {
pub fn log( pub fn log(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
action: []const u8, action: []const u8,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
ctx: *Ctx, ctx: *Ctx,
) ![]const u8 { ) ![]const u8 {
const method = std.meta.stringToEnum(LogMethods, action) orelse const method = std.meta.stringToEnum(LogMethods, action) orelse
return error.UnknownMethod; return error.UnknownMethod;
return switch (method) { return switch (method) {
.enable => enable(alloc, id, scanner, ctx), .enable => logEnable(alloc, id, scanner, ctx),
}; };
} }
fn enable( fn logEnable(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
_: *Ctx, _: *Ctx,
) ![]const u8 { ) ![]const u8 {
const sessionID = try cdp.getSessionID(scanner); const msg = try getMsg(alloc, void, scanner);
return result(alloc, id, null, null, sessionID);
return result(alloc, id orelse msg.id.?, null, null, msg.sessionID);
} }

View File

@@ -4,7 +4,7 @@ const server = @import("../server.zig");
const Ctx = server.Cmd; const Ctx = server.Cmd;
const cdp = @import("cdp.zig"); const cdp = @import("cdp.zig");
const result = cdp.result; const result = cdp.result;
const getParams = cdp.getParams; const getMsg = cdp.getMsg;
const stringify = cdp.stringify; const stringify = cdp.stringify;
const NetworkMethods = enum { const NetworkMethods = enum {
@@ -13,24 +13,26 @@ const NetworkMethods = enum {
pub fn network( pub fn network(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
action: []const u8, action: []const u8,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
ctx: *Ctx, ctx: *Ctx,
) ![]const u8 { ) ![]const u8 {
const method = std.meta.stringToEnum(NetworkMethods, action) orelse const method = std.meta.stringToEnum(NetworkMethods, action) orelse
return error.UnknownMethod; return error.UnknownMethod;
return switch (method) { return switch (method) {
.enable => enable(alloc, id, scanner, ctx), .enable => networkEnable(alloc, id, scanner, ctx),
}; };
} }
fn enable( fn networkEnable(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
_: *Ctx, _: *Ctx,
) ![]const u8 { ) ![]const u8 {
const sessionID = try cdp.getSessionID(scanner); const msg = try getMsg(alloc, void, scanner);
return result(alloc, id, null, null, sessionID);
return result(alloc, id orelse msg.id.?, null, null, msg.sessionID);
} }

View File

@@ -4,7 +4,7 @@ const server = @import("../server.zig");
const Ctx = server.Cmd; const Ctx = server.Cmd;
const cdp = @import("cdp.zig"); const cdp = @import("cdp.zig");
const result = cdp.result; const result = cdp.result;
const getParams = cdp.getParams; const getMsg = cdp.getMsg;
const stringify = cdp.stringify; const stringify = cdp.stringify;
const sendEvent = cdp.sendEvent; const sendEvent = cdp.sendEvent;
@@ -21,7 +21,7 @@ const PageMethods = enum {
pub fn page( pub fn page(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
action: []const u8, action: []const u8,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
ctx: *Ctx, ctx: *Ctx,
@@ -40,12 +40,12 @@ pub fn page(
fn enable( fn enable(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
_: *Ctx, _: *Ctx,
) ![]const u8 { ) ![]const u8 {
const sessionID = try cdp.getSessionID(scanner); const msg = try getMsg(alloc, void, scanner);
return result(alloc, id, null, null, sessionID); return result(alloc, id orelse msg.id.?, null, null, msg.sessionID);
} }
const Frame = struct { const Frame = struct {
@@ -65,11 +65,12 @@ const Frame = struct {
fn getFrameTree( fn getFrameTree(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
ctx: *Ctx, ctx: *Ctx,
) ![]const u8 { ) ![]const u8 {
const sessionID = try cdp.getSessionID(scanner); const msg = try cdp.getMsg(alloc, void, scanner);
const FrameTree = struct { const FrameTree = struct {
frameTree: struct { frameTree: struct {
frame: Frame, frame: Frame,
@@ -87,12 +88,12 @@ fn getFrameTree(
}, },
}, },
}; };
return result(alloc, id, FrameTree, frameTree, sessionID); return result(alloc, id orelse msg.id.?, FrameTree, frameTree, msg.sessionID);
} }
fn setLifecycleEventsEnabled( fn setLifecycleEventsEnabled(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
ctx: *Ctx, ctx: *Ctx,
) ![]const u8 { ) ![]const u8 {
@@ -101,13 +102,12 @@ fn setLifecycleEventsEnabled(
const Params = struct { const Params = struct {
enabled: bool, enabled: bool,
}; };
_ = try getParams(alloc, Params, scanner); const msg = try getMsg(alloc, Params, scanner);
const sessionID = try cdp.getSessionID(scanner);
ctx.state.page_life_cycle_events = true; ctx.state.page_life_cycle_events = true;
// output // output
return result(alloc, id, null, null, sessionID); return result(alloc, id orelse msg.id.?, null, null, msg.sessionID);
} }
const LifecycleEvent = struct { const LifecycleEvent = struct {
@@ -119,7 +119,7 @@ const LifecycleEvent = struct {
fn addScriptToEvaluateOnNewDocument( fn addScriptToEvaluateOnNewDocument(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
_: *Ctx, _: *Ctx,
) ![]const u8 { ) ![]const u8 {
@@ -131,37 +131,34 @@ fn addScriptToEvaluateOnNewDocument(
includeCommandLineAPI: bool = false, includeCommandLineAPI: bool = false,
runImmediately: bool = false, runImmediately: bool = false,
}; };
_ = try getParams(alloc, Params, scanner); const msg = try getMsg(alloc, Params, scanner);
const sessionID = try cdp.getSessionID(scanner);
// output // output
const Res = struct { const Res = struct {
identifier: []const u8 = "1", identifier: []const u8 = "1",
}; };
return result(alloc, id, Res, Res{}, sessionID); return result(alloc, id orelse msg.id.?, Res, Res{}, msg.sessionID);
} }
fn createIsolatedWorld( fn createIsolatedWorld(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
_: *Ctx, _: *Ctx,
) ![]const u8 { ) ![]const u8 {
const msg = try getMsg(alloc, void, scanner);
// input
const content = try cdp.getContent(alloc, void, scanner);
// output // output
const Resp = struct { const Resp = struct {
executionContextId: u8 = 2, executionContextId: u8 = 2,
}; };
return result(alloc, id, Resp, .{}, content.sessionID); return result(alloc, id orelse msg.id.?, Resp, .{}, msg.sessionID);
} }
fn navigate( fn navigate(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
ctx: *Ctx, ctx: *Ctx,
) ![]const u8 { ) ![]const u8 {
@@ -174,12 +171,12 @@ fn navigate(
frameId: ?[]const u8 = null, frameId: ?[]const u8 = null,
referrerPolicy: ?[]const u8 = null, // TODO: enum referrerPolicy: ?[]const u8 = null, // TODO: enum
}; };
const input = try cdp.getContent(alloc, Params, scanner); const msg = try getMsg(alloc, Params, scanner);
const sessionID = input.sessionID; std.debug.assert(msg.sessionID != null);
std.debug.assert(sessionID != null); const params = msg.params.?;
// change state // change state
ctx.state.url = input.params.url; ctx.state.url = params.url;
ctx.state.loaderID = "AF8667A203C5392DBE9AC290044AA4C2"; ctx.state.loaderID = "AF8667A203C5392DBE9AC290044AA4C2";
var life_event = LifecycleEvent{ var life_event = LifecycleEvent{
@@ -193,11 +190,25 @@ fn navigate(
frameId: []const u8, frameId: []const u8,
}; };
const frame_started_loading = FrameStartedLoading{ .frameId = ctx.state.frameID }; const frame_started_loading = FrameStartedLoading{ .frameId = ctx.state.frameID };
try sendEvent(alloc, ctx, "Page.frameStartedLoading", FrameStartedLoading, frame_started_loading, sessionID); try sendEvent(
alloc,
ctx,
"Page.frameStartedLoading",
FrameStartedLoading,
frame_started_loading,
msg.sessionID,
);
if (ctx.state.page_life_cycle_events) { if (ctx.state.page_life_cycle_events) {
life_event.name = "init"; life_event.name = "init";
life_event.timestamp = 343721.796037; life_event.timestamp = 343721.796037;
try sendEvent(alloc, ctx, "Page.lifecycleEvent", LifecycleEvent, life_event, sessionID); try sendEvent(
alloc,
ctx,
"Page.lifecycleEvent",
LifecycleEvent,
life_event,
msg.sessionID,
);
} }
// output // output
@@ -210,16 +221,16 @@ fn navigate(
.frameId = ctx.state.frameID, .frameId = ctx.state.frameID,
.loaderId = ctx.state.loaderID, .loaderId = ctx.state.loaderID,
}; };
const res = try result(alloc, id, Resp, resp, sessionID); const res = try result(alloc, id orelse msg.id.?, Resp, resp, msg.sessionID);
std.log.debug("res {s}", .{res}); std.log.debug("res {s}", .{res});
try server.sendSync(ctx, res); try server.sendSync(ctx, res);
// Runtime.executionContextsCleared event // Runtime.executionContextsCleared event
try sendEvent(alloc, ctx, "Runtime.executionContextsCleared", void, {}, sessionID); try sendEvent(alloc, ctx, "Runtime.executionContextsCleared", void, {}, msg.sessionID);
// launch navigate // launch navigate
var p = try ctx.browser.currentSession().createPage(); var p = try ctx.browser.currentSession().createPage();
_ = try p.navigate(input.params.url); _ = try p.navigate(params.url);
// frameNavigated event // frameNavigated event
const FrameNavigated = struct { const FrameNavigated = struct {
@@ -235,11 +246,25 @@ fn navigate(
.loaderId = ctx.state.loaderID, .loaderId = ctx.state.loaderID,
}, },
}; };
try sendEvent(alloc, ctx, "Page.frameNavigated", FrameNavigated, frame_navigated, sessionID); try sendEvent(
alloc,
ctx,
"Page.frameNavigated",
FrameNavigated,
frame_navigated,
msg.sessionID,
);
if (ctx.state.page_life_cycle_events) { if (ctx.state.page_life_cycle_events) {
life_event.name = "load"; life_event.name = "load";
life_event.timestamp = 343721.824655; life_event.timestamp = 343721.824655;
try sendEvent(alloc, ctx, "Page.lifecycleEvent", LifecycleEvent, life_event, sessionID); try sendEvent(
alloc,
ctx,
"Page.lifecycleEvent",
LifecycleEvent,
life_event,
msg.sessionID,
);
} }
try Runtime.executionContextCreated( try Runtime.executionContextCreated(
@@ -250,7 +275,7 @@ fn navigate(
"", "",
"7102379147004877974.3265385113993241162", "7102379147004877974.3265385113993241162",
.{ .frameId = ctx.state.frameID }, .{ .frameId = ctx.state.frameID },
sessionID, msg.sessionID,
); );
try Runtime.executionContextCreated( try Runtime.executionContextCreated(
@@ -261,30 +286,65 @@ fn navigate(
"__playwright_utility_world__", "__playwright_utility_world__",
"-4572718120346458707.6016875269626438350", "-4572718120346458707.6016875269626438350",
.{ .isDefault = false, .type = "isolated", .frameId = ctx.state.frameID }, .{ .isDefault = false, .type = "isolated", .frameId = ctx.state.frameID },
sessionID, msg.sessionID,
); );
// domContentEventFired event // domContentEventFired event
ts_event = .{ .timestamp = 343721.803338 }; ts_event = .{ .timestamp = 343721.803338 };
try sendEvent(alloc, ctx, "Page.domContentEventFired", cdp.TimestampEvent, ts_event, sessionID); try sendEvent(
alloc,
ctx,
"Page.domContentEventFired",
cdp.TimestampEvent,
ts_event,
msg.sessionID,
);
if (ctx.state.page_life_cycle_events) { if (ctx.state.page_life_cycle_events) {
life_event.name = "DOMContentLoaded"; life_event.name = "DOMContentLoaded";
life_event.timestamp = 343721.803338; life_event.timestamp = 343721.803338;
try sendEvent(alloc, ctx, "Page.lifecycleEvent", LifecycleEvent, life_event, sessionID); try sendEvent(
alloc,
ctx,
"Page.lifecycleEvent",
LifecycleEvent,
life_event,
msg.sessionID,
);
} }
// loadEventFired event // loadEventFired event
ts_event = .{ .timestamp = 343721.824655 }; ts_event = .{ .timestamp = 343721.824655 };
try sendEvent(alloc, ctx, "Page.loadEventFired", cdp.TimestampEvent, ts_event, sessionID); try sendEvent(
alloc,
ctx,
"Page.loadEventFired",
cdp.TimestampEvent,
ts_event,
msg.sessionID,
);
if (ctx.state.page_life_cycle_events) { if (ctx.state.page_life_cycle_events) {
life_event.name = "load"; life_event.name = "load";
life_event.timestamp = 343721.824655; life_event.timestamp = 343721.824655;
try sendEvent(alloc, ctx, "Page.lifecycleEvent", LifecycleEvent, life_event, sessionID); try sendEvent(
alloc,
ctx,
"Page.lifecycleEvent",
LifecycleEvent,
life_event,
msg.sessionID,
);
} }
// frameStoppedLoading // frameStoppedLoading
const FrameStoppedLoading = struct { frameId: []const u8 }; const FrameStoppedLoading = struct { frameId: []const u8 };
try sendEvent(alloc, ctx, "Page.frameStoppedLoading", FrameStoppedLoading, .{ .frameId = ctx.state.frameID }, sessionID); try sendEvent(
alloc,
ctx,
"Page.frameStoppedLoading",
FrameStoppedLoading,
.{ .frameId = ctx.state.frameID },
msg.sessionID,
);
return ""; return "";
} }

View File

@@ -6,7 +6,7 @@ const server = @import("../server.zig");
const Ctx = server.Cmd; const Ctx = server.Cmd;
const cdp = @import("cdp.zig"); const cdp = @import("cdp.zig");
const result = cdp.result; const result = cdp.result;
const getParams = cdp.getParams; const getMsg = cdp.getMsg;
const stringify = cdp.stringify; const stringify = cdp.stringify;
const RuntimeMethods = enum { const RuntimeMethods = enum {
@@ -17,7 +17,7 @@ const RuntimeMethods = enum {
pub fn runtime( pub fn runtime(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
action: []const u8, action: []const u8,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
ctx: *Ctx, ctx: *Ctx,
@@ -33,14 +33,13 @@ pub fn runtime(
fn enable( fn enable(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
ctx: *Ctx, _: *Ctx,
) ![]const u8 { ) ![]const u8 {
_ = ctx;
// input // input
const sessionID = try cdp.getSessionID(scanner); const msg = try getMsg(alloc, void, scanner);
// output // output
// const uniqueID = "1367118932354479079.-1471398151593995849"; // const uniqueID = "1367118932354479079.-1471398151593995849";
@@ -56,7 +55,7 @@ fn enable(
// std.log.debug("res {s}", .{mainCtx}); // std.log.debug("res {s}", .{mainCtx});
// try server.sendAsync(ctx, mainCtx); // try server.sendAsync(ctx, mainCtx);
return result(alloc, id, null, null, sessionID); return result(alloc, id orelse msg.id.?, null, null, msg.sessionID);
} }
pub const AuxData = struct { pub const AuxData = struct {
@@ -76,7 +75,7 @@ const ExecutionContextDescription = struct {
pub fn executionContextCreated( pub fn executionContextCreated(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
ctx: *Ctx, ctx: *Ctx,
id: u64, id: u16,
origin: []const u8, origin: []const u8,
name: []const u8, name: []const u8,
uniqueID: []const u8, uniqueID: []const u8,
@@ -100,17 +99,18 @@ pub fn executionContextCreated(
fn runIfWaitingForDebugger( fn runIfWaitingForDebugger(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
_: *Ctx, _: *Ctx,
) ![]const u8 { ) ![]const u8 {
const sessionID = try cdp.getSessionID(scanner); const msg = try getMsg(alloc, void, scanner);
return result(alloc, id, null, null, sessionID);
return result(alloc, id orelse msg.id.?, null, null, msg.sessionID);
} }
fn evaluate( fn evaluate(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, _id: ?u16,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
ctx: *Ctx, ctx: *Ctx,
) ![]const u8 { ) ![]const u8 {
@@ -124,20 +124,21 @@ fn evaluate(
contextId: ?u8, contextId: ?u8,
}; };
const input = try cdp.getContent(alloc, Params, scanner); const msg = try getMsg(alloc, Params, scanner);
const sessionID = input.sessionID; std.debug.assert(msg.sessionID != null);
std.debug.assert(sessionID != null); const params = msg.params.?;
const id = _id orelse msg.id.?;
// save script in file at debug mode // save script in file at debug mode
std.log.debug("script {d} length: {d}", .{ id, input.params.expression.len }); std.log.debug("script {d} length: {d}", .{ id, params.expression.len });
if (std.log.defaultLogEnabled(.debug)) { if (std.log.defaultLogEnabled(.debug)) {
const name = try std.fmt.allocPrint(alloc, "id_{d}.js", .{id}); const name = try std.fmt.allocPrint(alloc, "id_{d}.js", .{id});
defer alloc.free(name); defer alloc.free(name);
const dir = try std.fs.cwd().makeOpenPath("zig-cache/tmp", .{}); const dir = try std.fs.cwd().makeOpenPath("zig-cache/tmp", .{});
const f = try dir.createFile(name, .{}); const f = try dir.createFile(name, .{});
defer f.close(); defer f.close();
const nb = try f.write(input.params.expression); const nb = try f.write(params.expression);
std.debug.assert(nb == input.params.expression.len); std.debug.assert(nb == params.expression.len);
const p = try dir.realpathAlloc(alloc, name); const p = try dir.realpathAlloc(alloc, name);
defer alloc.free(p); defer alloc.free(p);
std.log.debug("Script {d} saved at {s}", .{ id, p }); std.log.debug("Script {d} saved at {s}", .{ id, p });
@@ -149,7 +150,7 @@ fn evaluate(
// const page_alloc = ctx.browser.currentSession().page.?.arena.allocator(); // const page_alloc = ctx.browser.currentSession().page.?.arena.allocator();
const session_alloc = ctx.browser.currentSession().alloc; const session_alloc = ctx.browser.currentSession().alloc;
var res = jsruntime.JSResult{}; var res = jsruntime.JSResult{};
try ctx.browser.currentSession().env.run(session_alloc, input.params.expression, "cdp", &res, null); try ctx.browser.currentSession().env.run(session_alloc, params.expression, "cdp", &res, null);
defer res.deinit(session_alloc); defer res.deinit(session_alloc);
if (!res.success) { if (!res.success) {
@@ -168,5 +169,5 @@ fn evaluate(
description: []const u8 = "UtilityScript", description: []const u8 = "UtilityScript",
objectId: []const u8 = "7481631759780215274.3.2", objectId: []const u8 = "7481631759780215274.3.2",
}; };
return result(alloc, id, Resp, Resp{}, sessionID); return result(alloc, id, Resp, Resp{}, msg.sessionID);
} }

View File

@@ -4,7 +4,7 @@ const server = @import("../server.zig");
const Ctx = server.Cmd; const Ctx = server.Cmd;
const cdp = @import("cdp.zig"); const cdp = @import("cdp.zig");
const result = cdp.result; const result = cdp.result;
const getParams = cdp.getParams; const getMsg = cdp.getMsg;
const stringify = cdp.stringify; const stringify = cdp.stringify;
const TargetMethods = enum { const TargetMethods = enum {
@@ -16,7 +16,7 @@ const TargetMethods = enum {
pub fn target( pub fn target(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
action: []const u8, action: []const u8,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
ctx: *Ctx, ctx: *Ctx,
@@ -56,7 +56,7 @@ const TargetFilter = struct {
fn tagetSetAutoAttach( fn tagetSetAutoAttach(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
ctx: *Ctx, ctx: *Ctx,
) ![]const u8 { ) ![]const u8 {
@@ -66,12 +66,10 @@ fn tagetSetAutoAttach(
flatten: bool = true, flatten: bool = true,
filter: ?[]TargetFilter = null, filter: ?[]TargetFilter = null,
}; };
const params = try getParams(alloc, Params, scanner); const msg = try getMsg(alloc, Params, scanner);
std.log.debug("params {any}", .{params}); std.log.debug("params {any}", .{msg.params});
const sessionID = try cdp.getSessionID(scanner); if (msg.sessionID == null) {
if (sessionID == null) {
const attached = AttachToTarget{ const attached = AttachToTarget{
.sessionId = cdp.SessionID, .sessionId = cdp.SessionID,
.targetInfo = .{ .targetInfo = .{
@@ -84,12 +82,12 @@ fn tagetSetAutoAttach(
try cdp.sendEvent(alloc, ctx, "Target.attachedToTarget", AttachToTarget, attached, null); try cdp.sendEvent(alloc, ctx, "Target.attachedToTarget", AttachToTarget, attached, null);
} }
return result(alloc, id, null, null, sessionID); return result(alloc, id orelse msg.id.?, null, null, msg.sessionID);
} }
fn tagetGetTargetInfo( fn tagetGetTargetInfo(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
_: *Ctx, _: *Ctx,
) ![]const u8 { ) ![]const u8 {
@@ -98,7 +96,7 @@ fn tagetGetTargetInfo(
const Params = struct { const Params = struct {
targetId: ?[]const u8 = null, targetId: ?[]const u8 = null,
}; };
_ = try getParams(alloc, Params, scanner); const msg = try getMsg(alloc, Params, scanner);
// output // output
const TargetInfo = struct { const TargetInfo = struct {
@@ -117,7 +115,7 @@ fn tagetGetTargetInfo(
.targetId = BrowserTargetID, .targetId = BrowserTargetID,
.type = "browser", .type = "browser",
}; };
return result(alloc, id, TargetInfo, targetInfo, null); return result(alloc, id orelse msg.id.?, TargetInfo, targetInfo, null);
} }
const ContextID = "22648B09EDCCDD11109E2D4FEFBE4F89"; const ContextID = "22648B09EDCCDD11109E2D4FEFBE4F89";
@@ -125,9 +123,9 @@ const ContextSessionID = "4FDC2CB760A23A220497A05C95417CF4";
fn createBrowserContext( fn createBrowserContext(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
_: *Ctx, ctx: *Ctx,
) ![]const u8 { ) ![]const u8 {
// input // input
@@ -137,21 +135,20 @@ fn createBrowserContext(
proxyBypassList: ?[]const u8 = null, proxyBypassList: ?[]const u8 = null,
originsWithUniversalNetworkAccess: ?[][]const u8 = null, originsWithUniversalNetworkAccess: ?[][]const u8 = null,
}; };
_ = try getParams(alloc, Params, scanner); const msg = try getMsg(alloc, Params, scanner);
const sessionID = try cdp.getSessionID(scanner);
// output // output
const Resp = struct { const Resp = struct {
browserContextId: []const u8 = ContextID, browserContextId: []const u8 = ContextID,
}; };
return result(alloc, id, Resp, Resp{}, sessionID); return result(alloc, id orelse msg.id.?, Resp, Resp{}, msg.sessionID);
} }
const TargetID = "57356548460A8F29706A2ADF14316298"; const TargetID = "57356548460A8F29706A2ADF14316298";
fn createTarget( fn createTarget(
alloc: std.mem.Allocator, alloc: std.mem.Allocator,
id: u64, id: ?u16,
scanner: *std.json.Scanner, scanner: *std.json.Scanner,
ctx: *Ctx, ctx: *Ctx,
) ![]const u8 { ) ![]const u8 {
@@ -167,8 +164,7 @@ fn createTarget(
background: bool = false, background: bool = false,
forTab: ?bool = null, forTab: ?bool = null,
}; };
_ = try getParams(alloc, Params, scanner); const msg = try getMsg(alloc, Params, scanner);
const sessionID = try cdp.getSessionID(scanner);
// change CDP state // change CDP state
ctx.state.frameID = TargetID; ctx.state.frameID = TargetID;
@@ -188,11 +184,11 @@ fn createTarget(
}, },
.waitingForDebugger = true, .waitingForDebugger = true,
}; };
try cdp.sendEvent(alloc, ctx, "Target.attachedToTarget", AttachToTarget, attached, sessionID); try cdp.sendEvent(alloc, ctx, "Target.attachedToTarget", AttachToTarget, attached, msg.sessionID);
// output // output
const Resp = struct { const Resp = struct {
targetId: []const u8 = TargetID, targetId: []const u8 = TargetID,
}; };
return result(alloc, id, Resp, Resp{}, sessionID); return result(alloc, id orelse msg.id.?, Resp, Resp{}, msg.sessionID);
} }