mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-28 22:53:28 +00:00
Allow webapis to register a destructor to do cleanup on scope (page) end
Add destructor to XHR to abort any inflight requests.
This commit is contained in:
@@ -257,6 +257,11 @@ pub const XMLHttpRequest = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn destructor(self: *XMLHttpRequest, _: anytype) void {
|
||||||
|
const request = &(self.request orelse return);
|
||||||
|
request.abort();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn reset(self: *XMLHttpRequest) void {
|
pub fn reset(self: *XMLHttpRequest) void {
|
||||||
self.url = null;
|
self.url = null;
|
||||||
|
|
||||||
@@ -278,13 +283,6 @@ pub const XMLHttpRequest = struct {
|
|||||||
self.priv_state = .new;
|
self.priv_state = .new;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *XMLHttpRequest, alloc: Allocator) void {
|
|
||||||
if (self.response_obj) |v| {
|
|
||||||
v.deinit();
|
|
||||||
}
|
|
||||||
self.proto.deinit(alloc);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_readyState(self: *XMLHttpRequest) u16 {
|
pub fn get_readyState(self: *XMLHttpRequest) u16 {
|
||||||
return @intFromEnum(self.state);
|
return @intFromEnum(self.state);
|
||||||
}
|
}
|
||||||
@@ -518,6 +516,7 @@ pub const XMLHttpRequest = struct {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.request = null;
|
||||||
self.state = .done;
|
self.state = .done;
|
||||||
self.send_flag = false;
|
self.send_flag = false;
|
||||||
self.dispatchEvt("readystatechange");
|
self.dispatchEvt("readystatechange");
|
||||||
|
|||||||
@@ -261,6 +261,13 @@ pub const Request = struct {
|
|||||||
self._client.state_pool.release(self._state);
|
self._client.state_pool.release(self._state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn abort(self: *Request) void {
|
||||||
|
const connection = self._connection orelse return;
|
||||||
|
self.destroyConnection(connection);
|
||||||
|
self._connection = null;
|
||||||
|
self.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
const DecomposedURL = struct {
|
const DecomposedURL = struct {
|
||||||
secure: bool,
|
secure: bool,
|
||||||
connect_port: u16,
|
connect_port: u16,
|
||||||
|
|||||||
@@ -502,14 +502,14 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
|
|
||||||
// Callbacks are PesistendObjects. When the scope ends, we need
|
// Callbacks are PesistendObjects. When the scope ends, we need
|
||||||
// to free every callback we created.
|
// to free every callback we created.
|
||||||
callbacks: std.ArrayListUnmanaged(v8.Persistent(v8.Function)) = .{},
|
callbacks: std.ArrayListUnmanaged(v8.Persistent(v8.Function)) = .empty,
|
||||||
|
|
||||||
// Serves two purposes. Like `callbacks` above, this is used to free
|
// Serves two purposes. Like `callbacks` above, this is used to free
|
||||||
// every PeristentObjet we've created during the lifetime of the scope.
|
// every PeristentObjet we've created during the lifetime of the scope.
|
||||||
// More importantly, it serves as an identity map - for a given Zig
|
// More importantly, it serves as an identity map - for a given Zig
|
||||||
// instance, we map it to the same PersistentObject.
|
// instance, we map it to the same PersistentObject.
|
||||||
// The key is the @intFromPtr of the Zig value
|
// The key is the @intFromPtr of the Zig value
|
||||||
identity_map: std.AutoHashMapUnmanaged(usize, PersistentObject) = .{},
|
identity_map: std.AutoHashMapUnmanaged(usize, PersistentObject) = .empty,
|
||||||
|
|
||||||
// Similar to the identity map, but used much less frequently. Some
|
// Similar to the identity map, but used much less frequently. Some
|
||||||
// web APIs have to manage opaque values. Ideally, they use an
|
// web APIs have to manage opaque values. Ideally, they use an
|
||||||
@@ -517,7 +517,7 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
// current call. They can call .persist() on their JsObject to get
|
// current call. They can call .persist() on their JsObject to get
|
||||||
// a `*PersistentObject()`. We need to track these to free them.
|
// a `*PersistentObject()`. We need to track these to free them.
|
||||||
// The key is the @intFromPtr of the v8.Object.handle.
|
// The key is the @intFromPtr of the v8.Object.handle.
|
||||||
js_object_map: std.AutoHashMapUnmanaged(usize, PersistentObject) = .{},
|
js_object_map: std.AutoHashMapUnmanaged(usize, PersistentObject) = .empty,
|
||||||
|
|
||||||
// When we need to load a resource (i.e. an external script), we call
|
// When we need to load a resource (i.e. an external script), we call
|
||||||
// this function to get the source. This is always a reference to the
|
// this function to get the source. This is always a reference to the
|
||||||
@@ -525,8 +525,11 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
// since this js module is decoupled from the browser implementation.
|
// since this js module is decoupled from the browser implementation.
|
||||||
module_loader: ModuleLoader,
|
module_loader: ModuleLoader,
|
||||||
|
|
||||||
|
// Some Zig types have code to execute to cleanup
|
||||||
|
destructor_callbacks: std.ArrayListUnmanaged(DestructorCallback) = .empty,
|
||||||
|
|
||||||
// Some Zig types have code to execute when the call scope ends
|
// Some Zig types have code to execute when the call scope ends
|
||||||
call_scope_end_callbacks: std.ArrayListUnmanaged(CallScopeEndCallback) = .{},
|
call_scope_end_callbacks: std.ArrayListUnmanaged(CallScopeEndCallback) = .empty,
|
||||||
|
|
||||||
const ModuleLoader = struct {
|
const ModuleLoader = struct {
|
||||||
ptr: *anyopaque,
|
ptr: *anyopaque,
|
||||||
@@ -536,6 +539,10 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
// no init, started with executor.startScope()
|
// no init, started with executor.startScope()
|
||||||
|
|
||||||
fn deinit(self: *Scope) void {
|
fn deinit(self: *Scope) void {
|
||||||
|
for (self.destructor_callbacks.items) |cb| {
|
||||||
|
cb.destructor(self);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var it = self.identity_map.valueIterator();
|
var it = self.identity_map.valueIterator();
|
||||||
while (it.next()) |p| {
|
while (it.next()) |p| {
|
||||||
@@ -694,6 +701,10 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
return gop.value_ptr.*;
|
return gop.value_ptr.*;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (comptime @hasDecl(ptr.child, "destructor")) {
|
||||||
|
try self.destructor_callbacks.append(scope_arena, DestructorCallback.init(value));
|
||||||
|
}
|
||||||
|
|
||||||
if (comptime @hasDecl(ptr.child, "jsCallScopeEnd")) {
|
if (comptime @hasDecl(ptr.child, "jsCallScopeEnd")) {
|
||||||
try self.call_scope_end_callbacks.append(scope_arena, CallScopeEndCallback.init(value));
|
try self.call_scope_end_callbacks.append(scope_arena, CallScopeEndCallback.init(value));
|
||||||
}
|
}
|
||||||
@@ -1672,7 +1683,35 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// An interface for types that want to their jsScopeEnd function to be
|
// An interface for types that want to have their jsDeinit function to be
|
||||||
|
// called when the call scope ends
|
||||||
|
const DestructorCallback = struct {
|
||||||
|
ptr: *anyopaque,
|
||||||
|
destructorFn: *const fn (ptr: *anyopaque, scope: *Scope) void,
|
||||||
|
|
||||||
|
fn init(ptr: anytype) DestructorCallback {
|
||||||
|
const T = @TypeOf(ptr);
|
||||||
|
const ptr_info = @typeInfo(T);
|
||||||
|
|
||||||
|
const gen = struct {
|
||||||
|
pub fn destructor(pointer: *anyopaque, scope: *Scope) void {
|
||||||
|
const self: T = @ptrCast(@alignCast(pointer));
|
||||||
|
return ptr_info.pointer.child.destructor(self, scope);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.ptr = ptr,
|
||||||
|
.destructorFn = gen.destructor,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destructor(self: DestructorCallback, scope: *Scope) void {
|
||||||
|
self.destructorFn(self.ptr, scope);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// An interface for types that want to have their jsScopeEnd function be
|
||||||
// called when the call scope ends
|
// called when the call scope ends
|
||||||
const CallScopeEndCallback = struct {
|
const CallScopeEndCallback = struct {
|
||||||
ptr: *anyopaque,
|
ptr: *anyopaque,
|
||||||
|
|||||||
Reference in New Issue
Block a user