Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add node:net module #3315

Merged
merged 7 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 64 additions & 18 deletions build/wd_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -65,30 +65,71 @@ def _wd_test_impl(ctx):
if is_windows:
# Batch script executables must end with ".bat"
executable = ctx.actions.declare_file("%s_wd_test.bat" % ctx.label.name)
ctx.actions.write(
output = executable,
# PowerShell correctly handles forward slashes in executable paths generated by Bazel (e.g. "bazel-bin/src/workerd/server/workerd.exe")
content = "powershell -Command \"%*\" `-dTEST_TMPDIR=$ENV:TEST_TMPDIR\r\n",
is_executable = True,
)
content = """
@echo off
setlocal EnableDelayedExpansion

REM Start sidecar if specified
if not "%SIDECAR%" == "" (
start /b "" "%SIDECAR%" > nul 2>&1
set SIDECAR_PID=!ERRORLEVEL!
timeout /t 1 > nul
)

REM Run the actual test
powershell -Command \"%*\" `-dTEST_TMPDIR=$ENV:TEST_TMPDIR
set TEST_EXIT=!ERRORLEVEL!

REM Cleanup sidecar if it was started
if defined SIDECAR_PID (
taskkill /F /PID !SIDECAR_PID! > nul 2>&1
)

exit /b !TEST_EXIT!
""".replace("$(SIDECAR)", ctx.file.sidecar.path if ctx.file.sidecar else "")
else:
executable = ctx.outputs.executable
ctx.actions.write(
output = executable,
content = """
#! /bin/sh
echo
echo \\(cd `pwd` \\&\\& \"$@\" -dTEST_TMPDIR=$TEST_TMPDIR\\)
echo
exec \"$@\" -dTEST_TMPDIR=$TEST_TMPDIR
""",
is_executable = True,
)
content = """#!/bin/sh
set -e

cleanup() {
if [ ! -z "$SIDECAR_PID" ]; then
kill $SIDECAR_PID 2>/dev/null || true
fi
}

trap cleanup EXIT

# Start sidecar if specified
if [ ! -z "$(SIDECAR)" ]; then
"$(SIDECAR)" & SIDECAR_PID=$!
# Wait until the process is ready
sleep 3
fi

# Run the actual test
"$@" -dTEST_TMPDIR=$TEST_TMPDIR
""".replace("$(SIDECAR)", ctx.file.sidecar.short_path if ctx.file.sidecar else "")

ctx.actions.write(
output = executable,
content = content,
is_executable = True,
)

runfiles = ctx.runfiles(files = ctx.files.data)
if ctx.file.sidecar:
runfiles = runfiles.merge(ctx.runfiles(files = [ctx.file.sidecar]))

# Also merge the sidecar's own runfiles if it has any
default_runfiles = ctx.attr.sidecar[DefaultInfo].default_runfiles
if default_runfiles:
runfiles = runfiles.merge(default_runfiles)

return [
DefaultInfo(
executable = executable,
runfiles = ctx.runfiles(files = ctx.files.data),
runfiles = runfiles,
),
]

Expand All @@ -104,6 +145,11 @@ _wd_test = rule(
),
"flags": attr.string_list(),
"data": attr.label_list(allow_files = True),
"sidecar": attr.label(
allow_single_file = True,
executable = True,
cfg = "exec",
),
"_platforms_os_windows": attr.label(default = "@platforms//os:windows"),
},
)
49 changes: 49 additions & 0 deletions src/node/internal/internal_errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,55 @@ export class DnsError extends NodeError {
}
}

export class ERR_OPTION_NOT_IMPLEMENTED extends NodeError {
constructor(name: string | symbol) {
if (typeof name === 'symbol') {
name = (name as symbol).description!;
}
super(
'ERR_OPTION_NOT_IMPLEMENTED',
`The ${name} option is not implemented`
);
}
}

