mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-02-04 06:23:45 +00:00
Merge pull request #1444 from lightpanda-io/inspector_rework
Rework Inspector usage
This commit is contained in:
@@ -50,10 +50,14 @@ session_arena: ArenaAllocator,
|
|||||||
transfer_arena: ArenaAllocator,
|
transfer_arena: ArenaAllocator,
|
||||||
notification: *Notification,
|
notification: *Notification,
|
||||||
|
|
||||||
pub fn init(app: *App) !Browser {
|
const InitOpts = struct {
|
||||||
|
env: js.Env.InitOpts = .{},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn init(app: *App, opts: InitOpts) !Browser {
|
||||||
const allocator = app.allocator;
|
const allocator = app.allocator;
|
||||||
|
|
||||||
var env = try js.Env.init(app);
|
var env = try js.Env.init(app, opts.env);
|
||||||
errdefer env.deinit();
|
errdefer env.deinit();
|
||||||
|
|
||||||
const notification = try Notification.init(allocator, app.notification);
|
const notification = try Notification.init(allocator, app.notification);
|
||||||
|
|||||||
@@ -68,7 +68,14 @@ templates: []*const v8.FunctionTemplate,
|
|||||||
// Global template created once per isolate and reused across all contexts
|
// Global template created once per isolate and reused across all contexts
|
||||||
global_template: v8.Eternal,
|
global_template: v8.Eternal,
|
||||||
|
|
||||||
pub fn init(app: *App) !Env {
|
// Inspector associated with the Isolate. Exists when CDP is being used.
|
||||||
|
inspector: ?*Inspector,
|
||||||
|
|
||||||
|
pub const InitOpts = struct {
|
||||||
|
with_inspector: bool = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn init(app: *App, opts: InitOpts) !Env {
|
||||||
const allocator = app.allocator;
|
const allocator = app.allocator;
|
||||||
const snapshot = &app.snapshot;
|
const snapshot = &app.snapshot;
|
||||||
|
|
||||||
@@ -84,17 +91,18 @@ pub fn init(app: *App) !Env {
|
|||||||
|
|
||||||
var isolate = js.Isolate.init(params);
|
var isolate = js.Isolate.init(params);
|
||||||
errdefer isolate.deinit();
|
errdefer isolate.deinit();
|
||||||
|
const isolate_handle = isolate.handle;
|
||||||
|
|
||||||
v8.v8__Isolate__SetHostImportModuleDynamicallyCallback(isolate.handle, Context.dynamicModuleCallback);
|
v8.v8__Isolate__SetHostImportModuleDynamicallyCallback(isolate_handle, Context.dynamicModuleCallback);
|
||||||
v8.v8__Isolate__SetPromiseRejectCallback(isolate.handle, promiseRejectCallback);
|
v8.v8__Isolate__SetPromiseRejectCallback(isolate_handle, promiseRejectCallback);
|
||||||
v8.v8__Isolate__SetMicrotasksPolicy(isolate.handle, v8.kExplicit);
|
v8.v8__Isolate__SetMicrotasksPolicy(isolate_handle, v8.kExplicit);
|
||||||
v8.v8__Isolate__SetFatalErrorHandler(isolate.handle, fatalCallback);
|
v8.v8__Isolate__SetFatalErrorHandler(isolate_handle, fatalCallback);
|
||||||
v8.v8__Isolate__SetOOMErrorHandler(isolate.handle, oomCallback);
|
v8.v8__Isolate__SetOOMErrorHandler(isolate_handle, oomCallback);
|
||||||
|
|
||||||
isolate.enter();
|
isolate.enter();
|
||||||
errdefer isolate.exit();
|
errdefer isolate.exit();
|
||||||
|
|
||||||
v8.v8__Isolate__SetHostInitializeImportMetaObjectCallback(isolate.handle, Context.metaObjectCallback);
|
v8.v8__Isolate__SetHostInitializeImportMetaObjectCallback(isolate_handle, Context.metaObjectCallback);
|
||||||
|
|
||||||
// Allocate arrays dynamically to avoid comptime dependency on JsApis.len
|
// Allocate arrays dynamically to avoid comptime dependency on JsApis.len
|
||||||
const eternal_function_templates = try allocator.alloc(v8.Eternal, JsApis.len);
|
const eternal_function_templates = try allocator.alloc(v8.Eternal, JsApis.len);
|
||||||
@@ -111,19 +119,19 @@ pub fn init(app: *App) !Env {
|
|||||||
|
|
||||||
inline for (JsApis, 0..) |JsApi, i| {
|
inline for (JsApis, 0..) |JsApi, i| {
|
||||||
JsApi.Meta.class_id = i;
|
JsApi.Meta.class_id = i;
|
||||||
const data = v8.v8__Isolate__GetDataFromSnapshotOnce(isolate.handle, snapshot.data_start + i);
|
const data = v8.v8__Isolate__GetDataFromSnapshotOnce(isolate_handle, snapshot.data_start + i);
|
||||||
const function_handle: *const v8.FunctionTemplate = @ptrCast(data);
|
const function_handle: *const v8.FunctionTemplate = @ptrCast(data);
|
||||||
// Make function template eternal
|
// Make function template eternal
|
||||||
v8.v8__Eternal__New(isolate.handle, @ptrCast(function_handle), &eternal_function_templates[i]);
|
v8.v8__Eternal__New(isolate_handle, @ptrCast(function_handle), &eternal_function_templates[i]);
|
||||||
|
|
||||||
// Extract the local handle from the global for easy access
|
// Extract the local handle from the global for easy access
|
||||||
const eternal_ptr = v8.v8__Eternal__Get(&eternal_function_templates[i], isolate.handle);
|
const eternal_ptr = v8.v8__Eternal__Get(&eternal_function_templates[i], isolate_handle);
|
||||||
templates[i] = @ptrCast(@alignCast(eternal_ptr.?));
|
templates[i] = @ptrCast(@alignCast(eternal_ptr.?));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create global template once per isolate
|
// Create global template once per isolate
|
||||||
const js_global = v8.v8__FunctionTemplate__New__DEFAULT(isolate.handle);
|
const js_global = v8.v8__FunctionTemplate__New__DEFAULT(isolate_handle);
|
||||||
const window_name = v8.v8__String__NewFromUtf8(isolate.handle, "Window", v8.kNormal, 6);
|
const window_name = v8.v8__String__NewFromUtf8(isolate_handle, "Window", v8.kNormal, 6);
|
||||||
v8.v8__FunctionTemplate__SetClassName(js_global, window_name);
|
v8.v8__FunctionTemplate__SetClassName(js_global, window_name);
|
||||||
|
|
||||||
// Find Window in JsApis by name (avoids circular import)
|
// Find Window in JsApis by name (avoids circular import)
|
||||||
@@ -142,7 +150,12 @@ pub fn init(app: *App) !Env {
|
|||||||
.data = null,
|
.data = null,
|
||||||
.flags = v8.kOnlyInterceptStrings | v8.kNonMasking,
|
.flags = v8.kOnlyInterceptStrings | v8.kNonMasking,
|
||||||
});
|
});
|
||||||
v8.v8__Eternal__New(isolate.handle, @ptrCast(global_template_local), &global_eternal);
|
v8.v8__Eternal__New(isolate_handle, @ptrCast(global_template_local), &global_eternal);
|
||||||
|
}
|
||||||
|
|
||||||
|
var inspector: ?*js.Inspector = null;
|
||||||
|
if (opts.with_inspector) {
|
||||||
|
inspector = try Inspector.init(allocator, isolate_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
@@ -153,6 +166,7 @@ pub fn init(app: *App) !Env {
|
|||||||
.platform = &app.platform,
|
.platform = &app.platform,
|
||||||
.templates = templates,
|
.templates = templates,
|
||||||
.isolate_params = params,
|
.isolate_params = params,
|
||||||
|
.inspector = inspector,
|
||||||
.eternal_function_templates = eternal_function_templates,
|
.eternal_function_templates = eternal_function_templates,
|
||||||
.global_template = global_eternal,
|
.global_template = global_eternal,
|
||||||
};
|
};
|
||||||
@@ -167,6 +181,10 @@ pub fn deinit(self: *Env) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const allocator = self.app.allocator;
|
const allocator = self.app.allocator;
|
||||||
|
if (self.inspector) |i| {
|
||||||
|
i.deinit(allocator);
|
||||||
|
}
|
||||||
|
|
||||||
self.contexts.deinit(allocator);
|
self.contexts.deinit(allocator);
|
||||||
|
|
||||||
allocator.free(self.templates);
|
allocator.free(self.templates);
|
||||||
@@ -220,8 +238,8 @@ pub fn createContext(self: *Env, page: *Page, enter: bool) !*Context {
|
|||||||
.arena = context_arena,
|
.arena = context_arena,
|
||||||
.handle = context_global,
|
.handle = context_global,
|
||||||
.templates = self.templates,
|
.templates = self.templates,
|
||||||
.script_manager = &page._script_manager,
|
|
||||||
.call_arena = page.call_arena,
|
.call_arena = page.call_arena,
|
||||||
|
.script_manager = &page._script_manager,
|
||||||
};
|
};
|
||||||
try context.identity_map.putNoClobber(context_arena, @intFromPtr(page.window), global_global);
|
try context.identity_map.putNoClobber(context_arena, @intFromPtr(page.window), global_global);
|
||||||
|
|
||||||
@@ -249,12 +267,6 @@ pub fn destroyContext(self: *Env, context: *Context) void {
|
|||||||
self.isolate.notifyContextDisposed();
|
self.isolate.notifyContextDisposed();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn newInspector(self: *Env, arena: Allocator, ctx: anytype) !*Inspector {
|
|
||||||
const inspector = try arena.create(Inspector);
|
|
||||||
try Inspector.init(inspector, self.isolate.handle, ctx);
|
|
||||||
return inspector;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn runMicrotasks(self: *const Env) void {
|
pub fn runMicrotasks(self: *const Env) void {
|
||||||
self.isolate.performMicrotasksCheckpoint();
|
self.isolate.performMicrotasksCheckpoint();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,99 +23,76 @@ const v8 = js.v8;
|
|||||||
const TaggedOpaque = @import("TaggedOpaque.zig");
|
const TaggedOpaque = @import("TaggedOpaque.zig");
|
||||||
|
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const RndGen = std.Random.DefaultPrng;
|
|
||||||
|
|
||||||
const CONTEXT_GROUP_ID = 1;
|
const CONTEXT_GROUP_ID = 1;
|
||||||
const CLIENT_TRUST_LEVEL = 1;
|
const CLIENT_TRUST_LEVEL = 1;
|
||||||
|
const IS_DEBUG = @import("builtin").mode == .Debug;
|
||||||
|
|
||||||
|
// Inspector exists for the lifetime of the Isolate/Env. 1 Isolate = 1 Inspector.
|
||||||
|
// It combines the v8.Inspector and the v8.InspectorClientImpl. The v8.InspectorClientImpl
|
||||||
|
// is our own implementation that fulfills the InspectorClient API, i.e. it's the
|
||||||
|
// mechanism v8 provides to let us tweak how the inspector works. For example, it
|
||||||
|
// Below, you'll find a few pub export fn v8_inspector__Client__IMPL__XYZ functions
|
||||||
|
// which is our implementation of what the v8::Inspector requires of our Client
|
||||||
|
// (not much at all)
|
||||||
const Inspector = @This();
|
const Inspector = @This();
|
||||||
|
|
||||||
handle: *v8.Inspector,
|
unique_id: i64,
|
||||||
isolate: *v8.Isolate,
|
isolate: *v8.Isolate,
|
||||||
client: Client,
|
handle: *v8.Inspector,
|
||||||
channel: Channel,
|
client: *v8.InspectorClientImpl,
|
||||||
session: Session,
|
|
||||||
rnd: RndGen = RndGen.init(0),
|
|
||||||
default_context: ?v8.Global,
|
default_context: ?v8.Global,
|
||||||
|
session: ?Session,
|
||||||
|
|
||||||
// We expect allocator to be an arena
|
pub fn init(allocator: Allocator, isolate: *v8.Isolate) !*Inspector {
|
||||||
// Note: This initializes the pre-allocated inspector in-place
|
const self = try allocator.create(Inspector);
|
||||||
pub fn init(self: *Inspector, isolate: *v8.Isolate, ctx: anytype) !void {
|
errdefer allocator.destroy(self);
|
||||||
const ContextT = @TypeOf(ctx);
|
|
||||||
|
|
||||||
const Container = switch (@typeInfo(ContextT)) {
|
|
||||||
.@"struct" => ContextT,
|
|
||||||
.pointer => |ptr| ptr.child,
|
|
||||||
.void => NoopInspector,
|
|
||||||
else => @compileError("invalid context type"),
|
|
||||||
};
|
|
||||||
// If necessary, turn a void context into something we can safely ptrCast
|
|
||||||
const safe_context: *anyopaque = if (ContextT == void) @ptrCast(@constCast(&{})) else ctx;
|
|
||||||
|
|
||||||
// Initialize the fields that callbacks need first
|
|
||||||
self.* = .{
|
self.* = .{
|
||||||
.handle = undefined,
|
.unique_id = 1,
|
||||||
|
.session = null,
|
||||||
.isolate = isolate,
|
.isolate = isolate,
|
||||||
.client = undefined,
|
.client = undefined,
|
||||||
.channel = undefined,
|
.handle = undefined,
|
||||||
.rnd = RndGen.init(0),
|
|
||||||
.default_context = null,
|
.default_context = null,
|
||||||
.session = undefined,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create client and set inspector data BEFORE creating the inspector
|
self.client = v8.v8_inspector__Client__IMPL__CREATE();
|
||||||
// because V8 will call generateUniqueId during inspector creation
|
errdefer v8.v8_inspector__Client__IMPL__DELETE(self.client);
|
||||||
const client = Client.init();
|
v8.v8_inspector__Client__IMPL__SET_DATA(self.client, self);
|
||||||
self.client = client;
|
|
||||||
client.setInspector(self);
|
|
||||||
|
|
||||||
// Now create the inspector - generateUniqueId will work because data is set
|
self.handle = v8.v8_inspector__Inspector__Create(isolate, self.client).?;
|
||||||
const handle = v8.v8_inspector__Inspector__Create(isolate, client.handle).?;
|
errdefer v8.v8_inspector__Inspector__DELETE(self.handle);
|
||||||
self.handle = handle;
|
|
||||||
|
|
||||||
// Create the channel
|
return self;
|
||||||
const channel = Channel.init(
|
|
||||||
safe_context,
|
|
||||||
Container.onInspectorResponse,
|
|
||||||
Container.onInspectorEvent,
|
|
||||||
Container.onRunMessageLoopOnPause,
|
|
||||||
Container.onQuitMessageLoopOnPause,
|
|
||||||
isolate,
|
|
||||||
);
|
|
||||||
self.channel = channel;
|
|
||||||
channel.setInspector(self);
|
|
||||||
|
|
||||||
// Create the session
|
|
||||||
const session_handle = v8.v8_inspector__Inspector__Connect(
|
|
||||||
handle,
|
|
||||||
CONTEXT_GROUP_ID,
|
|
||||||
channel.handle,
|
|
||||||
CLIENT_TRUST_LEVEL,
|
|
||||||
).?;
|
|
||||||
self.session = .{ .handle = session_handle };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *const Inspector) void {
|
pub fn deinit(self: *const Inspector, allocator: Allocator) void {
|
||||||
var hs: v8.HandleScope = undefined;
|
var hs: v8.HandleScope = undefined;
|
||||||
v8.v8__HandleScope__CONSTRUCT(&hs, self.isolate);
|
v8.v8__HandleScope__CONSTRUCT(&hs, self.isolate);
|
||||||
defer v8.v8__HandleScope__DESTRUCT(&hs);
|
defer v8.v8__HandleScope__DESTRUCT(&hs);
|
||||||
|
|
||||||
self.session.deinit();
|
if (self.session) |*s| {
|
||||||
self.client.deinit();
|
s.deinit();
|
||||||
self.channel.deinit();
|
}
|
||||||
|
v8.v8_inspector__Client__IMPL__DELETE(self.client);
|
||||||
v8.v8_inspector__Inspector__DELETE(self.handle);
|
v8.v8_inspector__Inspector__DELETE(self.handle);
|
||||||
|
allocator.destroy(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send(self: *const Inspector, msg: []const u8) void {
|
pub fn startSession(self: *Inspector, ctx: anytype) *Session {
|
||||||
// Can't assume the main Context exists (with its HandleScope)
|
if (comptime IS_DEBUG) {
|
||||||
// available when doing this. Pages (and thus the HandleScope)
|
std.debug.assert(self.session == null);
|
||||||
// comes and goes, but CDP can keep sending messages.
|
}
|
||||||
const isolate = self.isolate;
|
|
||||||
var temp_scope: v8.HandleScope = undefined;
|
|
||||||
v8.v8__HandleScope__CONSTRUCT(&temp_scope, isolate);
|
|
||||||
defer v8.v8__HandleScope__DESTRUCT(&temp_scope);
|
|
||||||
|
|
||||||
self.session.dispatchProtocolMessage(isolate, msg);
|
self.session = undefined;
|
||||||
|
Session.init(&self.session.?, self, ctx);
|
||||||
|
return &self.session.?;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stopSession(self: *Inspector) void {
|
||||||
|
self.session.?.deinit();
|
||||||
|
self.session = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// From CDP docs
|
// From CDP docs
|
||||||
@@ -163,51 +140,6 @@ pub fn resetContextGroup(self: *const Inspector) void {
|
|||||||
v8.v8_inspector__Inspector__ResetContextGroup(self.handle, CONTEXT_GROUP_ID);
|
v8.v8_inspector__Inspector__ResetContextGroup(self.handle, CONTEXT_GROUP_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieves the RemoteObject for a given value.
|
|
||||||
// The value is loaded through the ExecutionWorld's mapZigInstanceToJs function,
|
|
||||||
// just like a method return value. Therefore, if we've mapped this
|
|
||||||
// value before, we'll get the existing js.Global(js.Object) and if not
|
|
||||||
// we'll create it and track it for cleanup when the context ends.
|
|
||||||
pub fn getRemoteObject(
|
|
||||||
self: *const Inspector,
|
|
||||||
local: *const js.Local,
|
|
||||||
group: []const u8,
|
|
||||||
value: anytype,
|
|
||||||
) !RemoteObject {
|
|
||||||
const js_val = try local.zigValueToJs(value, .{});
|
|
||||||
|
|
||||||
// We do not want to expose this as a parameter for now
|
|
||||||
const generate_preview = false;
|
|
||||||
return self.session.wrapObject(
|
|
||||||
local.isolate.handle,
|
|
||||||
local.handle,
|
|
||||||
js_val.handle,
|
|
||||||
group,
|
|
||||||
generate_preview,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gets a value by object ID regardless of which context it is in.
|
|
||||||
// Our TaggedOpaque stores the "resolved" ptr value (the most specific _type,
|
|
||||||
// e.g. we store the ptr to the Div not the EventTarget). But, this is asking for
|
|
||||||
// the pointer to the Node, so we need to use the same resolution mechanism which
|
|
||||||
// is used when we're calling a function to turn the Div into a Node, which is
|
|
||||||
// what TaggedOpaque.fromJS does.
|
|
||||||
pub fn getNodePtr(self: *const Inspector, allocator: Allocator, object_id: []const u8, local: *js.Local) !*anyopaque {
|
|
||||||
// just to indicate that the caller is responsible for ensure there's a local environment
|
|
||||||
_ = local;
|
|
||||||
const unwrapped = try self.session.unwrapObject(allocator, object_id);
|
|
||||||
// The values context and groupId are not used here
|
|
||||||
const js_val = unwrapped.value;
|
|
||||||
if (!v8.v8__Value__IsObject(js_val)) {
|
|
||||||
return error.ObjectIdIsNotANode;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Node = @import("../webapi/Node.zig");
|
|
||||||
// Cast to *const v8.Object for typeTaggedAnyOpaque
|
|
||||||
return TaggedOpaque.fromJS(*Node, @ptrCast(js_val)) catch return error.ObjectIdIsNotANode;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const RemoteObject = struct {
|
pub const RemoteObject = struct {
|
||||||
handle: *v8.RemoteObject,
|
handle: *v8.RemoteObject,
|
||||||
|
|
||||||
@@ -254,20 +186,109 @@ pub const RemoteObject = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const Session = struct {
|
// Combines a v8::InspectorSession and a v8::InspectorChannelImpl. The
|
||||||
|
// InspectorSession is for zig -> v8 (sending messages to the inspector). The
|
||||||
|
// Channel is for v8 -> zig, getting events from the Inspector (that we'll pass
|
||||||
|
// back ot some opaque context, i.e the CDP BrowserContext).
|
||||||
|
// The channel callbacks are defined below, as:
|
||||||
|
// pub export fn v8_inspector__Channel__IMPL__XYZ
|
||||||
|
pub const Session = struct {
|
||||||
|
inspector: *Inspector,
|
||||||
handle: *v8.InspectorSession,
|
handle: *v8.InspectorSession,
|
||||||
|
channel: *v8.InspectorChannelImpl,
|
||||||
|
|
||||||
fn deinit(self: Session) void {
|
// callbacks
|
||||||
v8.v8_inspector__Session__DELETE(self.handle);
|
ctx: *anyopaque,
|
||||||
|
onNotif: *const fn (ctx: *anyopaque, msg: []const u8) void,
|
||||||
|
onResp: *const fn (ctx: *anyopaque, call_id: u32, msg: []const u8) void,
|
||||||
|
|
||||||
|
fn init(self: *Session, inspector: *Inspector, ctx: anytype) void {
|
||||||
|
const Container = @typeInfo(@TypeOf(ctx)).pointer.child;
|
||||||
|
|
||||||
|
const channel = v8.v8_inspector__Channel__IMPL__CREATE(inspector.isolate);
|
||||||
|
const handle = v8.v8_inspector__Inspector__Connect(
|
||||||
|
inspector.handle,
|
||||||
|
CONTEXT_GROUP_ID,
|
||||||
|
channel,
|
||||||
|
CLIENT_TRUST_LEVEL,
|
||||||
|
).?;
|
||||||
|
v8.v8_inspector__Channel__IMPL__SET_DATA(channel, self);
|
||||||
|
|
||||||
|
self.* = .{
|
||||||
|
.ctx = ctx,
|
||||||
|
.handle = handle,
|
||||||
|
.channel = channel,
|
||||||
|
.inspector = inspector,
|
||||||
|
.onResp = Container.onInspectorResponse,
|
||||||
|
.onNotif = Container.onInspectorEvent,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dispatchProtocolMessage(self: Session, isolate: *v8.Isolate, msg: []const u8) void {
|
fn deinit(self: *const Session) void {
|
||||||
|
v8.v8_inspector__Session__DELETE(self.handle);
|
||||||
|
v8.v8_inspector__Channel__IMPL__DELETE(self.channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send(self: *const Session, msg: []const u8) void {
|
||||||
|
const isolate = self.inspector.isolate;
|
||||||
|
var hs: v8.HandleScope = undefined;
|
||||||
|
v8.v8__HandleScope__CONSTRUCT(&hs, isolate);
|
||||||
|
defer v8.v8__HandleScope__DESTRUCT(&hs);
|
||||||
|
|
||||||
v8.v8_inspector__Session__dispatchProtocolMessage(
|
v8.v8_inspector__Session__dispatchProtocolMessage(
|
||||||
self.handle,
|
self.handle,
|
||||||
isolate,
|
isolate,
|
||||||
msg.ptr,
|
msg.ptr,
|
||||||
msg.len,
|
msg.len,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
v8.v8__Isolate__PerformMicrotaskCheckpoint(isolate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets a value by object ID regardless of which context it is in.
|
||||||
|
// Our TaggedOpaque stores the "resolved" ptr value (the most specific _type,
|
||||||
|
// e.g. we store the ptr to the Div not the EventTarget). But, this is asking for
|
||||||
|
// the pointer to the Node, so we need to use the same resolution mechanism which
|
||||||
|
// is used when we're calling a function to turn the Div into a Node, which is
|
||||||
|
// what TaggedOpaque.fromJS does.
|
||||||
|
pub fn getNodePtr(self: *const Session, allocator: Allocator, object_id: []const u8, local: *js.Local) !*anyopaque {
|
||||||
|
// just to indicate that the caller is responsible for ensuring there's a local environment
|
||||||
|
_ = local;
|
||||||
|
|
||||||
|
const unwrapped = try self.unwrapObject(allocator, object_id);
|
||||||
|
// The values context and groupId are not used here
|
||||||
|
const js_val = unwrapped.value;
|
||||||
|
if (!v8.v8__Value__IsObject(js_val)) {
|
||||||
|
return error.ObjectIdIsNotANode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Node = @import("../webapi/Node.zig");
|
||||||
|
// Cast to *const v8.Object for typeTaggedAnyOpaque
|
||||||
|
return TaggedOpaque.fromJS(*Node, @ptrCast(js_val)) catch return error.ObjectIdIsNotANode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieves the RemoteObject for a given value.
|
||||||
|
// The value is loaded through the ExecutionWorld's mapZigInstanceToJs function,
|
||||||
|
// just like a method return value. Therefore, if we've mapped this
|
||||||
|
// value before, we'll get the existing js.Global(js.Object) and if not
|
||||||
|
// we'll create it and track it for cleanup when the context ends.
|
||||||
|
pub fn getRemoteObject(
|
||||||
|
self: *const Session,
|
||||||
|
local: *const js.Local,
|
||||||
|
group: []const u8,
|
||||||
|
value: anytype,
|
||||||
|
) !RemoteObject {
|
||||||
|
const js_val = try local.zigValueToJs(value, .{});
|
||||||
|
|
||||||
|
// We do not want to expose this as a parameter for now
|
||||||
|
const generate_preview = false;
|
||||||
|
return self.wrapObject(
|
||||||
|
local.isolate.handle,
|
||||||
|
local.handle,
|
||||||
|
js_val.handle,
|
||||||
|
group,
|
||||||
|
generate_preview,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrapObject(
|
fn wrapObject(
|
||||||
@@ -334,84 +355,6 @@ const UnwrappedObject = struct {
|
|||||||
object_group: ?[]const u8,
|
object_group: ?[]const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
const Channel = struct {
|
|
||||||
handle: *v8.InspectorChannelImpl,
|
|
||||||
|
|
||||||
// callbacks
|
|
||||||
ctx: *anyopaque,
|
|
||||||
onNotif: onNotifFn = undefined,
|
|
||||||
onResp: onRespFn = undefined,
|
|
||||||
onRunMessageLoopOnPause: onRunMessageLoopOnPauseFn = undefined,
|
|
||||||
onQuitMessageLoopOnPause: onQuitMessageLoopOnPauseFn = undefined,
|
|
||||||
|
|
||||||
pub const onNotifFn = *const fn (ctx: *anyopaque, msg: []const u8) void;
|
|
||||||
pub const onRespFn = *const fn (ctx: *anyopaque, call_id: u32, msg: []const u8) void;
|
|
||||||
pub const onRunMessageLoopOnPauseFn = *const fn (ctx: *anyopaque, context_group_id: u32) void;
|
|
||||||
pub const onQuitMessageLoopOnPauseFn = *const fn (ctx: *anyopaque) void;
|
|
||||||
|
|
||||||
fn init(
|
|
||||||
ctx: *anyopaque,
|
|
||||||
onResp: onRespFn,
|
|
||||||
onNotif: onNotifFn,
|
|
||||||
onRunMessageLoopOnPause: onRunMessageLoopOnPauseFn,
|
|
||||||
onQuitMessageLoopOnPause: onQuitMessageLoopOnPauseFn,
|
|
||||||
isolate: *v8.Isolate,
|
|
||||||
) Channel {
|
|
||||||
const handle = v8.v8_inspector__Channel__IMPL__CREATE(isolate);
|
|
||||||
return .{
|
|
||||||
.handle = handle,
|
|
||||||
.ctx = ctx,
|
|
||||||
.onResp = onResp,
|
|
||||||
.onNotif = onNotif,
|
|
||||||
.onRunMessageLoopOnPause = onRunMessageLoopOnPause,
|
|
||||||
.onQuitMessageLoopOnPause = onQuitMessageLoopOnPause,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deinit(self: Channel) void {
|
|
||||||
v8.v8_inspector__Channel__IMPL__DELETE(self.handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setInspector(self: Channel, inspector: *anyopaque) void {
|
|
||||||
v8.v8_inspector__Channel__IMPL__SET_DATA(self.handle, inspector);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resp(self: Channel, call_id: u32, msg: []const u8) void {
|
|
||||||
self.onResp(self.ctx, call_id, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn notif(self: Channel, msg: []const u8) void {
|
|
||||||
self.onNotif(self.ctx, msg);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const Client = struct {
|
|
||||||
handle: *v8.InspectorClientImpl,
|
|
||||||
|
|
||||||
fn init() Client {
|
|
||||||
return .{ .handle = v8.v8_inspector__Client__IMPL__CREATE() };
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deinit(self: Client) void {
|
|
||||||
v8.v8_inspector__Client__IMPL__DELETE(self.handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setInspector(self: Client, inspector: *anyopaque) void {
|
|
||||||
v8.v8_inspector__Client__IMPL__SET_DATA(self.handle, inspector);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const NoopInspector = struct {
|
|
||||||
pub fn onInspectorResponse(_: *anyopaque, _: u32, _: []const u8) void {}
|
|
||||||
pub fn onInspectorEvent(_: *anyopaque, _: []const u8) void {}
|
|
||||||
pub fn onRunMessageLoopOnPause(_: *anyopaque, _: u32) void {}
|
|
||||||
pub fn onQuitMessageLoopOnPause(_: *anyopaque) void {}
|
|
||||||
};
|
|
||||||
|
|
||||||
fn fromData(data: *anyopaque) *Inspector {
|
|
||||||
return @ptrCast(@alignCast(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn getTaggedOpaque(value: *const v8.Value) ?*TaggedOpaque {
|
pub fn getTaggedOpaque(value: *const v8.Value) ?*TaggedOpaque {
|
||||||
if (!v8.v8__Value__IsObject(value)) {
|
if (!v8.v8__Value__IsObject(value)) {
|
||||||
return null;
|
return null;
|
||||||
@@ -437,24 +380,25 @@ pub export fn v8_inspector__Client__IMPL__generateUniqueId(
|
|||||||
data: *anyopaque,
|
data: *anyopaque,
|
||||||
) callconv(.c) i64 {
|
) callconv(.c) i64 {
|
||||||
const inspector: *Inspector = @ptrCast(@alignCast(data));
|
const inspector: *Inspector = @ptrCast(@alignCast(data));
|
||||||
return inspector.rnd.random().int(i64);
|
const unique_id = inspector.unique_id + 1;
|
||||||
|
inspector.unique_id = unique_id;
|
||||||
|
return unique_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub export fn v8_inspector__Client__IMPL__runMessageLoopOnPause(
|
pub export fn v8_inspector__Client__IMPL__runMessageLoopOnPause(
|
||||||
_: *v8.InspectorClientImpl,
|
_: *v8.InspectorClientImpl,
|
||||||
data: *anyopaque,
|
data: *anyopaque,
|
||||||
ctx_group_id: c_int,
|
context_group_id: c_int,
|
||||||
) callconv(.c) void {
|
) callconv(.c) void {
|
||||||
const inspector: *Inspector = @ptrCast(@alignCast(data));
|
_ = data;
|
||||||
inspector.channel.onRunMessageLoopOnPause(inspector.channel.ctx, @intCast(ctx_group_id));
|
_ = context_group_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub export fn v8_inspector__Client__IMPL__quitMessageLoopOnPause(
|
pub export fn v8_inspector__Client__IMPL__quitMessageLoopOnPause(
|
||||||
_: *v8.InspectorClientImpl,
|
_: *v8.InspectorClientImpl,
|
||||||
data: *anyopaque,
|
data: *anyopaque,
|
||||||
) callconv(.c) void {
|
) callconv(.c) void {
|
||||||
const inspector: *Inspector = @ptrCast(@alignCast(data));
|
_ = data;
|
||||||
inspector.channel.onQuitMessageLoopOnPause(inspector.channel.ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub export fn v8_inspector__Client__IMPL__runIfWaitingForDebugger(
|
pub export fn v8_inspector__Client__IMPL__runIfWaitingForDebugger(
|
||||||
@@ -493,8 +437,8 @@ pub export fn v8_inspector__Channel__IMPL__sendResponse(
|
|||||||
msg: [*c]u8,
|
msg: [*c]u8,
|
||||||
length: usize,
|
length: usize,
|
||||||
) callconv(.c) void {
|
) callconv(.c) void {
|
||||||
const inspector: *Inspector = @ptrCast(@alignCast(data));
|
const session: *Session = @ptrCast(@alignCast(data));
|
||||||
inspector.channel.resp(@as(u32, @intCast(call_id)), msg[0..length]);
|
session.onResp(session.ctx, @intCast(call_id), msg[0..length]);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub export fn v8_inspector__Channel__IMPL__sendNotification(
|
pub export fn v8_inspector__Channel__IMPL__sendNotification(
|
||||||
@@ -503,8 +447,8 @@ pub export fn v8_inspector__Channel__IMPL__sendNotification(
|
|||||||
msg: [*c]u8,
|
msg: [*c]u8,
|
||||||
length: usize,
|
length: usize,
|
||||||
) callconv(.c) void {
|
) callconv(.c) void {
|
||||||
const inspector: *Inspector = @ptrCast(@alignCast(data));
|
const session: *Session = @ptrCast(@alignCast(data));
|
||||||
inspector.channel.notif(msg[0..length]);
|
session.onNotif(session.ctx, msg[0..length]);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub export fn v8_inspector__Channel__IMPL__flushProtocolNotifications(
|
pub export fn v8_inspector__Channel__IMPL__flushProtocolNotifications(
|
||||||
|
|||||||
@@ -80,7 +80,9 @@ pub fn CDPT(comptime TypeProvider: type) type {
|
|||||||
|
|
||||||
pub fn init(app: *App, client: TypeProvider.Client) !Self {
|
pub fn init(app: *App, client: TypeProvider.Client) !Self {
|
||||||
const allocator = app.allocator;
|
const allocator = app.allocator;
|
||||||
const browser = try Browser.init(app);
|
const browser = try Browser.init(app, .{
|
||||||
|
.env = .{ .with_inspector = true },
|
||||||
|
});
|
||||||
errdefer browser.deinit();
|
errdefer browser.deinit();
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
@@ -352,7 +354,7 @@ pub fn BrowserContext(comptime CDP_T: type) type {
|
|||||||
node_registry: Node.Registry,
|
node_registry: Node.Registry,
|
||||||
node_search_list: Node.Search.List,
|
node_search_list: Node.Search.List,
|
||||||
|
|
||||||
inspector: *js.Inspector,
|
inspector_session: *js.Inspector.Session,
|
||||||
isolated_worlds: std.ArrayListUnmanaged(IsolatedWorld),
|
isolated_worlds: std.ArrayListUnmanaged(IsolatedWorld),
|
||||||
|
|
||||||
http_proxy_changed: bool = false,
|
http_proxy_changed: bool = false,
|
||||||
@@ -381,7 +383,9 @@ pub fn BrowserContext(comptime CDP_T: type) type {
|
|||||||
const session = try cdp.browser.newSession();
|
const session = try cdp.browser.newSession();
|
||||||
const arena = session.arena;
|
const arena = session.arena;
|
||||||
|
|
||||||
const inspector = try cdp.browser.env.newInspector(arena, self);
|
const browser = &cdp.browser;
|
||||||
|
const inspector_session = browser.env.inspector.?.startSession(self);
|
||||||
|
errdefer browser.env.inspector.?.stopSession();
|
||||||
|
|
||||||
var registry = Node.Registry.init(allocator);
|
var registry = Node.Registry.init(allocator);
|
||||||
errdefer registry.deinit();
|
errdefer registry.deinit();
|
||||||
@@ -400,7 +404,7 @@ pub fn BrowserContext(comptime CDP_T: type) type {
|
|||||||
.node_registry = registry,
|
.node_registry = registry,
|
||||||
.node_search_list = undefined,
|
.node_search_list = undefined,
|
||||||
.isolated_worlds = .empty,
|
.isolated_worlds = .empty,
|
||||||
.inspector = inspector,
|
.inspector_session = inspector_session,
|
||||||
.notification_arena = cdp.notification_arena.allocator(),
|
.notification_arena = cdp.notification_arena.allocator(),
|
||||||
.intercept_state = try InterceptState.init(allocator),
|
.intercept_state = try InterceptState.init(allocator),
|
||||||
.captured_responses = .empty,
|
.captured_responses = .empty,
|
||||||
@@ -409,27 +413,28 @@ pub fn BrowserContext(comptime CDP_T: type) type {
|
|||||||
self.node_search_list = Node.Search.List.init(allocator, &self.node_registry);
|
self.node_search_list = Node.Search.List.init(allocator, &self.node_registry);
|
||||||
errdefer self.deinit();
|
errdefer self.deinit();
|
||||||
|
|
||||||
try cdp.browser.notification.register(.page_remove, self, onPageRemove);
|
try browser.notification.register(.page_remove, self, onPageRemove);
|
||||||
try cdp.browser.notification.register(.page_created, self, onPageCreated);
|
try browser.notification.register(.page_created, self, onPageCreated);
|
||||||
try cdp.browser.notification.register(.page_navigate, self, onPageNavigate);
|
try browser.notification.register(.page_navigate, self, onPageNavigate);
|
||||||
try cdp.browser.notification.register(.page_navigated, self, onPageNavigated);
|
try browser.notification.register(.page_navigated, self, onPageNavigated);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Self) void {
|
pub fn deinit(self: *Self) void {
|
||||||
// safe to call even if never registered
|
// safe to call even if never registered
|
||||||
log.unregisterInterceptor();
|
log.unregisterInterceptor();
|
||||||
self.log_interceptor.deinit();
|
self.log_interceptor.deinit();
|
||||||
|
const browser = &self.cdp.browser;
|
||||||
|
|
||||||
// Drain microtasks makes sure we don't have inspector's callback
|
// Drain microtasks makes sure we don't have inspector's callback
|
||||||
// in progress before deinit.
|
// in progress before deinit.
|
||||||
self.cdp.browser.env.runMicrotasks();
|
browser.env.runMicrotasks();
|
||||||
|
|
||||||
// resetContextGroup detach the inspector from all contexts.
|
// resetContextGroup detach the inspector from all contexts.
|
||||||
// It append async tasks, so we make sure we run the message loop
|
// It append async tasks, so we make sure we run the message loop
|
||||||
// before deinit it.
|
// before deinit it.
|
||||||
self.inspector.resetContextGroup();
|
browser.env.inspector.?.resetContextGroup();
|
||||||
self.session.browser.runMessageLoop();
|
browser.runMessageLoop();
|
||||||
self.inspector.deinit();
|
browser.env.inspector.?.stopSession();
|
||||||
|
|
||||||
// abort all intercepted requests before closing the sesion/page
|
// abort all intercepted requests before closing the sesion/page
|
||||||
// since some of these might callback into the page/scriptmanager
|
// since some of these might callback into the page/scriptmanager
|
||||||
@@ -445,16 +450,16 @@ pub fn BrowserContext(comptime CDP_T: type) type {
|
|||||||
// If the session has a page, we need to clear it first. The page
|
// If the session has a page, we need to clear it first. The page
|
||||||
// context is always nested inside of the isolated world context,
|
// context is always nested inside of the isolated world context,
|
||||||
// so we need to shutdown the page one first.
|
// so we need to shutdown the page one first.
|
||||||
self.cdp.browser.closeSession();
|
browser.closeSession();
|
||||||
|
|
||||||
self.node_registry.deinit();
|
self.node_registry.deinit();
|
||||||
self.node_search_list.deinit();
|
self.node_search_list.deinit();
|
||||||
self.cdp.browser.notification.unregisterAll(self);
|
browser.notification.unregisterAll(self);
|
||||||
|
|
||||||
if (self.http_proxy_changed) {
|
if (self.http_proxy_changed) {
|
||||||
// has to be called after browser.closeSession, since it won't
|
// has to be called after browser.closeSession, since it won't
|
||||||
// work if there are active connections.
|
// work if there are active connections.
|
||||||
self.cdp.browser.http_client.restoreOriginalProxy() catch |err| {
|
browser.http_client.restoreOriginalProxy() catch |err| {
|
||||||
log.warn(.http, "restoreOriginalProxy", .{ .err = err });
|
log.warn(.http, "restoreOriginalProxy", .{ .err = err });
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -650,9 +655,7 @@ pub fn BrowserContext(comptime CDP_T: type) type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn callInspector(self: *const Self, msg: []const u8) void {
|
pub fn callInspector(self: *const Self, msg: []const u8) void {
|
||||||
self.inspector.send(msg);
|
self.inspector_session.send(msg);
|
||||||
// force running micro tasks after send input to the inspector.
|
|
||||||
self.cdp.browser.runMicrotasks();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn onInspectorResponse(ctx: *anyopaque, _: u32, msg: []const u8) void {
|
pub fn onInspectorResponse(ctx: *anyopaque, _: u32, msg: []const u8) void {
|
||||||
@@ -678,18 +681,6 @@ pub fn BrowserContext(comptime CDP_T: type) type {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// debugger events
|
|
||||||
|
|
||||||
pub fn onRunMessageLoopOnPause(_: *anyopaque, _: u32) void {
|
|
||||||
// onRunMessageLoopOnPause is called when a breakpoint is hit.
|
|
||||||
// Until quit pause, we must continue to run a nested message loop
|
|
||||||
// to interact with the the debugger ony (ie. Chrome DevTools).
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn onQuitMessageLoopOnPause(_: *anyopaque) void {
|
|
||||||
// Quit breakpoint pause.
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is hacky x 2. First, we create the JSON payload by gluing our
|
// 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
|
// session_id onto it. Second, we're much more client/websocket aware than
|
||||||
// we should be.
|
// we should be.
|
||||||
|
|||||||
@@ -305,7 +305,7 @@ fn resolveNode(cmd: anytype) !void {
|
|||||||
|
|
||||||
// node._node is a *DOMNode we need this to be able to find its most derived type e.g. Node -> Element -> HTMLElement
|
// node._node is a *DOMNode we need this to be able to find its most derived type e.g. Node -> Element -> HTMLElement
|
||||||
// So we use the Node.Union when retrieve the value from the environment
|
// So we use the Node.Union when retrieve the value from the environment
|
||||||
const remote_object = try bc.inspector.getRemoteObject(
|
const remote_object = try bc.inspector_session.getRemoteObject(
|
||||||
&ls.?.local,
|
&ls.?.local,
|
||||||
params.objectGroup orelse "",
|
params.objectGroup orelse "",
|
||||||
node.dom,
|
node.dom,
|
||||||
@@ -404,7 +404,7 @@ fn getNode(arena: Allocator, bc: anytype, node_id: ?Node.Id, backend_node_id: ?N
|
|||||||
defer ls.deinit();
|
defer ls.deinit();
|
||||||
|
|
||||||
// Retrieve the object from which ever context it is in.
|
// Retrieve the object from which ever context it is in.
|
||||||
const parser_node = try bc.inspector.getNodePtr(arena, object_id_, &ls.local);
|
const parser_node = try bc.inspector_session.getNodePtr(arena, object_id_, &ls.local);
|
||||||
return try bc.node_registry.register(@ptrCast(@alignCast(parser_node)));
|
return try bc.node_registry.register(@ptrCast(@alignCast(parser_node)));
|
||||||
}
|
}
|
||||||
return error.MissingParams;
|
return error.MissingParams;
|
||||||
|
|||||||
@@ -189,17 +189,9 @@ fn createIsolatedWorld(cmd: anytype) !void {
|
|||||||
|
|
||||||
const world = try bc.createIsolatedWorld(params.worldName, params.grantUniveralAccess);
|
const world = try bc.createIsolatedWorld(params.worldName, params.grantUniveralAccess);
|
||||||
const page = bc.session.currentPage() orelse return error.PageNotLoaded;
|
const page = bc.session.currentPage() orelse return error.PageNotLoaded;
|
||||||
|
|
||||||
const js_context = try world.createContext(page);
|
const js_context = try world.createContext(page);
|
||||||
|
return cmd.sendResult(.{ .executionContextId = js_context.id }, .{});
|
||||||
// Create the auxdata json for the contextCreated event
|
|
||||||
// Calling contextCreated will assign a Id to the context and send the contextCreated event
|
|
||||||
const aux_data = try std.fmt.allocPrint(cmd.arena, "{{\"isDefault\":false,\"type\":\"isolated\",\"frameId\":\"{s}\"}}", .{params.frameId});
|
|
||||||
var ls: js.Local.Scope = undefined;
|
|
||||||
js_context.localScope(&ls);
|
|
||||||
defer ls.deinit();
|
|
||||||
|
|
||||||
bc.inspector.contextCreated(&ls.local, world.name, "", aux_data, false);
|
|
||||||
return cmd.sendResult(.{ .executionContextId = ls.local.debugContextId() }, .{});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn navigate(cmd: anytype) !void {
|
fn navigate(cmd: anytype) !void {
|
||||||
@@ -359,7 +351,7 @@ pub fn pageNavigated(arena: Allocator, bc: anytype, event: *const Notification.P
|
|||||||
page.js.localScope(&ls);
|
page.js.localScope(&ls);
|
||||||
defer ls.deinit();
|
defer ls.deinit();
|
||||||
|
|
||||||
bc.inspector.contextCreated(
|
bc.inspector_session.inspector.contextCreated(
|
||||||
&ls.local,
|
&ls.local,
|
||||||
"",
|
"",
|
||||||
try page.getOrigin(arena) orelse "",
|
try page.getOrigin(arena) orelse "",
|
||||||
@@ -376,7 +368,7 @@ pub fn pageNavigated(arena: Allocator, bc: anytype, event: *const Notification.P
|
|||||||
(isolated_world.context orelse continue).localScope(&ls);
|
(isolated_world.context orelse continue).localScope(&ls);
|
||||||
defer ls.deinit();
|
defer ls.deinit();
|
||||||
|
|
||||||
bc.inspector.contextCreated(
|
bc.inspector_session.inspector.contextCreated(
|
||||||
&ls.local,
|
&ls.local,
|
||||||
isolated_world.name,
|
isolated_world.name,
|
||||||
"://",
|
"://",
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ fn createTarget(cmd: anytype) !void {
|
|||||||
defer ls.deinit();
|
defer ls.deinit();
|
||||||
|
|
||||||
const aux_data = try std.fmt.allocPrint(cmd.arena, "{{\"isDefault\":true,\"type\":\"default\",\"frameId\":\"{s}\"}}", .{target_id});
|
const aux_data = try std.fmt.allocPrint(cmd.arena, "{{\"isDefault\":true,\"type\":\"default\",\"frameId\":\"{s}\"}}", .{target_id});
|
||||||
bc.inspector.contextCreated(
|
bc.inspector_session.inspector.contextCreated(
|
||||||
&ls.local,
|
&ls.local,
|
||||||
"",
|
"",
|
||||||
"", // @ZIGDOM
|
"", // @ZIGDOM
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ pub const FetchOpts = struct {
|
|||||||
writer: ?*std.Io.Writer = null,
|
writer: ?*std.Io.Writer = null,
|
||||||
};
|
};
|
||||||
pub fn fetch(app: *App, url: [:0]const u8, opts: FetchOpts) !void {
|
pub fn fetch(app: *App, url: [:0]const u8, opts: FetchOpts) !void {
|
||||||
var browser = try Browser.init(app);
|
var browser = try Browser.init(app, .{});
|
||||||
defer browser.deinit();
|
defer browser.deinit();
|
||||||
|
|
||||||
var session = try browser.newSession();
|
var session = try browser.newSession();
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ pub fn main() !void {
|
|||||||
var test_arena = std.heap.ArenaAllocator.init(allocator);
|
var test_arena = std.heap.ArenaAllocator.init(allocator);
|
||||||
defer test_arena.deinit();
|
defer test_arena.deinit();
|
||||||
|
|
||||||
var browser = try lp.Browser.init(app);
|
var browser = try lp.Browser.init(app, .{});
|
||||||
defer browser.deinit();
|
defer browser.deinit();
|
||||||
|
|
||||||
const session = try browser.newSession();
|
const session = try browser.newSession();
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ pub fn main() !void {
|
|||||||
});
|
});
|
||||||
defer app.deinit();
|
defer app.deinit();
|
||||||
|
|
||||||
var browser = try lp.Browser.init(app);
|
var browser = try lp.Browser.init(app, .{});
|
||||||
defer browser.deinit();
|
defer browser.deinit();
|
||||||
|
|
||||||
// An arena for running each tests. Is reset after every test.
|
// An arena for running each tests. Is reset after every test.
|
||||||
|
|||||||
@@ -460,7 +460,7 @@ test "tests:beforeAll" {
|
|||||||
});
|
});
|
||||||
errdefer test_app.deinit();
|
errdefer test_app.deinit();
|
||||||
|
|
||||||
test_browser = try Browser.init(test_app);
|
test_browser = try Browser.init(test_app, .{});
|
||||||
errdefer test_browser.deinit();
|
errdefer test_browser.deinit();
|
||||||
|
|
||||||
test_session = try test_browser.newSession();
|
test_session = try test_browser.newSession();
|
||||||
|
|||||||
Reference in New Issue
Block a user