aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-10-15 03:06:41 -0700
committerGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-10-15 03:06:41 -0700
commit4b5af13ac09e32e8e446cb8000fe5d8d101b3afb (patch)
treed7431bfea4723717fe4a2f6db89b2a97d017f201
parent35cbfa63a6e54d37ad5edb14ef2c025acf7bbddd (diff)
downloadbun-4b5af13ac09e32e8e446cb8000fe5d8d101b3afb.tar.gz
bun-4b5af13ac09e32e8e446cb8000fe5d8d101b3afb.tar.zst
bun-4b5af13ac09e32e8e446cb8000fe5d8d101b3afb.zip
WebSocket Server support
-rw-r--r--build-id2
-rw-r--r--src/bun.js/api/server.classes.ts78
-rw-r--r--src/bun.js/api/server.zig1261
-rw-r--r--src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h3
-rw-r--r--src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h3
-rw-r--r--src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h6
-rw-r--r--src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h7
-rw-r--r--src/bun.js/bindings/ZigGeneratedClasses.cpp490
-rw-r--r--src/bun.js/bindings/ZigGeneratedClasses.h125
-rw-r--r--src/bun.js/bindings/generated_classes.zig198
-rw-r--r--src/bun.js/bindings/generated_classes_list.zig1
-rw-r--r--src/bun.js/bindings/headers-cpp.h2
-rw-r--r--src/bun.js/bindings/headers.h2
-rw-r--r--src/deps/_libusockets.h10
-rw-r--r--src/deps/libuwsockets.cpp29
-rw-r--r--src/deps/uws.zig441
-rw-r--r--src/jsc.zig1
17 files changed, 2430 insertions, 229 deletions
diff --git a/build-id b/build-id
index c22708346..56a6051ca 100644
--- a/build-id
+++ b/build-id
@@ -1 +1 @@
-0 \ No newline at end of file
+1 \ No newline at end of file
diff --git a/src/bun.js/api/server.classes.ts b/src/bun.js/api/server.classes.ts
new file mode 100644
index 000000000..5ae4f1739
--- /dev/null
+++ b/src/bun.js/api/server.classes.ts
@@ -0,0 +1,78 @@
+import { define } from "../scripts/class-definitions";
+
+function generate(name) {
+ return define({
+ name,
+ proto: {
+ fetch: {
+ fn: "fetch",
+ length: 1,
+ },
+ },
+ values: ["callback"],
+ klass: {},
+ finalize: true,
+ construct: true,
+ });
+}
+export default [
+ // generate(`HTTPServer`),
+ // generate(`DebugModeHTTPServer`),
+ // generate(`HTTPSServer`),
+ // generate(`DebugModeHTTPSServer`),
+
+ define({
+ name: "ServerWebSocket",
+ JSType: "0b11101110",
+ proto: {
+ send: {
+ fn: "send",
+ length: 2,
+ },
+ close: {
+ fn: "close",
+ length: 1,
+ },
+ getBufferedAmount: {
+ fn: "getBufferedAmount",
+ length: 0,
+ },
+ publish: {
+ fn: "publish",
+ length: 3,
+ },
+ data: {
+ getter: "getData",
+ cache: true,
+ setter: "setData",
+ },
+ readyState: {
+ getter: "getReadyState",
+ },
+ subscribe: {
+ fn: "subscribe",
+ length: 1,
+ },
+ unsubscribe: {
+ fn: "unsubscribe",
+ length: 1,
+ },
+ isSubscribed: {
+ fn: "isSubscribed",
+ length: 1,
+ },
+
+ // topics: {
+ // getter: "getTopics",
+ // },
+
+ remoteAddress: {
+ getter: "getRemoteAddress",
+ cache: true,
+ },
+ },
+ finalize: true,
+ construct: true,
+ klass: {},
+ }),
+];
diff --git a/src/bun.js/api/server.zig b/src/bun.js/api/server.zig
index 11400dde5..9b26f4b11 100644
--- a/src/bun.js/api/server.zig
+++ b/src/bun.js/api/server.zig
@@ -109,6 +109,9 @@ pub const ServerConfig = struct {
onError: JSC.JSValue = JSC.JSValue.zero,
onRequest: JSC.JSValue = JSC.JSValue.zero,
+ websockets: WebSocketServer.List = .{},
+ websocket: WebSocketServer = .{},
+
pub const SSLConfig = struct {
server_name: [*c]const u8 = null,
@@ -274,12 +277,89 @@ pub const ServerConfig = struct {
args.base_uri = origin;
}
+ var websockets = WebSocketServer.List{};
+
if (arguments.next()) |arg| {
if (arg.isUndefinedOrNull() or !arg.isObject()) {
JSC.throwInvalidArguments("Bun.serve expects an object", .{}, global, exception);
return args;
}
+ if (arg.getTruthy(global, "webSocket") orelse arg.getTruthy(global, "websocket")) |websocket_object| {
+ if (!websocket_object.isObject()) {
+ JSC.throwInvalidArguments("Expected webSocket to be an object", .{}, global, exception);
+ if (args.ssl_config) |*conf| {
+ conf.deinit();
+ }
+ return args;
+ }
+
+ if (WebSocketServer.onCreate(global, websocket_object)) |wss| {
+ args.websocket = wss;
+ } else {
+ if (args.ssl_config) |*conf| {
+ conf.deinit();
+ }
+ return args;
+ }
+ }
+
+ if (arg.getTruthy(global, "webSockets") orelse arg.getTruthy(global, "websockets")) |websocket_object| {
+ if (!websocket_object.isObject()) {
+ JSC.throwInvalidArguments("Expected webSockets to be an object", .{}, global, exception);
+ if (args.ssl_config) |*conf| {
+ conf.deinit();
+ }
+ return args;
+ }
+
+ var property_names = JSC.JSPropertyIterator(.{
+ .include_value = true,
+ .skip_empty_name = true,
+ }).init(global, websocket_object.asObjectRef());
+
+ defer property_names.deinit();
+ websockets.ensureTotalCapacity(bun.default_allocator, property_names.len) catch unreachable;
+ while (property_names.next()) |name| {
+ var str = name.toSlice(bun.default_allocator);
+ defer str.deinit();
+ const slice = str.slice();
+ if (slice.len == 0) continue;
+ if (slice[0] != '/') {
+ JSC.throwInvalidArguments("Expected webSocket path to start with /", .{}, global, exception);
+ if (args.ssl_config) |*conf| {
+ conf.deinit();
+ }
+ return args;
+ }
+
+ const object = property_names.value;
+ if (object.isEmptyOrUndefinedOrNull() or !object.isObject()) {
+ JSC.throwInvalidArguments("Expected webSocket to be an object", .{}, global, exception);
+ if (args.ssl_config) |*conf| {
+ conf.deinit();
+ }
+ websockets.deinit(bun.default_allocator);
+ return args;
+ }
+
+ const handler = WebSocketServer.onCreate(global, object) orelse {
+ if (args.ssl_config) |*conf| {
+ conf.deinit();
+ }
+ websockets.deinit(bun.default_allocator);
+ return args;
+ };
+
+ websockets.putAssumeCapacity(
+ bun.span(bun.default_allocator.dupeZ(u8, slice) catch unreachable),
+ handler,
+ );
+ }
+
+ args.websockets = websockets;
+ }
+
if (arg.getTruthy(global, "port")) |port_| {
args.port = @intCast(u16, @minimum(@maximum(0, port_.toInt32()), std.math.maxInt(u16)));
}
@@ -1386,6 +1466,118 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
const streamLog = Output.scoped(.ReadableStream, false);
+ pub fn onResponse(
+ ctx: *RequestContext,
+ this: *ThisServer,
+ req: *uws.Request,
+ request_object: *Request,
+ request_value: JSValue,
+ response_value: JSValue,
+ ) void {
+ request_value.ensureStillAlive();
+ response_value.ensureStillAlive();
+
+ if (ctx.aborted) {
+ ctx.finalizeForAbort();
+ return;
+ }
+ if (response_value.isEmptyOrUndefinedOrNull() and !ctx.resp.hasResponded()) {
+ ctx.renderMissing();
+ return;
+ }
+
+ if (response_value.isError() or response_value.isAggregateError(this.globalThis) or response_value.isException(this.globalThis.vm())) {
+ ctx.runErrorHandler(response_value);
+
+ return;
+ }
+
+ if (response_value.as(JSC.WebCore.Response)) |response| {
+ ctx.response_jsvalue = response_value;
+ ctx.response_jsvalue.ensureStillAlive();
+ ctx.response_protected = false;
+ switch (response.body.value) {
+ .Blob => |*blob| {
+ if (blob.needsToReadFile()) {
+ response_value.protect();
+ ctx.response_protected = true;
+ }
+ },
+ .Locked => {
+ response_value.protect();
+ ctx.response_protected = true;
+ },
+ else => {},
+ }
+ ctx.render(response);
+ return;
+ }
+
+ var wait_for_promise = false;
+ var vm = this.vm;
+
+ if (response_value.asPromise()) |promise| {
+ // If we immediately have the value available, we can skip the extra event loop tick
+ switch (promise.status(vm.global.vm())) {
+ .Pending => {},
+ .Fulfilled => {
+ ctx.handleResolve(promise.result(vm.global.vm()));
+ return;
+ },
+ .Rejected => {
+ ctx.handleReject(promise.result(vm.global.vm()));
+ return;
+ },
+ }
+ wait_for_promise = true;
+ // I don't think this case should happen
+ // But I'm uncertain
+ } else if (response_value.asInternalPromise()) |promise| {
+ switch (promise.status(vm.global.vm())) {
+ .Pending => {},
+ .Fulfilled => {
+ ctx.handleResolve(promise.result(vm.global.vm()));
+ return;
+ },
+ .Rejected => {
+ ctx.handleReject(promise.result(vm.global.vm()));
+ return;
+ },
+ }
+ wait_for_promise = true;
+ }
+
+ if (wait_for_promise) {
+ request_object.uws_request = req;
+
+ request_object.ensureURL() catch {
+ request_object.url = "";
+ };
+
+ // we have to clone the request headers here since they will soon belong to a different request
+ if (request_object.headers == null) {
+ request_object.headers = JSC.FetchHeaders.createFromUWS(this.globalThis, req);
+ }
+
+ if (comptime debug_mode) {
+ ctx.pathname = bun.default_allocator.dupe(u8, request_object.url) catch unreachable;
+ }
+
+ // This object dies after the stack frame is popped
+ // so we have to clear it in here too
+ request_object.uws_request = null;
+
+ ctx.setAbortHandler();
+ ctx.pending_promises_for_abort += 1;
+
+ response_value.then(this.globalThis, ctx, RequestContext.onResolve, RequestContext.onReject);
+ return;
+ }
+
+ // The user returned something that wasn't a promise or a promise with a response
+ if (!ctx.resp.hasResponded()) ctx.renderMissing();
+ }
+
pub fn handleResolveStream(req: *RequestContext) void {
streamLog("onResolve", .{});
var wrote_anything = false;
@@ -2060,6 +2252,738 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
};
}
+pub const WebSocketServer = struct {
+ onOpen: JSC.JSValue = .zero,
+ onUpgrade: JSC.JSValue = .zero,
+ onMessage: JSC.JSValue = .zero,
+ onClose: JSC.JSValue = .zero,
+ onDrain: JSC.JSValue = .zero,
+ globalObject: *JSC.JSGlobalObject = undefined,
+ active_connections: usize = 0,
+
+ maxPayloadLength: u32 = 1024 * 1024 * 16,
+ maxLifetime: u16 = 0,
+ idleTimeout: u16 = 120,
+ compression: i32 = 0,
+ backpressureLimit: u32 = 1024 * 1024 * 16,
+ sendPingsAutomatically: bool = true,
+ resetIdleTimeoutOnSend: bool = true,
+ closeOnBackpressureLimit: bool = false,
+
+ pub fn toBehavior(this: WebSocketServer) uws.WebSocketBehavior {
+ return .{
+ .maxPayloadLength = this.maxPayloadLength,
+ .idleTimeout = this.idleTimeout,
+ .compression = this.compression,
+ .maxBackpressure = this.backpressureLimit,
+ .sendPingsAutomatically = this.sendPingsAutomatically,
+ .maxLifetime = this.maxLifetime,
+ .resetIdleTimeoutOnSend = this.resetIdleTimeoutOnSend,
+ .closeOnBackpressureLimit = this.closeOnBackpressureLimit,
+ };
+ }
+
+ pub fn protect(this: WebSocketServer) void {
+ this.onUpgrade.protect();
+ this.onOpen.protect();
+ this.onMessage.protect();
+ this.onClose.protect();
+ this.onDrain.protect();
+ }
+
+ pub fn unprotect(this: WebSocketServer) void {
+ this.onUpgrade.unprotect();
+ this.onOpen.unprotect();
+ this.onMessage.unprotect();
+ this.onClose.unprotect();
+ this.onDrain.unprotect();
+ }
+
+ const CompressTable = bun.ComptimeStringMap(i32, .{
+ .{ "disable", 0 },
+ .{ "shared", uws.SHARED_COMPRESSOR },
+ .{ "dedicated", uws.DEDICATED_COMPRESSOR },
+ .{ "3KB", uws.DEDICATED_COMPRESSOR_3KB },
+ .{ "4KB", uws.DEDICATED_COMPRESSOR_4KB },
+ .{ "8KB", uws.DEDICATED_COMPRESSOR_8KB },
+ .{ "16KB", uws.DEDICATED_COMPRESSOR_16KB },
+ .{ "32KB", uws.DEDICATED_COMPRESSOR_32KB },
+ .{ "64KB", uws.DEDICATED_COMPRESSOR_64KB },
+ .{ "128KB", uws.DEDICATED_COMPRESSOR_128KB },
+ .{ "256KB", uws.DEDICATED_COMPRESSOR_256KB },
+ });
+
+ const DecompressTable = bun.ComptimeStringMap(i32, .{
+ .{ "disable", 0 },
+ .{ "shared", uws.SHARED_DECOMPRESSOR },
+ .{ "dedicated", uws.DEDICATED_DECOMPRESSOR },
+ .{ "3KB", uws.DEDICATED_COMPRESSOR_3KB },
+ .{ "4KB", uws.DEDICATED_COMPRESSOR_4KB },
+ .{ "8KB", uws.DEDICATED_COMPRESSOR_8KB },
+ .{ "16KB", uws.DEDICATED_COMPRESSOR_16KB },
+ .{ "32KB", uws.DEDICATED_COMPRESSOR_32KB },
+ .{ "64KB", uws.DEDICATED_COMPRESSOR_64KB },
+ .{ "128KB", uws.DEDICATED_COMPRESSOR_128KB },
+ .{ "256KB", uws.DEDICATED_COMPRESSOR_256KB },
+ });
+
+ pub fn onCreate(globalObject: *JSC.JSGlobalObject, object: JSValue) ?WebSocketServer {
+ if (!object.isObject()) {
+ globalObject.throwInvalidArguments("websocket expects an options object", .{});
+ return null;
+ }
+
+ var server = WebSocketServer{};
+
+ if (object.getTruthy(globalObject, "compressor")) |compression| {
+ if (compression.isBoolean()) {
+ server.compression |= if (compression.toBoolean()) uws.SHARED_COMPRESSOR else 0;
+ } else if (compression.isString()) {
+ var slice = compression.toSlice(globalObject, bun.default_allocator);
+ defer slice.deinit();
+ server.compression |= CompressTable.get(slice.slice()) orelse {
+ globalObject.throwInvalidArguments(
+ "websocket expects a valid compressor option, either disable \"shared\" \"dedicated\" \"3KB\" \"4KB\" \"8KB\" \"16KB\" \"32KB\" \"64KB\" \"128KB\" or \"256KB\"",
+ .{},
+ );
+ return null;
+ };
+ } else {
+ globalObject.throwInvalidArguments(
+ "websocket expects a valid compressor option, either disable \"shared\" \"dedicated\" \"3KB\" \"4KB\" \"8KB\" \"16KB\" \"32KB\" \"64KB\" \"128KB\" or \"256KB\"",
+ .{},
+ );
+ return null;
+ }
+ }
+ if (object.getTruthy(globalObject, "decompressor")) |compression| {
+ if (compression.isBoolean()) {
+ server.compression |= if (compression.toBoolean()) uws.SHARED_DECOMPRESSOR else 0;
+ } else if (compression.isString()) {
+ var slice = compression.toSlice(globalObject, bun.default_allocator);
+ defer slice.deinit();
+ server.compression |= DecompressTable.get(slice.slice()) orelse {
+ globalObject.throwInvalidArguments(
+ "websocket expects a valid decompressor option, either \"disable\" \"shared\" \"dedicated\" \"3KB\" \"4KB\" \"8KB\" \"16KB\" \"32KB\" \"64KB\" \"128KB\" or \"256KB\"",
+ .{},
+ );
+ return null;
+ };
+ } else {
+ globalObject.throwInvalidArguments(
+ "websocket expects a valid decompressor option, either \"disable\" \"shared\" \"dedicated\" \"3KB\" \"4KB\" \"8KB\" \"16KB\" \"32KB\" \"64KB\" \"128KB\" or \"256KB\"",
+ .{},
+ );
+ return null;
+ }
+ }
+
+ if (object.get(globalObject, "maxPayloadLength")) |value| {
+ if (!value.isUndefinedOrNull()) {
+ if (!value.isAnyInt()) {
+ globalObject.throwInvalidArguments("websocket expects maxPayloadLength to be an integer", .{});
+ return null;
+ }
+ server.maxPayloadLength = @intCast(u32, @truncate(i33, @maximum(value.toInt64(), 0)));
+ }
+ }
+ if (object.get(globalObject, "idleTimeout")) |value| {
+ if (!value.isUndefinedOrNull()) {
+ if (!value.isAnyInt()) {
+ globalObject.throwInvalidArguments("websocket expects idleTimeout to be an integer", .{});
+ return null;
+ }
+
+ server.idleTimeout = value.to(u16);
+ }
+ }
+ if (object.get(globalObject, "backpressureLimit")) |value| {
+ if (!value.isUndefinedOrNull()) {
+ if (!value.isAnyInt()) {
+ globalObject.throwInvalidArguments("websocket expects backpressureLimit to be an integer", .{});
+ return null;
+ }
+
+ server.backpressureLimit = @intCast(u32, @truncate(i33, @maximum(value.toInt64(), 0)));
+ }
+ }
+ // if (object.get(globalObject, "sendPings")) |value| {
+ // if (!value.isUndefinedOrNull()) {
+ // if (!value.isBoolean()) {
+ // globalObject.throwInvalidArguments("websocket expects sendPings to be a boolean", .{});
+ // return null;
+ // }
+
+ // server.sendPings = value.toBoolean();
+ // }
+ // }
+
+ if (object.get(globalObject, "closeOnBackpressureLimit")) |value| {
+ if (!value.isUndefinedOrNull()) {
+ if (!value.isBoolean()) {
+ globalObject.throwInvalidArguments("websocket expects closeOnBackpressureLimit to be a boolean", .{});
+ return null;
+ }
+
+ server.closeOnBackpressureLimit = value.toBoolean();
+ }
+ }
+
+ if (object.getTruthy(globalObject, "message")) |message| {
+ if (!message.isCallable(globalObject.vm())) {
+ globalObject.throwInvalidArguments("websocket expects a function for the message option", .{});
+ return null;
+ }
+ server.onMessage = message;
+ message.ensureStillAlive();
+ }
+
+ if (object.getTruthy(globalObject, "open")) |open| {
+ if (!open.isCallable(globalObject.vm())) {
+ globalObject.throwInvalidArguments("websocket expects a function for the open option", .{});
+ return null;
+ }
+ server.onOpen = open;
+ open.ensureStillAlive();
+ }
+
+ if (object.getTruthy(globalObject, "close")) |close| {
+ if (!close.isCallable(globalObject.vm())) {
+ globalObject.throwInvalidArguments("websocket expects a function for the close option", .{});
+ return null;
+ }
+ server.onClose = close;
+ close.ensureStillAlive();
+ }
+
+ if (object.getTruthy(globalObject, "drain")) |drain| {
+ if (!drain.isCallable(globalObject.vm())) {
+ globalObject.throwInvalidArguments("websocket expects a function for the drain option", .{});
+ return null;
+ }
+ server.onDrain = drain;
+ drain.ensureStillAlive();
+ }
+
+ if (object.getTruthy(globalObject, "upgrade")) |upgrade| {
+ if (!upgrade.isCallable(globalObject.vm())) {
+ globalObject.throwInvalidArguments("websocket expects a function for the upgrade option", .{});
+ return null;
+ }
+ server.onUpgrade = upgrade;
+ upgrade.ensureStillAlive();
+ }
+
+ server.protect();
+ return server;
+ }
+
+ pub const List = std.StringArrayHashMapUnmanaged(WebSocketServer);
+};
+
+const Corker = struct {
+ args: []const JSValue,
+ globalObject: *JSC.JSGlobalObject,
+ callback: JSC.JSValue,
+ result: JSValue = .zero,
+
+ pub fn run(this: *Corker) void {
+ this.result = this.callback.call(this.globalObject, this.args);
+ }
+};
+
+pub const ServerWebSocket = struct {
+ handler: *WebSocketServer,
+ this_value: JSValue = .zero,
+ websocket: uws.AnyWebSocket = undefined,
+ closed: bool = false,
+
+ pub usingnamespace JSC.Codegen.JSServerWebSocket;
+
+ const log = Output.scoped(.WebSocketServer, false);
+
+ pub fn onOpen(this: *ServerWebSocket, ws: uws.AnyWebSocket) void {
+ log("OnOpen", .{});
+
+ this.websocket = ws;
+ this.closed = false;
+
+ // the this value is initially set to whatever the user passed in
+ const value_to_cache = this.this_value;
+
+ var handler = this.handler;
+ handler.active_connections +|= 1;
+ var globalObject = handler.globalObject;
+
+ const onOpenHandler = handler.onOpen;
+ this.this_value = .zero;
+ if (value_to_cache != .zero) {
+ const current_this = this.getThisValue();
+ ServerWebSocket.dataSetCached(current_this, globalObject, value_to_cache);
+ }
+
+ if (onOpenHandler.isEmptyOrUndefinedOrNull()) return;
+ var args = [_]JSValue{this.this_value};
+
+ var corker = Corker{
+ .args = &args,
+ .globalObject = globalObject,
+ .callback = onOpenHandler,
+ };
+ ws.cork(&corker, Corker.run);
+ if (corker.result.isAnyError(globalObject)) {
+ log("onOpen exception", .{});
+
+ ws.close();
+ _ = ServerWebSocket.dangerouslySetPtr(this.this_value, null);
+ handler.active_connections -|= 1;
+ this.this_value.unprotect();
+ bun.default_allocator.destroy(this);
+ globalObject.bunVM().runErrorHandler(corker.result, null);
+ }
+ }
+
+ pub fn getThisValue(this: *ServerWebSocket) JSValue {
+ var this_value = this.this_value;
+ if (this_value == .zero) {
+ this_value = this.toJS(this.handler.globalObject);
+ this_value.protect();
+ this.this_value = this_value;
+ }
+ return this_value;
+ }
+
+ pub fn onMessage(
+ this: *ServerWebSocket,
+ ws: uws.AnyWebSocket,
+ message: []const u8,
+ opcode: uws.Opcode,
+ ) void {
+ log("onMessage({d}): {s}", .{
+ @enumToInt(opcode),
+ message,
+ });
+ const onMessageHandler = this.handler.onMessage;
+ if (onMessageHandler.isEmptyOrUndefinedOrNull()) return;
+ var globalObject = this.handler.globalObject;
+
+ const arguments = [_]JSValue{
+ this.getThisValue(),
+ switch (opcode) {
+ .text => brk: {
+ var str = ZigString.init(message);
+ str.markUTF8();
+ break :brk str.toValueGC(globalObject);
+ },
+ .binary => JSC.ArrayBuffer.create(globalObject, message, .Uint8Array),
+ else => unreachable,
+ },
+ };
+
+ var corker = Corker{
+ .args = &arguments,
+ .globalObject = globalObject,
+ .callback = onMessageHandler,
+ };
+
+ ws.cork(&corker, Corker.run);
+ const result = corker.result;
+
+ if (result.isEmptyOrUndefinedOrNull()) return;
+
+ if (result.isAnyError(globalObject)) {
+ this.handler.globalObject.bunVM().runErrorHandler(result, null);
+ return;
+ }
+
+ if (result.asPromise()) |promise| {
+ switch (promise.status(globalObject.vm())) {
+ .Rejected => {
+ _ = promise.result(globalObject.vm());
+ return;
+ },
+
+ else => {},
+ }
+ }
+ }
+ pub fn onDrain(this: *ServerWebSocket, _: uws.AnyWebSocket) void {
+ log("onDrain", .{});
+
+ var handler = this.handler;
+ if (handler.onDrain != .zero) {
+ const result = handler.onDrain.call(handler.globalObject, &[_]JSC.JSValue{this.this_value});
+
+ if (result.isAnyError(handler.globalObject)) {
+ log("onDrain error", .{});
+ handler.globalObject.bunVM().runErrorHandler(result, null);
+ }
+ }
+ }
+ pub fn onPing(_: *ServerWebSocket, _: uws.AnyWebSocket, _: []const u8) void {
+ log("onPing", .{});
+ }
+ pub fn onPong(_: *ServerWebSocket, _: uws.AnyWebSocket, _: []const u8) void {
+ log("onPong", .{});
+ }
+ pub fn onClose(this: *ServerWebSocket, _: uws.AnyWebSocket, code: i32, message: []const u8) void {
+ log("onClose", .{});
+ var handler = this.handler;
+ this.closed = true;
+ defer handler.active_connections -|= 1;
+
+ if (handler.onClose != .zero) {
+ const result = handler.onClose.call(
+ handler.globalObject,
+ &[_]JSC.JSValue{ this.this_value, JSValue.jsNumber(code), ZigString.init(message).toValueGC(handler.globalObject) },
+ );
+
+ if (result.isAnyError(handler.globalObject)) {
+ log("onClose error", .{});
+ handler.globalObject.bunVM().runErrorHandler(result, null);
+ }
+ }
+
+ this.this_value.unprotect();
+ }
+
+ pub fn behavior(comptime ServerType: type, comptime ssl: bool, opts: uws.WebSocketBehavior) uws.WebSocketBehavior {
+ return uws.WebSocketBehavior.Wrap(ServerType, @This(), ssl).apply(opts);
+ }
+
+ pub fn constructor(globalObject: *JSC.JSGlobalObject, _: *JSC.CallFrame) callconv(.C) ?*ServerWebSocket {
+ globalObject.throw("Cannot construct ServerWebSocket", .{});
+ return null;
+ }
+
+ pub fn finalize(this: *ServerWebSocket) callconv(.C) void {
+ bun.default_allocator.destroy(this);
+ }
+
+ pub fn publish(
+ this: *ServerWebSocket,
+ globalThis: *JSC.JSGlobalObject,
+ callframe: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ const args = callframe.arguments(4);
+
+ if (args.len < 1) {
+ log("publish()", .{});
+ globalThis.throw("publish requires at least 1 argument", .{});
+ return .zero;
+ }
+
+ if (this.closed) {
+ log("publish() closed", .{});
+ return JSValue.jsNumber(0);
+ }
+
+ const topic_value = args.ptr[0];
+ const message_value = args.ptr[1];
+ const compress_value = args.ptr[2];
+
+ if (topic_value.isEmptyOrUndefinedOrNull() or !topic_value.isString()) {
+ log("publish() topic invalid", .{});
+ globalThis.throw("publish requires a topic string", .{});
+ return .zero;
+ }
+
+ var topic_slice = topic_value.toSlice(globalThis, bun.default_allocator);
+ defer topic_slice.deinit();
+ if (topic_slice.len == 0) {
+ globalThis.throw("publish requires a non-empty topic", .{});
+ return JSValue.jsNumber(0);
+ }
+
+ const compress = args.len > 1 and compress_value.toBoolean();
+
+ if (message_value.isEmptyOrUndefinedOrNull()) {
+ globalThis.throw("publish requires a non-empty message", .{});
+ return .zero;
+ }
+
+ if (message_value.asArrayBuffer(globalThis)) |buffer| {
+ if (buffer.len == 0) {
+ globalThis.throw("publish requires a non-empty message", .{});
+ return .zero;
+ }
+
+ return JSValue.jsNumber(
+ // if 0, return 0
+ // else return number of bytes sent
+ @as(i32, @boolToInt(this.websocket.publishWithOptions(topic_slice.slice(), buffer.slice(), .text, compress))) * @intCast(i32, @truncate(u31, buffer.len)),
+ );
+ }
+
+ {
+ var string_slice = message_value.toSlice(globalThis, bun.default_allocator);
+ defer string_slice.deinit();
+ if (string_slice.len == 0) {
+ return JSValue.jsNumber(0);
+ }
+
+ const buffer = string_slice.slice();
+ return JSValue.jsNumber(
+ // if 0, return 0
+ // else return number of bytes sent
+ @as(i32, @boolToInt(this.websocket.publishWithOptions(topic_slice.slice(), buffer, .text, compress))) * @intCast(i32, @truncate(u31, buffer.len)),
+ );
+ }
+
+ return .zero;
+ }
+
+ pub fn send(
+ this: *ServerWebSocket,
+ globalThis: *JSC.JSGlobalObject,
+ callframe: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ const args = callframe.arguments(2);
+
+ if (args.len < 1) {
+ log("send()", .{});
+ globalThis.throw("send requires at least 1 argument", .{});
+ return .zero;
+ }
+
+ if (this.closed) {
+ log("send() closed", .{});
+ return JSValue.jsNumber(0);
+ }
+
+ const message_value = args.ptr[0];
+ const compress_value = args.ptr[1];
+
+ const compress = args.len > 1 and compress_value.toBoolean();
+
+ if (message_value.isEmptyOrUndefinedOrNull()) {
+ globalThis.throw("send requires a non-empty message", .{});
+ return .zero;
+ }
+
+ if (message_value.asArrayBuffer(globalThis)) |buffer| {
+ if (buffer.len == 0) {
+ globalThis.throw("send requires a non-empty message", .{});
+ return .zero;
+ }
+
+ switch (this.websocket.send(buffer.slice(), .binary, compress, true)) {
+ .backpressure => {
+ log("send() backpressure ({d} bytes)", .{buffer.len});
+ return JSValue.jsNumber(-1);
+ },
+ .success => {
+ log("send() success ({d} bytes)", .{buffer.len});
+ return JSValue.jsNumber(buffer.slice().len);
+ },
+ .dropped => {
+ log("send() dropped ({d} bytes)", .{buffer.len});
+ return JSValue.jsNumber(0);
+ },
+ }
+ }
+
+ {
+ var string_slice = message_value.toSlice(globalThis, bun.default_allocator);
+ defer string_slice.deinit();
+ if (string_slice.len == 0) {
+ return JSValue.jsNumber(0);
+ }
+
+ const buffer = string_slice.slice();
+ switch (this.websocket.send(buffer, .text, compress, true)) {
+ .backpressure => {
+ log("send() backpressure ({d} bytes string)", .{buffer.len});
+ return JSValue.jsNumber(-1);
+ },
+ .success => {
+ log("send() success ({d} bytes string)", .{buffer.len});
+ return JSValue.jsNumber(buffer.len);
+ },
+ .dropped => {
+ log("send() dropped ({d} bytes string)", .{buffer.len});
+ return JSValue.jsNumber(0);
+ },
+ }
+ }
+
+ return .zero;
+ }
+
+ pub fn getData(
+ _: *ServerWebSocket,
+ _: *JSC.JSGlobalObject,
+ ) callconv(.C) JSValue {
+ log("getData()", .{});
+ return JSValue.jsUndefined();
+ }
+
+ pub fn setData(
+ this: *ServerWebSocket,
+ globalObject: *JSC.JSGlobalObject,
+ value: JSC.JSValue,
+ ) callconv(.C) bool {
+ log("setData()", .{});
+ ServerWebSocket.dataSetCached(this.this_value, globalObject, value);
+ return true;
+ }
+
+ pub fn getReadyState(
+ this: *ServerWebSocket,
+ _: *JSC.JSGlobalObject,
+ ) callconv(.C) JSValue {
+ log("getReadyState()", .{});
+
+ if (this.closed) {
+ return JSValue.jsNumber(3);
+ }
+
+ return JSValue.jsNumber(1);
+ }
+
+ pub fn close(
+ this: *ServerWebSocket,
+ globalThis: *JSC.JSGlobalObject,
+ callframe: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ const args = callframe.arguments(2);
+ log("close()", .{});
+
+ if (this.closed) {
+ return .zero;
+ }
+
+ const code = if (args.len > 0) args.ptr[0].toInt32() else @as(i32, 1000);
+ var message_value = if (args.len > 1) args.ptr[1].toSlice(globalThis, bun.default_allocator) else ZigString.Slice.empty;
+ defer message_value.deinit();
+ if (code > 0) {
+ this.websocket.end(code, message_value.slice());
+ } else {
+ this.closed = true;
+ this.this_value.unprotect();
+ this.websocket.close();
+ }
+
+ return JSValue.jsUndefined();
+ }
+ pub fn getBufferedAmount(
+ this: *ServerWebSocket,
+ _: *JSC.JSGlobalObject,
+ _: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ log("getBufferedAmount()", .{});
+
+ if (this.closed) {
+ return JSValue.jsNumber(0);
+ }
+
+ return JSValue.jsNumber(this.websocket.getBufferedAmount());
+ }
+ pub fn subscribe(
+ this: *ServerWebSocket,
+ globalThis: *JSC.JSGlobalObject,
+ callframe: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ const args = callframe.arguments(1);
+ if (args.len < 1) {
+ globalThis.throw("subscribe requires at least 1 argument", .{});
+ return .zero;
+ }
+
+ if (this.closed) {
+ return JSValue.jsBoolean(true);
+ }
+
+ var topic = args.ptr[0].toSlice(globalThis, bun.default_allocator);
+ defer topic.deinit();
+
+ if (topic.len == 0) {
+ globalThis.throw("subscribe requires a non-empty topic name", .{});
+ return .zero;
+ }
+
+ return JSValue.jsBoolean(this.websocket.subscribe(topic.slice()));
+ }
+ pub fn unsubscribe(
+ this: *ServerWebSocket,
+ globalThis: *JSC.JSGlobalObject,
+ callframe: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ const args = callframe.arguments(1);
+ if (args.len < 1) {
+ globalThis.throw("unsubscribe requires at least 1 argument", .{});
+ return .zero;
+ }
+
+ if (this.closed) {
+ return JSValue.jsBoolean(true);
+ }
+
+ var topic = args.ptr[0].toSlice(globalThis, bun.default_allocator);
+ defer topic.deinit();
+
+ if (topic.len == 0) {
+ globalThis.throw("unsubscribe requires a non-empty topic name", .{});
+ return .zero;
+ }
+
+ return JSValue.jsBoolean(this.websocket.unsubscribe(topic.slice()));
+ }
+ pub fn isSubscribed(
+ this: *ServerWebSocket,
+ globalThis: *JSC.JSGlobalObject,
+ callframe: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ const args = callframe.arguments(1);
+ if (args.len < 1) {
+ globalThis.throw("isSubscribed requires at least 1 argument", .{});
+ return .zero;
+ }
+
+ if (this.closed) {
+ return JSValue.jsBoolean(false);
+ }
+
+ var topic = args.ptr[0].toSlice(globalThis, bun.default_allocator);
+ defer topic.deinit();
+
+ if (topic.len == 0) {
+ globalThis.throw("isSubscribed requires a non-empty topic name", .{});
+ return .zero;
+ }
+
+ return JSValue.jsBoolean(this.websocket.isSubscribed(topic.slice()));
+ }
+
+ // pub fn getTopics(
+ // this: *ServerWebSocket,
+ // globalThis: *JSC.JSGlobalObject,
+ // ) callconv(.C) JSValue {
+ // if (this.closed) {
+ // return JSValue.createStringArray(globalThis, bun.default_allocator, null, 0, false);
+ // }
+
+ // this
+ // }
+
+ pub fn getRemoteAddress(
+ this: *ServerWebSocket,
+ globalThis: *JSC.JSGlobalObject,
+ ) callconv(.C) JSValue {
+ if (this.closed) {
+ return JSValue.jsUndefined();
+ }
+
+ var buf: [512]u8 = undefined;
+ const address = this.websocket.getRemoteAddress(&buf);
+ if (address.len == 0) {
+ return JSValue.jsUndefined();
+ }
+
+ return ZigString.init(address).toValueGC(globalThis);
+ }
+};
+
pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
return struct {
pub const ssl_enabled = ssl_enabled_;
@@ -2119,6 +3043,9 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
.pendingRequests = .{
.get = JSC.getterWrap(ThisServer, "getPendingRequests"),
},
+ .pendingSockets = .{
+ .get = JSC.getterWrap(ThisServer, "getPendingSockets"),
+ },
},
);
@@ -2150,6 +3077,54 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
this.config.onError = new_config.onError;
}
+ if (new_config.websocket.onMessage != .zero or new_config.websocket.onOpen != .zero) {
+ this.config.websocket.unprotect();
+ if (this.config.websocket.onMessage == .zero) {
+ this.app.ws("/*", this, 0, ServerWebSocket.behavior(
+ ThisServer,
+ ssl_enabled,
+ this.config.websocket.toBehavior(),
+ ));
+ }
+
+ new_config.websocket.globalObject = ctx;
+ this.config.websocket = new_config.websocket;
+ } else if (this.config.websocket.onMessage != .zero or this.config.websocket.onOpen != .zero) {
+ this.config.websocket.unprotect();
+ this.config.websocket = .{};
+ }
+
+ // we are going to leak the old memory
+ const new_keys = new_config.websockets.keys();
+ const old_keys = this.config.websockets.keys();
+
+ if (new_keys.len + old_keys.len > 0) {
+ var all_match = old_keys.len <= new_keys.len;
+
+ // any existing websockets will now call the new config
+ for (new_keys) |key, i| {
+ if (this.config.websockets.getPtr(key)) |old_val| {
+ old_val.unprotect();
+ old_val.* = new_config.websockets.values()[i];
+ old_val.globalObject = ctx;
+ } else {
+ all_match = false;
+ var new_value = &new_config.websockets.values()[i];
+ new_value.globalObject = ctx;
+ this.app.ws(
+ key,
+ this,
+ i,
+ ServerWebSocket.behavior(ThisServer, ssl_enabled, new_value.toBehavior()),
+ );
+ }
+ }
+
+ if (!all_match) {
+ this.config.websockets = new_config.websockets;
+ }
+ }
+
return this.thisObject.asObjectRef();
}
@@ -2289,6 +3264,10 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
return JSC.JSValue.jsNumber(@intCast(i32, @truncate(u31, this.pending_requests)));
}
+ pub fn getPendingSockets(this: *ThisServer) JSC.JSValue {
+ return JSC.JSValue.jsNumber(@intCast(i32, @truncate(u31, this.activeSocketsCount())));
+ }
+
pub fn getHostname(this: *ThisServer, globalThis: *JSGlobalObject) JSC.JSValue {
return ZigString.init(bun.span(this.config.hostname)).toValue(globalThis);
}
@@ -2317,8 +3296,21 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
this.deinitIfWeCan();
}
+ pub fn activeSocketsCount(this: *const ThisServer) u32 {
+ var count = this.config.websocket.active_connections;
+ for (this.config.websockets.values()) |conn| {
+ count += conn.active_connections;
+ }
+
+ return @truncate(u32, count);
+ }
+
+ pub fn hasActiveWebSockets(this: *const ThisServer) bool {
+ return this.activeSocketsCount() > 0;
+ }
+
pub fn deinitIfWeCan(this: *ThisServer) void {
- if (this.pending_requests == 0 and this.listener == null and this.has_js_deinited) {
+ if (this.pending_requests == 0 and this.listener == null and this.has_js_deinited and !this.hasActiveWebSockets()) {
this.unref();
this.deinit();
}
@@ -2517,10 +3509,13 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
}
}
- pub fn onRequest(this: *ThisServer, req: *uws.Request, resp: *App.Response) void {
+ pub fn onRequest(
+ this: *ThisServer,
+ req: *uws.Request,
+ resp: *App.Response,
+ ) void {
JSC.markBinding();
this.pending_requests += 1;
- var vm = this.vm;
req.setYield(false);
var ctx = this.request_pool_allocator.create(RequestContext) catch @panic("ran out of memory");
ctx.create(this, req, resp);
@@ -2573,112 +3568,21 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
}
// We keep the Request object alive for the duration of the request so that we can remove the pointer to the UWS request object.
- var args = [_]JSC.C.JSValueRef{request_object.toJS(this.globalThis).asObjectRef()};
+ var args = [_]JSC.C.JSValueRef{
+ request_object.toJS(this.globalThis).asObjectRef(),
+ };
ctx.request_js_object = args[0];
const request_value = JSValue.c(args[0]);
request_value.ensureStillAlive();
const response_value = JSC.C.JSObjectCallAsFunctionReturnValue(this.globalThis, this.config.onRequest.asObjectRef(), this.thisObject.asObjectRef(), 1, &args);
- request_value.ensureStillAlive();
- response_value.ensureStillAlive();
- if (ctx.aborted) {
- ctx.finalizeForAbort();
- return;
- }
- if (response_value.isEmptyOrUndefinedOrNull() and !ctx.resp.hasResponded()) {
- ctx.renderMissing();
- return;
- }
-
- if (response_value.isError() or response_value.isAggregateError(this.globalThis) or response_value.isException(this.globalThis.vm())) {
- ctx.runErrorHandler(response_value);
-
- return;
- }
-
- if (response_value.as(JSC.WebCore.Response)) |response| {
- ctx.response_jsvalue = response_value;
- ctx.response_jsvalue.ensureStillAlive();
- ctx.response_protected = false;
- switch (response.body.value) {
- .Blob => |*blob| {
- if (blob.needsToReadFile()) {
- response_value.protect();
- ctx.response_protected = true;
- }
- },
- .Locked => {
- response_value.protect();
- ctx.response_protected = true;
- },
- else => {},
- }
- ctx.render(response);
- return;
- }
-
- var wait_for_promise = false;
-
- if (response_value.asPromise()) |promise| {
- // If we immediately have the value available, we can skip the extra event loop tick
- switch (promise.status(vm.global.vm())) {
- .Pending => {},
- .Fulfilled => {
- ctx.handleResolve(promise.result(vm.global.vm()));
- return;
- },
- .Rejected => {
- ctx.handleReject(promise.result(vm.global.vm()));
- return;
- },
- }
- wait_for_promise = true;
- // I don't think this case should happen
- // But I'm uncertain
- } else if (response_value.asInternalPromise()) |promise| {
- switch (promise.status(vm.global.vm())) {
- .Pending => {},
- .Fulfilled => {
- ctx.handleResolve(promise.result(vm.global.vm()));
- return;
- },
- .Rejected => {
- ctx.handleReject(promise.result(vm.global.vm()));
- return;
- },
- }
- wait_for_promise = true;
- }
-
- if (wait_for_promise) {
- request_object.uws_request = req;
-
- request_object.ensureURL() catch {
- request_object.url = "";
- };
-
- // we have to clone the request headers here since they will soon belong to a different request
- if (request_object.headers == null) {
- request_object.headers = JSC.FetchHeaders.createFromUWS(this.globalThis, req);
- }
-
- if (comptime debug_mode) {
- ctx.pathname = bun.default_allocator.dupe(u8, request_object.url) catch unreachable;
- }
-
- // This object dies after the stack frame is popped
- // so we have to clear it in here too
- request_object.uws_request = null;
-
- ctx.setAbortHandler();
- ctx.pending_promises_for_abort += 1;
-
- response_value.then(this.globalThis, ctx, RequestContext.onResolve, RequestContext.onReject);
- return;
- }
-
- // The user returned something that wasn't a promise or a promise with a response
- if (!ctx.resp.hasResponded()) ctx.renderMissing();
+ ctx.onResponse(
+ this,
+ req,
+ request_object,
+ request_value,
+ response_value,
+ );
}
pub fn listen(this: *ThisServer) void {
@@ -2701,6 +3605,30 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
this.app = App.create(.{});
}
+ const websocket_patterns = this.config.websockets.keys();
+ {
+ const values = this.config.websockets.values();
+ for (websocket_patterns) |pattern, i| {
+ values[i].globalObject = this.globalThis;
+
+ this.app.ws(pattern, this, i + 1, ServerWebSocket.behavior(
+ ThisServer,
+ ssl_enabled,
+ values[i].toBehavior(),
+ ));
+ } else {
+ if (this.config.websocket.onMessage != .zero or this.config.websocket.onOpen != .zero) {
+ this.config.websocket.globalObject = this.globalThis;
+ this.app.ws(
+ "/*",
+ this,
+ 0,
+ ServerWebSocket.behavior(ThisServer, ssl_enabled, this.config.websocket.toBehavior()),
+ );
+ }
+ }
+ }
+
this.app.any("/*", *ThisServer, this, onRequest);
if (comptime debug_mode) {
@@ -2718,12 +3646,137 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
this.config.hostname;
this.ref();
+
this.app.listenWithConfig(*ThisServer, this, onListen, .{
.port = this.config.port,
.host = host,
.options = 0,
});
}
+
+ pub fn onWebSocketUpgrade(this: *ThisServer, resp: *App.Response, req: *uws.Request, ctx: *uws.uws_socket_context_t, id: usize) void {
+ var websocket_handler: *WebSocketServer = switch (id) {
+ 0 => &this.config.websocket,
+ else => &this.config.websockets.values()[id - 1],
+ };
+ req.setYield(false);
+
+ const onUpgrade = websocket_handler.onUpgrade;
+
+ if (onUpgrade == .zero) {
+ var upgrader = this.allocator.create(ServerWebSocket) catch @panic("Out of memory");
+ upgrader.* = .{
+ .handler = websocket_handler,
+ .this_value = .zero,
+ };
+ resp.upgrade(
+ *ServerWebSocket,
+ upgrader,
+ req.header("sec-websocket-key") orelse "",
+ req.header("sec-websocket-protocol") orelse "",
+ req.header("sec-websocket-extensions") orelse "",
+ ctx,
+ );
+ return;
+ }
+
+ const method = HTTP.Method.which(req.method()) orelse HTTP.Method.GET;
+
+ var request_object = this.allocator.create(JSC.WebCore.Request) catch unreachable;
+ request_object.* = .{
+ .url = "",
+ .method = method,
+ .uws_request = req,
+ .base_url_string_for_joining = this.base_url_string_for_joining,
+ .body = .{
+ .Empty = .{},
+ },
+ };
+
+ var args = [_]JSC.JSValue{
+ request_object.toJS(this.globalThis),
+ };
+ var request_value = args[0];
+ request_value.ensureStillAlive();
+ const response_value = websocket_handler.onUpgrade.call(this.globalThis, &args);
+ request_value.ensureStillAlive();
+ response_value.ensureStillAlive();
+
+ if (response_value.isBoolean() or response_value.isEmptyOrUndefinedOrNull()) {
+ if (response_value.toBoolean()) {
+ var upgrader = this.allocator.create(ServerWebSocket) catch @panic("Out of memory");
+ upgrader.* = .{
+ .handler = websocket_handler,
+ };
+ resp.upgrade(
+ *ServerWebSocket,
+ upgrader,
+ req.header("sec-websocket-key") orelse "",
+ req.header("sec-websocket-protocol") orelse "",
+ req.header("sec-websocket-extensions") orelse "",
+ ctx,
+ );
+ return;
+ } else {
+ req.setYield(true);
+ return;
+ }
+ }
+
+ if (response_value.as(Response)) |response| {
+ if (response.statusCode() == 101) {
+ var upgrader = this.allocator.create(ServerWebSocket) catch @panic("Out of memory");
+ upgrader.* = .{
+ .handler = websocket_handler,
+ .this_value = response_value,
+ };
+ response_value.ensureStillAlive();
+ resp.upgrade(
+ *ServerWebSocket,
+ upgrader,
+ response.header(.SecWebSocketKey) orelse req.header("sec-websocket-key") orelse "",
+ response.header(.SecWebSocketProtocol) orelse req.header("sec-websocket-protocol") orelse "",
+ response.header(.SecWebSocketExtensions) orelse req.header("sec-websocket-extensions") orelse "",
+ ctx,
+ );
+ return;
+ }
+ }
+
+ // The returned object becomes the data for the ServerWebSocket
+ if (response_value.isObject() or (response_value.isString() and response_value.getLengthOfArray(this.globalThis) > 0)) {
+ var upgrader = this.allocator.create(ServerWebSocket) catch @panic("Out of memory");
+ upgrader.* = .{
+ .handler = websocket_handler,
+ .this_value = response_value,
+ };
+ response_value.ensureStillAlive();
+
+ resp.upgrade(
+ *ServerWebSocket,
+ upgrader,
+ req.header("sec-websocket-key") orelse "",
+ req.header("sec-websocket-protocol") orelse "",
+ req.header("sec-websocket-extensions") orelse "",
+ ctx,
+ );
+ return;
+ }
+
+ var req_ctx = this.request_pool_allocator.create(RequestContext) catch @panic("ran out of memory");
+ req_ctx.create(this, req, resp);
+ req_ctx.request_js_object = request_value.asObjectRef();
+ req_ctx.response_jsvalue = response_value;
+ req_ctx.resp = resp;
+
+ req_ctx.onResponse(
+ this,
+ req,
+ request_object,
+ request_value,
+ response_value,
+ );
+ }
};
}
diff --git a/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h b/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h
index cd67081d1..5014f0d4e 100644
--- a/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h
+++ b/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h
@@ -7,7 +7,8 @@ std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA224Constructor;std:
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA512Constructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA384;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA384Constructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA256;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA256Constructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA512_256;
-std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA512_256Constructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForTextDecoder;
+std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA512_256Constructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForServerWebSocket;
+std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForServerWebSocketConstructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForTextDecoder;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForTextDecoderConstructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForRequest;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForRequestConstructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForResponse;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForResponseConstructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForBlob;
diff --git a/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h b/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h
index 4d1104f99..149dfe8b8 100644
--- a/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h
+++ b/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h
@@ -7,7 +7,8 @@ std::unique_ptr<IsoSubspace> m_subspaceForSHA224Constructor;std::unique_ptr<IsoS
std::unique_ptr<IsoSubspace> m_subspaceForSHA512Constructor;std::unique_ptr<IsoSubspace> m_subspaceForSHA384;
std::unique_ptr<IsoSubspace> m_subspaceForSHA384Constructor;std::unique_ptr<IsoSubspace> m_subspaceForSHA256;
std::unique_ptr<IsoSubspace> m_subspaceForSHA256Constructor;std::unique_ptr<IsoSubspace> m_subspaceForSHA512_256;
-std::unique_ptr<IsoSubspace> m_subspaceForSHA512_256Constructor;std::unique_ptr<IsoSubspace> m_subspaceForTextDecoder;
+std::unique_ptr<IsoSubspace> m_subspaceForSHA512_256Constructor;std::unique_ptr<IsoSubspace> m_subspaceForServerWebSocket;
+std::unique_ptr<IsoSubspace> m_subspaceForServerWebSocketConstructor;std::unique_ptr<IsoSubspace> m_subspaceForTextDecoder;
std::unique_ptr<IsoSubspace> m_subspaceForTextDecoderConstructor;std::unique_ptr<IsoSubspace> m_subspaceForRequest;
std::unique_ptr<IsoSubspace> m_subspaceForRequestConstructor;std::unique_ptr<IsoSubspace> m_subspaceForResponse;
std::unique_ptr<IsoSubspace> m_subspaceForResponseConstructor;std::unique_ptr<IsoSubspace> m_subspaceForBlob;
diff --git a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h
index c37518fe5..3de6262da 100644
--- a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h
+++ b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h
@@ -52,6 +52,12 @@ JSC::Structure* JSSHA512_256Structure() { return m_JSSHA512_256.getInitializedOn
JSC::LazyClassStructure m_JSSHA512_256;
bool hasJSSHA512_256SetterValue { false };
mutable JSC::WriteBarrier<JSC::Unknown> m_JSSHA512_256SetterValue;
+JSC::Structure* JSServerWebSocketStructure() { return m_JSServerWebSocket.getInitializedOnMainThread(this); }
+ JSC::JSObject* JSServerWebSocketConstructor() { return m_JSServerWebSocket.constructorInitializedOnMainThread(this); }
+ JSC::JSValue JSServerWebSocketPrototype() { return m_JSServerWebSocket.prototypeInitializedOnMainThread(this); }
+ JSC::LazyClassStructure m_JSServerWebSocket;
+ bool hasJSServerWebSocketSetterValue { false };
+ mutable JSC::WriteBarrier<JSC::Unknown> m_JSServerWebSocketSetterValue;
JSC::Structure* JSTextDecoderStructure() { return m_JSTextDecoder.getInitializedOnMainThread(this); }
JSC::JSObject* JSTextDecoderConstructor() { return m_JSTextDecoder.constructorInitializedOnMainThread(this); }
JSC::JSValue JSTextDecoderPrototype() { return m_JSTextDecoder.prototypeInitializedOnMainThread(this); }
diff --git a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h
index 1b6ac7ade..e449c2904 100644
--- a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h
+++ b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h
@@ -53,6 +53,12 @@ void GlobalObject::initGeneratedLazyClasses() {
init.setStructure(WebCore::JSSHA512_256::createStructure(init.vm, init.global, init.prototype));
init.setConstructor(WebCore::JSSHA512_256Constructor::create(init.vm, init.global, WebCore::JSSHA512_256Constructor::createStructure(init.vm, init.global, init.global->functionPrototype()), jsCast<WebCore::JSSHA512_256Prototype*>(init.prototype)));
});
+ m_JSServerWebSocket.initLater(
+ [](LazyClassStructure::Initializer& init) {
+ init.setPrototype(WebCore::JSServerWebSocket::createPrototype(init.vm, reinterpret_cast<Zig::GlobalObject*>(init.global)));
+ init.setStructure(WebCore::JSServerWebSocket::createStructure(init.vm, init.global, init.prototype));
+ init.setConstructor(WebCore::JSServerWebSocketConstructor::create(init.vm, init.global, WebCore::JSServerWebSocketConstructor::createStructure(init.vm, init.global, init.global->functionPrototype()), jsCast<WebCore::JSServerWebSocketPrototype*>(init.prototype)));
+ });
m_JSTextDecoder.initLater(
[](LazyClassStructure::Initializer& init) {
init.setPrototype(WebCore::JSTextDecoder::createPrototype(init.vm, reinterpret_cast<Zig::GlobalObject*>(init.global)));
@@ -90,6 +96,7 @@ void GlobalObject::visitGeneratedLazyClasses(GlobalObject *thisObject, Visitor&
thisObject->m_JSSHA384.visit(visitor); visitor.append(thisObject->m_JSSHA384SetterValue);
thisObject->m_JSSHA256.visit(visitor); visitor.append(thisObject->m_JSSHA256SetterValue);
thisObject->m_JSSHA512_256.visit(visitor); visitor.append(thisObject->m_JSSHA512_256SetterValue);
+ thisObject->m_JSServerWebSocket.visit(visitor); visitor.append(thisObject->m_JSServerWebSocketSetterValue);
thisObject->m_JSTextDecoder.visit(visitor); visitor.append(thisObject->m_JSTextDecoderSetterValue);
thisObject->m_JSRequest.visit(visitor); visitor.append(thisObject->m_JSRequestSetterValue);
thisObject->m_JSResponse.visit(visitor); visitor.append(thisObject->m_JSResponseSetterValue);
diff --git a/src/bun.js/bindings/ZigGeneratedClasses.cpp b/src/bun.js/bindings/ZigGeneratedClasses.cpp
index c737103fc..9fbc436ac 100644
--- a/src/bun.js/bindings/ZigGeneratedClasses.cpp
+++ b/src/bun.js/bindings/ZigGeneratedClasses.cpp
@@ -199,6 +199,12 @@ JSC_DEFINE_CUSTOM_GETTER(SubprocessPrototype__readableGetterWrap, (JSGlobalObjec
thisObject->m_stdout.set(vm, thisObject, result);
RELEASE_AND_RETURN(throwScope, JSValue::encode(result));
}
+extern "C" void SubprocessPrototype__readableSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject *globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSSubprocess*>(JSValue::decode(thisValue));
+ thisObject->m_stdout.set(vm, thisObject, JSValue::decode(value));
+}
JSC_DEFINE_HOST_FUNCTION(SubprocessPrototype__refCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
@@ -236,6 +242,12 @@ JSC_DEFINE_CUSTOM_GETTER(SubprocessPrototype__stderrGetterWrap, (JSGlobalObject
thisObject->m_stderr.set(vm, thisObject, result);
RELEASE_AND_RETURN(throwScope, JSValue::encode(result));
}
+extern "C" void SubprocessPrototype__stderrSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject *globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSSubprocess*>(JSValue::decode(thisValue));
+ thisObject->m_stderr.set(vm, thisObject, JSValue::decode(value));
+}
JSC_DEFINE_CUSTOM_GETTER(SubprocessPrototype__stdinGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
@@ -256,6 +268,12 @@ JSC_DEFINE_CUSTOM_GETTER(SubprocessPrototype__stdinGetterWrap, (JSGlobalObject *
thisObject->m_stdin.set(vm, thisObject, result);
RELEASE_AND_RETURN(throwScope, JSValue::encode(result));
}
+extern "C" void SubprocessPrototype__stdinSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject *globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSSubprocess*>(JSValue::decode(thisValue));
+ thisObject->m_stdin.set(vm, thisObject, JSValue::decode(value));
+}
JSC_DEFINE_CUSTOM_GETTER(SubprocessPrototype__stdoutGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
@@ -276,6 +294,12 @@ JSC_DEFINE_CUSTOM_GETTER(SubprocessPrototype__stdoutGetterWrap, (JSGlobalObject
thisObject->m_stdout.set(vm, thisObject, result);
RELEASE_AND_RETURN(throwScope, JSValue::encode(result));
}
+extern "C" void SubprocessPrototype__stdoutSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject *globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSSubprocess*>(JSValue::decode(thisValue));
+ thisObject->m_stdout.set(vm, thisObject, JSValue::decode(value));
+}
JSC_DEFINE_HOST_FUNCTION(SubprocessPrototype__unrefCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
@@ -313,6 +337,12 @@ JSC_DEFINE_CUSTOM_GETTER(SubprocessPrototype__writableGetterWrap, (JSGlobalObjec
thisObject->m_stdin.set(vm, thisObject, result);
RELEASE_AND_RETURN(throwScope, JSValue::encode(result));
}
+extern "C" void SubprocessPrototype__writableSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject *globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSSubprocess*>(JSValue::decode(thisValue));
+ thisObject->m_stdin.set(vm, thisObject, JSValue::decode(value));
+}
void JSSubprocessPrototype::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
@@ -2327,7 +2357,417 @@ void JSSHA512_256::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer)
JSObject* JSSHA512_256::createPrototype(VM& vm, JSDOMGlobalObject* globalObject)
{
return JSSHA512_256Prototype::create(vm, globalObject, JSSHA512_256Prototype::createStructure(vm, globalObject, globalObject->objectPrototype()));
-}extern "C" void* TextDecoderClass__construct(JSC::JSGlobalObject*, JSC::CallFrame*);
+}extern "C" void* ServerWebSocketClass__construct(JSC::JSGlobalObject*, JSC::CallFrame*);
+JSC_DECLARE_CUSTOM_GETTER(jsServerWebSocketConstructor);
+extern "C" void ServerWebSocketClass__finalize(void*);
+
+extern "C" EncodedJSValue ServerWebSocketPrototype__close(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(ServerWebSocketPrototype__closeCallback);
+
+
+extern "C" JSC::EncodedJSValue ServerWebSocketPrototype__getData(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject);
+JSC_DECLARE_CUSTOM_GETTER(ServerWebSocketPrototype__dataGetterWrap);
+
+
+extern "C" EncodedJSValue ServerWebSocketPrototype__getBufferedAmount(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(ServerWebSocketPrototype__getBufferedAmountCallback);
+
+
+extern "C" EncodedJSValue ServerWebSocketPrototype__isSubscribed(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(ServerWebSocketPrototype__isSubscribedCallback);
+
+
+extern "C" EncodedJSValue ServerWebSocketPrototype__publish(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(ServerWebSocketPrototype__publishCallback);
+
+
+extern "C" JSC::EncodedJSValue ServerWebSocketPrototype__getReadyState(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject);
+JSC_DECLARE_CUSTOM_GETTER(ServerWebSocketPrototype__readyStateGetterWrap);
+
+
+extern "C" JSC::EncodedJSValue ServerWebSocketPrototype__getRemoteAddress(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject);
+JSC_DECLARE_CUSTOM_GETTER(ServerWebSocketPrototype__remoteAddressGetterWrap);
+
+
+extern "C" EncodedJSValue ServerWebSocketPrototype__send(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(ServerWebSocketPrototype__sendCallback);
+
+
+extern "C" EncodedJSValue ServerWebSocketPrototype__subscribe(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(ServerWebSocketPrototype__subscribeCallback);
+
+
+extern "C" EncodedJSValue ServerWebSocketPrototype__unsubscribe(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(ServerWebSocketPrototype__unsubscribeCallback);
+
+
+STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSServerWebSocketPrototype, JSServerWebSocketPrototype::Base);
+
+
+ static const HashTableValue JSServerWebSocketPrototypeTableValues[] = {
+{ "close"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ServerWebSocketPrototype__closeCallback, 1 } } ,
+{ "data"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, ServerWebSocketPrototype__dataGetterWrap, 0 } } ,
+{ "getBufferedAmount"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ServerWebSocketPrototype__getBufferedAmountCallback, 0 } } ,
+{ "isSubscribed"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ServerWebSocketPrototype__isSubscribedCallback, 1 } } ,
+{ "publish"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ServerWebSocketPrototype__publishCallback, 3 } } ,
+{ "readyState"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, ServerWebSocketPrototype__readyStateGetterWrap, 0 } } ,
+{ "remoteAddress"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, ServerWebSocketPrototype__remoteAddressGetterWrap, 0 } } ,
+{ "send"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ServerWebSocketPrototype__sendCallback, 2 } } ,
+{ "subscribe"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ServerWebSocketPrototype__subscribeCallback, 1 } } ,
+{ "unsubscribe"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ServerWebSocketPrototype__unsubscribeCallback, 1 } }
+ };
+
+
+const ClassInfo JSServerWebSocketPrototype::s_info = { "ServerWebSocket"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSServerWebSocketPrototype) };
+
+
+
+JSC_DEFINE_CUSTOM_GETTER(jsServerWebSocketConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName))
+{
+ VM& vm = JSC::getVM(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ auto* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ auto* prototype = jsDynamicCast<JSServerWebSocketPrototype*>(JSValue::decode(thisValue));
+
+ if (UNLIKELY(!prototype))
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ return JSValue::encode(globalObject->JSServerWebSocketConstructor());
+}
+
+
+
+JSC_DEFINE_HOST_FUNCTION(ServerWebSocketPrototype__closeCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSServerWebSocket* thisObject = jsDynamicCast<JSServerWebSocket*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return ServerWebSocketPrototype__close(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+JSC_DEFINE_CUSTOM_GETTER(ServerWebSocketPrototype__dataGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ Zig::GlobalObject *globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSServerWebSocket* thisObject = jsCast<JSServerWebSocket*>(JSValue::decode(thisValue));
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ if (JSValue cachedValue = thisObject->m_data.get())
+ return JSValue::encode(cachedValue);
+
+ JSC::JSValue result = JSC::JSValue::decode(
+ ServerWebSocketPrototype__getData(thisObject->wrapped(), globalObject)
+ );
+ RETURN_IF_EXCEPTION(throwScope, {});
+ thisObject->m_data.set(vm, thisObject, result);
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(result));
+}
+extern "C" void ServerWebSocketPrototype__dataSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject *globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSServerWebSocket*>(JSValue::decode(thisValue));
+ thisObject->m_data.set(vm, thisObject, JSValue::decode(value));
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(ServerWebSocketPrototype__getBufferedAmountCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSServerWebSocket* thisObject = jsDynamicCast<JSServerWebSocket*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return ServerWebSocketPrototype__getBufferedAmount(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(ServerWebSocketPrototype__isSubscribedCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSServerWebSocket* thisObject = jsDynamicCast<JSServerWebSocket*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return ServerWebSocketPrototype__isSubscribed(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(ServerWebSocketPrototype__publishCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSServerWebSocket* thisObject = jsDynamicCast<JSServerWebSocket*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return ServerWebSocketPrototype__publish(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+JSC_DEFINE_CUSTOM_GETTER(ServerWebSocketPrototype__readyStateGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ Zig::GlobalObject *globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSServerWebSocket* thisObject = jsCast<JSServerWebSocket*>(JSValue::decode(thisValue));
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+ JSC::EncodedJSValue result = ServerWebSocketPrototype__getReadyState(thisObject->wrapped(), globalObject);
+ RETURN_IF_EXCEPTION(throwScope, {});
+ RELEASE_AND_RETURN(throwScope, result);
+}
+
+
+JSC_DEFINE_CUSTOM_GETTER(ServerWebSocketPrototype__remoteAddressGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ Zig::GlobalObject *globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSServerWebSocket* thisObject = jsCast<JSServerWebSocket*>(JSValue::decode(thisValue));
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ if (JSValue cachedValue = thisObject->m_remoteAddress.get())
+ return JSValue::encode(cachedValue);
+
+ JSC::JSValue result = JSC::JSValue::decode(
+ ServerWebSocketPrototype__getRemoteAddress(thisObject->wrapped(), globalObject)
+ );
+ RETURN_IF_EXCEPTION(throwScope, {});
+ thisObject->m_remoteAddress.set(vm, thisObject, result);
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(result));
+}
+extern "C" void ServerWebSocketPrototype__remoteAddressSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject *globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSServerWebSocket*>(JSValue::decode(thisValue));
+ thisObject->m_remoteAddress.set(vm, thisObject, JSValue::decode(value));
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(ServerWebSocketPrototype__sendCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSServerWebSocket* thisObject = jsDynamicCast<JSServerWebSocket*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return ServerWebSocketPrototype__send(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(ServerWebSocketPrototype__subscribeCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSServerWebSocket* thisObject = jsDynamicCast<JSServerWebSocket*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return ServerWebSocketPrototype__subscribe(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(ServerWebSocketPrototype__unsubscribeCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSServerWebSocket* thisObject = jsDynamicCast<JSServerWebSocket*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return ServerWebSocketPrototype__unsubscribe(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+void JSServerWebSocketPrototype::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
+{
+ Base::finishCreation(vm);
+ reifyStaticProperties(vm, JSServerWebSocket::info(), JSServerWebSocketPrototypeTableValues, *this);
+ JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
+}
+
+void JSServerWebSocketConstructor::finishCreation(VM& vm, JSC::JSGlobalObject* globalObject, JSServerWebSocketPrototype* prototype)
+{
+ Base::finishCreation(vm, 0, "ServerWebSocket"_s, PropertyAdditionMode::WithoutStructureTransition);
+
+ putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
+ ASSERT(inherits(info()));
+}
+
+JSServerWebSocketConstructor* JSServerWebSocketConstructor::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSServerWebSocketPrototype* prototype) {
+ JSServerWebSocketConstructor* ptr = new (NotNull, JSC::allocateCell<JSServerWebSocketConstructor>(vm)) JSServerWebSocketConstructor(vm, structure, construct);
+ ptr->finishCreation(vm, globalObject, prototype);
+ return ptr;
+}
+
+JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSServerWebSocketConstructor::construct(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame)
+{
+ Zig::GlobalObject *globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ JSC::VM &vm = globalObject->vm();
+ JSObject* newTarget = asObject(callFrame->newTarget());
+ auto* constructor = globalObject->JSServerWebSocketConstructor();
+ Structure* structure = globalObject->JSServerWebSocketStructure();
+ if (constructor != newTarget) {
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto* functionGlobalObject = reinterpret_cast<Zig::GlobalObject*>(
+ // ShadowRealm functions belong to a different global object.
+ getFunctionRealm(globalObject, newTarget)
+ );
+ RETURN_IF_EXCEPTION(scope, {});
+ structure = InternalFunction::createSubclassStructure(
+ globalObject,
+ newTarget,
+ functionGlobalObject->JSServerWebSocketStructure()
+ );
+ }
+
+ void* ptr = ServerWebSocketClass__construct(globalObject, callFrame);
+
+ if (UNLIKELY(!ptr)) {
+ return JSValue::encode(JSC::jsUndefined());
+ }
+
+ JSServerWebSocket* instance = JSServerWebSocket::create(vm, globalObject, structure, ptr);
+
+
+ return JSValue::encode(instance);
+}
+
+extern "C" EncodedJSValue ServerWebSocket__create(Zig::GlobalObject* globalObject, void* ptr) {
+ auto &vm = globalObject->vm();
+ JSC::Structure* structure = globalObject->JSServerWebSocketStructure();
+ JSServerWebSocket* instance = JSServerWebSocket::create(vm, globalObject, structure, ptr);
+
+ return JSValue::encode(instance);
+}
+
+void JSServerWebSocketConstructor::initializeProperties(VM& vm, JSC::JSGlobalObject* globalObject, JSServerWebSocketPrototype* prototype)
+{
+
+}
+
+const ClassInfo JSServerWebSocketConstructor::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSServerWebSocketConstructor) };
+
+
+ extern "C" EncodedJSValue ServerWebSocket__getConstructor(Zig::GlobalObject* globalObject) {
+ return JSValue::encode(globalObject->JSServerWebSocketConstructor());
+ }
+
+JSServerWebSocket::~JSServerWebSocket()
+{
+ if (m_ctx) {
+ ServerWebSocketClass__finalize(m_ctx);
+ }
+}
+void JSServerWebSocket::destroy(JSCell* cell)
+{
+ static_cast<JSServerWebSocket*>(cell)->JSServerWebSocket::~JSServerWebSocket();
+}
+
+const ClassInfo JSServerWebSocket::s_info = { "ServerWebSocket"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSServerWebSocket) };
+
+void JSServerWebSocket::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+}
+
+JSServerWebSocket* JSServerWebSocket::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* ctx) {
+ JSServerWebSocket* ptr = new (NotNull, JSC::allocateCell<JSServerWebSocket>(vm)) JSServerWebSocket(vm, structure, ctx);
+ ptr->finishCreation(vm);
+ return ptr;
+}
+
+extern "C" void* ServerWebSocket__fromJS(JSC::EncodedJSValue value) {
+ JSServerWebSocket* object = JSC::jsDynamicCast<JSServerWebSocket*>(JSValue::decode(value));
+ if (!object)
+ return nullptr;
+
+ return object->wrapped();
+}
+
+extern "C" bool ServerWebSocket__dangerouslySetPtr(JSC::EncodedJSValue value, void* ptr) {
+ JSServerWebSocket* object = JSC::jsDynamicCast<JSServerWebSocket*>(JSValue::decode(value));
+ if (!object)
+ return false;
+
+ object->m_ctx = ptr;
+ return true;
+}
+
+
+extern "C" const size_t ServerWebSocket__ptrOffset = JSServerWebSocket::offsetOfWrapped();
+
+void JSServerWebSocket::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer)
+{
+ auto* thisObject = jsCast<JSServerWebSocket*>(cell);
+ if (void* wrapped = thisObject->wrapped()) {
+ // if (thisObject->scriptExecutionContext())
+ // analyzer.setLabelForCell(cell, "url " + thisObject->scriptExecutionContext()->url().string());
+ }
+ Base::analyzeHeap(cell, analyzer);
+}
+
+JSObject* JSServerWebSocket::createPrototype(VM& vm, JSDOMGlobalObject* globalObject)
+{
+ return JSServerWebSocketPrototype::create(vm, globalObject, JSServerWebSocketPrototype::createStructure(vm, globalObject, globalObject->objectPrototype()));
+}
+
+template<typename Visitor>
+void JSServerWebSocket::visitChildrenImpl(JSCell* cell, Visitor& visitor)
+{
+ JSServerWebSocket* thisObject = jsCast<JSServerWebSocket*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+
+
+ visitor.append(thisObject->m_data);
+ visitor.append(thisObject->m_remoteAddress);
+}
+
+DEFINE_VISIT_CHILDREN(JSServerWebSocket);extern "C" void* TextDecoderClass__construct(JSC::JSGlobalObject*, JSC::CallFrame*);
JSC_DECLARE_CUSTOM_GETTER(jsTextDecoderConstructor);
extern "C" void TextDecoderClass__finalize(void*);
@@ -2406,6 +2846,12 @@ JSC_DEFINE_CUSTOM_GETTER(TextDecoderPrototype__encodingGetterWrap, (JSGlobalObje
thisObject->m_encoding.set(vm, thisObject, result);
RELEASE_AND_RETURN(throwScope, JSValue::encode(result));
}
+extern "C" void TextDecoderPrototype__encodingSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject *globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSTextDecoder*>(JSValue::decode(thisValue));
+ thisObject->m_encoding.set(vm, thisObject, JSValue::decode(value));
+}
JSC_DEFINE_CUSTOM_GETTER(TextDecoderPrototype__fatalGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
@@ -2738,6 +3184,12 @@ JSC_DEFINE_CUSTOM_GETTER(RequestPrototype__bodyGetterWrap, (JSGlobalObject * lex
thisObject->m_body.set(vm, thisObject, result);
RELEASE_AND_RETURN(throwScope, JSValue::encode(result));
}
+extern "C" void RequestPrototype__bodySetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject *globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSRequest*>(JSValue::decode(thisValue));
+ thisObject->m_body.set(vm, thisObject, JSValue::decode(value));
+}
JSC_DEFINE_CUSTOM_GETTER(RequestPrototype__bodyUsedGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
@@ -2827,6 +3279,12 @@ JSC_DEFINE_CUSTOM_GETTER(RequestPrototype__headersGetterWrap, (JSGlobalObject *
thisObject->m_headers.set(vm, thisObject, result);
RELEASE_AND_RETURN(throwScope, JSValue::encode(result));
}
+extern "C" void RequestPrototype__headersSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject *globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSRequest*>(JSValue::decode(thisValue));
+ thisObject->m_headers.set(vm, thisObject, JSValue::decode(value));
+}
JSC_DEFINE_CUSTOM_GETTER(RequestPrototype__integrityGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
@@ -2959,6 +3417,12 @@ JSC_DEFINE_CUSTOM_GETTER(RequestPrototype__urlGetterWrap, (JSGlobalObject * lexi
thisObject->m_url.set(vm, thisObject, result);
RELEASE_AND_RETURN(throwScope, JSValue::encode(result));
}
+extern "C" void RequestPrototype__urlSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject *globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSRequest*>(JSValue::decode(thisValue));
+ thisObject->m_url.set(vm, thisObject, JSValue::decode(value));
+}
void JSRequestPrototype::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
@@ -3266,6 +3730,12 @@ JSC_DEFINE_CUSTOM_GETTER(ResponsePrototype__bodyGetterWrap, (JSGlobalObject * le
thisObject->m_body.set(vm, thisObject, result);
RELEASE_AND_RETURN(throwScope, JSValue::encode(result));
}
+extern "C" void ResponsePrototype__bodySetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject *globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSResponse*>(JSValue::decode(thisValue));
+ thisObject->m_body.set(vm, thisObject, JSValue::decode(value));
+}
JSC_DEFINE_CUSTOM_GETTER(ResponsePrototype__bodyUsedGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
@@ -3316,6 +3786,12 @@ JSC_DEFINE_CUSTOM_GETTER(ResponsePrototype__headersGetterWrap, (JSGlobalObject *
thisObject->m_headers.set(vm, thisObject, result);
RELEASE_AND_RETURN(throwScope, JSValue::encode(result));
}
+extern "C" void ResponsePrototype__headersSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject *globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSResponse*>(JSValue::decode(thisValue));
+ thisObject->m_headers.set(vm, thisObject, JSValue::decode(value));
+}
JSC_DEFINE_HOST_FUNCTION(ResponsePrototype__jsonCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
@@ -3392,6 +3868,12 @@ JSC_DEFINE_CUSTOM_GETTER(ResponsePrototype__statusTextGetterWrap, (JSGlobalObjec
thisObject->m_statusText.set(vm, thisObject, result);
RELEASE_AND_RETURN(throwScope, JSValue::encode(result));
}
+extern "C" void ResponsePrototype__statusTextSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject *globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSResponse*>(JSValue::decode(thisValue));
+ thisObject->m_statusText.set(vm, thisObject, JSValue::decode(value));
+}
JSC_DEFINE_HOST_FUNCTION(ResponsePrototype__textCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
@@ -3442,6 +3924,12 @@ JSC_DEFINE_CUSTOM_GETTER(ResponsePrototype__urlGetterWrap, (JSGlobalObject * lex
thisObject->m_url.set(vm, thisObject, result);
RELEASE_AND_RETURN(throwScope, JSValue::encode(result));
}
+extern "C" void ResponsePrototype__urlSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject *globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSResponse*>(JSValue::decode(thisValue));
+ thisObject->m_url.set(vm, thisObject, JSValue::decode(value));
+}
void JSResponsePrototype::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
diff --git a/src/bun.js/bindings/ZigGeneratedClasses.h b/src/bun.js/bindings/ZigGeneratedClasses.h
index b51637efa..45e47f81a 100644
--- a/src/bun.js/bindings/ZigGeneratedClasses.h
+++ b/src/bun.js/bindings/ZigGeneratedClasses.h
@@ -1133,6 +1133,131 @@ class JSSHA512_256Prototype final : public JSC::JSNonFinalObject {
void finishCreation(JSC::VM&, JSC::JSGlobalObject* globalObject, JSSHA512_256Prototype* prototype);
};
+class JSServerWebSocket final : public JSC::JSDestructibleObject {
+ public:
+ using Base = JSC::JSDestructibleObject;
+ static JSServerWebSocket* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* ctx);
+
+ DECLARE_EXPORT_INFO;
+ template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ if constexpr (mode == JSC::SubspaceAccess::Concurrently)
+ return nullptr;
+ return WebCore::subspaceForImpl<JSServerWebSocket, WebCore::UseCustomHeapCellType::No>(
+ vm,
+ [](auto& spaces) { return spaces.m_clientSubspaceForServerWebSocket.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForServerWebSocket = WTFMove(space); },
+ [](auto& spaces) { return spaces.m_subspaceForServerWebSocket.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_subspaceForServerWebSocket = WTFMove(space); });
+ }
+
+ static void destroy(JSC::JSCell*);
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(static_cast<JSC::JSType>(0b11101110), StructureFlags), info());
+ }
+
+ static JSObject* createPrototype(VM& vm, JSDOMGlobalObject* globalObject);
+
+ ~JSServerWebSocket();
+
+ void* wrapped() const { return m_ctx; }
+
+ void detach()
+ {
+ m_ctx = nullptr;
+ }
+
+ static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
+ static ptrdiff_t offsetOfWrapped() { return OBJECT_OFFSETOF(JSServerWebSocket, m_ctx); }
+
+ void* m_ctx { nullptr };
+
+
+ JSServerWebSocket(JSC::VM& vm, JSC::Structure* structure, void* sinkPtr)
+ : Base(vm, structure)
+ {
+ m_ctx = sinkPtr;
+ }
+
+ void finishCreation(JSC::VM&);
+
+ DECLARE_VISIT_CHILDREN;
+
+ mutable JSC::WriteBarrier<JSC::Unknown> m_data;
+mutable JSC::WriteBarrier<JSC::Unknown> m_remoteAddress;
+ };
+class JSServerWebSocketPrototype final : public JSC::JSNonFinalObject {
+ public:
+ using Base = JSC::JSNonFinalObject;
+
+ static JSServerWebSocketPrototype* create(JSC::VM& vm, JSGlobalObject* globalObject, JSC::Structure* structure)
+ {
+ JSServerWebSocketPrototype* ptr = new (NotNull, JSC::allocateCell<JSServerWebSocketPrototype>(vm)) JSServerWebSocketPrototype(vm, globalObject, structure);
+ ptr->finishCreation(vm, globalObject);
+ return ptr;
+ }
+
+ DECLARE_INFO;
+ template<typename CellType, JSC::SubspaceAccess>
+ static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ return &vm.plainObjectSpace();
+ }
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
+ }
+
+ private:
+ JSServerWebSocketPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)
+ : Base(vm, structure)
+ {
+ }
+
+ void finishCreation(JSC::VM&, JSC::JSGlobalObject*);
+ };
+
+ class JSServerWebSocketConstructor final : public JSC::InternalFunction {
+ public:
+ using Base = JSC::InternalFunction;
+ static JSServerWebSocketConstructor* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSServerWebSocketPrototype* prototype);
+
+ static constexpr unsigned StructureFlags = Base::StructureFlags;
+ static constexpr bool needsDestruction = false;
+
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::InternalFunctionType, StructureFlags), info());
+ }
+
+ template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ if constexpr (mode == JSC::SubspaceAccess::Concurrently)
+ return nullptr;
+ return WebCore::subspaceForImpl<JSServerWebSocketConstructor, WebCore::UseCustomHeapCellType::No>(
+ vm,
+ [](auto& spaces) { return spaces.m_clientSubspaceForServerWebSocketConstructor.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForServerWebSocketConstructor = WTFMove(space); },
+ [](auto& spaces) { return spaces.m_subspaceForServerWebSocketConstructor.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_subspaceForServerWebSocketConstructor = WTFMove(space); });
+ }
+
+
+ void initializeProperties(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSServerWebSocketPrototype* prototype);
+
+ // Must be defined for each specialization class.
+ static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES construct(JSC::JSGlobalObject*, JSC::CallFrame*);
+ DECLARE_EXPORT_INFO;
+ private:
+ JSServerWebSocketConstructor(JSC::VM& vm, JSC::Structure* structure, JSC::NativeFunction nativeFunction)
+ : Base(vm, structure, nativeFunction, nativeFunction)
+
+ {
+ }
+
+ void finishCreation(JSC::VM&, JSC::JSGlobalObject* globalObject, JSServerWebSocketPrototype* prototype);
+ };
class JSTextDecoder final : public JSC::JSDestructibleObject {
public:
using Base = JSC::JSDestructibleObject;
diff --git a/src/bun.js/bindings/generated_classes.zig b/src/bun.js/bindings/generated_classes.zig
index 124602918..80ef7d873 100644
--- a/src/bun.js/bindings/generated_classes.zig
+++ b/src/bun.js/bindings/generated_classes.zig
@@ -20,6 +20,30 @@ pub const JSSubprocess = struct {
return Subprocess__fromJS(value);
}
+ extern fn SubprocessPrototype__stderrSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ /// Set the cached value for stderr on Subprocess
+ /// This value will be visited by the garbage collector.
+ pub fn stderrSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ SubprocessPrototype__stderrSetCachedValue(thisValue, globalObject, value);
+ }
+
+ extern fn SubprocessPrototype__stdinSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ /// Set the cached value for stdin on Subprocess
+ /// This value will be visited by the garbage collector.
+ pub fn stdinSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ SubprocessPrototype__stdinSetCachedValue(thisValue, globalObject, value);
+ }
+
+ extern fn SubprocessPrototype__stdoutSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ /// Set the cached value for stdout on Subprocess
+ /// This value will be visited by the garbage collector.
+ pub fn stdoutSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ SubprocessPrototype__stdoutSetCachedValue(thisValue, globalObject, value);
+ }
+
/// Get the Subprocess constructor value.
/// This loads lazily from the global object.
pub fn getConstructor(globalObject: *JSC.JSGlobalObject) JSC.JSValue {
@@ -726,6 +750,115 @@ pub const JSSHA512_256 = struct {
}
}
};
+pub const JSServerWebSocket = struct {
+ const ServerWebSocket = Classes.ServerWebSocket;
+ const GetterType = fn (*ServerWebSocket, *JSC.JSGlobalObject) callconv(.C) JSC.JSValue;
+ const SetterType = fn (*ServerWebSocket, *JSC.JSGlobalObject, JSC.JSValue) callconv(.C) bool;
+ const CallbackType = fn (*ServerWebSocket, *JSC.JSGlobalObject, *JSC.CallFrame) callconv(.C) JSC.JSValue;
+
+ /// Return the pointer to the wrapped object.
+ /// If the object does not match the type, return null.
+ pub fn fromJS(value: JSC.JSValue) ?*ServerWebSocket {
+ JSC.markBinding();
+ return ServerWebSocket__fromJS(value);
+ }
+
+ extern fn ServerWebSocketPrototype__dataSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ /// Set the cached value for data on ServerWebSocket
+ /// This value will be visited by the garbage collector.
+ pub fn dataSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ ServerWebSocketPrototype__dataSetCachedValue(thisValue, globalObject, value);
+ }
+
+ extern fn ServerWebSocketPrototype__remoteAddressSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ /// Set the cached value for remoteAddress on ServerWebSocket
+ /// This value will be visited by the garbage collector.
+ pub fn remoteAddressSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ ServerWebSocketPrototype__remoteAddressSetCachedValue(thisValue, globalObject, value);
+ }
+
+ /// Get the ServerWebSocket constructor value.
+ /// This loads lazily from the global object.
+ pub fn getConstructor(globalObject: *JSC.JSGlobalObject) JSC.JSValue {
+ JSC.markBinding();
+ return ServerWebSocket__getConstructor(globalObject);
+ }
+
+ /// Create a new instance of ServerWebSocket
+ pub fn toJS(this: *ServerWebSocket, globalObject: *JSC.JSGlobalObject) JSC.JSValue {
+ JSC.markBinding();
+ if (comptime Environment.allow_assert) {
+ const value__ = ServerWebSocket__create(globalObject, this);
+ std.debug.assert(value__.as(ServerWebSocket).? == this); // If this fails, likely a C ABI issue.
+ return value__;
+ } else {
+ return ServerWebSocket__create(globalObject, this);
+ }
+ }
+
+ /// Modify the internal ptr to point to a new instance of ServerWebSocket.
+ pub fn dangerouslySetPtr(value: JSC.JSValue, ptr: ?*ServerWebSocket) bool {
+ JSC.markBinding();
+ return ServerWebSocket__dangerouslySetPtr(value, ptr);
+ }
+
+ extern fn ServerWebSocket__fromJS(JSC.JSValue) ?*ServerWebSocket;
+ extern fn ServerWebSocket__getConstructor(*JSC.JSGlobalObject) JSC.JSValue;
+
+ extern fn ServerWebSocket__create(globalObject: *JSC.JSGlobalObject, ptr: ?*ServerWebSocket) JSC.JSValue;
+
+ extern fn ServerWebSocket__dangerouslySetPtr(JSC.JSValue, ?*ServerWebSocket) bool;
+
+ comptime {
+ if (@TypeOf(ServerWebSocket.constructor) != (fn (*JSC.JSGlobalObject, *JSC.CallFrame) callconv(.C) ?*ServerWebSocket)) {
+ @compileLog("ServerWebSocket.constructor is not a constructor");
+ }
+
+ if (@TypeOf(ServerWebSocket.finalize) != (fn (*ServerWebSocket) callconv(.C) void)) {
+ @compileLog("ServerWebSocket.finalize is not a finalizer");
+ }
+
+ if (@TypeOf(ServerWebSocket.close) != CallbackType)
+ @compileLog("Expected ServerWebSocket.close to be a callback");
+ if (@TypeOf(ServerWebSocket.getData) != GetterType)
+ @compileLog("Expected ServerWebSocket.getData to be a getter");
+
+ if (@TypeOf(ServerWebSocket.getBufferedAmount) != CallbackType)
+ @compileLog("Expected ServerWebSocket.getBufferedAmount to be a callback");
+ if (@TypeOf(ServerWebSocket.isSubscribed) != CallbackType)
+ @compileLog("Expected ServerWebSocket.isSubscribed to be a callback");
+ if (@TypeOf(ServerWebSocket.publish) != CallbackType)
+ @compileLog("Expected ServerWebSocket.publish to be a callback");
+ if (@TypeOf(ServerWebSocket.getReadyState) != GetterType)
+ @compileLog("Expected ServerWebSocket.getReadyState to be a getter");
+
+ if (@TypeOf(ServerWebSocket.getRemoteAddress) != GetterType)
+ @compileLog("Expected ServerWebSocket.getRemoteAddress to be a getter");
+
+ if (@TypeOf(ServerWebSocket.send) != CallbackType)
+ @compileLog("Expected ServerWebSocket.send to be a callback");
+ if (@TypeOf(ServerWebSocket.subscribe) != CallbackType)
+ @compileLog("Expected ServerWebSocket.subscribe to be a callback");
+ if (@TypeOf(ServerWebSocket.unsubscribe) != CallbackType)
+ @compileLog("Expected ServerWebSocket.unsubscribe to be a callback");
+ if (!JSC.is_bindgen) {
+ @export(ServerWebSocket.close, .{ .name = "ServerWebSocketPrototype__close" });
+ @export(ServerWebSocket.constructor, .{ .name = "ServerWebSocketClass__construct" });
+ @export(ServerWebSocket.finalize, .{ .name = "ServerWebSocketClass__finalize" });
+ @export(ServerWebSocket.getBufferedAmount, .{ .name = "ServerWebSocketPrototype__getBufferedAmount" });
+ @export(ServerWebSocket.getData, .{ .name = "ServerWebSocketPrototype__getData" });
+ @export(ServerWebSocket.getReadyState, .{ .name = "ServerWebSocketPrototype__getReadyState" });
+ @export(ServerWebSocket.getRemoteAddress, .{ .name = "ServerWebSocketPrototype__getRemoteAddress" });
+ @export(ServerWebSocket.isSubscribed, .{ .name = "ServerWebSocketPrototype__isSubscribed" });
+ @export(ServerWebSocket.publish, .{ .name = "ServerWebSocketPrototype__publish" });
+ @export(ServerWebSocket.send, .{ .name = "ServerWebSocketPrototype__send" });
+ @export(ServerWebSocket.subscribe, .{ .name = "ServerWebSocketPrototype__subscribe" });
+ @export(ServerWebSocket.unsubscribe, .{ .name = "ServerWebSocketPrototype__unsubscribe" });
+ }
+ }
+};
pub const JSTextDecoder = struct {
const TextDecoder = Classes.TextDecoder;
const GetterType = fn (*TextDecoder, *JSC.JSGlobalObject) callconv(.C) JSC.JSValue;
@@ -739,6 +872,14 @@ pub const JSTextDecoder = struct {
return TextDecoder__fromJS(value);
}
+ extern fn TextDecoderPrototype__encodingSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ /// Set the cached value for encoding on TextDecoder
+ /// This value will be visited by the garbage collector.
+ pub fn encodingSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ TextDecoderPrototype__encodingSetCachedValue(thisValue, globalObject, value);
+ }
+
/// Get the TextDecoder constructor value.
/// This loads lazily from the global object.
pub fn getConstructor(globalObject: *JSC.JSGlobalObject) JSC.JSValue {
@@ -810,6 +951,30 @@ pub const JSRequest = struct {
return Request__fromJS(value);
}
+ extern fn RequestPrototype__bodySetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ /// Set the cached value for body on Request
+ /// This value will be visited by the garbage collector.
+ pub fn bodySetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ RequestPrototype__bodySetCachedValue(thisValue, globalObject, value);
+ }
+
+ extern fn RequestPrototype__headersSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ /// Set the cached value for headers on Request
+ /// This value will be visited by the garbage collector.
+ pub fn headersSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ RequestPrototype__headersSetCachedValue(thisValue, globalObject, value);
+ }
+
+ extern fn RequestPrototype__urlSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ /// Set the cached value for url on Request
+ /// This value will be visited by the garbage collector.
+ pub fn urlSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ RequestPrototype__urlSetCachedValue(thisValue, globalObject, value);
+ }
+
/// Get the Request constructor value.
/// This loads lazily from the global object.
pub fn getConstructor(globalObject: *JSC.JSGlobalObject) JSC.JSValue {
@@ -942,6 +1107,38 @@ pub const JSResponse = struct {
return Response__fromJS(value);
}
+ extern fn ResponsePrototype__bodySetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ /// Set the cached value for body on Response
+ /// This value will be visited by the garbage collector.
+ pub fn bodySetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ ResponsePrototype__bodySetCachedValue(thisValue, globalObject, value);
+ }
+
+ extern fn ResponsePrototype__headersSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ /// Set the cached value for headers on Response
+ /// This value will be visited by the garbage collector.
+ pub fn headersSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ ResponsePrototype__headersSetCachedValue(thisValue, globalObject, value);
+ }
+
+ extern fn ResponsePrototype__statusTextSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ /// Set the cached value for statusText on Response
+ /// This value will be visited by the garbage collector.
+ pub fn statusTextSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ ResponsePrototype__statusTextSetCachedValue(thisValue, globalObject, value);
+ }
+
+ extern fn ResponsePrototype__urlSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ /// Set the cached value for url on Response
+ /// This value will be visited by the garbage collector.
+ pub fn urlSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ ResponsePrototype__urlSetCachedValue(thisValue, globalObject, value);
+ }
+
/// Get the Response constructor value.
/// This loads lazily from the global object.
pub fn getConstructor(globalObject: *JSC.JSGlobalObject) JSC.JSValue {
@@ -1154,6 +1351,7 @@ comptime {
_ = JSSHA384;
_ = JSSHA256;
_ = JSSHA512_256;
+ _ = JSServerWebSocket;
_ = JSTextDecoder;
_ = JSRequest;
_ = JSResponse;
diff --git a/src/bun.js/bindings/generated_classes_list.zig b/src/bun.js/bindings/generated_classes_list.zig
index dbfa6c792..0f74343f6 100644
--- a/src/bun.js/bindings/generated_classes_list.zig
+++ b/src/bun.js/bindings/generated_classes_list.zig
@@ -14,4 +14,5 @@ pub const Classes = struct {
pub const TextDecoder = JSC.WebCore.TextDecoder;
pub const Blob = JSC.WebCore.Blob;
pub const Subprocess = JSC.Subprocess;
+ pub const ServerWebSocket = JSC.API.ServerWebSocket;
};
diff --git a/src/bun.js/bindings/headers-cpp.h b/src/bun.js/bindings/headers-cpp.h
index a22987a0c..b64b6cbd0 100644
--- a/src/bun.js/bindings/headers-cpp.h
+++ b/src/bun.js/bindings/headers-cpp.h
@@ -1,4 +1,4 @@
-//-- AUTOGENERATED FILE -- 1665267248
+//-- AUTOGENERATED FILE -- 1665309067
// clang-format off
#pragma once
diff --git a/src/bun.js/bindings/headers.h b/src/bun.js/bindings/headers.h
index f06d534fb..85e865618 100644
--- a/src/bun.js/bindings/headers.h
+++ b/src/bun.js/bindings/headers.h
@@ -1,5 +1,5 @@
// clang-format off
-//-- AUTOGENERATED FILE -- 1665267248
+//-- AUTOGENERATED FILE -- 1665309067
#pragma once
#include <stddef.h>
diff --git a/src/deps/_libusockets.h b/src/deps/_libusockets.h
index 75090aba9..157275686 100644
--- a/src/deps/_libusockets.h
+++ b/src/deps/_libusockets.h
@@ -90,9 +90,10 @@ typedef void (*uws_websocket_ping_pong_handler)(uws_websocket_t *ws,
size_t length);
typedef void (*uws_websocket_close_handler)(uws_websocket_t *ws, int code,
const char *message, size_t length);
-typedef void (*uws_websocket_upgrade_handler)(uws_res_t *response,
+typedef void (*uws_websocket_upgrade_handler)(void *, uws_res_t *response,
uws_req_t *request,
- uws_socket_context_t *context);
+ uws_socket_context_t *context,
+ size_t id);
typedef struct {
uws_compress_options_t compression;
@@ -177,8 +178,9 @@ void uws_filter(int ssl, uws_app_t *app, uws_filter_handler handler,
void *user_data);
// WebSocket
-void uws_ws(int ssl, uws_app_t *app, const char *pattern,
- uws_socket_behavior_t behavior);
+void uws_ws(int ssl, uws_app_t *app, void *upgradeCtx, const char *pattern,
+ size_t pattern_length, size_t id,
+ const uws_socket_behavior_t *behavior);
void *uws_ws_get_user_data(int ssl, uws_websocket_t *ws);
void uws_ws_close(int ssl, uws_websocket_t *ws);
uws_sendstatus_t uws_ws_send(int ssl, uws_websocket_t *ws, const char *message,
diff --git a/src/deps/libuwsockets.cpp b/src/deps/libuwsockets.cpp
index 5acfead19..d542b7ecb 100644
--- a/src/deps/libuwsockets.cpp
+++ b/src/deps/libuwsockets.cpp
@@ -339,8 +339,11 @@ void uws_filter(int ssl, uws_app_t *app, uws_filter_handler handler,
}
}
-void uws_ws(int ssl, uws_app_t *app, const char *pattern,
- uws_socket_behavior_t behavior) {
+void uws_ws(int ssl, uws_app_t *app, void *upgradeContext, const char *pattern,
+ size_t pattern_length, size_t id,
+ const uws_socket_behavior_t *behavior_) {
+ uws_socket_behavior_t behavior = *behavior_;
+
if (ssl) {
auto generic_handler = uWS::SSLApp::WebSocketBehavior<void *>{
.compression = (uWS::CompressOptions)(uint64_t)behavior.compression,
@@ -354,10 +357,10 @@ void uws_ws(int ssl, uws_app_t *app, const char *pattern,
};
if (behavior.upgrade)
- generic_handler.upgrade = [behavior](auto *res, auto *req,
- auto *context) {
- behavior.upgrade((uws_res_t *)res, (uws_req_t *)req,
- (uws_socket_context_t *)context);
+ generic_handler.upgrade = [behavior, upgradeContext,
+ id](auto *res, auto *req, auto *context) {
+ behavior.upgrade(upgradeContext, (uws_res_t *)res, (uws_req_t *)req,
+ (uws_socket_context_t *)context, id);
};
if (behavior.open)
generic_handler.open = [behavior](auto *ws) {
@@ -388,7 +391,8 @@ void uws_ws(int ssl, uws_app_t *app, const char *pattern,
};
uWS::SSLApp *uwsApp = (uWS::SSLApp *)app;
- uwsApp->ws<void *>(pattern, std::move(generic_handler));
+ uwsApp->ws<void *>(std::string(pattern, pattern_length),
+ std::move(generic_handler));
} else {
auto generic_handler = uWS::App::WebSocketBehavior<void *>{
.compression = (uWS::CompressOptions)(uint64_t)behavior.compression,
@@ -402,10 +406,10 @@ void uws_ws(int ssl, uws_app_t *app, const char *pattern,
};
if (behavior.upgrade)
- generic_handler.upgrade = [behavior](auto *res, auto *req,
- auto *context) {
- behavior.upgrade((uws_res_t *)res, (uws_req_t *)req,
- (uws_socket_context_t *)context);
+ generic_handler.upgrade = [behavior, upgradeContext,
+ id](auto *res, auto *req, auto *context) {
+ behavior.upgrade(upgradeContext, (uws_res_t *)res, (uws_req_t *)req,
+ (uws_socket_context_t *)context, id);
};
if (behavior.open)
generic_handler.open = [behavior](auto *ws) {
@@ -435,7 +439,8 @@ void uws_ws(int ssl, uws_app_t *app, const char *pattern,
message.length());
};
uWS::App *uwsApp = (uWS::App *)app;
- uwsApp->ws<void *>(pattern, std::move(generic_handler));
+ uwsApp->ws<void *>(std::string(pattern, pattern_length),
+ std::move(generic_handler));
}
}
diff --git a/src/deps/uws.zig b/src/deps/uws.zig
index d2940f43f..51fa14e24 100644
--- a/src/deps/uws.zig
+++ b/src/deps/uws.zig
@@ -573,28 +573,229 @@ pub const uws_app_t = uws_app_s;
pub const uws_socket_context_s = opaque {};
pub const uws_socket_context_t = uws_socket_context_s;
+pub const AnyWebSocket = union(enum) {
+ ssl: *NewApp(true).WebSocket,
+ tcp: *NewApp(false).WebSocket,
+
+ pub fn raw(this: AnyWebSocket) *RawWebSocket {
+ return switch (this) {
+ .ssl => this.ssl.raw(),
+ .tcp => this.tcp.raw(),
+ };
+ }
+ pub fn as(this: AnyWebSocket, comptime Type: type) ?*Type {
+ @setRuntimeSafety(false);
+ return switch (this) {
+ .ssl => this.ssl.as(Type),
+ .tcp => this.tcp.as(Type),
+ };
+ }
+
+ pub fn close(this: AnyWebSocket) void {
+ const ssl_flag = @boolToInt(this == .ssl);
+ return uws_ws_close(ssl_flag, this.raw());
+ }
+
+ pub fn send(this: AnyWebSocket, message: []const u8, opcode: Opcode, compress: bool, fin: bool) SendStatus {
+ return switch (this) {
+ .ssl => uws_ws_send_with_options(1, this.ssl.raw(), message.ptr, message.len, opcode, compress, fin),
+ .tcp => uws_ws_send_with_options(0, this.tcp.raw(), message.ptr, message.len, opcode, compress, fin),
+ };
+ }
+ pub fn sendLastFragment(this: AnyWebSocket, message: []const u8, compress: bool) SendStatus {
+ switch (this) {
+ .tcp => return uws_ws_send_last_fragment(0, this.raw(), message.ptr, message.len, compress),
+ .ssl => return uws_ws_send_last_fragment(1, this.raw(), message.ptr, message.len, compress),
+ }
+ }
+ pub fn end(this: AnyWebSocket, code: i32, message: []const u8) void {
+ switch (this) {
+ .tcp => uws_ws_end(1, this.tcp.raw(), code, message.ptr, message.len),
+ .ssl => uws_ws_end(0, this.ssl.raw(), code, message.ptr, message.len),
+ }
+ }
+ pub fn cork(this: AnyWebSocket, ctx: anytype, comptime callback: anytype) void {
+ const ContextType = @TypeOf(ctx);
+ const Wrapper = struct {
+ pub fn wrap(user_data: ?*anyopaque) callconv(.C) void {
+ @call(.{ .modifier = .always_inline }, callback, .{bun.cast(ContextType, user_data.?)});
+ }
+ };
+
+ switch (this) {
+ .ssl => uws_ws_cork(1, this.raw(), Wrapper.wrap, ctx),
+ .tcp => uws_ws_cork(0, this.raw(), Wrapper.wrap, ctx),
+ }
+ }
+ pub fn subscribe(this: AnyWebSocket, topic: []const u8) bool {
+ return switch (this) {
+ .ssl => uws_ws_subscribe(0, this.ssl.raw(), topic.ptr, topic.len),
+ .tcp => uws_ws_subscribe(1, this.tcp.raw(), topic.ptr, topic.len),
+ };
+ }
+ pub fn unsubscribe(this: AnyWebSocket, topic: []const u8) bool {
+ return switch (this) {
+ .ssl => uws_ws_unsubscribe(1, this.raw(), topic.ptr, topic.len),
+ .tcp => uws_ws_unsubscribe(0, this.raw(), topic.ptr, topic.len),
+ };
+ }
+ pub fn isSubscribed(this: AnyWebSocket, topic: []const u8) bool {
+ return switch (this) {
+ .ssl => uws_ws_is_subscribed(1, this.raw(), topic.ptr, topic.len),
+ .tcp => uws_ws_is_subscribed(0, this.raw(), topic.ptr, topic.len),
+ };
+ }
+ // pub fn iterateTopics(this: AnyWebSocket) {
+ // return uws_ws_iterate_topics(ssl_flag, this.raw(), callback: ?fn ([*c]const u8, usize, ?*anyopaque) callconv(.C) void, user_data: ?*anyopaque) void;
+ // }
+ pub fn publish(this: AnyWebSocket, topic: []const u8, message: []const u8) bool {
+ return switch (this) {
+ .ssl => uws_ws_publish(1, this.ssl.raw(), topic.ptr, topic.len, message.ptr, message.len),
+ .tcp => uws_ws_publish(0, this.tcp.raw(), topic.ptr, topic.len, message.ptr, message.len),
+ };
+ }
+ pub fn publishWithOptions(this: AnyWebSocket, topic: []const u8, message: []const u8, opcode: Opcode, compress: bool) bool {
+ return switch (this) {
+ .ssl => uws_ws_publish_with_options(1, this.ssl.raw(), topic.ptr, topic.len, message.ptr, message.len, opcode, compress),
+ .tcp => uws_ws_publish_with_options(0, this.tcp.raw(), topic.ptr, topic.len, message.ptr, message.len, opcode, compress),
+ };
+ }
+ pub fn getBufferedAmount(this: AnyWebSocket) u32 {
+ return switch (this) {
+ .ssl => uws_ws_get_buffered_amount(1, this.ssl.raw()),
+ .tcp => uws_ws_get_buffered_amount(0, this.tcp.raw()),
+ };
+ }
+
+ pub fn getRemoteAddress(this: AnyWebSocket, buf: []u8) []u8 {
+ return switch (this) {
+ .ssl => this.ssl.getRemoteAddressAsText(buf),
+ .tcp => this.tcp.getRemoteAddressAsText(buf),
+ };
+ }
+};
+
pub const RawWebSocket = opaque {};
-pub const uws_websocket_handler = ?fn (?*RawWebSocket) callconv(.C) void;
-pub const uws_websocket_message_handler = ?fn (?*RawWebSocket, [*c]const u8, usize, uws_opcode_t) callconv(.C) void;
-pub const uws_websocket_ping_pong_handler = ?fn (?*RawWebSocket, [*c]const u8, usize) callconv(.C) void;
-pub const uws_websocket_close_handler = ?fn (?*RawWebSocket, i32, [*c]const u8, usize) callconv(.C) void;
-pub const uws_websocket_upgrade_handler = ?fn (*uws_res, ?*Request, ?*uws_socket_context_t) callconv(.C) void;
-pub const uws_socket_behavior_t = extern struct {
- compression: uws_compress_options_t,
- maxPayloadLength: c_uint,
- idleTimeout: c_ushort,
- maxBackpressure: c_uint,
- closeOnBackpressureLimit: bool,
- resetIdleTimeoutOnSend: bool,
- sendPingsAutomatically: bool,
- maxLifetime: c_ushort,
- upgrade: uws_websocket_upgrade_handler,
- open: uws_websocket_handler,
- message: uws_websocket_message_handler,
- drain: uws_websocket_handler,
- ping: uws_websocket_ping_pong_handler,
- pong: uws_websocket_ping_pong_handler,
- close: uws_websocket_close_handler,
+
+pub const uws_websocket_handler = ?fn (*RawWebSocket) callconv(.C) void;
+pub const uws_websocket_message_handler = ?fn (*RawWebSocket, [*c]const u8, usize, Opcode) callconv(.C) void;
+pub const uws_websocket_close_handler = ?fn (*RawWebSocket, i32, [*c]const u8, usize) callconv(.C) void;
+pub const uws_websocket_upgrade_handler = ?fn (*anyopaque, *uws_res, *Request, *uws_socket_context_t, usize) callconv(.C) void;
+
+pub const uws_websocket_ping_pong_handler = ?fn (*RawWebSocket, [*c]const u8, usize) callconv(.C) void;
+
+pub const WebSocketBehavior = extern struct {
+ compression: uws_compress_options_t = 0,
+ maxPayloadLength: c_uint = std.math.maxInt(u32),
+ idleTimeout: c_ushort = 120,
+ maxBackpressure: c_uint = 1024 * 1024,
+ closeOnBackpressureLimit: bool = false,
+ resetIdleTimeoutOnSend: bool = true,
+ sendPingsAutomatically: bool = true,
+ maxLifetime: c_ushort = 0,
+ upgrade: uws_websocket_upgrade_handler = null,
+ open: uws_websocket_handler = null,
+ message: uws_websocket_message_handler = null,
+ drain: uws_websocket_handler = null,
+ ping: uws_websocket_ping_pong_handler = null,
+ pong: uws_websocket_ping_pong_handler = null,
+ close: uws_websocket_close_handler = null,
+
+ pub fn Wrap(
+ comptime ServerType: type,
+ comptime Type: type,
+ comptime ssl: bool,
+ ) type {
+ return extern struct {
+ const is_ssl = ssl;
+ const WebSocket = NewApp(is_ssl).WebSocket;
+ const Server = ServerType;
+
+ const active_field_name = if (is_ssl) "ssl" else "tcp";
+
+ pub fn _open(raw_ws: *RawWebSocket) callconv(.C) void {
+ var ws = @unionInit(AnyWebSocket, active_field_name, @ptrCast(*WebSocket, raw_ws));
+ var this = ws.as(Type).?;
+ @call(.{ .modifier = .always_inline }, Type.onOpen, .{ this, ws });
+ }
+ pub fn _message(raw_ws: *RawWebSocket, message: [*c]const u8, length: usize, opcode: Opcode) callconv(.C) void {
+ var ws = @unionInit(AnyWebSocket, active_field_name, @ptrCast(*WebSocket, raw_ws));
+ var this = ws.as(Type).?;
+ @call(
+ .{ .modifier = .always_inline },
+ Type.onMessage,
+ .{ this, ws, if (length > 0) message.?[0..length] else "", opcode },
+ );
+ }
+ pub fn _drain(raw_ws: *RawWebSocket) callconv(.C) void {
+ var ws = @unionInit(AnyWebSocket, active_field_name, @ptrCast(*WebSocket, raw_ws));
+ var this = ws.as(Type).?;
+ @call(.{ .modifier = .always_inline }, Type.onDrain, .{
+ this,
+ ws,
+ });
+ }
+ pub fn _ping(raw_ws: *RawWebSocket, message: [*c]const u8, length: usize) callconv(.C) void {
+ var ws = @unionInit(AnyWebSocket, active_field_name, @ptrCast(*WebSocket, raw_ws));
+ var this = ws.as(Type).?;
+ @call(.{ .modifier = .always_inline }, Type.onPing, .{
+ this,
+ ws,
+ if (length > 0) message.?[0..length] else "",
+ });
+ }
+ pub fn _pong(raw_ws: *RawWebSocket, message: [*c]const u8, length: usize) callconv(.C) void {
+ var ws = @unionInit(AnyWebSocket, active_field_name, @ptrCast(*WebSocket, raw_ws));
+ var this = ws.as(Type).?;
+ @call(.{ .modifier = .always_inline }, Type.onPong, .{
+ this,
+ ws,
+ if (length > 0) message.?[0..length] else "",
+ });
+ }
+ pub fn _close(raw_ws: *RawWebSocket, code: i32, message: [*c]const u8, length: usize) callconv(.C) void {
+ var ws = @unionInit(AnyWebSocket, active_field_name, @ptrCast(*WebSocket, raw_ws));
+ var this = ws.as(Type).?;
+ @call(
+ .{ .modifier = .always_inline },
+ Type.onClose,
+ .{
+ this,
+ ws,
+ code,
+ if (length > 0) message.?[0..length] else "",
+ },
+ );
+ }
+ pub fn _upgrade(ptr: *anyopaque, res: *uws_res, req: *Request, context: *uws_socket_context_t, id: usize) callconv(.C) void {
+ @call(
+ .{ .modifier = .always_inline },
+ Server.onWebSocketUpgrade,
+ .{ bun.cast(*Server, ptr), @ptrCast(*NewApp(is_ssl).Response, res), req, context, id },
+ );
+ }
+
+ pub fn apply(behavior: WebSocketBehavior) WebSocketBehavior {
+ return WebSocketBehavior{
+ .compression = behavior.compression,
+ .maxPayloadLength = behavior.maxPayloadLength,
+ .idleTimeout = behavior.idleTimeout,
+ .maxBackpressure = behavior.maxBackpressure,
+ .closeOnBackpressureLimit = behavior.closeOnBackpressureLimit,
+ .resetIdleTimeoutOnSend = behavior.resetIdleTimeoutOnSend,
+ .sendPingsAutomatically = behavior.sendPingsAutomatically,
+ .maxLifetime = behavior.maxLifetime,
+ .upgrade = _upgrade,
+ .open = _open,
+ .message = _message,
+ .drain = _drain,
+ .ping = _ping,
+ .pong = _pong,
+ .close = _close,
+ };
+ }
+ };
+ }
};
pub const uws_listen_handler = ?fn (?*listen_socket_t, ?*anyopaque) callconv(.C) void;
pub const uws_method_handler = ?fn (*uws_res, *Request, ?*anyopaque) callconv(.C) void;
@@ -886,7 +1087,7 @@ pub fn NewApp(comptime ssl: bool) type {
pub fn num_subscribers(app: *ThisApp, topic: [:0]const u8) c_uint {
return uws_num_subscribers(ssl_flag, @ptrCast(*uws_app_t, app), topic);
}
- pub fn publish(app: *ThisApp, topic: []const u8, message: []const u8, opcode: uws_opcode_t, compress: bool) bool {
+ pub fn publish(app: *ThisApp, topic: []const u8, message: []const u8, opcode: Opcode, compress: bool) bool {
return uws_publish(ssl_flag, @ptrCast(*uws_app_t, app), topic.ptr, topic.len, message.ptr, message.len, opcode, compress);
}
pub fn getNativeHandle(app: *ThisApp) ?*anyopaque {
@@ -907,8 +1108,9 @@ pub fn NewApp(comptime ssl: bool) type {
pub fn filter(app: *ThisApp, handler: uws_filter_handler, user_data: ?*anyopaque) void {
return uws_filter(ssl_flag, @ptrCast(*uws_app_t, app), handler, user_data);
}
- pub fn ws(app: *ThisApp, pattern: [:0]const u8, behavior: uws_socket_behavior_t) void {
- return uws_ws(ssl_flag, @ptrCast(*uws_app_t, app), pattern, behavior);
+ pub fn ws(app: *ThisApp, pattern: []const u8, ctx: *anyopaque, id: usize, behavior_: WebSocketBehavior) void {
+ var behavior = behavior_;
+ uws_ws(ssl_flag, @ptrCast(*uws_app_t, app), ctx, pattern.ptr, pattern.len, id, &behavior);
}
pub const Response = opaque {
@@ -1158,78 +1360,102 @@ pub fn NewApp(comptime ssl: bool) type {
uws_res_write_headers(ssl_flag, res.downcast(), names.ptr, values.ptr, values.len, buf.ptr);
}
- pub const WebSocket = opaque {
- pub fn raw(this: *WebSocket) *RawWebSocket {
- return @ptrCast(*RawWebSocket, this);
- }
- pub fn as(this: *WebSocket, comptime Type: type) ?*Type {
- @setRuntimeSafety(false);
- return @ptrCast(*?Type, @alignCast(@alignOf(Type), uws_ws_get_user_data(this))).*;
- }
+ pub fn upgrade(
+ res: *Response,
+ comptime Data: type,
+ data: Data,
+ sec_web_socket_key: []const u8,
+ sec_web_socket_protocol: []const u8,
+ sec_web_socket_extensions: []const u8,
+ ctx: ?*uws_socket_context_t,
+ ) void {
+ uws_res_upgrade(
+ ssl_flag,
+ res.downcast(),
+ data,
+ sec_web_socket_key.ptr,
+ sec_web_socket_key.len,
+ sec_web_socket_protocol.ptr,
+ sec_web_socket_protocol.len,
+ sec_web_socket_extensions.ptr,
+ sec_web_socket_extensions.len,
+ ctx,
+ );
+ }
+ };
- pub fn close(this: *WebSocket) void {
- return uws_ws_close(ssl_flag, this.raw());
- }
- pub fn send(this: *WebSocket, message: []const u8, opcode: uws_opcode_t) SendStatus {
- return uws_ws_send(ssl_flag, this.raw(), message.ptr, message.len, opcode);
- }
- pub fn sendWithOptions(this: *WebSocket, message: []const u8, opcode: uws_opcode_t, compress: bool, fin: bool) SendStatus {
- return uws_ws_send_with_options(ssl_flag, this.raw(), message.ptr, message.len, opcode, compress, fin);
- }
- // pub fn sendFragment(this: *WebSocket, message: []const u8) SendStatus {
- // return uws_ws_send_fragment(ssl_flag, this.raw(), message: [*c]const u8, length: usize, compress: bool);
- // }
- // pub fn sendFirstFragment(this: *WebSocket, message: []const u8) SendStatus {
- // return uws_ws_send_first_fragment(ssl_flag, this.raw(), message: [*c]const u8, length: usize, compress: bool);
- // }
- // pub fn sendFirstFragmentWithOpcode(this: *WebSocket, message: []const u8, opcode: u32, compress: bool) SendStatus {
- // return uws_ws_send_first_fragment_with_opcode(ssl_flag, this.raw(), message: [*c]const u8, length: usize, opcode: uws_opcode_t, compress: bool);
- // }
- pub fn sendLastFragment(this: *WebSocket, message: []const u8, compress: bool) SendStatus {
- return uws_ws_send_last_fragment(ssl_flag, this.raw(), message.ptr, message.len, compress);
- }
- pub fn end(this: *WebSocket, code: i32, message: []const u8) void {
- return uws_ws_end(ssl_flag, this.raw(), code, message.ptr, message.len);
- }
- pub fn cork(this: *WebSocket, ctx: anytype, comptime callback: anytype) void {
- const ContextType = @TypeOf(ctx);
- const Wrapper = struct {
- pub fn wrap(user_data: ?*anyopaque) callconv(.C) void {
- @call(.{ .modifier = .always_inline }, callback, .{bun.cast(ContextType, user_data.?)});
- }
- };
+ pub const WebSocket = opaque {
+ pub fn raw(this: *WebSocket) *RawWebSocket {
+ return @ptrCast(*RawWebSocket, this);
+ }
+ pub fn as(this: *WebSocket, comptime Type: type) ?*Type {
+ @setRuntimeSafety(false);
+ return @ptrCast(?*Type, @alignCast(@alignOf(Type), uws_ws_get_user_data(ssl_flag, this.raw())));
+ }
- return uws_ws_cork(ssl_flag, this.raw(), Wrapper.wrap, ctx);
- }
- pub fn subscribe(this: *WebSocket, topic: []const u8) bool {
- return uws_ws_subscribe(ssl_flag, this.raw(), topic.ptr, topic.len);
- }
- pub fn unsubscribe(this: *WebSocket, topic: []const u8) bool {
- return uws_ws_unsubscribe(ssl_flag, this.raw(), topic.ptr, topic.len);
- }
- pub fn isSubscribed(this: *WebSocket, topic: []const u8) bool {
- return uws_ws_is_subscribed(ssl_flag, this.raw(), topic.ptr, topic.len);
- }
- // pub fn iterateTopics(this: *WebSocket) {
- // return uws_ws_iterate_topics(ssl_flag, this.raw(), callback: ?fn ([*c]const u8, usize, ?*anyopaque) callconv(.C) void, user_data: ?*anyopaque) void;
- // }
- pub fn publish(this: *WebSocket, topic: []const u8, message: []const u8) bool {
- return uws_ws_publish(ssl_flag, this.raw(), topic.ptr, topic.len, message.ptr, message.len);
- }
- pub fn publishWithOptions(this: *WebSocket, topic: []const u8, message: []const u8, opcode: uws_opcode_t, compress: bool) bool {
- return uws_ws_publish_with_options(ssl_flag, this.raw(), topic.ptr, topic.len, message.ptr, message.len, opcode, compress);
- }
- pub fn getBufferedAmount(this: *WebSocket) u32 {
- return uws_ws_get_buffered_amount(ssl_flag, this.raw());
- }
- pub fn getRemoteAddress(this: *WebSocket, buf: []u8) []u8 {
- return buf[0..uws_ws_get_remote_address(ssl_flag, this.raw(), &buf.ptr)];
- }
+ pub fn close(this: *WebSocket) void {
+ return uws_ws_close(ssl_flag, this.raw());
+ }
+ pub fn send(this: *WebSocket, message: []const u8, opcode: Opcode) SendStatus {
+ return uws_ws_send(ssl_flag, this.raw(), message.ptr, message.len, opcode);
+ }
+ pub fn sendWithOptions(this: *WebSocket, message: []const u8, opcode: Opcode, compress: bool, fin: bool) SendStatus {
+ return uws_ws_send_with_options(ssl_flag, this.raw(), message.ptr, message.len, opcode, compress, fin);
+ }
+ // pub fn sendFragment(this: *WebSocket, message: []const u8) SendStatus {
+ // return uws_ws_send_fragment(ssl_flag, this.raw(), message: [*c]const u8, length: usize, compress: bool);
+ // }
+ // pub fn sendFirstFragment(this: *WebSocket, message: []const u8) SendStatus {
+ // return uws_ws_send_first_fragment(ssl_flag, this.raw(), message: [*c]const u8, length: usize, compress: bool);
+ // }
+ // pub fn sendFirstFragmentWithOpcode(this: *WebSocket, message: []const u8, opcode: u32, compress: bool) SendStatus {
+ // return uws_ws_send_first_fragment_with_opcode(ssl_flag, this.raw(), message: [*c]const u8, length: usize, opcode: Opcode, compress: bool);
+ // }
+ pub fn sendLastFragment(this: *WebSocket, message: []const u8, compress: bool) SendStatus {
+ return uws_ws_send_last_fragment(ssl_flag, this.raw(), message.ptr, message.len, compress);
+ }
+ pub fn end(this: *WebSocket, code: i32, message: []const u8) void {
+ return uws_ws_end(ssl_flag, this.raw(), code, message.ptr, message.len);
+ }
+ pub fn cork(this: *WebSocket, ctx: anytype, comptime callback: anytype) void {
+ const ContextType = @TypeOf(ctx);
+ const Wrapper = struct {
+ pub fn wrap(user_data: ?*anyopaque) callconv(.C) void {
+ @call(.{ .modifier = .always_inline }, callback, .{bun.cast(ContextType, user_data.?)});
+ }
+ };
- pub fn getRemoteAddressAsText(this: *WebSocket, buf: []u8) []u8 {
- return buf[0..uws_ws_get_remote_address_as_text(ssl_flag, this.raw(), &buf.ptr)];
- }
- };
+ return uws_ws_cork(ssl_flag, this.raw(), Wrapper.wrap, ctx);
+ }
+ pub fn subscribe(this: *WebSocket, topic: []const u8) bool {
+ return uws_ws_subscribe(ssl_flag, this.raw(), topic.ptr, topic.len);
+ }
+ pub fn unsubscribe(this: *WebSocket, topic: []const u8) bool {
+ return uws_ws_unsubscribe(ssl_flag, this.raw(), topic.ptr, topic.len);
+ }
+ pub fn isSubscribed(this: *WebSocket, topic: []const u8) bool {
+ return uws_ws_is_subscribed(ssl_flag, this.raw(), topic.ptr, topic.len);
+ }
+ // pub fn iterateTopics(this: *WebSocket) {
+ // return uws_ws_iterate_topics(ssl_flag, this.raw(), callback: ?fn ([*c]const u8, usize, ?*anyopaque) callconv(.C) void, user_data: ?*anyopaque) void;
+ // }
+ pub fn publish(this: *WebSocket, topic: []const u8, message: []const u8) bool {
+ return uws_ws_publish(ssl_flag, this.raw(), topic.ptr, topic.len, message.ptr, message.len);
+ }
+ pub fn publishWithOptions(this: *WebSocket, topic: []const u8, message: []const u8, opcode: Opcode, compress: bool) bool {
+ return uws_ws_publish_with_options(ssl_flag, this.raw(), topic.ptr, topic.len, message.ptr, message.len, opcode, compress);
+ }
+ pub fn getBufferedAmount(this: *WebSocket) u32 {
+ return uws_ws_get_buffered_amount(ssl_flag, this.raw());
+ }
+ pub fn getRemoteAddress(this: *WebSocket, buf: []u8) []u8 {
+ return buf[0..uws_ws_get_remote_address(ssl_flag, this.raw(), &buf.ptr)];
+ }
+
+ pub fn getRemoteAddressAsText(this: *WebSocket, buf: []u8) []u8 {
+ var copy = buf;
+ return buf[0..uws_ws_get_remote_address_as_text(ssl_flag, this.raw(), &copy.ptr)];
+ }
};
};
}
@@ -1261,22 +1487,22 @@ extern fn uws_app_listen_with_config(
) void;
extern fn uws_constructor_failed(ssl: i32, app: *uws_app_t) bool;
extern fn uws_num_subscribers(ssl: i32, app: *uws_app_t, topic: [*c]const u8) c_uint;
-extern fn uws_publish(ssl: i32, app: *uws_app_t, topic: [*c]const u8, topic_length: usize, message: [*c]const u8, message_length: usize, opcode: uws_opcode_t, compress: bool) bool;
+extern fn uws_publish(ssl: i32, app: *uws_app_t, topic: [*c]const u8, topic_length: usize, message: [*c]const u8, message_length: usize, opcode: Opcode, compress: bool) bool;
extern fn uws_get_native_handle(ssl: i32, app: *uws_app_t) ?*anyopaque;
extern fn uws_remove_server_name(ssl: i32, app: *uws_app_t, hostname_pattern: [*c]const u8) void;
extern fn uws_add_server_name(ssl: i32, app: *uws_app_t, hostname_pattern: [*c]const u8) void;
extern fn uws_add_server_name_with_options(ssl: i32, app: *uws_app_t, hostname_pattern: [*c]const u8, options: us_socket_context_options_t) void;
extern fn uws_missing_server_name(ssl: i32, app: *uws_app_t, handler: uws_missing_server_handler, user_data: ?*anyopaque) void;
extern fn uws_filter(ssl: i32, app: *uws_app_t, handler: uws_filter_handler, user_data: ?*anyopaque) void;
-extern fn uws_ws(ssl: i32, app: *uws_app_t, pattern: [*c]const u8, behavior: uws_socket_behavior_t) void;
+extern fn uws_ws(ssl: i32, app: *uws_app_t, ctx: *anyopaque, pattern: [*]const u8, pattern_len: usize, id: usize, behavior: *const WebSocketBehavior) void;
extern fn uws_ws_get_user_data(ssl: i32, ws: ?*RawWebSocket) ?*anyopaque;
extern fn uws_ws_close(ssl: i32, ws: ?*RawWebSocket) void;
-extern fn uws_ws_send(ssl: i32, ws: ?*RawWebSocket, message: [*c]const u8, length: usize, opcode: uws_opcode_t) SendStatus;
-extern fn uws_ws_send_with_options(ssl: i32, ws: ?*RawWebSocket, message: [*c]const u8, length: usize, opcode: uws_opcode_t, compress: bool, fin: bool) SendStatus;
+extern fn uws_ws_send(ssl: i32, ws: ?*RawWebSocket, message: [*c]const u8, length: usize, opcode: Opcode) SendStatus;
+extern fn uws_ws_send_with_options(ssl: i32, ws: ?*RawWebSocket, message: [*c]const u8, length: usize, opcode: Opcode, compress: bool, fin: bool) SendStatus;
extern fn uws_ws_send_fragment(ssl: i32, ws: ?*RawWebSocket, message: [*c]const u8, length: usize, compress: bool) SendStatus;
extern fn uws_ws_send_first_fragment(ssl: i32, ws: ?*RawWebSocket, message: [*c]const u8, length: usize, compress: bool) SendStatus;
-extern fn uws_ws_send_first_fragment_with_opcode(ssl: i32, ws: ?*RawWebSocket, message: [*c]const u8, length: usize, opcode: uws_opcode_t, compress: bool) SendStatus;
+extern fn uws_ws_send_first_fragment_with_opcode(ssl: i32, ws: ?*RawWebSocket, message: [*c]const u8, length: usize, opcode: Opcode, compress: bool) SendStatus;
extern fn uws_ws_send_last_fragment(ssl: i32, ws: ?*RawWebSocket, message: [*c]const u8, length: usize, compress: bool) SendStatus;
extern fn uws_ws_end(ssl: i32, ws: ?*RawWebSocket, code: i32, message: [*c]const u8, length: usize) void;
extern fn uws_ws_cork(ssl: i32, ws: ?*RawWebSocket, handler: ?fn (?*anyopaque) callconv(.C) void, user_data: ?*anyopaque) void;
@@ -1285,10 +1511,10 @@ extern fn uws_ws_unsubscribe(ssl: i32, ws: ?*RawWebSocket, topic: [*c]const u8,
extern fn uws_ws_is_subscribed(ssl: i32, ws: ?*RawWebSocket, topic: [*c]const u8, length: usize) bool;
extern fn uws_ws_iterate_topics(ssl: i32, ws: ?*RawWebSocket, callback: ?fn ([*c]const u8, usize, ?*anyopaque) callconv(.C) void, user_data: ?*anyopaque) void;
extern fn uws_ws_publish(ssl: i32, ws: ?*RawWebSocket, topic: [*c]const u8, topic_length: usize, message: [*c]const u8, message_length: usize) bool;
-extern fn uws_ws_publish_with_options(ssl: i32, ws: ?*RawWebSocket, topic: [*c]const u8, topic_length: usize, message: [*c]const u8, message_length: usize, opcode: uws_opcode_t, compress: bool) bool;
+extern fn uws_ws_publish_with_options(ssl: i32, ws: ?*RawWebSocket, topic: [*c]const u8, topic_length: usize, message: [*c]const u8, message_length: usize, opcode: Opcode, compress: bool) bool;
extern fn uws_ws_get_buffered_amount(ssl: i32, ws: ?*RawWebSocket) c_uint;
-extern fn uws_ws_get_remote_address(ssl: i32, ws: ?*RawWebSocket, dest: [*c][*c]const u8) usize;
-extern fn uws_ws_get_remote_address_as_text(ssl: i32, ws: ?*RawWebSocket, dest: [*c][*c]const u8) usize;
+extern fn uws_ws_get_remote_address(ssl: i32, ws: ?*RawWebSocket, dest: *[*]u8) usize;
+extern fn uws_ws_get_remote_address_as_text(ssl: i32, ws: ?*RawWebSocket, dest: *[*]u8) usize;
const uws_res = opaque {};
extern fn uws_res_uncork(ssl: i32, res: *uws_res) void;
extern fn uws_res_end(ssl: i32, res: *uws_res, data: [*c]const u8, length: usize, close_connection: bool) void;
@@ -1361,14 +1587,23 @@ pub const DEDICATED_COMPRESSOR_64KB: i32 = 214;
pub const DEDICATED_COMPRESSOR_128KB: i32 = 231;
pub const DEDICATED_COMPRESSOR_256KB: i32 = 248;
pub const DEDICATED_COMPRESSOR: i32 = 248;
-pub const uws_compress_options_t = c_uint;
+pub const uws_compress_options_t = i32;
pub const CONTINUATION: i32 = 0;
pub const TEXT: i32 = 1;
pub const BINARY: i32 = 2;
pub const CLOSE: i32 = 8;
pub const PING: i32 = 9;
pub const PONG: i32 = 10;
-pub const uws_opcode_t = c_uint;
+
+pub const Opcode = enum(i32) {
+ text = 1,
+ binary = 2,
+ close = 8,
+ ping = 9,
+ pong = 10,
+ _,
+};
+
pub const SendStatus = enum(c_uint) {
backpressure = 0,
success = 1,
diff --git a/src/jsc.zig b/src/jsc.zig
index f4adbcc3a..df0bbec6c 100644
--- a/src/jsc.zig
+++ b/src/jsc.zig
@@ -26,6 +26,7 @@ pub const Jest = @import("./bun.js/test/jest.zig");
pub const API = struct {
pub const Transpiler = @import("./bun.js/api/transpiler.zig");
pub const Server = @import("./bun.js/api/server.zig").Server;
+ pub const ServerWebSocket = @import("./bun.js/api/server.zig").ServerWebSocket;
pub const SSLServer = @import("./bun.js/api/server.zig").SSLServer;
pub const DebugServer = @import("./bun.js/api/server.zig").DebugServer;
pub const DebugSSLServer = @import("./bun.js/api/server.zig").DebugSSLServer;