Compare commits

...

6 Commits

Author SHA1 Message Date
Claude Bot
cb20d4b269 Add debug output to investigate test failures
onOpen() is never being called when running under test runner, even though
manual tests work perfectly. This suggests issue is with test environment
or how servers are created/registered, not with the GC or callback storage.

Debug output shows manual tests have valid context and non-null handlers.
Test runner shows no debug output at all, meaning onOpen never fires.

Need to investigate:
- Why WebSocket connections work in manual tests but not test runner
- Whether uWS handlers are being registered correctly
- If there's something different about test environment
2025-10-26 08:02:28 +00:00
Claude Bot
e3c0fa384f Add visitChildren and protect/unprotect for JSWebSocketServerContext
- Implement DECLARE_VISIT_CHILDREN and visitChildrenImpl to ensure GC properly traverses internal fields
- Protect JSValue immediately after creation to prevent premature GC
- Unprotect after storing on server object

Status: Manual WebSocket tests work perfectly. Test suite shows 2/76 tests passing (up from 0).
Issue persists with test runner - investigating why callbacks aren't being invoked in test context.
2025-10-26 07:49:42 +00:00
Claude Bot
f638fd93d4 Fix: Set websocketServerContext field after server toJS()
Move the websocketServerContextSetCached call from listen() to BunObject.serve(),
right after toJS() creates the server JSValue. This ensures:
1. The server JSValue exists before we try to set fields on it
2. The websocket context is stored in the correct place alongside routeList
3. The GC can properly track the relationship
2025-10-26 06:42:32 +00:00
Claude Bot
edb7ba6332 Critical fix: Store websocket_js_context in server's websocketServerContext field
This keeps the JSWebSocketServerContext alive through GC by storing it in
the server's 'values' field. Without this, the context gets freed while
still in use, causing use-after-poison errors.

The generated code creates m_websocketServerContext which is visited by
the GC, ensuring the JSWebSocketServerContext stays alive as long as the
server is alive.
2025-10-26 06:30:26 +00:00
Claude Bot
802fae5093 Fix: Use fromJS instead of unsafe pointer casts, remove js_context field
- Remove unsafe js_context JSValue field from WebSocketServerContext
- Store websocket_js_context in ServerConfig instead
- Access JSWebSocketServerContext through fromJS() everywhere
- Pass all callbacks/settings to create() function at construction time
- Use setWithoutWriteBarrier in constructor for initial field setup
2025-10-26 06:25:59 +00:00
Claude Bot
2666848d5d Refactor WebSocketServerContext to use GC-managed JSInternalFieldObjectImpl
This refactors the WebSocket server context from manual protect()/unprotect()
memory management to automatic GC management using JSInternalFieldObjectImpl.

Changes:
- Created JSWebSocketServerContext C++ class as JSInternalFieldObjectImpl<8>
  - 8 internal fields for GC-tracked callbacks (onOpen, onMessage, onClose,
    onDrain, onError, onPing, onPong, server)
  - C++ members for non-GC data (app, vm, flags, active_connections)
- Added subspaces in DOMClientIsoSubspaces.h and DOMIsoSubspaces.h
- Added structure lazy init in ZigGlobalObject
- Updated server.classes.ts to add websocketServerContext field to both
  HTTPServer variants and ServerWebSocket
- Removed protect()/unprotect() methods from Handler and WebSocketServerContext
- Updated ServerWebSocket to use JSWebSocketServerContext instead of handler
  pointer, accessing all data through context getters
- Updated all callbacks (onOpen, onMessage, onClose, onDrain, onPing, onPong)
  and publish methods to use context
- Updated server.zig to pass JSWebSocketServerContext to ServerWebSocket.init
  and reload logic

This eliminates manual memory management and potential leaks/use-after-free
bugs by letting the GC handle callback lifetimes automatically.
2025-10-26 06:10:33 +00:00
13 changed files with 713 additions and 105 deletions

View File

