Merge pull request #286 from lightpanda-io/cdp-refacto-input

cdp: refacto message JSON read
This commit is contained in:
Francis Bouvier
2024-11-15 01:03:53 +01:00
committed by GitHub
12 changed files with 433 additions and 409 deletions

View File

@@ -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);
}

View File

@@ -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
// ------

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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
View 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());
}
}

View File

@@ -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);
}

View File

@@ -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 "";

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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,
);

View File

@@ -321,6 +321,8 @@ test {
const queryTest = @import("url/query.zig");
std.testing.refAllDecls(queryTest);
std.testing.refAllDecls(@import("cdp/msg.zig"));
}
fn testJSRuntime(alloc: std.mem.Allocator) !void {