diff --git a/.github/actions/install/action.yml b/.github/actions/install/action.yml index 423a00a..ac5489d 100644 --- a/.github/actions/install/action.yml +++ b/.github/actions/install/action.yml @@ -17,7 +17,7 @@ inputs: zig-v8: description: 'zig v8 version to install' required: false - default: 'v0.1.6' + default: 'v0.1.7' v8: description: 'v8 version to install' required: false diff --git a/src/api.zig b/src/api.zig index 478acdd..70c3357 100644 --- a/src/api.zig +++ b/src/api.zig @@ -83,6 +83,10 @@ pub const TryCatch = Engine.TryCatch; pub const VM = Engine.VM; pub const Env = Engine.Env; +pub const Inspector = Engine.Inspector; +pub const InspectorOnResponseFn = *const fn (ctx: *anyopaque, call_id: u32, msg: []const u8) void; +pub const InspectorOnEventFn = *const fn (ctx: *anyopaque, msg: []const u8) void; + pub const engineType = enum { v8, }; diff --git a/src/engines/v8/v8.zig b/src/engines/v8/v8.zig index 7cff259..d11aec7 100644 --- a/src/engines/v8/v8.zig +++ b/src/engines/v8/v8.zig @@ -86,6 +86,7 @@ pub const Env = struct { isolate_params: v8.CreateParams, hscope: v8.HandleScope, globals: v8.FunctionTemplate, + inspector: ?Inspector = null, js_ctx: ?v8.Context = null, @@ -152,6 +153,14 @@ pub const Env = struct { self.* = undefined; } + pub fn setInspector(self: *Env, inspector: Inspector) void { + self.inspector = inspector; + } + + pub inline fn getInspector(self: Env) ?Inspector { + return self.inspector; + } + pub fn setUserContext(self: *Env, userctx: public.UserContext) anyerror!void { self.nat_ctx.userctx = userctx; } @@ -220,6 +229,7 @@ pub const Env = struct { // Native context self.nat_ctx.stop(); } + pub fn getGlobal(self: Env) anyerror!Object { if (self.js_ctx == null) { return error.EnvNotStarted; @@ -504,3 +514,54 @@ pub fn jsExec(script: []const u8, name: ?[]const u8, isolate: v8.Isolate, js_ctx const value = scr.run(js_ctx) catch return error.JSExec; return .{ .value = value }; } + +// Inspector + +pub const Inspector = struct { + inner: *v8.Inspector, + session: v8.InspectorSession, + + pub fn init( + alloc: std.mem.Allocator, + env: Env, + ctx: *anyopaque, + onResp: public.InspectorOnResponseFn, + onEvent: public.InspectorOnEventFn, + ) anyerror!Inspector { + const inner = try alloc.create(v8.Inspector); + const channel = v8.InspectorChannel.init(ctx, onResp, onEvent, env.isolate); + const client = v8.InspectorClient.init(); + v8.Inspector.init(inner, client, channel, env.isolate); + const session = inner.connect(); + return .{ .inner = inner, .session = session }; + } + + pub fn deinit(self: Inspector, alloc: std.mem.Allocator) void { + self.inner.deinit(); + alloc.destroy(self.inner); + } + + // From CDP docs + // https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-ExecutionContextDescription + // ---- + // - name: Human readable name describing given context. + // - origin: Execution context origin (ie. URL who initialised the request) + // - auxData: Embedder-specific auxiliary data likely matching + // {isDefault: boolean, type: 'default'|'isolated'|'worker', frameId: string} + pub fn contextCreated( + self: Inspector, + env: Env, + name: []const u8, + origin: []const u8, + auxData: ?[]const u8, + ) void { + self.inner.contextCreated(env.js_ctx.?, name, origin, auxData); + } + + // msg should be formatted for the Inspector protocol + // for v8 it's the CDP protocol https://chromedevtools.github.io/devtools-protocol/ + // with only some domains being relevant (mainly Runtime and Debugger) + pub fn send(self: Inspector, env: Env, msg: []const u8) void { + return self.session.dispatchProtocolMessage(env.isolate, msg); + } +}; diff --git a/src/interfaces.zig b/src/interfaces.zig index 7de3a36..5e98f51 100644 --- a/src/interfaces.zig +++ b/src/interfaces.zig @@ -46,6 +46,7 @@ pub fn VM(comptime T: type) void { pub fn Env( comptime T: type, + comptime Inspector_T: type, comptime JSValue_T: type, comptime Object_T: type, ) void { @@ -64,6 +65,9 @@ pub fn Env( assertDecl(T, "bindGlobal", fn (self: *T, ob: anytype) anyerror!void); + assertDecl(T, "setInspector", fn (self: *T, inspector: Inspector_T) void); + assertDecl(T, "getInspector", fn (self: T) callconv(.Inline) ?Inspector_T); + assertDecl(T, "setUserContext", fn ( self: *T, userctx: public.UserContext, @@ -192,6 +196,33 @@ pub fn CallbackResult(comptime T: type) void { // TODO: how to get the result? } +pub fn Inspector(comptime T: type, comptime Env_T: type) void { + + // init() + assertDecl(T, "init", fn ( + alloc: std.mem.Allocator, + env: Env_T, + ctx: *anyopaque, + onResp: public.InspectorOnResponseFn, + onEvent: public.InspectorOnEventFn, + ) anyerror!T); + + // deinit() + assertDecl(T, "deinit", fn (self: T, alloc: std.mem.Allocator) void); + + // contextCreated() + assertDecl(T, "contextCreated", fn ( + self: T, + env: Env_T, + name: []const u8, + origin: []const u8, + auxData: ?[]const u8, + ) void); + + // send() + assertDecl(T, "send", fn (self: T, env: Env_T, msg: []const u8) void); +} + // Utils // ----- diff --git a/src/private_api.zig b/src/private_api.zig index 57703f4..fe72e5e 100644 --- a/src/private_api.zig +++ b/src/private_api.zig @@ -34,10 +34,13 @@ fn checkInterfaces(engine: anytype) void { interfaces.VM(engine.VM); interfaces.Env( engine.Env, + engine.Inspector, engine.JSValue, engine.Object, ); + interfaces.Inspector(engine.Inspector, engine.Env); + // private api } diff --git a/vendor/zig-v8 b/vendor/zig-v8 index 0c61a85..43b7d62 160000 --- a/vendor/zig-v8 +++ b/vendor/zig-v8 @@ -1 +1 @@ -Subproject commit 0c61a85fc02c37997adb471b0b032ae68ea4a89d +Subproject commit 43b7d6279aee8ef75a1daefa85d5ba6a0103c823