@@ -1086,6 +1086,11 @@ pub fn serve(globalObject: *jsc.JSGlobalObject, callframe: *jsc.CallFrame) bun.J
if (route_list_object != .zero) {
ServerType.js.routeListSetCached(obj, globalObject, route_list_object);
}
if (config.websocket_js_context != .zero) {
ServerType.js.websocketServerContextSetCached(obj, globalObject, config.websocket_js_context);
// Now that it's stored on the server, we can unprotect it
config.websocket_js_context.unprotect();
}
server.js_value.setStrong(obj, globalObject);
if (config.allow_hot) {

View File

@@ -87,7 +87,7 @@ function generate(name) {
finalize: true,
construct: true,
noConstructor: true,
values: ["routeList"],
values: ["routeList", "websocketServerContext"],
});
}
export default [
@@ -320,7 +320,7 @@ export default [
finalize: true,
construct: true,
klass: {},
values: ["socket"],
values: ["socket", "websocketServerContext"],
}),
define({

View File

@@ -4,6 +4,7 @@ const ctxLog = Output.scoped(.RequestContext, .visible);
pub const WebSocketServerContext = @import("./server/WebSocketServerContext.zig");
pub const HTTPStatusText = @import("./server/HTTPStatusText.zig");
pub const HTMLBundle = @import("./server/HTMLBundle.zig");
const JSWebSocketServerContext = @import("../bindings/JSWebSocketServerContext.zig").JSWebSocketServerContext;
pub fn writeStatus(comptime ssl: bool, resp_ptr: ?*uws.NewApp(ssl).Response, status: u16) void {
if (resp_ptr) |resp| {
@@ -989,7 +990,8 @@ pub fn NewServer(protocol_enum: enum { http, https }, development_kind: enum { d
upgrader.request_weakref.deref();
data_value.ensureStillAlive();
const ws = ServerWebSocket.init(&this.config.websocket.?.handler, data_value, signal);
const ws_ctx = JSWebSocketServerContext.fromJS(this.config.websocket_js_context) orelse unreachable;
const ws = ServerWebSocket.init(ws_ctx, data_value, signal);
data_value.ensureStillAlive();
var sec_websocket_protocol_str = sec_websocket_protocol.toSlice(bun.default_allocator);
@@ -1038,12 +1040,21 @@ pub fn NewServer(protocol_enum: enum { http, https }, development_kind: enum { d
if (new_config.websocket) |*ws| {
ws.handler.flags.ssl = ssl_enabled;
if (ws.handler.onMessage != .zero or ws.handler.onOpen != .zero) {
if (this.config.websocket) |old_ws| {
old_ws.unprotect();
// Update the existing JSWebSocketServerContext with new callbacks
if (JSWebSocketServerContext.fromJS(new_config.websocket_js_context)) |ws_ctx| {
ws_ctx.setSSL(ssl_enabled);
ws_ctx.setOnOpen(globalThis, ws.handler.onOpen);
ws_ctx.setOnMessage(globalThis, ws.handler.onMessage);
ws_ctx.setOnClose(globalThis, ws.handler.onClose);
ws_ctx.setOnDrain(globalThis, ws.handler.onDrain);
ws_ctx.setOnError(globalThis, ws.handler.onError);
ws_ctx.setOnPing(globalThis, ws.handler.onPing);
ws_ctx.setOnPong(globalThis, ws.handler.onPong);
}
ws.globalObject = globalThis;
this.config.websocket = ws.*;
this.config.websocket_js_context = new_config.websocket_js_context;
} // we don't remove it
}
@@ -3115,7 +3126,7 @@ pub const AnyServer = struct {
};
}
pub fn webSocketHandler(this: AnyServer) ?*WebSocketServerContext.Handler {
pub fn webSocketHandler(this: AnyServer) ?*JSWebSocketServerContext {
const server_config: *ServerConfig = switch (this.ptr.tag()) {
Ptr.case(HTTPServer) => &this.ptr.as(HTTPServer).config,
Ptr.case(HTTPSServer) => &this.ptr.as(HTTPSServer).config,
@@ -3124,7 +3135,7 @@ pub const AnyServer = struct {
else => bun.unreachablePanic("Invalid pointer tag", .{}),
};
if (server_config.websocket == null) return null;
return &server_config.websocket.?.handler;
return JSWebSocketServerContext.fromJS(server_config.websocket_js_context);
}
pub fn onRequest(

View File

@@ -47,6 +47,7 @@ onRequest: jsc.JSValue = jsc.JSValue.zero,
onNodeHTTPRequest: jsc.JSValue = jsc.JSValue.zero,
websocket: ?WebSocketServerContext = null,
websocket_js_context: jsc.JSValue = jsc.JSValue.zero,
inspector: bool = false,
reuse_port: bool = false,
@@ -744,7 +745,9 @@ pub fn fromJS(
}
errdefer if (args.ssl_config) |*conf| conf.deinit();
args.websocket = try WebSocketServerContext.onCreate(global, websocket_object);
const ws_result = try WebSocketServerContext.onCreate(global, websocket_object);
args.websocket = ws_result.context;
args.websocket_js_context = ws_result.js_context;
}
if (global.hasException()) return error.JSError;

View File

@@ -1,6 +1,6 @@
const ServerWebSocket = @This();
#handler: *WebSocketServer.Handler,
#websocket_context: *JSWebSocketServerContext,
#this_value: jsc.JSRef = .empty(),
#flags: Flags = .{},
#signal: ?*bun.webcore.AbortSignal = null,
@@ -36,12 +36,13 @@ pub const fromJSDirect = js.fromJSDirect;
const new = bun.TrivialNew(ServerWebSocket);
/// Initialize a ServerWebSocket with the given handler, data value, and signal.
/// Initialize a ServerWebSocket with the given websocket context, data value, and signal.
/// The signal will not be ref'd inside the ServerWebSocket init function, but will unref itself when the ServerWebSocket is destroyed.
pub fn init(handler: *WebSocketServer.Handler, data_value: jsc.JSValue, signal: ?*bun.webcore.AbortSignal) *ServerWebSocket {
const globalObject = handler.globalObject;
pub fn init(websocket_context: *JSWebSocketServerContext, data_value: jsc.JSValue, signal: ?*bun.webcore.AbortSignal) *ServerWebSocket {
const vm = websocket_context.getVM();
const globalObject = vm.global;
const this = ServerWebSocket.new(.{
.#handler = handler,
.#websocket_context = websocket_context,
.#signal = signal,
});
// Get a strong ref and downgrade when terminating/close and GC will be able to collect the newly created value
@@ -67,11 +68,13 @@ pub fn onOpen(this: *ServerWebSocket, ws: uws.AnyWebSocket) void {
this.#flags.closed = false;
this.#flags.ssl = ws == .ssl;
var handler = this.#handler;
const vm = this.#handler.vm;
handler.active_connections +|= 1;
const globalObject = handler.globalObject;
const onOpenHandler = handler.onOpen;
const ctx = this.#websocket_context;
bun.Output.printErrorln("DEBUG onOpen: ctx ptr={*}", .{ctx});
const vm = ctx.getVM();
ctx.incrementActiveConnections();
const globalObject = vm.global;
const onOpenHandler = ctx.getOnOpen();
bun.Output.printErrorln("DEBUG onOpen: isEmpty={}", .{onOpenHandler.isEmptyOrUndefinedOrNull()});
if (vm.isShuttingDown()) {
log("onOpen called after script execution", .{});
ws.close();
@@ -81,6 +84,7 @@ pub fn onOpen(this: *ServerWebSocket, ws: uws.AnyWebSocket) void {
this.#flags.opened = false;
if (onOpenHandler.isEmptyOrUndefinedOrNull()) {
bun.Output.printErrorln("DEBUG onOpen: EARLY RETURN - handler is null!", .{});
return;
}
@@ -108,11 +112,11 @@ pub fn onOpen(this: *ServerWebSocket, ws: uws.AnyWebSocket) void {
// we don't want any event handlers to fire after this for anything other than error()
// https://github.com/oven-sh/bun/issues/1480
this.websocket().close();
handler.active_connections -|= 1;
ctx.decrementActiveConnections();
this_value.unprotect();
}
handler.runErrorCallback(vm, globalObject, err_value);
runErrorCallback(ctx, vm, globalObject, err_value);
}
}
@@ -126,11 +130,12 @@ pub fn onMessage(
@intFromEnum(opcode),
message,
});
const onMessageHandler = this.#handler.onMessage;
const ctx = this.#websocket_context;
const onMessageHandler = ctx.getOnMessage();
if (onMessageHandler.isEmptyOrUndefinedOrNull()) return;
var globalObject = this.#handler.globalObject;
const vm = ctx.getVM();
const globalObject = vm.global;
// This is the start of a task.
const vm = this.#handler.vm;
if (vm.isShuttingDown()) {
log("onMessage called after script execution", .{});
ws.close();
@@ -162,7 +167,7 @@ pub fn onMessage(
if (result.isEmptyOrUndefinedOrNull()) return;
if (result.toError()) |err_value| {
this.#handler.runErrorCallback(vm, globalObject, err_value);
runErrorCallback(ctx, vm, globalObject, err_value);
return;
}
@@ -185,18 +190,19 @@ pub inline fn isClosed(this: *const ServerWebSocket) bool {
pub fn onDrain(this: *ServerWebSocket, _: uws.AnyWebSocket) void {
log("onDrain", .{});
const handler = this.#handler;
const vm = handler.vm;
const ctx = this.#websocket_context;
const vm = ctx.getVM();
if (this.isClosed() or vm.isShuttingDown())
return;
if (handler.onDrain != .zero) {
const globalObject = handler.globalObject;
const onDrainHandler = ctx.getOnDrain();
if (onDrainHandler != .zero) {
const globalObject = vm.global;
var corker = Corker{
.args = &[_]jsc.JSValue{this.#this_value.tryGet() orelse .js_undefined},
.globalObject = globalObject,
.callback = handler.onDrain,
.callback = onDrainHandler,
};
const loop = vm.eventLoop();
loop.enter();
@@ -205,7 +211,7 @@ pub fn onDrain(this: *ServerWebSocket, _: uws.AnyWebSocket) void {
const result = corker.result;
if (result.toError()) |err_value| {
handler.runErrorCallback(vm, globalObject, err_value);
runErrorCallback(ctx, vm, globalObject, err_value);
}
}
}
@@ -232,11 +238,11 @@ fn binaryToJS(this: *const ServerWebSocket, globalThis: *jsc.JSGlobalObject, dat
pub fn onPing(this: *ServerWebSocket, _: uws.AnyWebSocket, data: []const u8) void {
log("onPing: {s}", .{data});
const handler = this.#handler;
var cb = handler.onPing;
const vm = handler.vm;
const ctx = this.#websocket_context;
const vm = ctx.getVM();
var cb = ctx.getOnPing();
if (cb.isEmptyOrUndefinedOrNull() or vm.isShuttingDown()) return;
const globalThis = handler.globalObject;
const globalThis = vm.global;
// This is the start of a task.
const loop = vm.eventLoop();
@@ -250,19 +256,19 @@ pub fn onPing(this: *ServerWebSocket, _: uws.AnyWebSocket, data: []const u8) voi
) catch |e| {
const err = globalThis.takeException(e);
log("onPing error", .{});
handler.runErrorCallback(vm, globalThis, err);
runErrorCallback(ctx, vm, globalThis, err);
};
}
pub fn onPong(this: *ServerWebSocket, _: uws.AnyWebSocket, data: []const u8) void {
log("onPong: {s}", .{data});
const handler = this.#handler;
var cb = handler.onPong;
const ctx = this.#websocket_context;
const vm = ctx.getVM();
var cb = ctx.getOnPong();
if (cb.isEmptyOrUndefinedOrNull()) return;
const globalThis = handler.globalObject;
const vm = handler.vm;
const globalThis = vm.global;
if (vm.isShuttingDown()) return;
@@ -278,19 +284,19 @@ pub fn onPong(this: *ServerWebSocket, _: uws.AnyWebSocket, data: []const u8) voi
) catch |e| {
const err = globalThis.takeException(e);
log("onPong error", .{});
handler.runErrorCallback(vm, globalThis, err);
runErrorCallback(ctx, vm, globalThis, err);
};
}
pub fn onClose(this: *ServerWebSocket, _: uws.AnyWebSocket, code: i32, message: []const u8) void {
log("onClose", .{});
// TODO: Can this called inside finalize?
var handler = this.#handler;
const ctx = this.#websocket_context;
const was_closed = this.isClosed();
this.#flags.closed = true;
defer {
if (!was_closed) {
handler.active_connections -|= 1;
ctx.decrementActiveConnections();
}
}
const signal = this.#signal;
@@ -307,13 +313,14 @@ pub fn onClose(this: *ServerWebSocket, _: uws.AnyWebSocket, code: i32, message:
}
}
const vm = handler.vm;
const vm = ctx.getVM();
if (vm.isShuttingDown()) {
return;
}
if (!handler.onClose.isEmptyOrUndefinedOrNull()) {
const globalObject = handler.globalObject;
const onCloseHandler = ctx.getOnClose();
if (!onCloseHandler.isEmptyOrUndefinedOrNull()) {
const globalObject = vm.global;
const loop = vm.eventLoop();
loop.enter();
@@ -321,31 +328,33 @@ pub fn onClose(this: *ServerWebSocket, _: uws.AnyWebSocket, code: i32, message:
if (signal) |sig| {
if (!sig.aborted()) {
sig.signal(handler.globalObject, .ConnectionClosed);
sig.signal(globalObject, .ConnectionClosed);
}
}
const message_js = bun.String.createUTF8ForJS(globalObject, message) catch |e| {
const err = globalObject.takeException(e);
log("onClose error (message) {}", .{this.#this_value.isNotEmpty()});
handler.runErrorCallback(vm, globalObject, err);
runErrorCallback(ctx, vm, globalObject, err);
return;
};
_ = handler.onClose.call(globalObject, .js_undefined, &[_]jsc.JSValue{ this.#this_value.tryGet() orelse .js_undefined, JSValue.jsNumber(code), message_js }) catch |e| {
_ = onCloseHandler.call(globalObject, .js_undefined, &[_]jsc.JSValue{ this.#this_value.tryGet() orelse .js_undefined, JSValue.jsNumber(code), message_js }) catch |e| {
const err = globalObject.takeException(e);
log("onClose error {}", .{this.#this_value.isNotEmpty()});
handler.runErrorCallback(vm, globalObject, err);
runErrorCallback(ctx, vm, globalObject, err);
return;
};
} else if (signal) |sig| {
const loop = vm.eventLoop();
const vm2 = ctx.getVM();
const globalObject = vm2.global;
const loop = vm2.eventLoop();
loop.enter();
defer loop.exit();
if (!sig.aborted()) {
sig.signal(handler.globalObject, .ConnectionClosed);
sig.signal(globalObject, .ConnectionClosed);
}
}
}
@@ -381,13 +390,13 @@ pub fn publish(
return globalThis.throw("publish requires at least 1 argument", .{});
}
const app = this.#handler.app orelse {
const ctx = this.#websocket_context;
const app = ctx.getApp() orelse {
log("publish() closed", .{});
return JSValue.jsNumber(0);
};
const flags = this.#handler.flags;
const ssl = flags.ssl;
const publish_to_self = flags.publish_to_self;
const ssl = ctx.getSSL();
const publish_to_self = ctx.getPublishToSelf();
const topic_value = args.ptr[0];
const message_value = args.ptr[1];
@@ -465,13 +474,13 @@ pub fn publishText(
return globalThis.throw("publish requires at least 1 argument", .{});
}
const app = this.#handler.app orelse {
const ctx = this.#websocket_context;
const app = ctx.getApp() orelse {
log("publish() closed", .{});
return JSValue.jsNumber(0);
};
const flags = this.#handler.flags;
const ssl = flags.ssl;
const publish_to_self = flags.publish_to_self;
const ssl = ctx.getSSL();
const publish_to_self = ctx.getPublishToSelf();
const topic_value = args.ptr[0];
const message_value = args.ptr[1];
@@ -528,13 +537,13 @@ pub fn publishBinary(
return globalThis.throw("publishBinary requires at least 1 argument", .{});
}
const app = this.#handler.app orelse {
const ctx = this.#websocket_context;
const app = ctx.getApp() orelse {
log("publish() closed", .{});
return JSValue.jsNumber(0);
};
const flags = this.#handler.flags;
const ssl = flags.ssl;
const publish_to_self = flags.publish_to_self;
const ssl = ctx.getSSL();
const publish_to_self = ctx.getPublishToSelf();
const topic_value = args.ptr[0];
const message_value = args.ptr[1];
const compress_value = args.ptr[2];
@@ -583,13 +592,13 @@ pub fn publishBinaryWithoutTypeChecks(
topic_str: *jsc.JSString,
array: *jsc.JSUint8Array,
) bun.JSError!jsc.JSValue {
const app = this.#handler.app orelse {
const ctx = this.#websocket_context;
const app = ctx.getApp() orelse {
log("publish() closed", .{});
return JSValue.jsNumber(0);
};
const flags = this.#handler.flags;
const ssl = flags.ssl;
const publish_to_self = flags.publish_to_self;
const ssl = ctx.getSSL();
const publish_to_self = ctx.getPublishToSelf();
var topic_slice = topic_str.toSlice(globalThis, bun.default_allocator);
defer topic_slice.deinit();
@@ -622,13 +631,13 @@ pub fn publishTextWithoutTypeChecks(
topic_str: *jsc.JSString,
str: *jsc.JSString,
) bun.JSError!jsc.JSValue {
const app = this.#handler.app orelse {
const ctx = this.#websocket_context;
const app = ctx.getApp() orelse {
log("publish() closed", .{});
return JSValue.jsNumber(0);
};
const flags = this.#handler.flags;
const ssl = flags.ssl;
const publish_to_self = flags.publish_to_self;
const ssl = ctx.getSSL();
const publish_to_self = ctx.getPublishToSelf();
var topic_slice = topic_str.toSlice(globalThis, bun.default_allocator);
defer topic_slice.deinit();
@@ -1254,6 +1263,17 @@ pub fn getRemoteAddress(
return bun.String.createUTF8ForJS(globalThis, text);
}
fn runErrorCallback(ctx: *JSWebSocketServerContext, vm: *jsc.VirtualMachine, globalObject: *jsc.JSGlobalObject, error_value: jsc.JSValue) void {
const onError = ctx.getOnError();
if (!onError.isEmptyOrUndefinedOrNull()) {
_ = onError.call(globalObject, .js_undefined, &.{error_value}) catch |err|
globalObject.reportActiveExceptionAsUnhandled(err);
return;
}
_ = vm.uncaughtException(globalObject, error_value, false);
}
const Corker = struct {
args: []const JSValue = &.{},
globalObject: *jsc.JSGlobalObject,
@@ -1284,3 +1304,4 @@ const jsc = bun.jsc;
const JSGlobalObject = jsc.JSGlobalObject;
const JSValue = jsc.JSValue;
const ZigString = jsc.ZigString;
const JSWebSocketServerContext = @import("../../bindings/JSWebSocketServerContext.zig").JSWebSocketServerContext;

View File

@@ -79,30 +79,6 @@ pub const Handler = struct {
return globalObject.throwInvalidArguments("WebSocketServerContext expects a message handler", .{});
}
pub fn protect(this: Handler) void {
this.onOpen.protect();
this.onMessage.protect();
this.onClose.protect();
this.onDrain.protect();
this.onError.protect();
this.onPing.protect();
this.onPong.protect();
}
pub fn unprotect(this: Handler) void {
if (this.vm.isShuttingDown()) {
return;
}
this.onOpen.unprotect();
this.onMessage.unprotect();
this.onClose.unprotect();
this.onDrain.unprotect();
this.onError.unprotect();
this.onPing.unprotect();
this.onPong.unprotect();
}
};
pub fn toBehavior(this: WebSocketServerContext) uws.WebSocketBehavior {
@@ -118,13 +94,6 @@ pub fn toBehavior(this: WebSocketServerContext) uws.WebSocketBehavior {
};
}
pub fn protect(this: WebSocketServerContext) void {
this.handler.protect();
}
pub fn unprotect(this: WebSocketServerContext) void {
this.handler.unprotect();
}
const CompressTable = bun.ComptimeStringMap(i32, .{
.{ "disable", 0 },
.{ "shared", uws.SHARED_COMPRESSOR },
@@ -153,9 +122,10 @@ const DecompressTable = bun.ComptimeStringMap(i32, .{
.{ "256KB", uws.DEDICATED_COMPRESSOR_256KB },
});
pub fn onCreate(globalObject: *jsc.JSGlobalObject, object: JSValue) bun.JSError!WebSocketServerContext {
pub fn onCreate(globalObject: *jsc.JSGlobalObject, object: JSValue) bun.JSError!struct { context: WebSocketServerContext, js_context: jsc.JSValue } {
var server = WebSocketServerContext{};
server.handler = try Handler.fromJS(globalObject, object);
server.globalObject = globalObject;
if (try object.get(globalObject, "perMessageDeflate")) |per_message_deflate| {
getter: {
@@ -265,8 +235,27 @@ pub fn onCreate(globalObject: *jsc.JSGlobalObject, object: JSValue) bun.JSError!
}
}
server.protect();
return server;
// Create the GC-managed JSWebSocketServerContext object with all callbacks and settings
const js_context = JSWebSocketServerContext.create(
globalObject,
server.handler.onOpen,
server.handler.onMessage,
server.handler.onClose,
server.handler.onDrain,
server.handler.onError,
server.handler.onPing,
server.handler.onPong,
.zero, // server - will be set later when the server is created
server.handler.app,
server.handler.vm,
false, // ssl - will be set later
server.handler.flags.publish_to_self,
);
// Protect the context from GC until it's stored on the server object
js_context.protect();
return .{ .context = server, .js_context = js_context };
}
const bun = @import("bun");
@@ -278,3 +267,4 @@ const JSGlobalObject = jsc.JSGlobalObject;
const JSValue = jsc.JSValue;
const VirtualMachine = jsc.VirtualMachine;
const ZigString = jsc.ZigString;
const JSWebSocketServerContext = @import("../../bindings/JSWebSocketServerContext.zig").JSWebSocketServerContext;

View File

@@ -0,0 +1,372 @@
#include "root.h"
#include <JavaScriptCore/JSCell.h>
#include <JavaScriptCore/JSInternalFieldObjectImplInlines.h>
#include <JavaScriptCore/ObjectConstructor.h>
#include "ZigGlobalObject.h"
#include <JavaScriptCore/Structure.h>
#include "ZigGeneratedClasses.h"
#include "JSWebSocketServerContext.h"
namespace Bun {
using namespace JSC;
using namespace WebCore;
/**
JSWebSocketServerContext holds all the callbacks used by WebSocket handlers in Bun.serve()
Instead of manually managing protect()/unprotect() calls, we use JSInternalFieldObjectImpl
to make the callbacks GC-managed. The GC will automatically track these references.
Internal fields (GC-tracked):
0: onOpen
1: onMessage
2: onClose
3: onDrain
4: onError
5: onPing
6: onPong
7: server (the server instance)
C++ members (not GC-tracked):
- app (uWS app pointer)
- vm (VirtualMachine pointer)
- flags (ssl, publish_to_self)
- active_connections (connection counter)
*/
class JSWebSocketServerContext final : public JSC::JSInternalFieldObjectImpl<8> {
public:
using Base = JSC::JSInternalFieldObjectImpl<8>;
static constexpr unsigned StructureFlags = Base::StructureFlags;
static constexpr uint8_t onOpenFieldIndex = 0;
static constexpr uint8_t onMessageFieldIndex = 1;
static constexpr uint8_t onCloseFieldIndex = 2;
static constexpr uint8_t onDrainFieldIndex = 3;
static constexpr uint8_t onErrorFieldIndex = 4;
static constexpr uint8_t onPingFieldIndex = 5;
static constexpr uint8_t onPongFieldIndex = 6;
static constexpr uint8_t serverFieldIndex = 7;
struct Flags {
bool ssl = false;
bool publish_to_self = false;
};
void* app = nullptr;
void* vm = nullptr;
Flags flags = {};
size_t active_connections = 0;
static JSWebSocketServerContext* create(
JSC::VM& vm,
JSC::Structure* structure,
JSValue onOpen,
JSValue onMessage,
JSValue onClose,
JSValue onDrain,
JSValue onError,
JSValue onPing,
JSValue onPong,
JSValue server,
void* app,
void* vmPtr,
bool ssl,
bool publishToSelf)
{
auto* context = new (NotNull, JSC::allocateCell<JSWebSocketServerContext>(vm))
JSWebSocketServerContext(vm, structure, onOpen, onMessage, onClose, onDrain, onError, onPing, onPong, server);
context->finishCreation(vm);
context->app = app;
context->vm = vmPtr;
context->flags.ssl = ssl;
context->flags.publish_to_self = publishToSelf;
context->active_connections = 0;
return context;
}
static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
{
return JSC::Structure::create(vm, globalObject, globalObject->nullPrototype(), JSC::TypeInfo(JSC::InternalFieldTupleType, StructureFlags), info());
}
static void destroy(JSCell* cell)
{
static_cast<JSWebSocketServerContext*>(cell)->~JSWebSocketServerContext();
}
~JSWebSocketServerContext() = default;
template<typename, JSC::SubspaceAccess mode>
static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
{
if constexpr (mode == JSC::SubspaceAccess::Concurrently)
return nullptr;
return WebCore::subspaceForImpl<JSWebSocketServerContext, WebCore::UseCustomHeapCellType::No>(
vm,
[](auto& spaces) { return spaces.m_clientSubspaceForJSWebSocketServerContext.get(); },
[](auto& spaces, auto&& space) { spaces.m_clientSubspaceForJSWebSocketServerContext = std::forward<decltype(space)>(space); },
[](auto& spaces) { return spaces.m_subspaceForJSWebSocketServerContext.get(); },
[](auto& spaces, auto&& space) { spaces.m_subspaceForJSWebSocketServerContext = std::forward<decltype(space)>(space); });
}
DECLARE_INFO;
DECLARE_VISIT_CHILDREN;
// Getters for each callback
JSValue onOpen() const { return Base::internalField(onOpenFieldIndex).get(); }
JSValue onMessage() const { return Base::internalField(onMessageFieldIndex).get(); }
JSValue onClose() const { return Base::internalField(onCloseFieldIndex).get(); }
JSValue onDrain() const { return Base::internalField(onDrainFieldIndex).get(); }
JSValue onError() const { return Base::internalField(onErrorFieldIndex).get(); }
JSValue onPing() const { return Base::internalField(onPingFieldIndex).get(); }
JSValue onPong() const { return Base::internalField(onPongFieldIndex).get(); }
JSValue server() const { return Base::internalField(serverFieldIndex).get(); }
// Setters for each callback
void setOnOpen(JSC::VM& vm, JSValue value) { Base::internalField(onOpenFieldIndex).set(vm, this, value); }
void setOnMessage(JSC::VM& vm, JSValue value) { Base::internalField(onMessageFieldIndex).set(vm, this, value); }
void setOnClose(JSC::VM& vm, JSValue value) { Base::internalField(onCloseFieldIndex).set(vm, this, value); }
void setOnDrain(JSC::VM& vm, JSValue value) { Base::internalField(onDrainFieldIndex).set(vm, this, value); }
void setOnError(JSC::VM& vm, JSValue value) { Base::internalField(onErrorFieldIndex).set(vm, this, value); }
void setOnPing(JSC::VM& vm, JSValue value) { Base::internalField(onPingFieldIndex).set(vm, this, value); }
void setOnPong(JSC::VM& vm, JSValue value) { Base::internalField(onPongFieldIndex).set(vm, this, value); }
void setServer(JSC::VM& vm, JSValue value) { Base::internalField(serverFieldIndex).set(vm, this, value); }
// Getters/setters for C++ members
void* getApp() const { return app; }
void setApp(void* value) { app = value; }
void* getVM() const { return vm; }
void setVM(void* value) { vm = value; }
Flags getFlags() const { return flags; }
void setFlags(Flags value) { flags = value; }
size_t getActiveConnections() const { return active_connections; }
void setActiveConnections(size_t value) { active_connections = value; }
void incrementActiveConnections() { active_connections++; }
void decrementActiveConnections() { if (active_connections > 0) active_connections--; }
private:
JSWebSocketServerContext(JSC::VM& vm, JSC::Structure* structure,
JSValue onOpen, JSValue onMessage, JSValue onClose,
JSValue onDrain, JSValue onError, JSValue onPing,
JSValue onPong, JSValue server)
: Base(vm, structure)
{
// Initialize internal fields with the provided callbacks
Base::internalField(onOpenFieldIndex).setWithoutWriteBarrier(onOpen);
Base::internalField(onMessageFieldIndex).setWithoutWriteBarrier(onMessage);
Base::internalField(onCloseFieldIndex).setWithoutWriteBarrier(onClose);
Base::internalField(onDrainFieldIndex).setWithoutWriteBarrier(onDrain);
Base::internalField(onErrorFieldIndex).setWithoutWriteBarrier(onError);
Base::internalField(onPingFieldIndex).setWithoutWriteBarrier(onPing);
Base::internalField(onPongFieldIndex).setWithoutWriteBarrier(onPong);
Base::internalField(serverFieldIndex).setWithoutWriteBarrier(server);
}
void finishCreation(JSC::VM& vm)
{
Base::finishCreation(vm);
}
};
const JSC::ClassInfo JSWebSocketServerContext::s_info = { "JSWebSocketServerContext"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSWebSocketServerContext) };
template<typename Visitor>
void JSWebSocketServerContext::visitChildrenImpl(JSCell* cell, Visitor& visitor)
{
JSWebSocketServerContext* thisObject = jsCast<JSWebSocketServerContext*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
Base::visitChildren(thisObject, visitor);
}
DEFINE_VISIT_CHILDREN(JSWebSocketServerContext);
extern "C" JSC::EncodedJSValue Bun__JSWebSocketServerContext__create(
Zig::GlobalObject* globalObject,
JSC::EncodedJSValue onOpen,
JSC::EncodedJSValue onMessage,
JSC::EncodedJSValue onClose,
JSC::EncodedJSValue onDrain,
JSC::EncodedJSValue onError,
JSC::EncodedJSValue onPing,
JSC::EncodedJSValue onPong,
JSC::EncodedJSValue server,
void* app,
void* vmPtr,
bool ssl,
bool publishToSelf)
{
auto& vm = globalObject->vm();
auto* structure = globalObject->m_JSWebSocketServerContextStructure.get(globalObject);
auto* context = JSWebSocketServerContext::create(
vm, structure,
JSValue::decode(onOpen),
JSValue::decode(onMessage),
JSValue::decode(onClose),
JSValue::decode(onDrain),
JSValue::decode(onError),
JSValue::decode(onPing),
JSValue::decode(onPong),
JSValue::decode(server),
app, vmPtr, ssl, publishToSelf);
return JSValue::encode(context);
}
extern "C" void Bun__JSWebSocketServerContext__setOnOpen(JSWebSocketServerContext* context, Zig::GlobalObject* globalObject, JSC::EncodedJSValue value)
{
context->setOnOpen(globalObject->vm(), JSValue::decode(value));
}
extern "C" void Bun__JSWebSocketServerContext__setOnMessage(JSWebSocketServerContext* context, Zig::GlobalObject* globalObject, JSC::EncodedJSValue value)
{
context->setOnMessage(globalObject->vm(), JSValue::decode(value));
}
extern "C" void Bun__JSWebSocketServerContext__setOnClose(JSWebSocketServerContext* context, Zig::GlobalObject* globalObject, JSC::EncodedJSValue value)
{
context->setOnClose(globalObject->vm(), JSValue::decode(value));
}
extern "C" void Bun__JSWebSocketServerContext__setOnDrain(JSWebSocketServerContext* context, Zig::GlobalObject* globalObject, JSC::EncodedJSValue value)
{
context->setOnDrain(globalObject->vm(), JSValue::decode(value));
}
extern "C" void Bun__JSWebSocketServerContext__setOnError(JSWebSocketServerContext* context, Zig::GlobalObject* globalObject, JSC::EncodedJSValue value)
{
context->setOnError(globalObject->vm(), JSValue::decode(value));
}
extern "C" void Bun__JSWebSocketServerContext__setOnPing(JSWebSocketServerContext* context, Zig::GlobalObject* globalObject, JSC::EncodedJSValue value)
{
context->setOnPing(globalObject->vm(), JSValue::decode(value));
}
extern "C" void Bun__JSWebSocketServerContext__setOnPong(JSWebSocketServerContext* context, Zig::GlobalObject* globalObject, JSC::EncodedJSValue value)
{
context->setOnPong(globalObject->vm(), JSValue::decode(value));
}
extern "C" void Bun__JSWebSocketServerContext__setServer(JSWebSocketServerContext* context, Zig::GlobalObject* globalObject, JSC::EncodedJSValue value)
{
context->setServer(globalObject->vm(), JSValue::decode(value));
}
extern "C" JSC::EncodedJSValue Bun__JSWebSocketServerContext__getOnOpen(JSWebSocketServerContext* context)
{
return JSValue::encode(context->onOpen());
}
extern "C" JSC::EncodedJSValue Bun__JSWebSocketServerContext__getOnMessage(JSWebSocketServerContext* context)
{
return JSValue::encode(context->onMessage());
}
extern "C" JSC::EncodedJSValue Bun__JSWebSocketServerContext__getOnClose(JSWebSocketServerContext* context)
{
return JSValue::encode(context->onClose());
}
extern "C" JSC::EncodedJSValue Bun__JSWebSocketServerContext__getOnDrain(JSWebSocketServerContext* context)
{
return JSValue::encode(context->onDrain());
}
extern "C" JSC::EncodedJSValue Bun__JSWebSocketServerContext__getOnError(JSWebSocketServerContext* context)
{
return JSValue::encode(context->onError());
}
extern "C" JSC::EncodedJSValue Bun__JSWebSocketServerContext__getOnPing(JSWebSocketServerContext* context)
{
return JSValue::encode(context->onPing());
}
extern "C" JSC::EncodedJSValue Bun__JSWebSocketServerContext__getOnPong(JSWebSocketServerContext* context)
{
return JSValue::encode(context->onPong());
}
extern "C" JSC::EncodedJSValue Bun__JSWebSocketServerContext__getServer(JSWebSocketServerContext* context)
{
return JSValue::encode(context->server());
}
extern "C" void Bun__JSWebSocketServerContext__setApp(JSWebSocketServerContext* context, void* app)
{
context->setApp(app);
}
extern "C" void* Bun__JSWebSocketServerContext__getApp(JSWebSocketServerContext* context)
{
return context->getApp();
}
extern "C" void Bun__JSWebSocketServerContext__setVM(JSWebSocketServerContext* context, void* vm)
{
context->setVM(vm);
}
extern "C" void* Bun__JSWebSocketServerContext__getVM(JSWebSocketServerContext* context)
{
return context->getVM();
}
extern "C" void Bun__JSWebSocketServerContext__setSSL(JSWebSocketServerContext* context, bool ssl)
{
auto flags = context->getFlags();
flags.ssl = ssl;
context->setFlags(flags);
}
extern "C" bool Bun__JSWebSocketServerContext__getSSL(JSWebSocketServerContext* context)
{
return context->getFlags().ssl;
}
extern "C" void Bun__JSWebSocketServerContext__setPublishToSelf(JSWebSocketServerContext* context, bool publish_to_self)
{
auto flags = context->getFlags();
flags.publish_to_self = publish_to_self;
context->setFlags(flags);
}
extern "C" bool Bun__JSWebSocketServerContext__getPublishToSelf(JSWebSocketServerContext* context)
{
return context->getFlags().publish_to_self;
}
extern "C" size_t Bun__JSWebSocketServerContext__getActiveConnections(JSWebSocketServerContext* context)
{
return context->getActiveConnections();
}
extern "C" void Bun__JSWebSocketServerContext__incrementActiveConnections(JSWebSocketServerContext* context)
{
context->incrementActiveConnections();
}
extern "C" void Bun__JSWebSocketServerContext__decrementActiveConnections(JSWebSocketServerContext* context)
{
context->decrementActiveConnections();
}
extern "C" JSWebSocketServerContext* Bun__JSWebSocketServerContext__fromJS(JSC::EncodedJSValue value)
{
JSValue jsValue = JSValue::decode(value);
if (!jsValue.isCell())
return nullptr;
JSCell* cell = jsValue.asCell();
if (cell->type() != JSC::InternalFieldTupleType)
return nullptr;
return jsCast<JSWebSocketServerContext*>(cell);
}
Structure* createJSWebSocketServerContextStructure(JSC::VM& vm, Zig::GlobalObject* globalObject)
{
return JSWebSocketServerContext::createStructure(vm, globalObject);
}
} // namespace Bun

View File

@@ -0,0 +1,5 @@
#pragma once
namespace Bun {
JSC::Structure* createJSWebSocketServerContextStructure(JSC::VM&, Zig::GlobalObject*);
}

View File

@@ -0,0 +1,192 @@
const bun = @import("bun");
const jsc = bun.jsc;
pub const JSWebSocketServerContext = opaque {
pub fn create(
globalObject: *jsc.JSGlobalObject,
onOpen: jsc.JSValue,
onMessage: jsc.JSValue,
onClose: jsc.JSValue,
onDrain: jsc.JSValue,
onError: jsc.JSValue,
onPing: jsc.JSValue,
onPong: jsc.JSValue,
server: jsc.JSValue,
app: ?*anyopaque,
vm: *jsc.VirtualMachine,
ssl: bool,
publishToSelf: bool,
) jsc.JSValue {
return Bun__JSWebSocketServerContext__create(
globalObject,
onOpen,
onMessage,
onClose,
onDrain,
onError,
onPing,
onPong,
server,
app,
vm,
ssl,
publishToSelf,
);
}
pub fn fromJS(value: jsc.JSValue) ?*JSWebSocketServerContext {
return Bun__JSWebSocketServerContext__fromJS(value);
}
pub fn setOnOpen(this: *JSWebSocketServerContext, globalObject: *jsc.JSGlobalObject, value: jsc.JSValue) void {
Bun__JSWebSocketServerContext__setOnOpen(this, globalObject, value);
}
pub fn setOnMessage(this: *JSWebSocketServerContext, globalObject: *jsc.JSGlobalObject, value: jsc.JSValue) void {
Bun__JSWebSocketServerContext__setOnMessage(this, globalObject, value);
}
pub fn setOnClose(this: *JSWebSocketServerContext, globalObject: *jsc.JSGlobalObject, value: jsc.JSValue) void {
Bun__JSWebSocketServerContext__setOnClose(this, globalObject, value);
}
pub fn setOnDrain(this: *JSWebSocketServerContext, globalObject: *jsc.JSGlobalObject, value: jsc.JSValue) void {
Bun__JSWebSocketServerContext__setOnDrain(this, globalObject, value);
}
pub fn setOnError(this: *JSWebSocketServerContext, globalObject: *jsc.JSGlobalObject, value: jsc.JSValue) void {
Bun__JSWebSocketServerContext__setOnError(this, globalObject, value);
}
pub fn setOnPing(this: *JSWebSocketServerContext, globalObject: *jsc.JSGlobalObject, value: jsc.JSValue) void {
Bun__JSWebSocketServerContext__setOnPing(this, globalObject, value);
}
pub fn setOnPong(this: *JSWebSocketServerContext, globalObject: *jsc.JSGlobalObject, value: jsc.JSValue) void {
Bun__JSWebSocketServerContext__setOnPong(this, globalObject, value);
}
pub fn setServer(this: *JSWebSocketServerContext, globalObject: *jsc.JSGlobalObject, value: jsc.JSValue) void {
Bun__JSWebSocketServerContext__setServer(this, globalObject, value);
}
pub fn getOnOpen(this: *JSWebSocketServerContext) jsc.JSValue {
return Bun__JSWebSocketServerContext__getOnOpen(this);
}
pub fn getOnMessage(this: *JSWebSocketServerContext) jsc.JSValue {
return Bun__JSWebSocketServerContext__getOnMessage(this);
}
pub fn getOnClose(this: *JSWebSocketServerContext) jsc.JSValue {
return Bun__JSWebSocketServerContext__getOnClose(this);
}
pub fn getOnDrain(this: *JSWebSocketServerContext) jsc.JSValue {
return Bun__JSWebSocketServerContext__getOnDrain(this);
}
pub fn getOnError(this: *JSWebSocketServerContext) jsc.JSValue {
return Bun__JSWebSocketServerContext__getOnError(this);
}
pub fn getOnPing(this: *JSWebSocketServerContext) jsc.JSValue {
return Bun__JSWebSocketServerContext__getOnPing(this);
}
pub fn getOnPong(this: *JSWebSocketServerContext) jsc.JSValue {
return Bun__JSWebSocketServerContext__getOnPong(this);
}
pub fn getServer(this: *JSWebSocketServerContext) jsc.JSValue {
return Bun__JSWebSocketServerContext__getServer(this);
}
pub fn setApp(this: *JSWebSocketServerContext, app: ?*anyopaque) void {
Bun__JSWebSocketServerContext__setApp(this, app);
}
pub fn getApp(this: *JSWebSocketServerContext) ?*anyopaque {
return Bun__JSWebSocketServerContext__getApp(this);
}
pub fn setVM(this: *JSWebSocketServerContext, vm: *jsc.VirtualMachine) void {
Bun__JSWebSocketServerContext__setVM(this, vm);
}
pub fn getVM(this: *JSWebSocketServerContext) *jsc.VirtualMachine {
return @ptrCast(@alignCast(Bun__JSWebSocketServerContext__getVM(this)));
}
pub fn setSSL(this: *JSWebSocketServerContext, ssl: bool) void {
Bun__JSWebSocketServerContext__setSSL(this, ssl);
}
pub fn getSSL(this: *JSWebSocketServerContext) bool {
return Bun__JSWebSocketServerContext__getSSL(this);
}
pub fn setPublishToSelf(this: *JSWebSocketServerContext, publish_to_self: bool) void {
Bun__JSWebSocketServerContext__setPublishToSelf(this, publish_to_self);
}
pub fn getPublishToSelf(this: *JSWebSocketServerContext) bool {
return Bun__JSWebSocketServerContext__getPublishToSelf(this);
}
pub fn getActiveConnections(this: *JSWebSocketServerContext) usize {
return Bun__JSWebSocketServerContext__getActiveConnections(this);
}
pub fn incrementActiveConnections(this: *JSWebSocketServerContext) void {
Bun__JSWebSocketServerContext__incrementActiveConnections(this);
}
pub fn decrementActiveConnections(this: *JSWebSocketServerContext) void {
Bun__JSWebSocketServerContext__decrementActiveConnections(this);
}
};
extern "C" fn Bun__JSWebSocketServerContext__create(
*jsc.JSGlobalObject,
jsc.JSValue, // onOpen
jsc.JSValue, // onMessage
jsc.JSValue, // onClose
jsc.JSValue, // onDrain
jsc.JSValue, // onError
jsc.JSValue, // onPing
jsc.JSValue, // onPong
jsc.JSValue, // server
?*anyopaque, // app
*jsc.VirtualMachine, // vm
bool, // ssl
bool, // publishToSelf
) jsc.JSValue;
extern "C" fn Bun__JSWebSocketServerContext__fromJS(jsc.JSValue) ?*JSWebSocketServerContext;
extern "C" fn Bun__JSWebSocketServerContext__setOnOpen(*JSWebSocketServerContext, *jsc.JSGlobalObject, jsc.JSValue) void;
extern "C" fn Bun__JSWebSocketServerContext__setOnMessage(*JSWebSocketServerContext, *jsc.JSGlobalObject, jsc.JSValue) void;
extern "C" fn Bun__JSWebSocketServerContext__setOnClose(*JSWebSocketServerContext, *jsc.JSGlobalObject, jsc.JSValue) void;
extern "C" fn Bun__JSWebSocketServerContext__setOnDrain(*JSWebSocketServerContext, *jsc.JSGlobalObject, jsc.JSValue) void;
extern "C" fn Bun__JSWebSocketServerContext__setOnError(*JSWebSocketServerContext, *jsc.JSGlobalObject, jsc.JSValue) void;
extern "C" fn Bun__JSWebSocketServerContext__setOnPing(*JSWebSocketServerContext, *jsc.JSGlobalObject, jsc.JSValue) void;
extern "C" fn Bun__JSWebSocketServerContext__setOnPong(*JSWebSocketServerContext, *jsc.JSGlobalObject, jsc.JSValue) void;
extern "C" fn Bun__JSWebSocketServerContext__setServer(*JSWebSocketServerContext, *jsc.JSGlobalObject, jsc.JSValue) void;
extern "C" fn Bun__JSWebSocketServerContext__getOnOpen(*JSWebSocketServerContext) jsc.JSValue;
extern "C" fn Bun__JSWebSocketServerContext__getOnMessage(*JSWebSocketServerContext) jsc.JSValue;
extern "C" fn Bun__JSWebSocketServerContext__getOnClose(*JSWebSocketServerContext) jsc.JSValue;
extern "C" fn Bun__JSWebSocketServerContext__getOnDrain(*JSWebSocketServerContext) jsc.JSValue;
extern "C" fn Bun__JSWebSocketServerContext__getOnError(*JSWebSocketServerContext) jsc.JSValue;
extern "C" fn Bun__JSWebSocketServerContext__getOnPing(*JSWebSocketServerContext) jsc.JSValue;
extern "C" fn Bun__JSWebSocketServerContext__getOnPong(*JSWebSocketServerContext) jsc.JSValue;
extern "C" fn Bun__JSWebSocketServerContext__getServer(*JSWebSocketServerContext) jsc.JSValue;
extern "C" fn Bun__JSWebSocketServerContext__setApp(*JSWebSocketServerContext, ?*anyopaque) void;
extern "C" fn Bun__JSWebSocketServerContext__getApp(*JSWebSocketServerContext) ?*anyopaque;
extern "C" fn Bun__JSWebSocketServerContext__setVM(*JSWebSocketServerContext, *jsc.VirtualMachine) void;
extern "C" fn Bun__JSWebSocketServerContext__getVM(*JSWebSocketServerContext) *anyopaque;
extern "C" fn Bun__JSWebSocketServerContext__setSSL(*JSWebSocketServerContext, bool) void;
extern "C" fn Bun__JSWebSocketServerContext__getSSL(*JSWebSocketServerContext) bool;
extern "C" fn Bun__JSWebSocketServerContext__setPublishToSelf(*JSWebSocketServerContext, bool) void;
extern "C" fn Bun__JSWebSocketServerContext__getPublishToSelf(*JSWebSocketServerContext) bool;
extern "C" fn Bun__JSWebSocketServerContext__getActiveConnections(*JSWebSocketServerContext) usize;
extern "C" fn Bun__JSWebSocketServerContext__incrementActiveConnections(*JSWebSocketServerContext) void;
extern "C" fn Bun__JSWebSocketServerContext__decrementActiveConnections(*JSWebSocketServerContext) void;

View File

@@ -194,6 +194,7 @@
#include <mutex>
#include "JSBunRequest.h"
#include "ServerRouteList.h"
#include "JSWebSocketServerContext.h"
#if ENABLE(REMOTE_INSPECTOR)
#include "JavaScriptCore/RemoteInspectorServer.h"
@@ -2047,6 +2048,11 @@ void GlobalObject::finishCreation(VM& vm)
init.set(Bun::createServerRouteListStructure(init.vm, static_cast<Zig::GlobalObject*>(init.owner)));
});
m_JSWebSocketServerContextStructure.initLater(
[](const JSC::LazyProperty<JSC::JSGlobalObject, Structure>::Initializer& init) {
init.set(Bun::createJSWebSocketServerContextStructure(init.vm, static_cast<Zig::GlobalObject*>(init.owner)));
});
m_JSBunRequestParamsPrototype.initLater(
[](const JSC::LazyProperty<JSC::JSGlobalObject, JSObject>::Initializer& init) {
init.set(Bun::createJSBunRequestParamsPrototype(init.vm, static_cast<Zig::GlobalObject*>(init.owner)));

View File

@@ -620,6 +620,7 @@ public:
V(public, LazyPropertyOfGlobalObject<Bun::Process>, m_processObject) \
V(public, LazyPropertyOfGlobalObject<CustomGetterSetter>, m_lazyStackCustomGetterSetter) \
V(public, LazyPropertyOfGlobalObject<Structure>, m_ServerRouteListStructure) \
V(public, LazyPropertyOfGlobalObject<Structure>, m_JSWebSocketServerContextStructure) \
V(public, LazyPropertyOfGlobalObject<Structure>, m_JSBunRequestStructure) \
V(public, LazyPropertyOfGlobalObject<JSObject>, m_JSBunRequestParamsPrototype) \
\

View File

@@ -946,6 +946,7 @@ public:
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForJSPublicKeyObject;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForJSPrivateKeyObject;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForServerRouteList;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForJSWebSocketServerContext;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForBunRequest;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForBakeResponse;

View File

@@ -941,6 +941,7 @@ public:
std::unique_ptr<IsoSubspace> m_subspaceForJSHmac;
std::unique_ptr<IsoSubspace> m_subspaceForJSHash;
std::unique_ptr<IsoSubspace> m_subspaceForServerRouteList;
std::unique_ptr<IsoSubspace> m_subspaceForJSWebSocketServerContext;
std::unique_ptr<IsoSubspace> m_subspaceForBunRequest;
std::unique_ptr<IsoSubspace> m_subspaceForBakeResponse;
std::unique_ptr<IsoSubspace> m_subspaceForJSDiffieHellman;