mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 07:03:29 +00:00
cdp: refacto message JSON read
This commit is contained in:
@@ -22,7 +22,7 @@ const server = @import("../server.zig");
|
||||
const Ctx = server.Ctx;
|
||||
const cdp = @import("cdp.zig");
|
||||
const result = cdp.result;
|
||||
const getMsg = cdp.getMsg;
|
||||
const IncomingMessage = @import("msg.zig").IncomingMessage;
|
||||
|
||||
const log = std.log.scoped(.cdp);
|
||||
|
||||
@@ -35,18 +35,17 @@ const Methods = enum {
|
||||
|
||||
pub fn browser(
|
||||
alloc: std.mem.Allocator,
|
||||
id: ?u16,
|
||||
msg: *IncomingMessage,
|
||||
action: []const u8,
|
||||
scanner: *std.json.Scanner,
|
||||
ctx: *Ctx,
|
||||
) ![]const u8 {
|
||||
const method = std.meta.stringToEnum(Methods, action) orelse
|
||||
return error.UnknownMethod;
|
||||
return switch (method) {
|
||||
.getVersion => getVersion(alloc, id, scanner, ctx),
|
||||
.setDownloadBehavior => setDownloadBehavior(alloc, id, scanner, ctx),
|
||||
.getWindowForTarget => getWindowForTarget(alloc, id, scanner, ctx),
|
||||
.setWindowBounds => setWindowBounds(alloc, id, scanner, ctx),
|
||||
.getVersion => getVersion(alloc, msg, ctx),
|
||||
.setDownloadBehavior => setDownloadBehavior(alloc, msg, ctx),
|
||||
.getWindowForTarget => getWindowForTarget(alloc, msg, ctx),
|
||||
.setWindowBounds => setWindowBounds(alloc, msg, ctx),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -59,14 +58,12 @@ const JsVersion = "12.4.254.8";
|
||||
|
||||
fn getVersion(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
_: *Ctx,
|
||||
) ![]const u8 {
|
||||
|
||||
// input
|
||||
const msg = try getMsg(alloc, _id, void, scanner);
|
||||
log.debug("Req > id {d}, method {s}", .{ msg.id, "browser.getVersion" });
|
||||
const input = try msg.getInput(alloc, void);
|
||||
log.debug("Req > id {d}, method {s}", .{ input.id, "browser.getVersion" });
|
||||
|
||||
// ouput
|
||||
const Res = struct {
|
||||
@@ -76,17 +73,15 @@ fn getVersion(
|
||||
userAgent: []const u8 = UserAgent,
|
||||
jsVersion: []const u8 = JsVersion,
|
||||
};
|
||||
return result(alloc, msg.id, Res, .{}, null);
|
||||
return result(alloc, input.id, Res, .{}, null);
|
||||
}
|
||||
|
||||
// TODO: noop method
|
||||
fn setDownloadBehavior(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
_: *Ctx,
|
||||
) ![]const u8 {
|
||||
|
||||
// input
|
||||
const Params = struct {
|
||||
behavior: []const u8,
|
||||
@@ -94,11 +89,11 @@ fn setDownloadBehavior(
|
||||
downloadPath: ?[]const u8 = null,
|
||||
eventsEnabled: ?bool = null,
|
||||
};
|
||||
const msg = try getMsg(alloc, _id, Params, scanner);
|
||||
log.debug("REQ > id {d}, method {s}", .{ msg.id, "browser.setDownloadBehavior" });
|
||||
const input = try msg.getInput(alloc, Params);
|
||||
log.debug("REQ > id {d}, method {s}", .{ input.id, "browser.setDownloadBehavior" });
|
||||
|
||||
// output
|
||||
return result(alloc, msg.id, null, null, null);
|
||||
return result(alloc, input.id, null, null, null);
|
||||
}
|
||||
|
||||
// TODO: hard coded ID
|
||||
@@ -106,8 +101,7 @@ const DevToolsWindowID = 1923710101;
|
||||
|
||||
fn getWindowForTarget(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
_: *Ctx,
|
||||
) ![]const u8 {
|
||||
|
||||
@@ -115,9 +109,9 @@ fn getWindowForTarget(
|
||||
const Params = struct {
|
||||
targetId: ?[]const u8 = null,
|
||||
};
|
||||
const msg = try cdp.getMsg(alloc, _id, ?Params, scanner);
|
||||
std.debug.assert(msg.sessionID != null);
|
||||
log.debug("Req > id {d}, method {s}", .{ msg.id, "browser.getWindowForTarget" });
|
||||
const input = try msg.getInput(alloc, Params);
|
||||
std.debug.assert(input.sessionId != null);
|
||||
log.debug("Req > id {d}, method {s}", .{ input.id, "browser.getWindowForTarget" });
|
||||
|
||||
// output
|
||||
const Resp = struct {
|
||||
@@ -130,21 +124,20 @@ fn getWindowForTarget(
|
||||
windowState: []const u8 = "normal",
|
||||
} = .{},
|
||||
};
|
||||
return result(alloc, msg.id, Resp, Resp{}, msg.sessionID.?);
|
||||
return result(alloc, input.id, Resp, Resp{}, input.sessionId);
|
||||
}
|
||||
|
||||
// TODO: noop method
|
||||
fn setWindowBounds(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
_: *Ctx,
|
||||
) ![]const u8 {
|
||||
const input = try msg.getInput(alloc, void);
|
||||
|
||||
// input
|
||||
const msg = try cdp.getMsg(alloc, _id, void, scanner);
|
||||
log.debug("Req > id {d}, method {s}", .{ msg.id, "browser.setWindowBounds" });
|
||||
log.debug("Req > id {d}, method {s}", .{ input.id, "browser.setWindowBounds" });
|
||||
|
||||
// output
|
||||
return result(alloc, msg.id, null, null, msg.sessionID);
|
||||
return result(alloc, input.id, null, null, input.sessionId);
|
||||
}
|
||||
|
||||
154
src/cdp/cdp.zig
154
src/cdp/cdp.zig
@@ -30,6 +30,7 @@ const network = @import("network.zig").network;
|
||||
const emulation = @import("emulation.zig").emulation;
|
||||
const fetch = @import("fetch.zig").fetch;
|
||||
const performance = @import("performance.zig").performance;
|
||||
const IncomingMessage = @import("msg.zig").IncomingMessage;
|
||||
|
||||
const log_cdp = std.log.scoped(.cdp);
|
||||
|
||||
@@ -70,51 +71,29 @@ pub fn do(
|
||||
ctx: *Ctx,
|
||||
) ![]const u8 {
|
||||
|
||||
// JSON scanner
|
||||
var scanner = std.json.Scanner.initCompleteInput(alloc, s);
|
||||
defer scanner.deinit();
|
||||
// incoming message parser
|
||||
var msg = IncomingMessage.init(alloc, s);
|
||||
defer msg.deinit();
|
||||
|
||||
std.debug.assert(try scanner.next() == .object_begin);
|
||||
|
||||
// handle 2 possible orders:
|
||||
// - id, method <...>
|
||||
// - method, id <...>
|
||||
var method_key = try nextString(&scanner);
|
||||
var method_token: std.json.Token = undefined;
|
||||
var id: ?u16 = null;
|
||||
// check swap order
|
||||
if (std.mem.eql(u8, method_key, "id")) {
|
||||
id = try getId(&scanner, method_key);
|
||||
method_key = try nextString(&scanner);
|
||||
method_token = try scanner.next();
|
||||
} else {
|
||||
method_token = try scanner.next();
|
||||
}
|
||||
try checkKey(method_key, "method");
|
||||
|
||||
// retrieve method
|
||||
if (method_token != .string) {
|
||||
return error.WrongTokenType;
|
||||
}
|
||||
const method_name = method_token.string;
|
||||
const method = try msg.getMethod();
|
||||
|
||||
// retrieve domain from method
|
||||
var iter = std.mem.splitScalar(u8, method_name, '.');
|
||||
var iter = std.mem.splitScalar(u8, method, '.');
|
||||
const domain = std.meta.stringToEnum(Domains, iter.first()) orelse
|
||||
return error.UnknonwDomain;
|
||||
|
||||
// select corresponding domain
|
||||
const action = iter.next() orelse return error.BadMethod;
|
||||
return switch (domain) {
|
||||
.Browser => browser(alloc, id, action, &scanner, ctx),
|
||||
.Target => target(alloc, id, action, &scanner, ctx),
|
||||
.Page => page(alloc, id, action, &scanner, ctx),
|
||||
.Log => log(alloc, id, action, &scanner, ctx),
|
||||
.Runtime => runtime(alloc, id, action, &scanner, s, ctx),
|
||||
.Network => network(alloc, id, action, &scanner, ctx),
|
||||
.Emulation => emulation(alloc, id, action, &scanner, ctx),
|
||||
.Fetch => fetch(alloc, id, action, &scanner, ctx),
|
||||
.Performance => performance(alloc, id, action, &scanner, ctx),
|
||||
.Browser => browser(alloc, &msg, action, ctx),
|
||||
.Target => target(alloc, &msg, action, ctx),
|
||||
.Page => page(alloc, &msg, action, ctx),
|
||||
.Log => log(alloc, &msg, action, ctx),
|
||||
.Runtime => runtime(alloc, &msg, action, ctx),
|
||||
.Network => network(alloc, &msg, action, ctx),
|
||||
.Emulation => emulation(alloc, &msg, action, ctx),
|
||||
.Fetch => fetch(alloc, &msg, action, ctx),
|
||||
.Performance => performance(alloc, &msg, action, ctx),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -133,14 +112,6 @@ pub const State = struct {
|
||||
// Utils
|
||||
// -----
|
||||
|
||||
fn nextString(scanner: *std.json.Scanner) ![]const u8 {
|
||||
const token = try scanner.next();
|
||||
if (token != .string) {
|
||||
return error.WrongTokenType;
|
||||
}
|
||||
return token.string;
|
||||
}
|
||||
|
||||
pub fn dumpFile(
|
||||
alloc: std.mem.Allocator,
|
||||
id: u16,
|
||||
@@ -158,10 +129,6 @@ pub fn dumpFile(
|
||||
defer alloc.free(p);
|
||||
}
|
||||
|
||||
fn checkKey(key: []const u8, token: []const u8) !void {
|
||||
if (!std.mem.eql(u8, key, token)) return error.WrongToken;
|
||||
}
|
||||
|
||||
// caller owns the slice returned
|
||||
pub fn stringify(alloc: std.mem.Allocator, res: anytype) ![]const u8 {
|
||||
var out = std.ArrayList(u8).init(alloc);
|
||||
@@ -229,97 +196,6 @@ pub fn sendEvent(
|
||||
try server.sendAsync(ctx, event_msg);
|
||||
}
|
||||
|
||||
fn getParams(
|
||||
alloc: std.mem.Allocator,
|
||||
comptime T: type,
|
||||
scanner: *std.json.Scanner,
|
||||
key: []const u8,
|
||||
) !?T {
|
||||
|
||||
// check key is "params"
|
||||
if (!std.mem.eql(u8, "params", key)) return null;
|
||||
|
||||
// skip "params" if not requested
|
||||
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"
|
||||
const options = std.json.ParseOptions{
|
||||
.max_value_len = scanner.input.len,
|
||||
.allocate = .alloc_if_needed,
|
||||
};
|
||||
return try std.json.innerParse(T, alloc, scanner, options);
|
||||
}
|
||||
|
||||
fn getId(scanner: *std.json.Scanner, key: []const u8) !?u16 {
|
||||
|
||||
// check key is "id"
|
||||
if (!std.mem.eql(u8, "id", key)) return null;
|
||||
|
||||
// parse "id"
|
||||
return try std.fmt.parseUnsigned(u16, (try scanner.next()).number, 10);
|
||||
}
|
||||
|
||||
fn getSessionId(scanner: *std.json.Scanner, key: []const u8) !?[]const u8 {
|
||||
|
||||
// check key is "sessionId"
|
||||
if (!std.mem.eql(u8, "sessionId", key)) return null;
|
||||
|
||||
// parse "sessionId"
|
||||
return try nextString(scanner);
|
||||
}
|
||||
|
||||
pub fn getMsg(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
comptime params_T: type,
|
||||
scanner: *std.json.Scanner,
|
||||
) !struct { id: u16, params: ?params_T, sessionID: ?[]const u8 } {
|
||||
var id_msg: ?u16 = null;
|
||||
var params: ?params_T = null;
|
||||
var sessionID: ?[]const u8 = null;
|
||||
|
||||
var t: std.json.Token = undefined;
|
||||
|
||||
while (true) {
|
||||
t = try scanner.next();
|
||||
if (t == .object_end) break;
|
||||
if (t != .string) {
|
||||
return error.WrongTokenType;
|
||||
}
|
||||
if (_id == null and id_msg == null) {
|
||||
id_msg = try getId(scanner, t.string);
|
||||
if (id_msg != null) continue;
|
||||
}
|
||||
if (params == null) {
|
||||
params = try getParams(alloc, params_T, scanner, t.string);
|
||||
if (params != null) continue;
|
||||
}
|
||||
if (sessionID == null) {
|
||||
sessionID = try getSessionId(scanner, t.string);
|
||||
}
|
||||
}
|
||||
|
||||
// end
|
||||
t = try scanner.next();
|
||||
if (t != .end_of_document) return error.CDPMsgEnd;
|
||||
|
||||
// check id
|
||||
if (_id == null and id_msg == null) return error.RequestWithoutID;
|
||||
|
||||
return .{ .id = _id orelse id_msg.?, .params = params, .sessionID = sessionID };
|
||||
}
|
||||
|
||||
// Common
|
||||
// ------
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@ const server = @import("../server.zig");
|
||||
const Ctx = server.Ctx;
|
||||
const cdp = @import("cdp.zig");
|
||||
const result = cdp.result;
|
||||
const getMsg = cdp.getMsg;
|
||||
const stringify = cdp.stringify;
|
||||
const IncomingMessage = @import("msg.zig").IncomingMessage;
|
||||
|
||||
const log = std.log.scoped(.cdp);
|
||||
|
||||
@@ -36,18 +36,17 @@ const Methods = enum {
|
||||
|
||||
pub fn emulation(
|
||||
alloc: std.mem.Allocator,
|
||||
id: ?u16,
|
||||
msg: *IncomingMessage,
|
||||
action: []const u8,
|
||||
scanner: *std.json.Scanner,
|
||||
ctx: *Ctx,
|
||||
) ![]const u8 {
|
||||
const method = std.meta.stringToEnum(Methods, action) orelse
|
||||
return error.UnknownMethod;
|
||||
return switch (method) {
|
||||
.setEmulatedMedia => setEmulatedMedia(alloc, id, scanner, ctx),
|
||||
.setFocusEmulationEnabled => setFocusEmulationEnabled(alloc, id, scanner, ctx),
|
||||
.setDeviceMetricsOverride => setDeviceMetricsOverride(alloc, id, scanner, ctx),
|
||||
.setTouchEmulationEnabled => setTouchEmulationEnabled(alloc, id, scanner, ctx),
|
||||
.setEmulatedMedia => setEmulatedMedia(alloc, msg, ctx),
|
||||
.setFocusEmulationEnabled => setFocusEmulationEnabled(alloc, msg, ctx),
|
||||
.setDeviceMetricsOverride => setDeviceMetricsOverride(alloc, msg, ctx),
|
||||
.setTouchEmulationEnabled => setTouchEmulationEnabled(alloc, msg, ctx),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -59,8 +58,7 @@ const MediaFeature = struct {
|
||||
// TODO: noop method
|
||||
fn setEmulatedMedia(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
_: *Ctx,
|
||||
) ![]const u8 {
|
||||
|
||||
@@ -69,57 +67,52 @@ fn setEmulatedMedia(
|
||||
media: ?[]const u8 = null,
|
||||
features: ?[]MediaFeature = null,
|
||||
};
|
||||
const msg = try getMsg(alloc, _id, Params, scanner);
|
||||
log.debug("Req > id {d}, method {s}", .{ msg.id, "emulation.setEmulatedMedia" });
|
||||
const input = try msg.getInput(alloc, Params);
|
||||
log.debug("Req > id {d}, method {s}", .{ input.id, "emulation.setEmulatedMedia" });
|
||||
|
||||
// output
|
||||
return result(alloc, msg.id, null, null, msg.sessionID);
|
||||
return result(alloc, input.id, null, null, input.sessionId);
|
||||
}
|
||||
|
||||
// TODO: noop method
|
||||
fn setFocusEmulationEnabled(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
_: *Ctx,
|
||||
) ![]const u8 {
|
||||
|
||||
// input
|
||||
const Params = struct {
|
||||
enabled: bool,
|
||||
};
|
||||
const msg = try getMsg(alloc, _id, Params, scanner);
|
||||
log.debug("Req > id {d}, method {s}", .{ msg.id, "emulation.setFocusEmulationEnabled" });
|
||||
const input = try msg.getInput(alloc, Params);
|
||||
log.debug("Req > id {d}, method {s}", .{ input.id, "emulation.setFocusEmulationEnabled" });
|
||||
|
||||
// output
|
||||
return result(alloc, msg.id, null, null, msg.sessionID);
|
||||
return result(alloc, input.id, null, null, input.sessionId);
|
||||
}
|
||||
|
||||
// TODO: noop method
|
||||
fn setDeviceMetricsOverride(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
_: *Ctx,
|
||||
) ![]const u8 {
|
||||
|
||||
// input
|
||||
const msg = try cdp.getMsg(alloc, _id, void, scanner);
|
||||
log.debug("Req > id {d}, method {s}", .{ msg.id, "emulation.setDeviceMetricsOverride" });
|
||||
const input = try msg.getInput(alloc, void);
|
||||
log.debug("Req > id {d}, method {s}", .{ input.id, "emulation.setDeviceMetricsOverride" });
|
||||
|
||||
// output
|
||||
return result(alloc, msg.id, null, null, msg.sessionID);
|
||||
return result(alloc, input.id, null, null, input.sessionId);
|
||||
}
|
||||
|
||||
// TODO: noop method
|
||||
fn setTouchEmulationEnabled(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
_: *Ctx,
|
||||
) ![]const u8 {
|
||||
const msg = try cdp.getMsg(alloc, _id, void, scanner);
|
||||
log.debug("Req > id {d}, method {s}", .{ msg.id, "emulation.setTouchEmulationEnabled" });
|
||||
const input = try msg.getInput(alloc, void);
|
||||
log.debug("Req > id {d}, method {s}", .{ input.id, "emulation.setTouchEmulationEnabled" });
|
||||
|
||||
return result(alloc, msg.id, null, null, msg.sessionID);
|
||||
return result(alloc, input.id, null, null, input.sessionId);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ const server = @import("../server.zig");
|
||||
const Ctx = server.Ctx;
|
||||
const cdp = @import("cdp.zig");
|
||||
const result = cdp.result;
|
||||
const getMsg = cdp.getMsg;
|
||||
const IncomingMessage = @import("msg.zig").IncomingMessage;
|
||||
|
||||
const log = std.log.scoped(.cdp);
|
||||
|
||||
@@ -32,28 +32,26 @@ const Methods = enum {
|
||||
|
||||
pub fn fetch(
|
||||
alloc: std.mem.Allocator,
|
||||
id: ?u16,
|
||||
msg: *IncomingMessage,
|
||||
action: []const u8,
|
||||
scanner: *std.json.Scanner,
|
||||
ctx: *Ctx,
|
||||
) ![]const u8 {
|
||||
const method = std.meta.stringToEnum(Methods, action) orelse
|
||||
return error.UnknownMethod;
|
||||
|
||||
return switch (method) {
|
||||
.disable => disable(alloc, id, scanner, ctx),
|
||||
.disable => disable(alloc, msg, ctx),
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: noop method
|
||||
fn disable(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
_: *Ctx,
|
||||
) ![]const u8 {
|
||||
const msg = try getMsg(alloc, _id, void, scanner);
|
||||
log.debug("Req > id {d}, method {s}", .{ msg.id, "fetch.disable" });
|
||||
const input = try msg.getInput(alloc, void);
|
||||
log.debug("Req > id {d}, method {s}", .{ input.id, "fetch.disable" });
|
||||
|
||||
return result(alloc, msg.id, null, null, msg.sessionID);
|
||||
return result(alloc, input.id, null, null, input.sessionId);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ const server = @import("../server.zig");
|
||||
const Ctx = server.Ctx;
|
||||
const cdp = @import("cdp.zig");
|
||||
const result = cdp.result;
|
||||
const getMsg = cdp.getMsg;
|
||||
const IncomingMessage = @import("msg.zig").IncomingMessage;
|
||||
const stringify = cdp.stringify;
|
||||
|
||||
const log_cdp = std.log.scoped(.cdp);
|
||||
@@ -33,27 +33,25 @@ const Methods = enum {
|
||||
|
||||
pub fn log(
|
||||
alloc: std.mem.Allocator,
|
||||
id: ?u16,
|
||||
msg: *IncomingMessage,
|
||||
action: []const u8,
|
||||
scanner: *std.json.Scanner,
|
||||
ctx: *Ctx,
|
||||
) ![]const u8 {
|
||||
const method = std.meta.stringToEnum(Methods, action) orelse
|
||||
return error.UnknownMethod;
|
||||
|
||||
return switch (method) {
|
||||
.enable => enable(alloc, id, scanner, ctx),
|
||||
.enable => enable(alloc, msg, ctx),
|
||||
};
|
||||
}
|
||||
|
||||
fn enable(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
_: *Ctx,
|
||||
) ![]const u8 {
|
||||
const msg = try getMsg(alloc, _id, void, scanner);
|
||||
log_cdp.debug("Req > id {d}, method {s}", .{ msg.id, "log.enable" });
|
||||
const input = try msg.getInput(alloc, void);
|
||||
log_cdp.debug("Req > id {d}, method {s}", .{ input.id, "log.enable" });
|
||||
|
||||
return result(alloc, msg.id, null, null, msg.sessionID);
|
||||
return result(alloc, input.id, null, null, input.sessionId);
|
||||
}
|
||||
|
||||
214
src/cdp/msg.zig
Normal file
214
src/cdp/msg.zig
Normal file
@@ -0,0 +1,214 @@
|
||||
// Copyright (C) 2023-2024 Lightpanda (Selecy SAS)
|
||||
//
|
||||
// Francis Bouvier <francis@lightpanda.io>
|
||||
// Pierre Tachoire <pierre@lightpanda.io>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
// Parse incoming protocol message in json format.
|
||||
pub const IncomingMessage = struct {
|
||||
scanner: std.json.Scanner,
|
||||
json: []const u8,
|
||||
|
||||
obj_begin: bool = false,
|
||||
obj_end: bool = false,
|
||||
|
||||
id: ?u16 = null,
|
||||
scan_sessionId: bool = false,
|
||||
sessionId: ?[]const u8 = null,
|
||||
method: ?[]const u8 = null,
|
||||
params_skip: bool = false,
|
||||
|
||||
pub fn init(alloc: std.mem.Allocator, json: []const u8) IncomingMessage {
|
||||
return .{
|
||||
.json = json,
|
||||
.scanner = std.json.Scanner.initCompleteInput(alloc, json),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *IncomingMessage) void {
|
||||
self.scanner.deinit();
|
||||
}
|
||||
|
||||
fn scanUntil(self: *IncomingMessage, key: []const u8) !void {
|
||||
while (true) {
|
||||
switch (try self.scanner.next()) {
|
||||
.end_of_document => return error.EndOfDocument,
|
||||
.object_begin => {
|
||||
if (self.obj_begin) return error.InvalidObjectBegin;
|
||||
self.obj_begin = true;
|
||||
},
|
||||
.object_end => {
|
||||
if (!self.obj_begin) return error.InvalidObjectEnd;
|
||||
if (self.obj_end) return error.InvalidObjectEnd;
|
||||
self.obj_end = true;
|
||||
},
|
||||
.string => |s| {
|
||||
// is the key what we expects?
|
||||
if (std.mem.eql(u8, s, key)) return;
|
||||
|
||||
// save other known keys
|
||||
if (std.mem.eql(u8, s, "id")) try self.scanId();
|
||||
if (std.mem.eql(u8, s, "sessionId")) try self.scanSessionId();
|
||||
if (std.mem.eql(u8, s, "method")) try self.scanMethod();
|
||||
if (std.mem.eql(u8, s, "params")) try self.scanParams();
|
||||
|
||||
// TODO should we skip unknown key?
|
||||
},
|
||||
else => return error.InvalidToken,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn scanId(self: *IncomingMessage) !void {
|
||||
const t = try self.scanner.next();
|
||||
if (t != .number) return error.InvalidId;
|
||||
self.id = try std.fmt.parseUnsigned(u16, t.number, 10);
|
||||
}
|
||||
|
||||
fn getId(self: *IncomingMessage) !u16 {
|
||||
if (self.id != null) return self.id.?;
|
||||
|
||||
try self.scanUntil("id");
|
||||
try self.scanId();
|
||||
return self.id.?;
|
||||
}
|
||||
|
||||
fn scanSessionId(self: *IncomingMessage) !void {
|
||||
switch (try self.scanner.next()) {
|
||||
// session id can be null.
|
||||
.null => return,
|
||||
.string => |s| self.sessionId = s,
|
||||
else => return error.InvalidSessionId,
|
||||
}
|
||||
|
||||
self.scan_sessionId = true;
|
||||
}
|
||||
|
||||
fn getSessionId(self: *IncomingMessage) !?[]const u8 {
|
||||
if (self.scan_sessionId) return self.sessionId;
|
||||
|
||||
self.scanUntil("sessionId") catch |err| {
|
||||
if (err != error.EndOfDocument) return err;
|
||||
// if the document doesn't contains any session id key, we must
|
||||
// return null value.
|
||||
self.scan_sessionId = true;
|
||||
return null;
|
||||
};
|
||||
try self.scanSessionId();
|
||||
return self.sessionId;
|
||||
}
|
||||
|
||||
fn scanMethod(self: *IncomingMessage) !void {
|
||||
const t = try self.scanner.next();
|
||||
if (t != .string) return error.InvalidMethod;
|
||||
self.method = t.string;
|
||||
}
|
||||
|
||||
pub fn getMethod(self: *IncomingMessage) ![]const u8 {
|
||||
if (self.method != null) return self.method.?;
|
||||
|
||||
try self.scanUntil("method");
|
||||
try self.scanMethod();
|
||||
return self.method.?;
|
||||
}
|
||||
|
||||
// scanParams skip found parameters b/c if we encounter params *before*
|
||||
// asking for getParams, we don't know how to parse them.
|
||||
fn scanParams(self: *IncomingMessage) !void {
|
||||
const tt = try self.scanner.peekNextTokenType();
|
||||
if (tt != .object_begin) return error.InvalidParams;
|
||||
try self.scanner.skipValue();
|
||||
self.params_skip = true;
|
||||
}
|
||||
|
||||
// getParams restart the JSON parsing
|
||||
fn getParams(self: *IncomingMessage, alloc: std.mem.Allocator, T: type) !T {
|
||||
if (T == void) return void{};
|
||||
|
||||
if (self.params_skip) {
|
||||
// TODO if the params have been skipped, we have to retart the
|
||||
// parsing from start.
|
||||
return error.SkippedParams;
|
||||
}
|
||||
|
||||
try self.scanUntil("params");
|
||||
|
||||
// parse "params"
|
||||
const options = std.json.ParseOptions{
|
||||
.max_value_len = self.scanner.input.len,
|
||||
.allocate = .alloc_if_needed,
|
||||
};
|
||||
return try std.json.innerParse(T, alloc, &self.scanner, options);
|
||||
}
|
||||
|
||||
pub fn getInput(self: *IncomingMessage, alloc: std.mem.Allocator, T: type) !struct { id: u16, sessionId: ?[]const u8, params: T } {
|
||||
return .{
|
||||
.params = try self.getParams(alloc, T),
|
||||
.id = try self.getId(),
|
||||
.sessionId = try self.getSessionId(),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
test "read incoming message" {
|
||||
const inputs = [_][]const u8{
|
||||
\\{"id":1,"method":"foo","sessionId":"bar","params":{"bar":"baz"}}
|
||||
,
|
||||
\\{"params":{"bar":"baz"},"id":1,"method":"foo","sessionId":"bar"}
|
||||
,
|
||||
\\{"sessionId":"bar","params":{"bar":"baz"},"id":1,"method":"foo"}
|
||||
,
|
||||
\\{"method":"foo","sessionId":"bar","params":{"bar":"baz"},"id":1}
|
||||
,
|
||||
};
|
||||
|
||||
for (inputs) |input| {
|
||||
var msg = IncomingMessage.init(std.testing.allocator, input);
|
||||
defer msg.deinit();
|
||||
|
||||
try std.testing.expectEqual(1, try msg.getId());
|
||||
try std.testing.expectEqualSlices(u8, "foo", try msg.getMethod());
|
||||
try std.testing.expectEqualSlices(u8, "bar", (try msg.getSessionId()).?);
|
||||
|
||||
const T = struct { bar: []const u8 };
|
||||
const in = msg.getInput(std.testing.allocator, T) catch |err| {
|
||||
if (err != error.SkippedParams) return err;
|
||||
// TODO remove this check when params in the beginning is handled.
|
||||
continue;
|
||||
};
|
||||
try std.testing.expectEqualSlices(u8, "baz", in.params.bar);
|
||||
}
|
||||
}
|
||||
|
||||
test "read incoming message with null session id" {
|
||||
const inputs = [_][]const u8{
|
||||
\\{"id":1}
|
||||
,
|
||||
\\{"params":{"bar":"baz"},"id":1,"method":"foo"}
|
||||
,
|
||||
\\{"sessionId":null,"params":{"bar":"baz"},"id":1,"method":"foo"}
|
||||
,
|
||||
};
|
||||
|
||||
for (inputs) |input| {
|
||||
var msg = IncomingMessage.init(std.testing.allocator, input);
|
||||
defer msg.deinit();
|
||||
|
||||
try std.testing.expect(try msg.getSessionId() == null);
|
||||
try std.testing.expectEqual(1, try msg.getId());
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ const server = @import("../server.zig");
|
||||
const Ctx = server.Ctx;
|
||||
const cdp = @import("cdp.zig");
|
||||
const result = cdp.result;
|
||||
const getMsg = cdp.getMsg;
|
||||
const IncomingMessage = @import("msg.zig").IncomingMessage;
|
||||
|
||||
const log = std.log.scoped(.cdp);
|
||||
|
||||
@@ -33,45 +33,40 @@ const Methods = enum {
|
||||
|
||||
pub fn network(
|
||||
alloc: std.mem.Allocator,
|
||||
id: ?u16,
|
||||
msg: *IncomingMessage,
|
||||
action: []const u8,
|
||||
scanner: *std.json.Scanner,
|
||||
ctx: *Ctx,
|
||||
) ![]const u8 {
|
||||
const method = std.meta.stringToEnum(Methods, action) orelse
|
||||
return error.UnknownMethod;
|
||||
|
||||
return switch (method) {
|
||||
.enable => enable(alloc, id, scanner, ctx),
|
||||
.setCacheDisabled => setCacheDisabled(alloc, id, scanner, ctx),
|
||||
.enable => enable(alloc, msg, ctx),
|
||||
.setCacheDisabled => setCacheDisabled(alloc, msg, ctx),
|
||||
};
|
||||
}
|
||||
|
||||
fn enable(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
_: *Ctx,
|
||||
) ![]const u8 {
|
||||
|
||||
// input
|
||||
const msg = try getMsg(alloc, _id, void, scanner);
|
||||
log.debug("Req > id {d}, method {s}", .{ msg.id, "network.enable" });
|
||||
const input = try msg.getInput(alloc, void);
|
||||
log.debug("Req > id {d}, method {s}", .{ input.id, "network.enable" });
|
||||
|
||||
return result(alloc, msg.id, null, null, msg.sessionID);
|
||||
return result(alloc, input.id, null, null, input.sessionId);
|
||||
}
|
||||
|
||||
// TODO: noop method
|
||||
fn setCacheDisabled(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
_: *Ctx,
|
||||
) ![]const u8 {
|
||||
|
||||
// input
|
||||
const msg = try getMsg(alloc, _id, void, scanner);
|
||||
log.debug("Req > id {d}, method {s}", .{ msg.id, "network.setCacheDisabled" });
|
||||
const input = try msg.getInput(alloc, void);
|
||||
log.debug("Req > id {d}, method {s}", .{ input.id, "network.setCacheDisabled" });
|
||||
|
||||
return result(alloc, msg.id, null, null, msg.sessionID);
|
||||
return result(alloc, input.id, null, null, input.sessionId);
|
||||
}
|
||||
|
||||
113
src/cdp/page.zig
113
src/cdp/page.zig
@@ -22,9 +22,9 @@ const server = @import("../server.zig");
|
||||
const Ctx = server.Ctx;
|
||||
const cdp = @import("cdp.zig");
|
||||
const result = cdp.result;
|
||||
const getMsg = cdp.getMsg;
|
||||
const stringify = cdp.stringify;
|
||||
const sendEvent = cdp.sendEvent;
|
||||
const IncomingMessage = @import("msg.zig").IncomingMessage;
|
||||
|
||||
const log = std.log.scoped(.cdp);
|
||||
|
||||
@@ -41,35 +41,32 @@ const Methods = enum {
|
||||
|
||||
pub fn page(
|
||||
alloc: std.mem.Allocator,
|
||||
id: ?u16,
|
||||
msg: *IncomingMessage,
|
||||
action: []const u8,
|
||||
scanner: *std.json.Scanner,
|
||||
ctx: *Ctx,
|
||||
) ![]const u8 {
|
||||
const method = std.meta.stringToEnum(Methods, action) orelse
|
||||
return error.UnknownMethod;
|
||||
return switch (method) {
|
||||
.enable => enable(alloc, id, scanner, ctx),
|
||||
.getFrameTree => getFrameTree(alloc, id, scanner, ctx),
|
||||
.setLifecycleEventsEnabled => setLifecycleEventsEnabled(alloc, id, scanner, ctx),
|
||||
.addScriptToEvaluateOnNewDocument => addScriptToEvaluateOnNewDocument(alloc, id, scanner, ctx),
|
||||
.createIsolatedWorld => createIsolatedWorld(alloc, id, scanner, ctx),
|
||||
.navigate => navigate(alloc, id, scanner, ctx),
|
||||
.enable => enable(alloc, msg, ctx),
|
||||
.getFrameTree => getFrameTree(alloc, msg, ctx),
|
||||
.setLifecycleEventsEnabled => setLifecycleEventsEnabled(alloc, msg, ctx),
|
||||
.addScriptToEvaluateOnNewDocument => addScriptToEvaluateOnNewDocument(alloc, msg, ctx),
|
||||
.createIsolatedWorld => createIsolatedWorld(alloc, msg, ctx),
|
||||
.navigate => navigate(alloc, msg, ctx),
|
||||
};
|
||||
}
|
||||
|
||||
fn enable(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
_: *Ctx,
|
||||
) ![]const u8 {
|
||||
|
||||
// input
|
||||
const msg = try getMsg(alloc, _id, void, scanner);
|
||||
log.debug("Req > id {d}, method {s}", .{ msg.id, "page.enable" });
|
||||
const input = try msg.getInput(alloc, void);
|
||||
log.debug("Req > id {d}, method {s}", .{ input.id, "page.enable" });
|
||||
|
||||
return result(alloc, msg.id, null, null, msg.sessionID);
|
||||
return result(alloc, input.id, null, null, input.sessionId);
|
||||
}
|
||||
|
||||
const Frame = struct {
|
||||
@@ -89,14 +86,12 @@ const Frame = struct {
|
||||
|
||||
fn getFrameTree(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
ctx: *Ctx,
|
||||
) ![]const u8 {
|
||||
|
||||
// input
|
||||
const msg = try cdp.getMsg(alloc, _id, void, scanner);
|
||||
log.debug("Req > id {d}, method {s}", .{ msg.id, "page.getFrameTree" });
|
||||
const input = try msg.getInput(alloc, void);
|
||||
log.debug("Req > id {d}, method {s}", .{ input.id, "page.getFrameTree" });
|
||||
|
||||
// output
|
||||
const FrameTree = struct {
|
||||
@@ -135,27 +130,25 @@ fn getFrameTree(
|
||||
},
|
||||
},
|
||||
};
|
||||
return result(alloc, msg.id, FrameTree, frameTree, msg.sessionID);
|
||||
return result(alloc, input.id, FrameTree, frameTree, input.sessionId);
|
||||
}
|
||||
|
||||
fn setLifecycleEventsEnabled(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
ctx: *Ctx,
|
||||
) ![]const u8 {
|
||||
|
||||
// input
|
||||
const Params = struct {
|
||||
enabled: bool,
|
||||
};
|
||||
const msg = try getMsg(alloc, _id, Params, scanner);
|
||||
log.debug("Req > id {d}, method {s}", .{ msg.id, "page.setLifecycleEventsEnabled" });
|
||||
const input = try msg.getInput(alloc, Params);
|
||||
log.debug("Req > id {d}, method {s}", .{ input.id, "page.setLifecycleEventsEnabled" });
|
||||
|
||||
ctx.state.page_life_cycle_events = true;
|
||||
|
||||
// output
|
||||
return result(alloc, msg.id, null, null, msg.sessionID);
|
||||
return result(alloc, input.id, null, null, input.sessionId);
|
||||
}
|
||||
|
||||
const LifecycleEvent = struct {
|
||||
@@ -168,11 +161,9 @@ const LifecycleEvent = struct {
|
||||
// TODO: hard coded method
|
||||
fn addScriptToEvaluateOnNewDocument(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
_: *Ctx,
|
||||
) ![]const u8 {
|
||||
|
||||
// input
|
||||
const Params = struct {
|
||||
source: []const u8,
|
||||
@@ -180,8 +171,8 @@ fn addScriptToEvaluateOnNewDocument(
|
||||
includeCommandLineAPI: bool = false,
|
||||
runImmediately: bool = false,
|
||||
};
|
||||
const msg = try getMsg(alloc, _id, Params, scanner);
|
||||
log.debug("Req > id {d}, method {s}", .{ msg.id, "page.addScriptToEvaluateOnNewDocument" });
|
||||
const input = try msg.getInput(alloc, Params);
|
||||
log.debug("Req > id {d}, method {s}", .{ input.id, "page.addScriptToEvaluateOnNewDocument" });
|
||||
|
||||
// output
|
||||
const Res = struct {
|
||||
@@ -199,27 +190,24 @@ fn addScriptToEvaluateOnNewDocument(
|
||||
try writer.writeAll(" }");
|
||||
}
|
||||
};
|
||||
return result(alloc, msg.id, Res, Res{}, msg.sessionID);
|
||||
return result(alloc, input.id, Res, Res{}, input.sessionId);
|
||||
}
|
||||
|
||||
// TODO: hard coded method
|
||||
fn createIsolatedWorld(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
ctx: *Ctx,
|
||||
) ![]const u8 {
|
||||
|
||||
// input
|
||||
const Params = struct {
|
||||
frameId: []const u8,
|
||||
worldName: []const u8,
|
||||
grantUniveralAccess: bool,
|
||||
};
|
||||
const msg = try getMsg(alloc, _id, Params, scanner);
|
||||
std.debug.assert(msg.sessionID != null);
|
||||
log.debug("Req > id {d}, method {s}", .{ msg.id, "page.createIsolatedWorld" });
|
||||
const params = msg.params.?;
|
||||
const input = try msg.getInput(alloc, Params);
|
||||
std.debug.assert(input.sessionId != null);
|
||||
log.debug("Req > id {d}, method {s}", .{ input.id, "page.createIsolatedWorld" });
|
||||
|
||||
// noop executionContextCreated event
|
||||
try Runtime.executionContextCreated(
|
||||
@@ -227,15 +215,15 @@ fn createIsolatedWorld(
|
||||
ctx,
|
||||
0,
|
||||
"",
|
||||
params.worldName,
|
||||
input.params.worldName,
|
||||
// TODO: hard coded ID
|
||||
"7102379147004877974.3265385113993241162",
|
||||
.{
|
||||
.isDefault = false,
|
||||
.type = "isolated",
|
||||
.frameId = params.frameId,
|
||||
.frameId = input.params.frameId,
|
||||
},
|
||||
msg.sessionID,
|
||||
input.sessionId,
|
||||
);
|
||||
|
||||
// output
|
||||
@@ -243,16 +231,14 @@ fn createIsolatedWorld(
|
||||
executionContextId: u8 = 0,
|
||||
};
|
||||
|
||||
return result(alloc, msg.id, Resp, .{}, msg.sessionID);
|
||||
return result(alloc, input.id, Resp, .{}, input.sessionId);
|
||||
}
|
||||
|
||||
fn navigate(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
ctx: *Ctx,
|
||||
) ![]const u8 {
|
||||
|
||||
// input
|
||||
const Params = struct {
|
||||
url: []const u8,
|
||||
@@ -261,13 +247,12 @@ fn navigate(
|
||||
frameId: ?[]const u8 = null,
|
||||
referrerPolicy: ?[]const u8 = null, // TODO: enum
|
||||
};
|
||||
const msg = try getMsg(alloc, _id, Params, scanner);
|
||||
std.debug.assert(msg.sessionID != null);
|
||||
log.debug("Req > id {d}, method {s}", .{ msg.id, "page.navigate" });
|
||||
const params = msg.params.?;
|
||||
const input = try msg.getInput(alloc, Params);
|
||||
std.debug.assert(input.sessionId != null);
|
||||
log.debug("Req > id {d}, method {s}", .{ input.id, "page.navigate" });
|
||||
|
||||
// change state
|
||||
ctx.state.url = params.url;
|
||||
ctx.state.url = input.params.url;
|
||||
// TODO: hard coded ID
|
||||
ctx.state.loaderID = "AF8667A203C5392DBE9AC290044AA4C2";
|
||||
|
||||
@@ -289,7 +274,7 @@ fn navigate(
|
||||
"Page.frameStartedLoading",
|
||||
FrameStartedLoading,
|
||||
frame_started_loading,
|
||||
msg.sessionID,
|
||||
input.sessionId,
|
||||
);
|
||||
if (ctx.state.page_life_cycle_events) {
|
||||
life_event.name = "init";
|
||||
@@ -300,7 +285,7 @@ fn navigate(
|
||||
"Page.lifecycleEvent",
|
||||
LifecycleEvent,
|
||||
life_event,
|
||||
msg.sessionID,
|
||||
input.sessionId,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -330,14 +315,14 @@ fn navigate(
|
||||
.frameId = ctx.state.frameID,
|
||||
.loaderId = ctx.state.loaderID,
|
||||
};
|
||||
const res = try result(alloc, msg.id, Resp, resp, msg.sessionID);
|
||||
const res = try result(alloc, input.id, Resp, resp, input.sessionId);
|
||||
try server.sendAsync(ctx, res);
|
||||
|
||||
// TODO: at this point do we need async the following actions to be async?
|
||||
|
||||
// Send Runtime.executionContextsCleared event
|
||||
// TODO: noop event, we have no env context at this point, is it necesarry?
|
||||
try sendEvent(alloc, ctx, "Runtime.executionContextsCleared", void, {}, msg.sessionID);
|
||||
try sendEvent(alloc, ctx, "Runtime.executionContextsCleared", void, {}, input.sessionId);
|
||||
|
||||
// Launch navigate
|
||||
const p = try ctx.browser.session.createPage();
|
||||
@@ -349,7 +334,7 @@ fn navigate(
|
||||
.{ctx.state.frameID},
|
||||
);
|
||||
defer alloc.free(auxData);
|
||||
try p.navigate(params.url, auxData);
|
||||
try p.navigate(input.params.url, auxData);
|
||||
|
||||
// Events
|
||||
|
||||
@@ -364,7 +349,7 @@ fn navigate(
|
||||
"Page.lifecycleEvent",
|
||||
LifecycleEvent,
|
||||
life_event,
|
||||
msg.sessionID,
|
||||
input.sessionId,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -388,7 +373,7 @@ fn navigate(
|
||||
"Page.frameNavigated",
|
||||
FrameNavigated,
|
||||
frame_navigated,
|
||||
msg.sessionID,
|
||||
input.sessionId,
|
||||
);
|
||||
|
||||
// domContentEventFired event
|
||||
@@ -400,7 +385,7 @@ fn navigate(
|
||||
"Page.domContentEventFired",
|
||||
cdp.TimestampEvent,
|
||||
ts_event,
|
||||
msg.sessionID,
|
||||
input.sessionId,
|
||||
);
|
||||
|
||||
// lifecycle DOMContentLoaded event
|
||||
@@ -414,7 +399,7 @@ fn navigate(
|
||||
"Page.lifecycleEvent",
|
||||
LifecycleEvent,
|
||||
life_event,
|
||||
msg.sessionID,
|
||||
input.sessionId,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -427,7 +412,7 @@ fn navigate(
|
||||
"Page.loadEventFired",
|
||||
cdp.TimestampEvent,
|
||||
ts_event,
|
||||
msg.sessionID,
|
||||
input.sessionId,
|
||||
);
|
||||
|
||||
// lifecycle DOMContentLoaded event
|
||||
@@ -441,7 +426,7 @@ fn navigate(
|
||||
"Page.lifecycleEvent",
|
||||
LifecycleEvent,
|
||||
life_event,
|
||||
msg.sessionID,
|
||||
input.sessionId,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -453,7 +438,7 @@ fn navigate(
|
||||
"Page.frameStoppedLoading",
|
||||
FrameStoppedLoading,
|
||||
.{ .frameId = ctx.state.frameID },
|
||||
msg.sessionID,
|
||||
input.sessionId,
|
||||
);
|
||||
|
||||
return "";
|
||||
|
||||
@@ -22,7 +22,7 @@ const server = @import("../server.zig");
|
||||
const Ctx = server.Ctx;
|
||||
const cdp = @import("cdp.zig");
|
||||
const result = cdp.result;
|
||||
const getMsg = cdp.getMsg;
|
||||
const IncomingMessage = @import("msg.zig").IncomingMessage;
|
||||
|
||||
const log = std.log.scoped(.cdp);
|
||||
|
||||
@@ -32,29 +32,26 @@ const Methods = enum {
|
||||
|
||||
pub fn performance(
|
||||
alloc: std.mem.Allocator,
|
||||
id: ?u16,
|
||||
msg: *IncomingMessage,
|
||||
action: []const u8,
|
||||
scanner: *std.json.Scanner,
|
||||
ctx: *Ctx,
|
||||
) ![]const u8 {
|
||||
const method = std.meta.stringToEnum(Methods, action) orelse
|
||||
return error.UnknownMethod;
|
||||
|
||||
return switch (method) {
|
||||
.enable => enable(alloc, id, scanner, ctx),
|
||||
.enable => enable(alloc, msg, ctx),
|
||||
};
|
||||
}
|
||||
|
||||
fn enable(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
_: *Ctx,
|
||||
) ![]const u8 {
|
||||
|
||||
// input
|
||||
const msg = try getMsg(alloc, _id, void, scanner);
|
||||
log.debug("Req > id {d}, method {s}", .{ msg.id, "performance.enable" });
|
||||
const input = try msg.getInput(alloc, void);
|
||||
log.debug("Req > id {d}, method {s}", .{ input.id, "performance.enable" });
|
||||
|
||||
return result(alloc, msg.id, null, null, msg.sessionID);
|
||||
return result(alloc, input.id, null, null, input.sessionId);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ const server = @import("../server.zig");
|
||||
const Ctx = server.Ctx;
|
||||
const cdp = @import("cdp.zig");
|
||||
const result = cdp.result;
|
||||
const getMsg = cdp.getMsg;
|
||||
const IncomingMessage = @import("msg.zig").IncomingMessage;
|
||||
const stringify = cdp.stringify;
|
||||
|
||||
const log = std.log.scoped(.cdp);
|
||||
@@ -41,27 +41,23 @@ const Methods = enum {
|
||||
|
||||
pub fn runtime(
|
||||
alloc: std.mem.Allocator,
|
||||
id: ?u16,
|
||||
msg: *IncomingMessage,
|
||||
action: []const u8,
|
||||
scanner: *std.json.Scanner,
|
||||
s: []const u8,
|
||||
ctx: *Ctx,
|
||||
) ![]const u8 {
|
||||
const method = std.meta.stringToEnum(Methods, action) orelse
|
||||
// NOTE: we could send it anyway to the JS runtime but it's good to check it
|
||||
return error.UnknownMethod;
|
||||
return switch (method) {
|
||||
.runIfWaitingForDebugger => runIfWaitingForDebugger(alloc, id, scanner, ctx),
|
||||
else => sendInspector(alloc, method, id, s, scanner, ctx),
|
||||
.runIfWaitingForDebugger => runIfWaitingForDebugger(alloc, msg, ctx),
|
||||
else => sendInspector(alloc, method, msg, ctx),
|
||||
};
|
||||
}
|
||||
|
||||
fn sendInspector(
|
||||
alloc: std.mem.Allocator,
|
||||
method: Methods,
|
||||
_id: ?u16,
|
||||
s: []const u8,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
ctx: *Ctx,
|
||||
) ![]const u8 {
|
||||
|
||||
@@ -69,8 +65,8 @@ fn sendInspector(
|
||||
if (std.log.defaultLogEnabled(.debug)) {
|
||||
|
||||
// input
|
||||
var script: ?[]const u8 = null;
|
||||
var id: u16 = undefined;
|
||||
var script: ?[]const u8 = null;
|
||||
|
||||
if (method == .evaluate) {
|
||||
const Params = struct {
|
||||
@@ -81,11 +77,10 @@ fn sendInspector(
|
||||
userGesture: ?bool = null,
|
||||
};
|
||||
|
||||
const msg = try getMsg(alloc, _id, Params, scanner);
|
||||
log.debug("Req > id {d}, method {s} (script saved on cache)", .{ msg.id, "runtime.evaluate" });
|
||||
const params = msg.params.?;
|
||||
script = params.expression;
|
||||
id = msg.id;
|
||||
const input = try msg.getInput(alloc, Params);
|
||||
log.debug("Req > id {d}, method {s} (script saved on cache)", .{ input.id, "runtime.evaluate" });
|
||||
script = input.params.expression;
|
||||
id = input.id;
|
||||
} else if (method == .callFunctionOn) {
|
||||
const Params = struct {
|
||||
functionDeclaration: []const u8,
|
||||
@@ -100,11 +95,10 @@ fn sendInspector(
|
||||
userGesture: ?bool = null,
|
||||
};
|
||||
|
||||
const msg = try getMsg(alloc, _id, Params, scanner);
|
||||
log.debug("Req > id {d}, method {s} (script saved on cache)", .{ msg.id, "runtime.callFunctionOn" });
|
||||
const params = msg.params.?;
|
||||
script = params.functionDeclaration;
|
||||
id = msg.id;
|
||||
const input = try msg.getInput(alloc, Params);
|
||||
log.debug("Req > id {d}, method {s} (script saved on cache)", .{ input.id, "runtime.callFunctionOn" });
|
||||
script = input.params.functionDeclaration;
|
||||
id = input.id;
|
||||
}
|
||||
|
||||
if (script) |src| {
|
||||
@@ -115,12 +109,12 @@ fn sendInspector(
|
||||
// remove awaitPromise true params
|
||||
// TODO: delete when Promise are correctly handled by zig-js-runtime
|
||||
if (method == .callFunctionOn or method == .evaluate) {
|
||||
const buf = try alloc.alloc(u8, s.len + 1);
|
||||
const buf = try alloc.alloc(u8, msg.json.len + 1);
|
||||
defer alloc.free(buf);
|
||||
_ = std.mem.replace(u8, s, "\"awaitPromise\":true", "\"awaitPromise\":false", buf);
|
||||
_ = std.mem.replace(u8, msg.json, "\"awaitPromise\":true", "\"awaitPromise\":false", buf);
|
||||
ctx.sendInspector(buf);
|
||||
} else {
|
||||
ctx.sendInspector(s);
|
||||
ctx.sendInspector(msg.json);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
@@ -166,14 +160,11 @@ pub fn executionContextCreated(
|
||||
// should we be passing this also to the JS Inspector?
|
||||
fn runIfWaitingForDebugger(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
_: *Ctx,
|
||||
) ![]const u8 {
|
||||
const input = try msg.getInput(alloc, void);
|
||||
log.debug("Req > id {d}, method {s}", .{ input.id, "runtime.runIfWaitingForDebugger" });
|
||||
|
||||
// input
|
||||
const msg = try getMsg(alloc, _id, void, scanner);
|
||||
log.debug("Req > id {d}, method {s}", .{ msg.id, "runtime.runIfWaitingForDebugger" });
|
||||
|
||||
return result(alloc, msg.id, null, null, msg.sessionID);
|
||||
return result(alloc, input.id, null, null, input.sessionId);
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@ const server = @import("../server.zig");
|
||||
const Ctx = server.Ctx;
|
||||
const cdp = @import("cdp.zig");
|
||||
const result = cdp.result;
|
||||
const getMsg = cdp.getMsg;
|
||||
const stringify = cdp.stringify;
|
||||
const IncomingMessage = @import("msg.zig").IncomingMessage;
|
||||
|
||||
const log = std.log.scoped(.cdp);
|
||||
|
||||
@@ -41,23 +41,22 @@ const Methods = enum {
|
||||
|
||||
pub fn target(
|
||||
alloc: std.mem.Allocator,
|
||||
id: ?u16,
|
||||
msg: *IncomingMessage,
|
||||
action: []const u8,
|
||||
scanner: *std.json.Scanner,
|
||||
ctx: *Ctx,
|
||||
) ![]const u8 {
|
||||
const method = std.meta.stringToEnum(Methods, action) orelse
|
||||
return error.UnknownMethod;
|
||||
return switch (method) {
|
||||
.setDiscoverTargets => setDiscoverTargets(alloc, id, scanner, ctx),
|
||||
.setAutoAttach => setAutoAttach(alloc, id, scanner, ctx),
|
||||
.attachToTarget => attachToTarget(alloc, id, scanner, ctx),
|
||||
.getTargetInfo => getTargetInfo(alloc, id, scanner, ctx),
|
||||
.getBrowserContexts => getBrowserContexts(alloc, id, scanner, ctx),
|
||||
.createBrowserContext => createBrowserContext(alloc, id, scanner, ctx),
|
||||
.disposeBrowserContext => disposeBrowserContext(alloc, id, scanner, ctx),
|
||||
.createTarget => createTarget(alloc, id, scanner, ctx),
|
||||
.closeTarget => closeTarget(alloc, id, scanner, ctx),
|
||||
.setDiscoverTargets => setDiscoverTargets(alloc, msg, ctx),
|
||||
.setAutoAttach => setAutoAttach(alloc, msg, ctx),
|
||||
.attachToTarget => attachToTarget(alloc, msg, ctx),
|
||||
.getTargetInfo => getTargetInfo(alloc, msg, ctx),
|
||||
.getBrowserContexts => getBrowserContexts(alloc, msg, ctx),
|
||||
.createBrowserContext => createBrowserContext(alloc, msg, ctx),
|
||||
.disposeBrowserContext => disposeBrowserContext(alloc, msg, ctx),
|
||||
.createTarget => createTarget(alloc, msg, ctx),
|
||||
.closeTarget => closeTarget(alloc, msg, ctx),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -69,17 +68,15 @@ const BrowserContextID = "65618675CB7D3585A95049E9DFE95EA9";
|
||||
// TODO: noop method
|
||||
fn setDiscoverTargets(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
_: *Ctx,
|
||||
) ![]const u8 {
|
||||
|
||||
// input
|
||||
const msg = try getMsg(alloc, _id, void, scanner);
|
||||
log.debug("Req > id {d}, method {s}", .{ msg.id, "target.setDiscoverTargets" });
|
||||
const input = try msg.getInput(alloc, void);
|
||||
log.debug("Req > id {d}, method {s}", .{ input.id, "target.setDiscoverTargets" });
|
||||
|
||||
// output
|
||||
return result(alloc, msg.id, null, null, msg.sessionID);
|
||||
return result(alloc, input.id, null, null, input.sessionId);
|
||||
}
|
||||
|
||||
const AttachToTarget = struct {
|
||||
@@ -104,11 +101,9 @@ const TargetFilter = struct {
|
||||
// TODO: noop method
|
||||
fn setAutoAttach(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
ctx: *Ctx,
|
||||
) ![]const u8 {
|
||||
|
||||
// input
|
||||
const Params = struct {
|
||||
autoAttach: bool,
|
||||
@@ -116,11 +111,11 @@ fn setAutoAttach(
|
||||
flatten: bool = true,
|
||||
filter: ?[]TargetFilter = null,
|
||||
};
|
||||
const msg = try getMsg(alloc, _id, Params, scanner);
|
||||
log.debug("Req > id {d}, method {s}", .{ msg.id, "target.setAutoAttach" });
|
||||
const input = try msg.getInput(alloc, Params);
|
||||
log.debug("Req > id {d}, method {s}", .{ input.id, "target.setAutoAttach" });
|
||||
|
||||
// attachedToTarget event
|
||||
if (msg.sessionID == null) {
|
||||
if (input.sessionId == null) {
|
||||
const attached = AttachToTarget{
|
||||
.sessionId = cdp.BrowserSessionID,
|
||||
.targetInfo = .{
|
||||
@@ -134,14 +129,13 @@ fn setAutoAttach(
|
||||
}
|
||||
|
||||
// output
|
||||
return result(alloc, msg.id, null, null, msg.sessionID);
|
||||
return result(alloc, input.id, null, null, input.sessionId);
|
||||
}
|
||||
|
||||
// TODO: noop method
|
||||
fn attachToTarget(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
ctx: *Ctx,
|
||||
) ![]const u8 {
|
||||
|
||||
@@ -150,11 +144,11 @@ fn attachToTarget(
|
||||
targetId: []const u8,
|
||||
flatten: bool = true,
|
||||
};
|
||||
const msg = try getMsg(alloc, _id, Params, scanner);
|
||||
log.debug("Req > id {d}, method {s}", .{ msg.id, "target.setAutoAttach" });
|
||||
const input = try msg.getInput(alloc, Params);
|
||||
log.debug("Req > id {d}, method {s}", .{ input.id, "target.attachToTarget" });
|
||||
|
||||
// attachedToTarget event
|
||||
if (msg.sessionID == null) {
|
||||
if (input.sessionId == null) {
|
||||
const attached = AttachToTarget{
|
||||
.sessionId = cdp.BrowserSessionID,
|
||||
.targetInfo = .{
|
||||
@@ -172,24 +166,22 @@ fn attachToTarget(
|
||||
sessionId: []const u8,
|
||||
};
|
||||
const output = SessionId{
|
||||
.sessionId = msg.sessionID orelse BrowserContextID,
|
||||
.sessionId = input.sessionId orelse BrowserContextID,
|
||||
};
|
||||
return result(alloc, msg.id, SessionId, output, null);
|
||||
return result(alloc, input.id, SessionId, output, null);
|
||||
}
|
||||
|
||||
fn getTargetInfo(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
_: *Ctx,
|
||||
) ![]const u8 {
|
||||
|
||||
// input
|
||||
const Params = struct {
|
||||
targetId: ?[]const u8 = null,
|
||||
};
|
||||
const msg = try getMsg(alloc, _id, Params, scanner);
|
||||
log.debug("Req > id {d}, method {s}", .{ msg.id, "target.getTargetInfo" });
|
||||
const input = try msg.getInput(alloc, Params);
|
||||
log.debug("Req > id {d}, method {s}", .{ input.id, "target.getTargetInfo" });
|
||||
|
||||
// output
|
||||
const TargetInfo = struct {
|
||||
@@ -208,7 +200,7 @@ fn getTargetInfo(
|
||||
.targetId = BrowserTargetID,
|
||||
.type = "browser",
|
||||
};
|
||||
return result(alloc, msg.id, TargetInfo, targetInfo, null);
|
||||
return result(alloc, input.id, TargetInfo, targetInfo, null);
|
||||
}
|
||||
|
||||
// Browser context are not handled and not in the roadmap for now
|
||||
@@ -217,14 +209,12 @@ fn getTargetInfo(
|
||||
// TODO: noop method
|
||||
fn getBrowserContexts(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
ctx: *Ctx,
|
||||
) ![]const u8 {
|
||||
|
||||
// input
|
||||
const msg = try getMsg(alloc, _id, void, scanner);
|
||||
log.debug("Req > id {d}, method {s}", .{ msg.id, "target.getBrowserContexts" });
|
||||
const input = try msg.getInput(alloc, void);
|
||||
log.debug("Req > id {d}, method {s}", .{ input.id, "target.getBrowserContexts" });
|
||||
|
||||
// ouptut
|
||||
const Resp = struct {
|
||||
@@ -238,7 +228,7 @@ fn getBrowserContexts(
|
||||
const contextIDs = [0][]const u8{};
|
||||
resp = .{ .browserContextIds = &contextIDs };
|
||||
}
|
||||
return result(alloc, msg.id, Resp, resp, null);
|
||||
return result(alloc, input.id, Resp, resp, null);
|
||||
}
|
||||
|
||||
const ContextID = "22648B09EDCCDD11109E2D4FEFBE4F89";
|
||||
@@ -246,11 +236,9 @@ const ContextID = "22648B09EDCCDD11109E2D4FEFBE4F89";
|
||||
// TODO: noop method
|
||||
fn createBrowserContext(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
ctx: *Ctx,
|
||||
) ![]const u8 {
|
||||
|
||||
// input
|
||||
const Params = struct {
|
||||
disposeOnDetach: bool = false,
|
||||
@@ -258,8 +246,8 @@ fn createBrowserContext(
|
||||
proxyBypassList: ?[]const u8 = null,
|
||||
originsWithUniversalNetworkAccess: ?[][]const u8 = null,
|
||||
};
|
||||
const msg = try getMsg(alloc, _id, Params, scanner);
|
||||
log.debug("Req > id {d}, method {s}", .{ msg.id, "target.createBrowserContext" });
|
||||
const input = try msg.getInput(alloc, Params);
|
||||
log.debug("Req > id {d}, method {s}", .{ input.id, "target.createBrowserContext" });
|
||||
|
||||
ctx.state.contextID = ContextID;
|
||||
|
||||
@@ -279,25 +267,23 @@ fn createBrowserContext(
|
||||
try writer.writeAll(" }");
|
||||
}
|
||||
};
|
||||
return result(alloc, msg.id, Resp, Resp{}, msg.sessionID);
|
||||
return result(alloc, input.id, Resp, Resp{}, input.sessionId);
|
||||
}
|
||||
|
||||
fn disposeBrowserContext(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
ctx: *Ctx,
|
||||
) ![]const u8 {
|
||||
|
||||
// input
|
||||
const Params = struct {
|
||||
browserContextId: []const u8,
|
||||
};
|
||||
const msg = try getMsg(alloc, _id, Params, scanner);
|
||||
log.debug("Req > id {d}, method {s}", .{ msg.id, "target.disposeBrowserContext" });
|
||||
const input = try msg.getInput(alloc, Params);
|
||||
log.debug("Req > id {d}, method {s}", .{ input.id, "target.disposeBrowserContext" });
|
||||
|
||||
// output
|
||||
const res = try result(alloc, msg.id, null, .{}, null);
|
||||
const res = try result(alloc, input.id, null, .{}, null);
|
||||
try server.sendAsync(ctx, res);
|
||||
|
||||
return error.DisposeBrowserContext;
|
||||
@@ -309,11 +295,9 @@ const LoaderID = "DD4A76F842AA389647D702B4D805F49A";
|
||||
|
||||
fn createTarget(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
ctx: *Ctx,
|
||||
) ![]const u8 {
|
||||
|
||||
// input
|
||||
const Params = struct {
|
||||
url: []const u8,
|
||||
@@ -325,8 +309,8 @@ fn createTarget(
|
||||
background: bool = false,
|
||||
forTab: ?bool = null,
|
||||
};
|
||||
const msg = try getMsg(alloc, _id, Params, scanner);
|
||||
log.debug("Req > id {d}, method {s}", .{ msg.id, "target.createTarget" });
|
||||
const input = try msg.getInput(alloc, Params);
|
||||
log.debug("Req > id {d}, method {s}", .{ input.id, "target.createTarget" });
|
||||
|
||||
// change CDP state
|
||||
ctx.state.frameID = TargetID;
|
||||
@@ -346,7 +330,7 @@ fn createTarget(
|
||||
},
|
||||
.waitingForDebugger = true,
|
||||
};
|
||||
try cdp.sendEvent(alloc, ctx, "Target.attachedToTarget", AttachToTarget, attached, msg.sessionID);
|
||||
try cdp.sendEvent(alloc, ctx, "Target.attachedToTarget", AttachToTarget, attached, input.sessionId);
|
||||
|
||||
// output
|
||||
const Resp = struct {
|
||||
@@ -364,28 +348,26 @@ fn createTarget(
|
||||
try writer.writeAll(" }");
|
||||
}
|
||||
};
|
||||
return result(alloc, msg.id, Resp, Resp{}, msg.sessionID);
|
||||
return result(alloc, input.id, Resp, Resp{}, input.sessionId);
|
||||
}
|
||||
|
||||
fn closeTarget(
|
||||
alloc: std.mem.Allocator,
|
||||
_id: ?u16,
|
||||
scanner: *std.json.Scanner,
|
||||
msg: *IncomingMessage,
|
||||
ctx: *Ctx,
|
||||
) ![]const u8 {
|
||||
|
||||
// input
|
||||
const Params = struct {
|
||||
targetId: []const u8,
|
||||
};
|
||||
const msg = try getMsg(alloc, _id, Params, scanner);
|
||||
log.debug("Req > id {d}, method {s}", .{ msg.id, "target.closeTarget" });
|
||||
const input = try msg.getInput(alloc, Params);
|
||||
log.debug("Req > id {d}, method {s}", .{ input.id, "target.closeTarget" });
|
||||
|
||||
// output
|
||||
const Resp = struct {
|
||||
success: bool = true,
|
||||
};
|
||||
const res = try result(alloc, msg.id, Resp, Resp{}, null);
|
||||
const res = try result(alloc, input.id, Resp, Resp{}, null);
|
||||
try server.sendAsync(ctx, res);
|
||||
|
||||
// Inspector.detached event
|
||||
@@ -398,7 +380,7 @@ fn closeTarget(
|
||||
"Inspector.detached",
|
||||
InspectorDetached,
|
||||
.{},
|
||||
msg.sessionID orelse cdp.ContextSessionID,
|
||||
input.sessionId orelse cdp.ContextSessionID,
|
||||
);
|
||||
|
||||
// detachedFromTarget event
|
||||
@@ -412,8 +394,8 @@ fn closeTarget(
|
||||
"Target.detachedFromTarget",
|
||||
TargetDetached,
|
||||
.{
|
||||
.sessionId = msg.sessionID orelse cdp.ContextSessionID,
|
||||
.targetId = msg.params.?.targetId,
|
||||
.sessionId = input.sessionId orelse cdp.ContextSessionID,
|
||||
.targetId = input.params.targetId,
|
||||
},
|
||||
null,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user