export class ERR_SOCKET_BAD_PORT extends NodeError {
constructor(name: string, port: any, allowZero: boolean) {
const operator = allowZero ? '>=' : '>';
super(
'ERR_SOCKET_BAD_PORT',
`${name} should be ${operator} 0 and < 65536. Received ${typeof port}.`
);
}
}

export class EPIPE extends NodeError {
constructor() {
super('EPIPE', 'This socket has been ended by the other party');
}
}

export class ERR_SOCKET_CLOSED_BEFORE_CONNECTION extends NodeError {
constructor() {
super(
'ERR_SOCKET_CLOSED_BEFORE_CONNETION',
'Socket closed before connection established'
);
}
}

export class ERR_SOCKET_CLOSED extends NodeError {
constructor() {
super('ERR_SOCKET_CLOSED', 'Socket is closed');
}
}

export class ERR_SOCKET_CONNECTING extends NodeError {
constructor() {
super('ERR_SOCKET_CONNECTING', 'Socket is already connecting');
}
}

export function aggregateTwoErrors(innerError: any, outerError: any) {
if (innerError && outerError && innerError !== outerError) {
if (Array.isArray(outerError.errors)) {
Expand Down
25 changes: 25 additions & 0 deletions src/node/internal/sockets.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { Buffer } from 'node-internal:internal_buffer';

declare namespace sockets {
function connect(
input: string,
options: Record<string, unknown>
): {
opened: Promise<void>;
closed: Promise<void>;
close(): Promise<void>;
readable: {
getReader(options: Record<string, string>): {
close(): Promise<void>;
read(value: unknown): Promise<{ value: Buffer; done: boolean }>;
};
};
writable: {
getWriter(): {
close(): Promise<void>;
write(data: string | ArrayBufferView): Promise<void>;
};
};
};
}
export default sockets;
7 changes: 7 additions & 0 deletions src/node/internal/streams_duplex.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export {
Duplex,
Writable,
WritableOptions,
Readable,
ReadableOptions,
} from 'node:stream';
1 change: 0 additions & 1 deletion src/node/internal/streams_util.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-redundant-type-constituents */
import type { FinishedOptions } from 'node:stream';

type FinishedStream =
Expand Down
21 changes: 20 additions & 1 deletion src/node/internal/validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,12 @@ import { normalizeEncoding } from 'node-internal:internal_utils';
import {
ERR_INVALID_ARG_TYPE,
ERR_INVALID_ARG_VALUE,
ERR_SOCKET_BAD_PORT,
ERR_OUT_OF_RANGE,
} from 'node-internal:internal_errors';
import { default as bufferUtil } from 'node-internal:buffer';

// TODO(someday): Not current implementing parseFileMode, validatePort
// TODO(someday): Not current implementing parseFileMode

export function isInt32(value: unknown): value is number {
// @ts-expect-error Due to value being unknown
Expand Down Expand Up @@ -301,6 +302,23 @@ export function checkRangesOrGetDefault(
return number;
}

export function validatePort(
port: unknown,
name = 'Port',
allowZero = true
): number {
if (
(typeof port !== 'number' && typeof port !== 'string') ||
(typeof port === 'string' && port.trim().length === 0) ||
+port !== +port >>> 0 ||
+port > 0xffff ||
(port === 0 && !allowZero)
) {
throw new ERR_SOCKET_BAD_PORT(name, port, allowZero);
}
return +port | 0;
}

export default {
isInt32,
isUint32,
Expand All @@ -316,6 +334,7 @@ export default {
validateOneOf,
validateString,
validateUint32,
validatePort,

// Zlib specific
checkFiniteNumber,
Expand Down
1 change: 0 additions & 1 deletion src/node/internal/zlib.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,6 @@ export abstract class CompressionStream {
public [owner_symbol]: Zlib;
// Not used by C++ implementation but required to be Node.js compatible.
public inOff: number;
/* eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents */
public buffer: NodeJS.TypedArray | null;
public cb: () => void;
public availOutBefore: number;
Expand Down
Loading
Loading