mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-06-11 09:35:59 -04:00
cdp: add runtime.consoleAPICalled
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
const std = @import("std");
|
||||
const lp = @import("lightpanda");
|
||||
|
||||
const js = @import("browser/js/js.zig");
|
||||
const Frame = @import("browser/Frame.zig");
|
||||
const Transfer = @import("browser/HttpClient.zig").Transfer;
|
||||
const Request = @import("browser/HttpClient.zig").Request;
|
||||
@@ -87,6 +88,7 @@ const EventListeners = struct {
|
||||
http_response_header_done: List = .{},
|
||||
javascript_dialog_opening: List = .{},
|
||||
console_message: List = .{},
|
||||
runtime_console_message: List = .{},
|
||||
};
|
||||
|
||||
const Events = union(enum) {
|
||||
@@ -108,6 +110,7 @@ const Events = union(enum) {
|
||||
http_response_header_done: *const ResponseHeaderDone,
|
||||
javascript_dialog_opening: *const JavascriptDialogOpening,
|
||||
console_message: *const ConsoleMessage,
|
||||
runtime_console_message: *const ConsoleMessage,
|
||||
};
|
||||
const EventType = std.meta.FieldEnum(Events);
|
||||
|
||||
@@ -226,6 +229,7 @@ pub const DialogResponse = struct {
|
||||
};
|
||||
|
||||
pub const ConsoleMessage = struct {
|
||||
timestamp: u64,
|
||||
source: enum {
|
||||
xml,
|
||||
javascript,
|
||||
@@ -240,7 +244,7 @@ pub const ConsoleMessage = struct {
|
||||
worker,
|
||||
},
|
||||
level: log.Level,
|
||||
text: []const u8,
|
||||
values: []js.Value,
|
||||
url: ?[]const u8 = null,
|
||||
line: ?u32 = null,
|
||||
columns: ?u32 = null,
|
||||
|
||||
@@ -21,6 +21,7 @@ const lp = @import("lightpanda");
|
||||
const js = @import("../js/js.zig");
|
||||
|
||||
const Notification = @import("../../Notification.zig");
|
||||
const datetime = @import("../../datetime.zig");
|
||||
|
||||
const logger = lp.log;
|
||||
const LogLevel = lp.log.Level;
|
||||
@@ -34,24 +35,21 @@ pub const init: Console = .{};
|
||||
|
||||
fn dispatchConsoleMessage(values: []js.Value, level: LogLevel, exec: *js.Execution) void {
|
||||
const notification = exec.context.page.session.notification;
|
||||
const text = formatValues(values, exec.call_arena) catch return;
|
||||
const ts = datetime.timestamp(.monotonic);
|
||||
|
||||
notification.dispatch(.console_message, &.{
|
||||
.source = .javascript,
|
||||
.level = level,
|
||||
.text = text,
|
||||
.values = values,
|
||||
.timestamp = ts,
|
||||
});
|
||||
}
|
||||
|
||||
fn formatValues(values: []js.Value, allocator: std.mem.Allocator) ![]const u8 {
|
||||
var aw: std.io.Writer.Allocating = .init(allocator);
|
||||
const w = &aw.writer;
|
||||
for (values, 0..) |v, i| {
|
||||
if (i != 0) try w.writeByte(' ');
|
||||
|
||||
const js_str = try v.toString();
|
||||
try js_str.format(w);
|
||||
}
|
||||
return aw.written();
|
||||
notification.dispatch(.runtime_console_message, &.{
|
||||
.source = .javascript,
|
||||
.level = level,
|
||||
.values = values,
|
||||
.timestamp = ts,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn trace(_: *const Console, values: []js.Value, exec: *js.Execution) !void {
|
||||
|
||||
@@ -641,6 +641,14 @@ pub const BrowserContext = struct {
|
||||
self.notification.unregister(.console_message, self);
|
||||
}
|
||||
|
||||
pub fn runtimeEnable(self: *BrowserContext) !void {
|
||||
try self.notification.register(.runtime_console_message, self, onRuntimeConsoleMessage);
|
||||
}
|
||||
|
||||
pub fn runtimeDisable(self: *BrowserContext) void {
|
||||
self.notification.unregister(.runtime_console_message, self);
|
||||
}
|
||||
|
||||
pub fn onFrameRemove(ctx: *anyopaque, _: Notification.FrameRemove) !void {
|
||||
const self: *BrowserContext = @ptrCast(@alignCast(ctx));
|
||||
@import("domains/page.zig").frameRemove(self);
|
||||
@@ -802,11 +810,6 @@ pub const BrowserContext = struct {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn onConsoleMessage(ctx: *anyopaque, msg: *const Notification.ConsoleMessage) !void {
|
||||
const self: *BrowserContext = @ptrCast(@alignCast(ctx));
|
||||
return @import("domains/console.zig").consoleMessage(self, msg);
|
||||
}
|
||||
|
||||
// This is hacky x 2. First, we create the JSON payload by gluing our
|
||||
// session_id onto it. Second, we're much more client/websocket aware than
|
||||
// we should be.
|
||||
@@ -846,6 +849,20 @@ pub const BrowserContext = struct {
|
||||
|
||||
try cdp.client.sendJSONRaw(buf);
|
||||
}
|
||||
|
||||
pub fn onConsoleMessage(ctx: *anyopaque, msg: *const Notification.ConsoleMessage) !void {
|
||||
const self: *BrowserContext = @ptrCast(@alignCast(ctx));
|
||||
defer self.resetNotificationArena();
|
||||
|
||||
return @import("domains/console.zig").consoleMessage(self, msg);
|
||||
}
|
||||
|
||||
pub fn onRuntimeConsoleMessage(ctx: *anyopaque, msg: *const Notification.ConsoleMessage) !void {
|
||||
const self: *BrowserContext = @ptrCast(@alignCast(ctx));
|
||||
defer self.resetNotificationArena();
|
||||
|
||||
return @import("domains/runtime.zig").consoleMessage(self, msg);
|
||||
}
|
||||
};
|
||||
|
||||
/// see: https://chromium.googlesource.com/chromium/src/+/master/third_party/blink/renderer/bindings/core/v8/V8BindingDesign.md#world
|
||||
|
||||
@@ -60,9 +60,19 @@ const ConsoleMessage = struct {
|
||||
pub fn consoleMessage(bc: *CDP.BrowserContext, event: *const Notification.ConsoleMessage) !void {
|
||||
const session_id = bc.session_id orelse return;
|
||||
|
||||
// format values
|
||||
var aw: std.io.Writer.Allocating = .init(bc.notification_arena);
|
||||
const w = &aw.writer;
|
||||
for (event.values, 0..) |v, i| {
|
||||
if (i != 0) try w.writeByte(' ');
|
||||
|
||||
const js_str = try v.toString();
|
||||
try js_str.format(w);
|
||||
}
|
||||
|
||||
return bc.cdp.sendEvent("Console.messageAdded", ConsoleMessage{
|
||||
.source = @tagName(event.source),
|
||||
.level = @tagName(event.level),
|
||||
.text = event.text,
|
||||
.text = aw.written(),
|
||||
}, .{ .session_id = session_id });
|
||||
}
|
||||
|
||||
@@ -19,11 +19,14 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
const js = @import("../../browser/js/js.zig");
|
||||
const CDP = @import("../CDP.zig");
|
||||
const Notification = @import("../../Notification.zig");
|
||||
|
||||
pub fn processMessage(cmd: *CDP.Command) !void {
|
||||
const action = std.meta.stringToEnum(enum {
|
||||
enable,
|
||||
disable,
|
||||
runIfWaitingForDebugger,
|
||||
evaluate,
|
||||
addBinding,
|
||||
@@ -34,10 +37,24 @@ pub fn processMessage(cmd: *CDP.Command) !void {
|
||||
|
||||
switch (action) {
|
||||
.runIfWaitingForDebugger => return cmd.sendResult(null, .{}),
|
||||
.enable => return enable(cmd),
|
||||
.disable => return disable(cmd),
|
||||
else => return sendInspector(cmd, action),
|
||||
}
|
||||
}
|
||||
|
||||
fn enable(cmd: *CDP.Command) !void {
|
||||
const bc = cmd.browser_context orelse return error.BrowserContextNotLoaded;
|
||||
try bc.runtimeEnable();
|
||||
return sendInspector(cmd, .enable);
|
||||
}
|
||||
|
||||
fn disable(cmd: *CDP.Command) !void {
|
||||
const bc = cmd.browser_context orelse return error.BrowserContextNotLoaded;
|
||||
bc.runtimeDisable();
|
||||
return sendInspector(cmd, .disable);
|
||||
}
|
||||
|
||||
fn sendInspector(cmd: *CDP.Command, action: anytype) !void {
|
||||
// save script in file at debug mode
|
||||
if (builtin.mode == .Debug) {
|
||||
@@ -91,3 +108,57 @@ fn logInspector(cmd: *CDP.Command, action: anytype) !void {
|
||||
defer f.close();
|
||||
try f.writeAll(script);
|
||||
}
|
||||
|
||||
const RemoteObject = struct {
|
||||
type: []const u8,
|
||||
subtype: ?[]const u8,
|
||||
className: ?[]const u8,
|
||||
description: ?[]const u8,
|
||||
objectId: ?[]const u8,
|
||||
value: js.Value,
|
||||
};
|
||||
|
||||
const ConsoleMessage = struct {
|
||||
type: []const u8,
|
||||
executionContextId: i32,
|
||||
timestamp: u64,
|
||||
args: []RemoteObject,
|
||||
};
|
||||
|
||||
pub fn consoleMessage(bc: *CDP.BrowserContext, event: *const Notification.ConsoleMessage) !void {
|
||||
const session_id = bc.session_id orelse return;
|
||||
const frame = bc.session.currentFrame() orelse return error.FrameNotLoaded;
|
||||
|
||||
var ls: js.Local.Scope = undefined;
|
||||
frame.js.localScope(&ls);
|
||||
defer ls.deinit();
|
||||
|
||||
const context_id = bc.inspector_session.inspector.getContextId(&ls.local);
|
||||
const arena = bc.notification_arena;
|
||||
|
||||
var args: std.ArrayList(RemoteObject) = .empty;
|
||||
for (event.values) |value| {
|
||||
const remote_object = try bc.inspector_session.getRemoteObject(
|
||||
&ls.local,
|
||||
"",
|
||||
value,
|
||||
);
|
||||
defer remote_object.deinit();
|
||||
|
||||
try args.append(arena, .{
|
||||
.type = try remote_object.getType(arena),
|
||||
.subtype = try remote_object.getSubtype(arena),
|
||||
.className = try remote_object.getClassName(arena),
|
||||
.description = try remote_object.getDescription(arena),
|
||||
.objectId = try remote_object.getObjectId(arena),
|
||||
.value = value,
|
||||
});
|
||||
}
|
||||
|
||||
return bc.cdp.sendEvent("Runtime.consoleAPICalled", ConsoleMessage{
|
||||
.type = @tagName(event.level),
|
||||
.timestamp = event.timestamp,
|
||||
.executionContextId = context_id,
|
||||
.args = args.items,
|
||||
}, .{ .session_id = session_id });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user