js: flesh out some of the props exposed on Bun.connect Socket (#18761)

This commit is contained in:
Meghan Denny
2025-04-03 15:36:56 -08:00
committed by GitHub
parent 94addcf2a5
commit 04a432f54f
6 changed files with 104 additions and 11 deletions

View File

@@ -2870,7 +2870,7 @@ declare module "bun" {
* outdir: './dist',
* env: 'inline'
* });
* // Only include specific env vars
* await Bun.build({
* entrypoints: ['./src/index.tsx'],
@@ -2896,12 +2896,12 @@ declare module "bun" {
* const result = await Bun.build({
* entrypoints: ['./src/index.tsx']
* });
* for (const artifact of result.outputs) {
* const text = await artifact.text();
* const buffer = await artifact.arrayBuffer();
* const bytes = await artifact.bytes();
* new Response(artifact);
* await Bun.write(artifact.path, artifact);
* }
@@ -5889,11 +5889,19 @@ declare module "bun" {
*/
readonly listener?: SocketListener;
readonly remoteFamily: "IPv4" | "IPv6";
/**
* Remote IP address connected to the socket
*/
readonly remoteAddress: string;
readonly remotePort: number;
readonly localFamily: "IPv4" | "IPv6";
readonly localAddress: string;
/**
* local port connected to the socket
*/

View File

@@ -37,6 +37,15 @@ int us_socket_local_port(int ssl, struct us_socket_t *s) {
}
}
int us_socket_remote_port(int ssl, struct us_socket_t *s) {
struct bsd_addr_t addr;
if (bsd_remote_addr(us_poll_fd(&s->p), &addr)) {
return -1;
} else {
return bsd_addr_get_port(&addr);
}
}
void us_socket_shutdown_read(int ssl, struct us_socket_t *s) {
/* This syscall is idempotent so no extra check is needed */
bsd_shutdown_socket_read(us_poll_fd((struct us_poll_t *) s));

View File

@@ -2088,10 +2088,40 @@ fn NewSocket(comptime ssl: bool) type {
};
}
pub fn getLocalPort(
this: *This,
_: *JSC.JSGlobalObject,
) JSValue {
pub fn getLocalFamily(this: *This, globalThis: *JSC.JSGlobalObject) JSValue {
if (this.socket.isDetached()) {
return JSValue.jsUndefined();
}
var buf: [64]u8 = [_]u8{0} ** 64;
const address_bytes: []const u8 = this.socket.localAddress(&buf) orelse return JSValue.jsUndefined();
return switch (address_bytes.len) {
4 => bun.String.static("IPv4").toJS(globalThis),
16 => bun.String.static("IPv6").toJS(globalThis),
else => return JSValue.jsUndefined(),
};
}
pub fn getLocalAddress(this: *This, globalThis: *JSC.JSGlobalObject) JSValue {
if (this.socket.isDetached()) {
return JSValue.jsUndefined();
}
var buf: [64]u8 = [_]u8{0} ** 64;
var text_buf: [512]u8 = undefined;
const address_bytes: []const u8 = this.socket.localAddress(&buf) orelse return JSValue.jsUndefined();
const address: std.net.Address = switch (address_bytes.len) {
4 => std.net.Address.initIp4(address_bytes[0..4].*, 0),
16 => std.net.Address.initIp6(address_bytes[0..16].*, 0, 0, 0),
else => return JSValue.jsUndefined(),
};
const text = bun.fmt.formatIp(address, &text_buf) catch unreachable;
return ZigString.init(text).toJS(globalThis);
}
pub fn getLocalPort(this: *This, _: *JSC.JSGlobalObject) JSValue {
if (this.socket.isDetached()) {
return JSValue.jsUndefined();
}
@@ -2099,10 +2129,21 @@ fn NewSocket(comptime ssl: bool) type {
return JSValue.jsNumber(this.socket.localPort());
}
pub fn getRemoteAddress(
this: *This,
globalThis: *JSC.JSGlobalObject,
) JSValue {
pub fn getRemoteFamily(this: *This, globalThis: *JSC.JSGlobalObject) JSValue {
if (this.socket.isDetached()) {
return JSValue.jsUndefined();
}
var buf: [64]u8 = [_]u8{0} ** 64;
const address_bytes: []const u8 = this.socket.remoteAddress(&buf) orelse return JSValue.jsUndefined();
return switch (address_bytes.len) {
4 => bun.String.static("IPv4").toJS(globalThis),
16 => bun.String.static("IPv6").toJS(globalThis),
else => return JSValue.jsUndefined(),
};
}
pub fn getRemoteAddress(this: *This, globalThis: *JSC.JSGlobalObject) JSValue {
if (this.socket.isDetached()) {
return JSValue.jsUndefined();
}
@@ -2121,6 +2162,14 @@ fn NewSocket(comptime ssl: bool) type {
return ZigString.init(text).toJS(globalThis);
}
pub fn getRemotePort(this: *This, _: *JSC.JSGlobalObject) JSValue {
if (this.socket.isDetached()) {
return JSValue.jsUndefined();
}
return JSValue.jsNumber(this.socket.remotePort());
}
pub fn writeMaybeCorked(this: *This, buffer: []const u8) i32 {
if (this.socket.isShutdown() or this.socket.isClosed()) {
return -1;

View File

@@ -150,6 +150,14 @@ function generate(ssl) {
length: 0,
},
localFamily: {
getter: "getLocalFamily",
cache: true,
},
localAddress: {
getter: "getLocalAddress",
cache: true,
},
localPort: {
getter: "getLocalPort",
},
@@ -170,10 +178,17 @@ function generate(ssl) {
// getter: "getTopics",
// },
remoteFamily: {
getter: "getRemoteFamily",
cache: true,
},
remoteAddress: {
getter: "getRemoteAddress",
cache: true,
},
remotePort: {
getter: "getRemotePort",
},
reload: {
fn: "reload",

View File

@@ -1653,6 +1653,13 @@ pub fn NewSocketHandler(comptime is_ssl: bool) type {
};
}
pub fn remotePort(this: ThisSocket) i32 {
return switch (this.socket) {
.connected => |socket| socket.remotePort(is_ssl),
.pipe, .upgradedDuplex, .connecting, .detached => 0,
};
}
/// `buf` cannot be longer than 2^31 bytes long.
pub fn remoteAddress(this: ThisSocket, buf: []u8) ?[]const u8 {
return switch (this.socket) {

View File

@@ -62,6 +62,10 @@ pub const Socket = opaque {
return us_socket_local_port(@intFromBool(ssl), this);
}
pub fn remotePort(this: *Socket, ssl: bool) i32 {
return us_socket_remote_port(@intFromBool(ssl), this);
}
/// Returned slice is a view into `buf`.
pub fn localAddress(this: *Socket, ssl: bool, buf: []u8) ![]const u8 {
var length: i32 = @intCast(buf.len);
@@ -151,6 +155,7 @@ pub const Socket = opaque {
extern fn us_socket_get_native_handle(ssl: i32, s: ?*Socket) ?*anyopaque;
extern fn us_socket_local_port(ssl: i32, s: ?*Socket) i32;
extern fn us_socket_remote_port(ssl: i32, s: ?*Socket) i32;
extern fn us_socket_remote_address(ssl: i32, s: ?*Socket, buf: [*c]u8, length: [*c]i32) void;
extern fn us_socket_local_address(ssl: i32, s: ?*Socket, buf: [*c]u8, length: [*c]i32) void;
extern fn us_socket_timeout(ssl: i32, s: ?*Socket, seconds: c_uint) void;