mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 23:18:47 +00:00
Compare commits
249 Commits
dave/reada
...
nektro-pat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7fdcd8e262 | ||
|
|
df33f2b2a2 | ||
|
|
923303047f | ||
|
|
3876ecfde8 | ||
|
|
2680deb5d3 | ||
|
|
e1aadd0d7a | ||
|
|
7a6efad44e | ||
|
|
4ed0c36063 | ||
|
|
b75c605a75 | ||
|
|
7da9e7c45d | ||
|
|
30d06dec47 | ||
|
|
3674493aa4 | ||
|
|
cacbaba524 | ||
|
|
0d7d789ebd | ||
|
|
1aa35089d6 | ||
|
|
1de1745085 | ||
|
|
639e9a83d5 | ||
|
|
9db3379cc5 | ||
|
|
c5c55c7ce4 | ||
|
|
43326b0b2d | ||
|
|
680f842948 | ||
|
|
363a4934d0 | ||
|
|
98f9e276b0 | ||
|
|
ce1286efef | ||
|
|
fd84ace83b | ||
|
|
483af7c33c | ||
|
|
6fbe3d8214 | ||
|
|
c552cb40d1 | ||
|
|
63cf732ab4 | ||
|
|
6303af3ce0 | ||
|
|
9104bd7210 | ||
|
|
b5c91a4b7e | ||
|
|
82239371ab | ||
|
|
26526cba38 | ||
|
|
214b3ccca0 | ||
|
|
ada020b69f | ||
|
|
deb6ff5e6c | ||
|
|
f25599a6e8 | ||
|
|
de64683b22 | ||
|
|
c6d508972f | ||
|
|
2f30e19835 | ||
|
|
0081ab4738 | ||
|
|
6f6ea0d6f3 | ||
|
|
622432e843 | ||
|
|
80eb6d00e8 | ||
|
|
b6715d2c64 | ||
|
|
f371a78568 | ||
|
|
c2cf528953 | ||
|
|
9911407f26 | ||
|
|
59c5c0fe48 | ||
|
|
e585f900c9 | ||
|
|
dc620ea837 | ||
|
|
49ab4c147a | ||
|
|
b2a4df68c3 | ||
|
|
4c0a1f2983 | ||
|
|
bec04c7341 | ||
|
|
a44b7e41d2 | ||
|
|
de5e56336c | ||
|
|
1c648063fa | ||
|
|
1c3354bc95 | ||
|
|
d5d4f53e82 | ||
|
|
7ab4dc738f | ||
|
|
ebc7045ca4 | ||
|
|
848ad19d9e | ||
|
|
1da3436266 | ||
|
|
49e496399a | ||
|
|
9b8340a5b3 | ||
|
|
8efcc61a7b | ||
|
|
4d6480050c | ||
|
|
fc2c134bc6 | ||
|
|
4c4db1da37 | ||
|
|
77e14c8482 | ||
|
|
fba5d65003 | ||
|
|
c181cf45a7 | ||
|
|
5aeb4d9f79 | ||
|
|
1d9a8b4134 | ||
|
|
30881444df | ||
|
|
a2b4e3d4c2 | ||
|
|
e5662caa33 | ||
|
|
1f1ea7bf24 | ||
|
|
175746e569 | ||
|
|
005dd776b6 | ||
|
|
81dec2657f | ||
|
|
dbd320ccfa | ||
|
|
8f8d3968a3 | ||
|
|
0bbdd880e6 | ||
|
|
51257d5668 | ||
|
|
a2ae28d158 | ||
|
|
f04991f6bb | ||
|
|
80e651aca3 | ||
|
|
a5ba02804f | ||
|
|
4199fd4515 | ||
|
|
848327d333 | ||
|
|
bfb72f84c4 | ||
|
|
e4022ec3c7 | ||
|
|
a7f34c15fc | ||
|
|
a0ebb051b0 | ||
|
|
70ca2b76c3 | ||
|
|
e5ac4f94fa | ||
|
|
d547d8a30e | ||
|
|
32d9bb3ced | ||
|
|
75df73ef90 | ||
|
|
13907c4c29 | ||
|
|
87169b6bb3 | ||
|
|
244100c32f | ||
|
|
8a78b2241d | ||
|
|
bf8b6922bb | ||
|
|
7aa05ec542 | ||
|
|
f95ae9baee | ||
|
|
f7cb2da542 | ||
|
|
d966129992 | ||
|
|
6cb5cd2a87 | ||
|
|
080a2806af | ||
|
|
92c83fcd9e | ||
|
|
277ed9d138 | ||
|
|
879cb23163 | ||
|
|
d321ee97c5 | ||
|
|
3bfeb83e7e | ||
|
|
5a18b7d2fc | ||
|
|
e75ef69fb4 | ||
|
|
78021e34ae | ||
|
|
d7187592c0 | ||
|
|
5f1b569c52 | ||
|
|
e54fe5995b | ||
|
|
a2f68989a0 | ||
|
|
4a1e01d076 | ||
|
|
dd8b0a5889 | ||
|
|
8cadf66143 | ||
|
|
77cd03dad1 | ||
|
|
82b42ed851 | ||
|
|
2de82c0b3b | ||
|
|
30df04cd35 | ||
|
|
585c8299d8 | ||
|
|
375d8da8e6 | ||
|
|
0bd8db7162 | ||
|
|
d97260869d | ||
|
|
fdb58dc861 | ||
|
|
5f118704ec | ||
|
|
610c7f5e47 | ||
|
|
1e0b20f514 | ||
|
|
f6c89f4c25 | ||
|
|
907cd8d45d | ||
|
|
ac4523e903 | ||
|
|
24574dddb2 | ||
|
|
2da57f6d7b | ||
|
|
e2c3749965 | ||
|
|
57c6a7db35 | ||
|
|
c37891471a | ||
|
|
8ba0791dc8 | ||
|
|
f9371e59f2 | ||
|
|
79ddf0e47a | ||
|
|
177f3a8622 | ||
|
|
5a5f3d6b30 | ||
|
|
4e5d759c37 | ||
|
|
1a702dfdc7 | ||
|
|
3ef84816a6 | ||
|
|
6e9b592c56 | ||
|
|
a6b5543bd8 | ||
|
|
a4759eb147 | ||
|
|
732ed2b7df | ||
|
|
63fab9a82b | ||
|
|
ff17b427c8 | ||
|
|
ca44df7c88 | ||
|
|
9daa7ea555 | ||
|
|
2f0020f00f | ||
|
|
599d27d93e | ||
|
|
696f209ec1 | ||
|
|
1a6ead667b | ||
|
|
bbf2f5d716 | ||
|
|
9574044083 | ||
|
|
822b725bec | ||
|
|
dc775f75f0 | ||
|
|
738947bdec | ||
|
|
b7efeafc03 | ||
|
|
f5d1a17a5c | ||
|
|
03024e6b4e | ||
|
|
1d61676c7b | ||
|
|
23fb63f45c | ||
|
|
0be71edf3f | ||
|
|
6b50deb7b7 | ||
|
|
6ad3e6a5e3 | ||
|
|
b1dce1e241 | ||
|
|
cc42052039 | ||
|
|
ecf5aea071 | ||
|
|
79d21a0d02 | ||
|
|
43949151b1 | ||
|
|
16aad326e4 | ||
|
|
1a6f2d38da | ||
|
|
c6149d36b3 | ||
|
|
34e493f945 | ||
|
|
866b301626 | ||
|
|
cabc0fa0e6 | ||
|
|
d703354fcd | ||
|
|
37036f2eb0 | ||
|
|
ff0dc62314 | ||
|
|
f05f13780e | ||
|
|
4d74855fd7 | ||
|
|
5088a360b5 | ||
|
|
891b1907ae | ||
|
|
ae988642fb | ||
|
|
75e442c170 | ||
|
|
8808af1c99 | ||
|
|
b9d2a03ffc | ||
|
|
157b56cca5 | ||
|
|
caaeae123a | ||
|
|
20235a0d22 | ||
|
|
ae19489250 | ||
|
|
242c48f302 | ||
|
|
110849355c | ||
|
|
36fd3115f1 | ||
|
|
7d9b876968 | ||
|
|
40f0da1254 | ||
|
|
aea3964abd | ||
|
|
780bff781d | ||
|
|
c6a2ab5165 | ||
|
|
ef1c660708 | ||
|
|
11f8d3cb24 | ||
|
|
3ac9c3cc1c | ||
|
|
aa0f54cb93 | ||
|
|
8a3f882ef7 | ||
|
|
b7dd57ac32 | ||
|
|
cf1c7772f3 | ||
|
|
329d5e2af5 | ||
|
|
0098678a1d | ||
|
|
bf4c2caa11 | ||
|
|
226f42e04a | ||
|
|
96d19fcfe2 | ||
|
|
58483426cd | ||
|
|
25f7ef7338 | ||
|
|
412806bb22 | ||
|
|
4c87406391 | ||
|
|
5f7b96b58f | ||
|
|
f1151a84ad | ||
|
|
cdc68a2237 | ||
|
|
e866793eb3 | ||
|
|
cf9c418bcb | ||
|
|
138ef1328e | ||
|
|
e5e6d7ca43 | ||
|
|
cb81fc5445 | ||
|
|
d8caf7f9fa | ||
|
|
6f8ceb0ea9 | ||
|
|
02b589b2ce | ||
|
|
55d59ebf1f | ||
|
|
e1bc6c55d5 | ||
|
|
e42dede529 | ||
|
|
73ef93ffa3 | ||
|
|
475f71a2a1 | ||
|
|
af6035ce36 | ||
|
|
bfa395d1d5 |
@@ -10,9 +10,10 @@ steps:
|
||||
blocked_state: "running"
|
||||
|
||||
- label: ":pipeline:"
|
||||
command: "buildkite-agent pipeline upload .buildkite/ci.yml"
|
||||
agents:
|
||||
queue: "build-linux"
|
||||
queue: "build-darwin"
|
||||
command:
|
||||
- ".buildkite/scripts/prepare-build.sh"
|
||||
|
||||
- if: "build.branch == 'main' && !build.pull_request.repository.fork"
|
||||
label: ":github:"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
55
.buildkite/scripts/build-bun.sh
Executable file
55
.buildkite/scripts/build-bun.sh
Executable file
@@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eo pipefail
|
||||
source "$(dirname "$0")/env.sh"
|
||||
|
||||
function run_command() {
|
||||
set -x
|
||||
"$@"
|
||||
{ set +x; } 2>/dev/null
|
||||
}
|
||||
|
||||
cwd="$(pwd)"
|
||||
|
||||
mkdir -p build
|
||||
source "$(dirname "$0")/download-artifact.sh" "build/bun-deps/**" --step "$BUILDKITE_GROUP_KEY-build-deps"
|
||||
source "$(dirname "$0")/download-artifact.sh" "build/bun-zig.o" --step "$BUILDKITE_GROUP_KEY-build-zig"
|
||||
source "$(dirname "$0")/download-artifact.sh" "build/bun-cpp-objects.a" --step "$BUILDKITE_GROUP_KEY-build-cpp" --split
|
||||
cd build
|
||||
|
||||
run_command cmake .. "${CMAKE_FLAGS[@]}" \
|
||||
-GNinja \
|
||||
-DBUN_LINK_ONLY="1" \
|
||||
-DNO_CONFIGURE_DEPENDS="1" \
|
||||
-DBUN_ZIG_OBJ_DIR="$cwd/build" \
|
||||
-DBUN_CPP_ARCHIVE="$cwd/build/bun-cpp-objects.a" \
|
||||
-DBUN_DEPS_OUT_DIR="$cwd/build/bun-deps" \
|
||||
-DCMAKE_BUILD_TYPE="$CMAKE_BUILD_TYPE" \
|
||||
-DCPU_TARGET="$CPU_TARGET" \
|
||||
-DUSE_LTO="$USE_LTO" \
|
||||
-DUSE_DEBUG_JSC="$USE_DEBUG_JSC" \
|
||||
-DCANARY="$CANARY" \
|
||||
-DGIT_SHA="$GIT_SHA"
|
||||
run_command ninja -v -j "$CPUS"
|
||||
run_command ls
|
||||
|
||||
tag="bun-$BUILDKITE_GROUP_KEY"
|
||||
if [ "$USE_LTO" == "OFF" ]; then
|
||||
# Remove OS check when LTO is enabled on macOS again
|
||||
if [[ "$tag" == *"darwin"* ]]; then
|
||||
tag="$tag-nolto"
|
||||
fi
|
||||
fi
|
||||
|
||||
for name in bun bun-profile; do
|
||||
dir="$tag"
|
||||
if [ "$name" == "bun-profile" ]; then
|
||||
dir="$tag-profile"
|
||||
fi
|
||||
run_command chmod +x "$name"
|
||||
run_command "./$name" --revision
|
||||
run_command mkdir -p "$dir"
|
||||
run_command mv "$name" "$dir/$name"
|
||||
run_command zip -r "$dir.zip" "$dir"
|
||||
source "$cwd/.buildkite/scripts/upload-artifact.sh" "$dir.zip"
|
||||
done
|
||||
35
.buildkite/scripts/build-cpp.sh
Executable file
35
.buildkite/scripts/build-cpp.sh
Executable file
@@ -0,0 +1,35 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eo pipefail
|
||||
source "$(dirname "$0")/env.sh"
|
||||
export FORCE_UPDATE_SUBMODULES=1
|
||||
source "$(realpath $(dirname "$0")/../../scripts/update-submodules.sh)"
|
||||
{ set +x; } 2>/dev/null
|
||||
|
||||
function run_command() {
|
||||
set -x
|
||||
"$@"
|
||||
{ set +x; } 2>/dev/null
|
||||
}
|
||||
|
||||
mkdir -p build
|
||||
cd build
|
||||
mkdir -p tmp_modules tmp_functions js codegen
|
||||
|
||||
run_command cmake .. "${CMAKE_FLAGS[@]}" \
|
||||
-GNinja \
|
||||
-DBUN_CPP_ONLY="1" \
|
||||
-DNO_CONFIGURE_DEPENDS="1" \
|
||||
-DCMAKE_BUILD_TYPE="$CMAKE_BUILD_TYPE" \
|
||||
-DCPU_TARGET="$CPU_TARGET" \
|
||||
-DUSE_LTO="$USE_LTO" \
|
||||
-DUSE_DEBUG_JSC="$USE_DEBUG_JSC" \
|
||||
-DCANARY="$CANARY" \
|
||||
-DGIT_SHA="$GIT_SHA"
|
||||
|
||||
chmod +x compile-cpp-only.sh
|
||||
source compile-cpp-only.sh -v -j "$CPUS"
|
||||
{ set +x; } 2>/dev/null
|
||||
|
||||
cd ..
|
||||
source "$(dirname "$0")/upload-artifact.sh" "build/bun-cpp-objects.a" --split
|
||||
0
.buildkite/scripts/build-deps.ps1
Normal file
0
.buildkite/scripts/build-deps.ps1
Normal file
22
.buildkite/scripts/build-deps.sh
Executable file
22
.buildkite/scripts/build-deps.sh
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eo pipefail
|
||||
source "$(dirname "$0")/env.sh"
|
||||
source "$(realpath $(dirname "$0")/../../scripts/all-dependencies.sh)"
|
||||
|
||||
artifacts=(
|
||||
libcrypto.a libssl.a libdecrepit.a
|
||||
libcares.a
|
||||
libarchive.a
|
||||
liblolhtml.a
|
||||
libmimalloc.a libmimalloc.o
|
||||
libtcc.a
|
||||
libz.a
|
||||
libzstd.a
|
||||
libdeflate.a
|
||||
liblshpack.a
|
||||
)
|
||||
|
||||
for artifact in "${artifacts[@]}"; do
|
||||
source "$(dirname "$0")/upload-artifact.sh" "build/bun-deps/$artifact"
|
||||
done
|
||||
40
.buildkite/scripts/build-old-js.sh
Executable file
40
.buildkite/scripts/build-old-js.sh
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eo pipefail
|
||||
source "$(dirname "$0")/env.sh"
|
||||
|
||||
function assert_bun() {
|
||||
if ! command -v bun &>/dev/null; then
|
||||
echo "error: bun is not installed" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function assert_make() {
|
||||
if ! command -v make &>/dev/null; then
|
||||
echo "error: make is not installed" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function run_command() {
|
||||
set -x
|
||||
"$@"
|
||||
{ set +x; } 2>/dev/null
|
||||
}
|
||||
|
||||
function build_node_fallbacks() {
|
||||
local cwd="src/node-fallbacks"
|
||||
run_command bun install --cwd "$cwd" --frozen-lockfile
|
||||
run_command bun run --cwd "$cwd" build
|
||||
}
|
||||
|
||||
function build_old_js() {
|
||||
run_command bun install --frozen-lockfile
|
||||
run_command make runtime_js fallback_decoder bun_error
|
||||
}
|
||||
|
||||
assert_bun
|
||||
assert_make
|
||||
build_node_fallbacks
|
||||
build_old_js
|
||||
80
.buildkite/scripts/build-zig.sh
Executable file
80
.buildkite/scripts/build-zig.sh
Executable file
@@ -0,0 +1,80 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eo pipefail
|
||||
source "$(dirname "$0")/env.sh"
|
||||
|
||||
function assert_target() {
|
||||
local arch="${2-$(uname -m)}"
|
||||
case "$(echo "$arch" | tr '[:upper:]' '[:lower:]')" in
|
||||
x64 | x86_64 | amd64)
|
||||
export ZIG_ARCH="x86_64"
|
||||
if [[ "$BUILDKITE_STEP_KEY" == *"baseline"* ]]; then
|
||||
export ZIG_CPU_TARGET="nehalem"
|
||||
else
|
||||
export ZIG_CPU_TARGET="haswell"
|
||||
fi
|
||||
;;
|
||||
aarch64 | arm64)
|
||||
export ZIG_ARCH="aarch64"
|
||||
export ZIG_CPU_TARGET="native"
|
||||
;;
|
||||
*)
|
||||
echo "error: Unsupported architecture: $arch" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
local os="${1-$(uname -s)}"
|
||||
case "$(echo "$os" | tr '[:upper:]' '[:lower:]')" in
|
||||
linux)
|
||||
export ZIG_TARGET="$ZIG_ARCH-linux-gnu" ;;
|
||||
darwin)
|
||||
export ZIG_TARGET="$ZIG_ARCH-macos-none" ;;
|
||||
windows)
|
||||
export ZIG_TARGET="$ZIG_ARCH-windows-msvc" ;;
|
||||
*)
|
||||
echo "error: Unsupported operating system: $os" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
function run_command() {
|
||||
set -x
|
||||
"$@"
|
||||
{ set +x; } 2>/dev/null
|
||||
}
|
||||
|
||||
assert_target "$@"
|
||||
|
||||
# Since the zig build depends on files from the zig submodule,
|
||||
# make sure to update the submodule before building.
|
||||
run_command git submodule update --init --recursive --progress --depth=1 --checkout src/deps/zig
|
||||
|
||||
# TODO: Move these to be part of the CMake build
|
||||
source "$(dirname "$0")/build-old-js.sh"
|
||||
|
||||
cwd="$(pwd)"
|
||||
mkdir -p build
|
||||
cd build
|
||||
|
||||
run_command cmake .. "${CMAKE_FLAGS[@]}" \
|
||||
-GNinja \
|
||||
-DNO_CONFIGURE_DEPENDS="1" \
|
||||
-DNO_CODEGEN="0" \
|
||||
-DWEBKIT_DIR="omit" \
|
||||
-DBUN_ZIG_OBJ_DIR="$cwd/build" \
|
||||
-DZIG_LIB_DIR="$cwd/src/deps/zig/lib" \
|
||||
-DCMAKE_BUILD_TYPE="$CMAKE_BUILD_TYPE" \
|
||||
-DARCH="$ZIG_ARCH" \
|
||||
-DCPU_TARGET="$ZIG_CPU_TARGET" \
|
||||
-DZIG_TARGET="$ZIG_TARGET" \
|
||||
-DUSE_LTO="$USE_LTO" \
|
||||
-DUSE_DEBUG_JSC="$USE_DEBUG_JSC" \
|
||||
-DCANARY="$CANARY" \
|
||||
-DGIT_SHA="$GIT_SHA"
|
||||
|
||||
export ONLY_ZIG="1"
|
||||
run_command ninja "$cwd/build/bun-zig.o" -v -j "$CPUS"
|
||||
|
||||
cd ..
|
||||
source "$(dirname "$0")/upload-artifact.sh" "build/bun-zig.o"
|
||||
47
.buildkite/scripts/download-artifact.ps1
Executable file
47
.buildkite/scripts/download-artifact.ps1
Executable file
@@ -0,0 +1,47 @@
|
||||
param (
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string[]] $Paths,
|
||||
[switch] $Split
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
function Assert-Buildkite-Agent() {
|
||||
if (-not (Get-Command "buildkite-agent" -ErrorAction SilentlyContinue)) {
|
||||
Write-Error "Cannot find buildkite-agent, please install it: https://buildkite.com/docs/agent/v3/install"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
function Assert-Join-File() {
|
||||
if (-not (Get-Command "Join-File" -ErrorAction SilentlyContinue)) {
|
||||
Write-Error "Cannot find Join-File, please install it: https://www.powershellgallery.com/packages/FileSplitter/1.3"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
function Download-Buildkite-Artifact() {
|
||||
param (
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $Path,
|
||||
)
|
||||
if ($Split) {
|
||||
& buildkite-agent artifact download "$Path.*" --debug --debug-http
|
||||
Join-File -Path "$(Resolve-Path .)\$Path" -Verbose -DeletePartFiles
|
||||
} else {
|
||||
& buildkite-agent artifact download "$Path" --debug --debug-http
|
||||
}
|
||||
if (-not (Test-Path $Path)) {
|
||||
Write-Error "Could not find artifact: $Path"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
Assert-Buildkite-Agent
|
||||
if ($Split) {
|
||||
Assert-Join-File
|
||||
}
|
||||
|
||||
foreach ($Path in $Paths) {
|
||||
Download-Buildkite-Artifact $Path
|
||||
}
|
||||
46
.buildkite/scripts/download-artifact.sh
Executable file
46
.buildkite/scripts/download-artifact.sh
Executable file
@@ -0,0 +1,46 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
function assert_buildkite_agent() {
|
||||
if ! command -v buildkite-agent &> /dev/null; then
|
||||
echo "error: Cannot find buildkite-agent, please install it:"
|
||||
echo "https://buildkite.com/docs/agent/v3/install"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function download_buildkite_artifact() {
|
||||
local path="$1"; shift
|
||||
local split="0"
|
||||
local args=()
|
||||
while true; do
|
||||
if [ -z "$1" ]; then
|
||||
break
|
||||
fi
|
||||
case "$1" in
|
||||
--split) split="1"; shift ;;
|
||||
*) args+=("$1"); shift ;;
|
||||
esac
|
||||
done
|
||||
if [ "$split" == "1" ]; then
|
||||
run_command buildkite-agent artifact download "$path.*" . "${args[@]}"
|
||||
run_command cat $path.?? > "$path"
|
||||
run_command rm -f $path.??
|
||||
else
|
||||
run_command buildkite-agent artifact download "$path" . "${args[@]}"
|
||||
fi
|
||||
if [[ "$path" != *"*"* ]] && [ ! -f "$path" ]; then
|
||||
echo "error: Could not find artifact: $path"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function run_command() {
|
||||
set -x
|
||||
"$@"
|
||||
{ set +x; } 2>/dev/null
|
||||
}
|
||||
|
||||
assert_buildkite_agent
|
||||
download_buildkite_artifact "$@"
|
||||
120
.buildkite/scripts/env.sh
Executable file
120
.buildkite/scripts/env.sh
Executable file
@@ -0,0 +1,120 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
function assert_os() {
|
||||
local os="$(uname -s)"
|
||||
case "$os" in
|
||||
Linux)
|
||||
echo "linux" ;;
|
||||
Darwin)
|
||||
echo "darwin" ;;
|
||||
*)
|
||||
echo "error: Unsupported operating system: $os" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
function assert_arch() {
|
||||
local arch="$(uname -m)"
|
||||
case "$arch" in
|
||||
aarch64 | arm64)
|
||||
echo "aarch64" ;;
|
||||
x86_64 | amd64)
|
||||
echo "x64" ;;
|
||||
*)
|
||||
echo "error: Unknown architecture: $arch" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
function assert_build() {
|
||||
if [ -z "$BUILDKITE_REPO" ]; then
|
||||
echo "error: Cannot find repository for this build"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$BUILDKITE_COMMIT" ]; then
|
||||
echo "error: Cannot find commit for this build"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$BUILDKITE_STEP_KEY" ]; then
|
||||
echo "error: Cannot find step key for this build"
|
||||
exit 1
|
||||
fi
|
||||
if [ -n "$BUILDKITE_GROUP_KEY" ] && [[ "$BUILDKITE_STEP_KEY" != "$BUILDKITE_GROUP_KEY"* ]]; then
|
||||
echo "error: Build step '$BUILDKITE_STEP_KEY' does not start with group key '$BUILDKITE_GROUP_KEY'"
|
||||
exit 1
|
||||
fi
|
||||
# Skip os and arch checks for Zig, since it's cross-compiled on macOS
|
||||
if [[ "$BUILDKITE_STEP_KEY" != *"zig"* ]]; then
|
||||
local os="$(assert_os)"
|
||||
if [[ "$BUILDKITE_STEP_KEY" != *"$os"* ]]; then
|
||||
echo "error: Build step '$BUILDKITE_STEP_KEY' does not match operating system '$os'"
|
||||
exit 1
|
||||
fi
|
||||
local arch="$(assert_arch)"
|
||||
if [[ "$BUILDKITE_STEP_KEY" != *"$arch"* ]]; then
|
||||
echo "error: Build step '$BUILDKITE_STEP_KEY' does not match architecture '$arch'"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function assert_buildkite_agent() {
|
||||
if ! command -v buildkite-agent &> /dev/null; then
|
||||
echo "error: Cannot find buildkite-agent, please install it:"
|
||||
echo "https://buildkite.com/docs/agent/v3/install"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function export_environment() {
|
||||
source "$(realpath $(dirname "$0")/../../scripts/env.sh)"
|
||||
source "$(realpath $(dirname "$0")/../../scripts/update-submodules.sh)"
|
||||
{ set +x; } 2>/dev/null
|
||||
export GIT_SHA="$BUILDKITE_COMMIT"
|
||||
export CCACHE_DIR="$HOME/.cache/ccache/$BUILDKITE_STEP_KEY"
|
||||
export SCCACHE_DIR="$HOME/.cache/sccache/$BUILDKITE_STEP_KEY"
|
||||
export ZIG_LOCAL_CACHE_DIR="$HOME/.cache/zig-cache/$BUILDKITE_STEP_KEY"
|
||||
export ZIG_GLOBAL_CACHE_DIR="$HOME/.cache/zig-cache/$BUILDKITE_STEP_KEY"
|
||||
export BUN_DEPS_CACHE_DIR="$HOME/.cache/bun-deps/$BUILDKITE_STEP_KEY"
|
||||
if [ "$(assert_os)" == "linux" ]; then
|
||||
export USE_LTO="ON"
|
||||
fi
|
||||
if [ "$(assert_arch)" == "aarch64" ]; then
|
||||
export CPU_TARGET="native"
|
||||
elif [[ "$BUILDKITE_STEP_KEY" == *"baseline"* ]]; then
|
||||
export CPU_TARGET="nehalem"
|
||||
else
|
||||
export CPU_TARGET="haswell"
|
||||
fi
|
||||
if $(buildkite-agent meta-data exists release &> /dev/null); then
|
||||
export CMAKE_BUILD_TYPE="$(buildkite-agent meta-data get release)"
|
||||
else
|
||||
export CMAKE_BUILD_TYPE="Release"
|
||||
fi
|
||||
if $(buildkite-agent meta-data exists canary &> /dev/null); then
|
||||
export CANARY="$(buildkite-agent meta-data get canary)"
|
||||
else
|
||||
export CANARY="1"
|
||||
fi
|
||||
if $(buildkite-agent meta-data exists assertions &> /dev/null); then
|
||||
export USE_DEBUG_JSC="$(buildkite-agent meta-data get assertions)"
|
||||
else
|
||||
export USE_DEBUG_JSC="OFF"
|
||||
fi
|
||||
if [ "$BUILDKITE_CLEAN_CHECKOUT" == "true" || "$BUILDKITE_BRANCH" == "main" ]; then
|
||||
rm -rf "$CCACHE_DIR"
|
||||
rm -rf "$SCCACHE_DIR"
|
||||
rm -rf "$ZIG_LOCAL_CACHE_DIR"
|
||||
rm -rf "$ZIG_GLOBAL_CACHE_DIR"
|
||||
rm -rf "$BUN_DEPS_CACHE_DIR"
|
||||
export CCACHE_RECACHE="1"
|
||||
fi
|
||||
}
|
||||
|
||||
assert_build
|
||||
assert_buildkite_agent
|
||||
export_environment
|
||||
97
.buildkite/scripts/prepare-build.sh
Executable file
97
.buildkite/scripts/prepare-build.sh
Executable file
@@ -0,0 +1,97 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
function assert_build() {
|
||||
if [ -z "$BUILDKITE_REPO" ]; then
|
||||
echo "error: Cannot find repository for this build"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$BUILDKITE_COMMIT" ]; then
|
||||
echo "error: Cannot find commit for this build"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function assert_buildkite_agent() {
|
||||
if ! command -v buildkite-agent &> /dev/null; then
|
||||
echo "error: Cannot find buildkite-agent, please install it:"
|
||||
echo "https://buildkite.com/docs/agent/v3/install"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function assert_jq() {
|
||||
assert_command "jq" "jq" "https://stedolan.github.io/jq/"
|
||||
}
|
||||
|
||||
function assert_curl() {
|
||||
assert_command "curl" "curl" "https://curl.se/download.html"
|
||||
}
|
||||
|
||||
function assert_command() {
|
||||
local command="$1"
|
||||
local package="$2"
|
||||
local help_url="$3"
|
||||
if ! command -v "$command" &> /dev/null; then
|
||||
echo "warning: $command is not installed, installing..."
|
||||
if command -v brew &> /dev/null; then
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install "$package"
|
||||
else
|
||||
echo "error: Cannot install $command, please install it"
|
||||
if [ -n "$help_url" ]; then
|
||||
echo ""
|
||||
echo "hint: See $help_url for help"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function assert_release() {
|
||||
if [ "$RELEASE" == "1" ]; then
|
||||
run_command buildkite-agent meta-data set canary "0"
|
||||
fi
|
||||
}
|
||||
|
||||
function assert_canary() {
|
||||
local canary="$(buildkite-agent meta-data get canary 2>/dev/null)"
|
||||
if [ -z "$canary" ]; then
|
||||
local repo=$(echo "$BUILDKITE_REPO" | sed -E 's#https://github.com/([^/]+)/([^/]+).git#\1/\2#g')
|
||||
local tag="$(curl -sL "https://api.github.com/repos/$repo/releases/latest" | jq -r ".tag_name")"
|
||||
if [ "$tag" == "null" ]; then
|
||||
canary="1"
|
||||
else
|
||||
local revision=$(curl -sL "https://api.github.com/repos/$repo/compare/$tag...$BUILDKITE_COMMIT" | jq -r ".ahead_by")
|
||||
if [ "$revision" == "null" ]; then
|
||||
canary="1"
|
||||
else
|
||||
canary="$revision"
|
||||
fi
|
||||
fi
|
||||
run_command buildkite-agent meta-data set canary "$canary"
|
||||
fi
|
||||
}
|
||||
|
||||
function upload_buildkite_pipeline() {
|
||||
local path="$1"
|
||||
if [ ! -f "$path" ]; then
|
||||
echo "error: Cannot find pipeline: $path"
|
||||
exit 1
|
||||
fi
|
||||
run_command buildkite-agent pipeline upload "$path"
|
||||
}
|
||||
|
||||
function run_command() {
|
||||
set -x
|
||||
"$@"
|
||||
{ set +x; } 2>/dev/null
|
||||
}
|
||||
|
||||
assert_build
|
||||
assert_buildkite_agent
|
||||
assert_jq
|
||||
assert_curl
|
||||
assert_release
|
||||
assert_canary
|
||||
upload_buildkite_pipeline ".buildkite/ci.yml"
|
||||
47
.buildkite/scripts/upload-artifact.ps1
Executable file
47
.buildkite/scripts/upload-artifact.ps1
Executable file
@@ -0,0 +1,47 @@
|
||||
param (
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string[]] $Paths,
|
||||
[switch] $Split
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
function Assert-Buildkite-Agent() {
|
||||
if (-not (Get-Command "buildkite-agent" -ErrorAction SilentlyContinue)) {
|
||||
Write-Error "Cannot find buildkite-agent, please install it: https://buildkite.com/docs/agent/v3/install"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
function Assert-Split-File() {
|
||||
if (-not (Get-Command "Split-File" -ErrorAction SilentlyContinue)) {
|
||||
Write-Error "Cannot find Split-File, please install it: https://www.powershellgallery.com/packages/FileSplitter/1.3"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
function Upload-Buildkite-Artifact() {
|
||||
param (
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $Path,
|
||||
)
|
||||
if (-not (Test-Path $Path)) {
|
||||
Write-Error "Could not find artifact: $Path"
|
||||
exit 1
|
||||
}
|
||||
if ($Split) {
|
||||
Remove-Item -Path "$Path.*" -Force
|
||||
Split-File -Path (Resolve-Path $Path) -PartSizeBytes "50MB" -Verbose
|
||||
$Path = "$Path.*"
|
||||
}
|
||||
& buildkite-agent artifact upload "$Path" --debug --debug-http
|
||||
}
|
||||
|
||||
Assert-Buildkite-Agent
|
||||
if ($Split) {
|
||||
Assert-Split-File
|
||||
}
|
||||
|
||||
foreach ($Path in $Paths) {
|
||||
Upload-Buildkite-Artifact $Path
|
||||
}
|
||||
54
.buildkite/scripts/upload-artifact.sh
Executable file
54
.buildkite/scripts/upload-artifact.sh
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
function assert_buildkite_agent() {
|
||||
if ! command -v buildkite-agent &> /dev/null; then
|
||||
echo "error: Cannot find buildkite-agent, please install it:"
|
||||
echo "https://buildkite.com/docs/agent/v3/install"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function assert_split() {
|
||||
if ! command -v split &> /dev/null; then
|
||||
echo "error: Cannot find split, please install it:"
|
||||
echo "https://www.gnu.org/software/coreutils/split"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function upload_buildkite_artifact() {
|
||||
local path="$1"; shift
|
||||
local split="0"
|
||||
local args=()
|
||||
while true; do
|
||||
if [ -z "$1" ]; then
|
||||
break
|
||||
fi
|
||||
case "$1" in
|
||||
--split) split="1"; shift ;;
|
||||
*) args+=("$1"); shift ;;
|
||||
esac
|
||||
done
|
||||
if [ ! -f "$path" ]; then
|
||||
echo "error: Could not find artifact: $path"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$split" == "1" ]; then
|
||||
run_command rm -f "$path."*
|
||||
run_command split -b 50MB -d "$path" "$path."
|
||||
run_command buildkite-agent artifact upload "$path.*" "${args[@]}"
|
||||
else
|
||||
run_command buildkite-agent artifact upload "$path" "${args[@]}"
|
||||
fi
|
||||
}
|
||||
|
||||
function run_command() {
|
||||
set -x
|
||||
"$@"
|
||||
{ set +x; } 2>/dev/null
|
||||
}
|
||||
|
||||
assert_buildkite_agent
|
||||
upload_buildkite_artifact "$@"
|
||||
@@ -3,7 +3,15 @@
|
||||
set -eo pipefail
|
||||
|
||||
function assert_main() {
|
||||
if [[ "$BUILDKITE_PULL_REQUEST_REPO" && "$BUILDKITE_REPO" != "$BUILDKITE_PULL_REQUEST_REPO" ]]; then
|
||||
if [ -z "$BUILDKITE_REPO" ]; then
|
||||
echo "error: Cannot find repository for this build"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$BUILDKITE_COMMIT" ]; then
|
||||
echo "error: Cannot find commit for this build"
|
||||
exit 1
|
||||
fi
|
||||
if [ -n "$BUILDKITE_PULL_REQUEST_REPO" ] && [ "$BUILDKITE_REPO" != "$BUILDKITE_PULL_REQUEST_REPO" ]; then
|
||||
echo "error: Cannot upload release from a fork"
|
||||
exit 1
|
||||
fi
|
||||
@@ -18,77 +26,191 @@ function assert_main() {
|
||||
}
|
||||
|
||||
function assert_buildkite_agent() {
|
||||
if ! command -v buildkite-agent &> /dev/null; then
|
||||
if ! command -v "buildkite-agent" &> /dev/null; then
|
||||
echo "error: Cannot find buildkite-agent, please install it:"
|
||||
echo "https://buildkite.com/docs/agent/v3/install"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function assert_gh() {
|
||||
if ! command -v gh &> /dev/null; then
|
||||
echo "warning: gh is not installed, installing..."
|
||||
function assert_github() {
|
||||
assert_command "gh" "gh" "https://github.com/cli/cli#installation"
|
||||
assert_buildkite_secret "GITHUB_TOKEN"
|
||||
# gh expects the token in $GH_TOKEN
|
||||
export GH_TOKEN="$GITHUB_TOKEN"
|
||||
}
|
||||
|
||||
function assert_aws() {
|
||||
assert_command "aws" "awscli" "https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html"
|
||||
for secret in "AWS_ACCESS_KEY_ID" "AWS_SECRET_ACCESS_KEY" "AWS_ENDPOINT"; do
|
||||
assert_buildkite_secret "$secret"
|
||||
done
|
||||
assert_buildkite_secret "AWS_BUCKET" --skip-redaction
|
||||
}
|
||||
|
||||
function assert_sentry() {
|
||||
assert_command "sentry-cli" "getsentry/tools/sentry-cli" "https://docs.sentry.io/cli/installation/"
|
||||
for secret in "SENTRY_AUTH_TOKEN" "SENTRY_ORG" "SENTRY_PROJECT"; do
|
||||
assert_buildkite_secret "$secret"
|
||||
done
|
||||
}
|
||||
|
||||
function run_command() {
|
||||
set -x
|
||||
"$@"
|
||||
{ set +x; } 2>/dev/null
|
||||
}
|
||||
|
||||
function assert_command() {
|
||||
local command="$1"
|
||||
local package="$2"
|
||||
local help_url="$3"
|
||||
if ! command -v "$command" &> /dev/null; then
|
||||
echo "warning: $command is not installed, installing..."
|
||||
if command -v brew &> /dev/null; then
|
||||
brew install gh
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 run_command brew install "$package"
|
||||
else
|
||||
echo "error: Cannot install gh, please install it:"
|
||||
echo "https://github.com/cli/cli#installation"
|
||||
echo "error: Cannot install $command, please install it"
|
||||
if [ -n "$help_url" ]; then
|
||||
echo ""
|
||||
echo "hint: See $help_url for help"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function assert_gh_token() {
|
||||
local token=$(buildkite-agent secret get GITHUB_TOKEN)
|
||||
if [ -z "$token" ]; then
|
||||
echo "error: Cannot find GITHUB_TOKEN secret"
|
||||
function assert_buildkite_secret() {
|
||||
local key="$1"
|
||||
local value=$(buildkite-agent secret get "$key" ${@:2})
|
||||
if [ -z "$value" ]; then
|
||||
echo "error: Cannot find $key secret"
|
||||
echo ""
|
||||
echo "hint: Create a secret named GITHUB_TOKEN with a GitHub access token:"
|
||||
echo "hint: Create a secret named $key with a value:"
|
||||
echo "https://buildkite.com/docs/pipelines/buildkite-secrets"
|
||||
exit 1
|
||||
fi
|
||||
export GH_TOKEN="$token"
|
||||
export "$key"="$value"
|
||||
}
|
||||
|
||||
function download_artifact() {
|
||||
local name=$1
|
||||
buildkite-agent artifact download "$name" .
|
||||
if [ ! -f "$name" ]; then
|
||||
function release_tag() {
|
||||
local version="$1"
|
||||
if [ "$version" == "canary" ]; then
|
||||
echo "canary"
|
||||
else
|
||||
echo "bun-v$version"
|
||||
fi
|
||||
}
|
||||
|
||||
function create_sentry_release() {
|
||||
local version="$1"
|
||||
local release="$version"
|
||||
if [ "$version" == "canary" ]; then
|
||||
release="$BUILDKITE_COMMIT-canary"
|
||||
fi
|
||||
run_command sentry-cli releases new "$release" --finalize
|
||||
run_command sentry-cli releases set-commits "$release" --auto --ignore-missing
|
||||
if [ "$version" == "canary" ]; then
|
||||
run_command sentry-cli deploys new --env="canary" --release="$release"
|
||||
fi
|
||||
}
|
||||
|
||||
function download_buildkite_artifact() {
|
||||
local name="$1"
|
||||
local dir="$2"
|
||||
if [ -z "$dir" ]; then
|
||||
dir="."
|
||||
fi
|
||||
run_command buildkite-agent artifact download "$name" "$dir"
|
||||
if [ ! -f "$dir/$name" ]; then
|
||||
echo "error: Cannot find Buildkite artifact: $name"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function upload_assets() {
|
||||
local tag=$1
|
||||
local files=${@:2}
|
||||
gh release upload "$tag" $files --clobber --repo "$BUILDKITE_REPO"
|
||||
function upload_github_asset() {
|
||||
local version="$1"
|
||||
local tag="$(release_tag "$version")"
|
||||
local file="$2"
|
||||
run_command gh release upload "$tag" "$file" --clobber --repo "$BUILDKITE_REPO"
|
||||
|
||||
# Sometimes the upload fails, maybe this is a race condition in the gh CLI?
|
||||
while [ "$(gh release view "$tag" --repo "$BUILDKITE_REPO" | grep -c "$file")" -eq 0 ]; do
|
||||
echo "warn: Uploading $file to $tag failed, retrying..."
|
||||
sleep "$((RANDOM % 5 + 1))"
|
||||
run_command gh release upload "$tag" "$file" --clobber --repo "$BUILDKITE_REPO"
|
||||
done
|
||||
}
|
||||
|
||||
assert_main
|
||||
assert_buildkite_agent
|
||||
assert_gh
|
||||
assert_gh_token
|
||||
function update_github_release() {
|
||||
local version="$1"
|
||||
local tag="$(release_tag "$version")"
|
||||
if [ "$tag" == "canary" ]; then
|
||||
sleep 5 # There is possibly a race condition where this overwrites artifacts?
|
||||
run_command gh release edit "$tag" --repo "$BUILDKITE_REPO" \
|
||||
--notes "This release of Bun corresponds to the commit: $BUILDKITE_COMMIT"
|
||||
fi
|
||||
}
|
||||
|
||||
declare artifacts=(
|
||||
bun-darwin-aarch64.zip
|
||||
bun-darwin-aarch64-profile.zip
|
||||
bun-darwin-x64.zip
|
||||
bun-darwin-x64-profile.zip
|
||||
bun-linux-aarch64.zip
|
||||
bun-linux-aarch64-profile.zip
|
||||
bun-linux-x64.zip
|
||||
bun-linux-x64-profile.zip
|
||||
bun-linux-x64-baseline.zip
|
||||
bun-linux-x64-baseline-profile.zip
|
||||
bun-windows-x64.zip
|
||||
bun-windows-x64-profile.zip
|
||||
bun-windows-x64-baseline.zip
|
||||
bun-windows-x64-baseline-profile.zip
|
||||
)
|
||||
function upload_s3_file() {
|
||||
local folder="$1"
|
||||
local file="$2"
|
||||
run_command aws --endpoint-url="$AWS_ENDPOINT" s3 cp "$file" "s3://$AWS_BUCKET/$folder/$file"
|
||||
}
|
||||
|
||||
for artifact in "${artifacts[@]}"; do
|
||||
download_artifact $artifact
|
||||
done
|
||||
function create_release() {
|
||||
assert_main
|
||||
assert_buildkite_agent
|
||||
assert_github
|
||||
assert_aws
|
||||
assert_sentry
|
||||
|
||||
upload_assets "canary" "${artifacts[@]}"
|
||||
local tag="$1" # 'canary' or 'x.y.z'
|
||||
local artifacts=(
|
||||
bun-darwin-aarch64.zip
|
||||
bun-darwin-aarch64-profile.zip
|
||||
bun-darwin-x64.zip
|
||||
bun-darwin-x64-profile.zip
|
||||
bun-linux-aarch64.zip
|
||||
bun-linux-aarch64-profile.zip
|
||||
bun-linux-x64.zip
|
||||
bun-linux-x64-profile.zip
|
||||
bun-linux-x64-baseline.zip
|
||||
bun-linux-x64-baseline-profile.zip
|
||||
bun-windows-x64.zip
|
||||
bun-windows-x64-profile.zip
|
||||
bun-windows-x64-baseline.zip
|
||||
bun-windows-x64-baseline-profile.zip
|
||||
)
|
||||
|
||||
function upload_artifact() {
|
||||
local artifact="$1"
|
||||
download_buildkite_artifact "$artifact"
|
||||
if [ "$tag" == "canary" ]; then
|
||||
upload_s3_file "releases/$BUILDKITE_COMMIT-canary" "$artifact" &
|
||||
else
|
||||
upload_s3_file "releases/$BUILDKITE_COMMIT" "$artifact" &
|
||||
fi
|
||||
upload_s3_file "releases/$tag" "$artifact" &
|
||||
upload_github_asset "$tag" "$artifact" &
|
||||
wait
|
||||
}
|
||||
|
||||
for artifact in "${artifacts[@]}"; do
|
||||
upload_artifact "$artifact"
|
||||
done
|
||||
|
||||
update_github_release "$tag"
|
||||
create_sentry_release "$tag"
|
||||
}
|
||||
|
||||
function assert_canary() {
|
||||
local canary="$(buildkite-agent meta-data get canary 2>/dev/null)"
|
||||
if [ -z "$canary" ] || [ "$canary" == "0" ]; then
|
||||
echo "warn: Skipping release because this is not a canary build"
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
assert_canary
|
||||
create_release "canary"
|
||||
|
||||
312
.github/workflows/build-darwin.yml
vendored
312
.github/workflows/build-darwin.yml
vendored
@@ -1,312 +0,0 @@
|
||||
name: Build Darwin
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
actions: write
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
runs-on:
|
||||
type: string
|
||||
default: macos-12-large
|
||||
tag:
|
||||
type: string
|
||||
required: true
|
||||
arch:
|
||||
type: string
|
||||
required: true
|
||||
cpu:
|
||||
type: string
|
||||
required: true
|
||||
assertions:
|
||||
type: boolean
|
||||
canary:
|
||||
type: boolean
|
||||
no-cache:
|
||||
type: boolean
|
||||
|
||||
env:
|
||||
LLVM_VERSION: 16
|
||||
BUN_VERSION: 1.1.8
|
||||
LC_CTYPE: "en_US.UTF-8"
|
||||
LC_ALL: "en_US.UTF-8"
|
||||
|
||||
jobs:
|
||||
build-submodules:
|
||||
name: Build Submodules
|
||||
runs-on: ${{ inputs.runs-on }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: |
|
||||
.gitmodules
|
||||
src/deps
|
||||
scripts
|
||||
- name: Hash Submodules
|
||||
id: hash
|
||||
run: |
|
||||
print_versions() {
|
||||
git submodule | grep -v WebKit
|
||||
echo "LLVM_VERSION=${{ env.LLVM_VERSION }}"
|
||||
cat $(echo scripts/build*.sh scripts/all-dependencies.sh | tr " " "\n" | sort)
|
||||
}
|
||||
echo "hash=$(print_versions | shasum)" >> $GITHUB_OUTPUT
|
||||
- if: ${{ !inputs.no-cache }}
|
||||
name: Restore Cache
|
||||
id: cache
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: ${{ runner.temp }}/bun-deps
|
||||
key: bun-${{ inputs.tag }}-deps-${{ steps.hash.outputs.hash }}
|
||||
# TODO: Figure out how to cache homebrew dependencies
|
||||
- if: ${{ inputs.no-cache || !steps.cache.outputs.cache-hit }}
|
||||
name: Install Dependencies
|
||||
env:
|
||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
|
||||
HOMEBREW_NO_AUTO_UPDATE: 1
|
||||
HOMEBREW_NO_INSTALL_CLEANUP: 1
|
||||
run: |
|
||||
brew install \
|
||||
llvm@${{ env.LLVM_VERSION }} \
|
||||
ccache \
|
||||
rust \
|
||||
pkg-config \
|
||||
coreutils \
|
||||
libtool \
|
||||
cmake \
|
||||
libiconv \
|
||||
automake \
|
||||
openssl@1.1 \
|
||||
ninja \
|
||||
golang \
|
||||
gnu-sed --force --overwrite
|
||||
echo "$(brew --prefix ccache)/bin" >> $GITHUB_PATH
|
||||
echo "$(brew --prefix coreutils)/libexec/gnubin" >> $GITHUB_PATH
|
||||
echo "$(brew --prefix llvm@$LLVM_VERSION)/bin" >> $GITHUB_PATH
|
||||
brew link --overwrite llvm@$LLVM_VERSION
|
||||
- if: ${{ inputs.no-cache || !steps.cache.outputs.cache-hit }}
|
||||
name: Clone Submodules
|
||||
run: |
|
||||
./scripts/update-submodules.sh
|
||||
- name: Build Submodules
|
||||
if: ${{ inputs.no-cache || !steps.cache.outputs.cache-hit }}
|
||||
env:
|
||||
CPU_TARGET: ${{ inputs.cpu }}
|
||||
BUN_DEPS_OUT_DIR: ${{ runner.temp }}/bun-deps
|
||||
run: |
|
||||
mkdir -p $BUN_DEPS_OUT_DIR
|
||||
./scripts/all-dependencies.sh
|
||||
- name: Save Cache
|
||||
if: ${{ inputs.no-cache || !steps.cache.outputs.cache-hit }}
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
path: ${{ runner.temp }}/bun-deps
|
||||
key: ${{ steps.cache.outputs.cache-primary-key }}
|
||||
- name: Upload bun-${{ inputs.tag }}-deps
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bun-${{ inputs.tag }}-deps
|
||||
path: ${{ runner.temp }}/bun-deps
|
||||
if-no-files-found: error
|
||||
build-cpp:
|
||||
name: Build C++
|
||||
runs-on: ${{ inputs.runs-on }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
# TODO: Figure out how to cache homebrew dependencies
|
||||
- name: Install Dependencies
|
||||
env:
|
||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
|
||||
HOMEBREW_NO_AUTO_UPDATE: 1
|
||||
HOMEBREW_NO_INSTALL_CLEANUP: 1
|
||||
run: |
|
||||
brew install \
|
||||
llvm@${{ env.LLVM_VERSION }} \
|
||||
ccache \
|
||||
rust \
|
||||
pkg-config \
|
||||
coreutils \
|
||||
libtool \
|
||||
cmake \
|
||||
libiconv \
|
||||
automake \
|
||||
openssl@1.1 \
|
||||
ninja \
|
||||
golang \
|
||||
gnu-sed --force --overwrite
|
||||
echo "$(brew --prefix ccache)/bin" >> $GITHUB_PATH
|
||||
echo "$(brew --prefix coreutils)/libexec/gnubin" >> $GITHUB_PATH
|
||||
echo "$(brew --prefix llvm@$LLVM_VERSION)/bin" >> $GITHUB_PATH
|
||||
brew link --overwrite llvm@$LLVM_VERSION
|
||||
- name: Setup Bun
|
||||
uses: ./.github/actions/setup-bun
|
||||
with:
|
||||
bun-version: ${{ env.BUN_VERSION }}
|
||||
- if: ${{ !inputs.no-cache }}
|
||||
name: Restore Cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ runner.temp }}/ccache
|
||||
key: bun-${{ inputs.tag }}-cpp-${{ hashFiles('Dockerfile', 'Makefile', 'CMakeLists.txt', 'build.zig', 'scripts/**', 'src/**', 'packages/bun-usockets/src/**', 'packages/bun-uws/src/**') }}
|
||||
restore-keys: |
|
||||
bun-${{ inputs.tag }}-cpp-
|
||||
- name: Compile
|
||||
env:
|
||||
CPU_TARGET: ${{ inputs.cpu }}
|
||||
SOURCE_DIR: ${{ github.workspace }}
|
||||
OBJ_DIR: ${{ runner.temp }}/bun-cpp-obj
|
||||
BUN_DEPS_OUT_DIR: ${{ runner.temp }}/bun-deps
|
||||
CCACHE_DIR: ${{ runner.temp }}/ccache
|
||||
run: |
|
||||
mkdir -p $OBJ_DIR
|
||||
cd $OBJ_DIR
|
||||
cmake -S $SOURCE_DIR -B $OBJ_DIR \
|
||||
-G Ninja \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DUSE_LTO=ON \
|
||||
-DBUN_CPP_ONLY=1 \
|
||||
-DNO_CONFIGURE_DEPENDS=1
|
||||
chmod +x compile-cpp-only.sh
|
||||
./compile-cpp-only.sh -v
|
||||
- name: Upload bun-${{ inputs.tag }}-cpp
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bun-${{ inputs.tag }}-cpp
|
||||
path: ${{ runner.temp }}/bun-cpp-obj/bun-cpp-objects.a
|
||||
if-no-files-found: error
|
||||
build-zig:
|
||||
name: Build Zig
|
||||
uses: ./.github/workflows/build-zig.yml
|
||||
with:
|
||||
os: darwin
|
||||
only-zig: true
|
||||
tag: ${{ inputs.tag }}
|
||||
arch: ${{ inputs.arch }}
|
||||
cpu: ${{ inputs.cpu }}
|
||||
assertions: ${{ inputs.assertions }}
|
||||
canary: ${{ inputs.canary }}
|
||||
no-cache: ${{ inputs.no-cache }}
|
||||
link:
|
||||
name: Link
|
||||
runs-on: ${{ inputs.runs-on }}
|
||||
needs:
|
||||
- build-submodules
|
||||
- build-cpp
|
||||
- build-zig
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
# TODO: Figure out how to cache homebrew dependencies
|
||||
- name: Install Dependencies
|
||||
env:
|
||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
|
||||
HOMEBREW_NO_AUTO_UPDATE: 1
|
||||
HOMEBREW_NO_INSTALL_CLEANUP: 1
|
||||
run: |
|
||||
brew install \
|
||||
llvm@${{ env.LLVM_VERSION }} \
|
||||
ccache \
|
||||
rust \
|
||||
pkg-config \
|
||||
coreutils \
|
||||
libtool \
|
||||
cmake \
|
||||
libiconv \
|
||||
automake \
|
||||
openssl@1.1 \
|
||||
ninja \
|
||||
golang \
|
||||
gnu-sed --force --overwrite
|
||||
echo "$(brew --prefix ccache)/bin" >> $GITHUB_PATH
|
||||
echo "$(brew --prefix coreutils)/libexec/gnubin" >> $GITHUB_PATH
|
||||
echo "$(brew --prefix llvm@$LLVM_VERSION)/bin" >> $GITHUB_PATH
|
||||
brew link --overwrite llvm@$LLVM_VERSION
|
||||
- name: Setup Bun
|
||||
uses: ./.github/actions/setup-bun
|
||||
with:
|
||||
bun-version: ${{ env.BUN_VERSION }}
|
||||
- name: Download bun-${{ inputs.tag }}-deps
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: bun-${{ inputs.tag }}-deps
|
||||
path: ${{ runner.temp }}/bun-deps
|
||||
- name: Download bun-${{ inputs.tag }}-cpp
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: bun-${{ inputs.tag }}-cpp
|
||||
path: ${{ runner.temp }}/bun-cpp-obj
|
||||
- name: Download bun-${{ inputs.tag }}-zig
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: bun-${{ inputs.tag }}-zig
|
||||
path: ${{ runner.temp }}/release
|
||||
- if: ${{ !inputs.no-cache }}
|
||||
name: Restore Cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ runner.temp }}/ccache
|
||||
key: bun-${{ inputs.tag }}-cpp-${{ hashFiles('Dockerfile', 'Makefile', 'CMakeLists.txt', 'build.zig', 'scripts/**', 'src/**', 'packages/bun-usockets/src/**', 'packages/bun-uws/src/**') }}
|
||||
restore-keys: |
|
||||
bun-${{ inputs.tag }}-cpp-
|
||||
- name: Link
|
||||
env:
|
||||
CPU_TARGET: ${{ inputs.cpu }}
|
||||
CCACHE_DIR: ${{ runner.temp }}/ccache
|
||||
run: |
|
||||
SRC_DIR=$PWD
|
||||
mkdir ${{ runner.temp }}/link-build
|
||||
cd ${{ runner.temp }}/link-build
|
||||
cmake $SRC_DIR \
|
||||
-G Ninja \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DUSE_LTO=ON \
|
||||
-DBUN_LINK_ONLY=1 \
|
||||
-DBUN_ZIG_OBJ_DIR="${{ runner.temp }}/release" \
|
||||
-DBUN_CPP_ARCHIVE="${{ runner.temp }}/bun-cpp-obj/bun-cpp-objects.a" \
|
||||
-DBUN_DEPS_OUT_DIR="${{ runner.temp }}/bun-deps" \
|
||||
-DNO_CONFIGURE_DEPENDS=1
|
||||
ninja -v
|
||||
- name: Prepare
|
||||
run: |
|
||||
cd ${{ runner.temp }}/link-build
|
||||
chmod +x bun-profile bun
|
||||
mkdir -p bun-${{ inputs.tag }}-profile/ bun-${{ inputs.tag }}/
|
||||
mv bun-profile bun-${{ inputs.tag }}-profile/bun-profile
|
||||
mv bun bun-${{ inputs.tag }}/bun
|
||||
zip -r bun-${{ inputs.tag }}-profile.zip bun-${{ inputs.tag }}-profile
|
||||
zip -r bun-${{ inputs.tag }}.zip bun-${{ inputs.tag }}
|
||||
- name: Upload bun-${{ inputs.tag }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bun-${{ inputs.tag }}
|
||||
path: ${{ runner.temp }}/link-build/bun-${{ inputs.tag }}.zip
|
||||
if-no-files-found: error
|
||||
- name: Upload bun-${{ inputs.tag }}-profile
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bun-${{ inputs.tag }}-profile
|
||||
path: ${{ runner.temp }}/link-build/bun-${{ inputs.tag }}-profile.zip
|
||||
if-no-files-found: error
|
||||
on-failure:
|
||||
if: ${{ github.repository_owner == 'oven-sh' && failure() }}
|
||||
name: On Failure
|
||||
needs: link
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Send Message
|
||||
uses: sarisia/actions-status-discord@v1
|
||||
with:
|
||||
webhook: ${{ secrets.DISCORD_WEBHOOK }}
|
||||
nodetail: true
|
||||
color: "#FF0000"
|
||||
title: ""
|
||||
description: |
|
||||
### ❌ [${{ github.event.pull_request.title }}](${{ github.event.pull_request.html_url }})
|
||||
|
||||
@${{ github.actor }}, the build for bun-${{ inputs.tag }} failed.
|
||||
|
||||
**[View logs](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})**
|
||||
64
.github/workflows/build-linux.yml
vendored
64
.github/workflows/build-linux.yml
vendored
@@ -1,64 +0,0 @@
|
||||
name: Build Linux
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
actions: write
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
runs-on:
|
||||
type: string
|
||||
required: true
|
||||
tag:
|
||||
type: string
|
||||
required: true
|
||||
arch:
|
||||
type: string
|
||||
required: true
|
||||
cpu:
|
||||
type: string
|
||||
required: true
|
||||
assertions:
|
||||
type: boolean
|
||||
zig-optimize:
|
||||
type: string
|
||||
canary:
|
||||
type: boolean
|
||||
no-cache:
|
||||
type: boolean
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build Linux
|
||||
uses: ./.github/workflows/build-zig.yml
|
||||
with:
|
||||
os: linux
|
||||
only-zig: false
|
||||
runs-on: ${{ inputs.runs-on }}
|
||||
tag: ${{ inputs.tag }}
|
||||
arch: ${{ inputs.arch }}
|
||||
cpu: ${{ inputs.cpu }}
|
||||
assertions: ${{ inputs.assertions }}
|
||||
zig-optimize: ${{ inputs.zig-optimize }}
|
||||
canary: ${{ inputs.canary }}
|
||||
no-cache: ${{ inputs.no-cache }}
|
||||
on-failure:
|
||||
if: ${{ github.repository_owner == 'oven-sh' && failure() }}
|
||||
name: On Failure
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Send Message
|
||||
uses: sarisia/actions-status-discord@v1
|
||||
with:
|
||||
webhook: ${{ secrets.DISCORD_WEBHOOK }}
|
||||
nodetail: true
|
||||
color: "#FF0000"
|
||||
title: ""
|
||||
description: |
|
||||
### ❌ [${{ github.event.pull_request.title }}](${{ github.event.pull_request.html_url }})
|
||||
|
||||
@${{ github.actor }}, the build for bun-${{ inputs.tag }} failed.
|
||||
|
||||
**[View logs](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})**
|
||||
339
.github/workflows/build-windows.yml
vendored
339
.github/workflows/build-windows.yml
vendored
@@ -1,339 +0,0 @@
|
||||
name: Build Windows
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
actions: write
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
runs-on:
|
||||
type: string
|
||||
default: windows
|
||||
tag:
|
||||
type: string
|
||||
required: true
|
||||
arch:
|
||||
type: string
|
||||
required: true
|
||||
cpu:
|
||||
type: string
|
||||
required: true
|
||||
assertions:
|
||||
type: boolean
|
||||
canary:
|
||||
type: boolean
|
||||
no-cache:
|
||||
type: boolean
|
||||
bun-version:
|
||||
type: string
|
||||
default: 1.1.7
|
||||
|
||||
env:
|
||||
# Must specify exact version of LLVM for Windows
|
||||
LLVM_VERSION: 16.0.6
|
||||
BUN_VERSION: ${{ inputs.bun-version }}
|
||||
BUN_GARBAGE_COLLECTOR_LEVEL: 1
|
||||
BUN_FEATURE_FLAG_INTERNAL_FOR_TESTING: 1
|
||||
CI: true
|
||||
USE_LTO: 1
|
||||
|
||||
jobs:
|
||||
build-submodules:
|
||||
name: Build Submodules
|
||||
runs-on: ${{ inputs.runs-on }}
|
||||
steps:
|
||||
- name: Install VS2022 BuildTools 17.9.7
|
||||
run: choco install -y visualstudio2022buildtools --version=117.9.7.0 --params "--add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 --installChannelUri https://aka.ms/vs/17/release/180911598_-255012421/channel"
|
||||
- name: Setup Git
|
||||
run: |
|
||||
git config --global core.autocrlf false
|
||||
git config --global core.eol lf
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: |
|
||||
.gitmodules
|
||||
src/deps
|
||||
scripts
|
||||
- name: Hash Submodules
|
||||
id: hash
|
||||
run: |
|
||||
$data = "$(& {
|
||||
git submodule | Where-Object { $_ -notmatch 'WebKit' }
|
||||
echo "LLVM_VERSION=${{ env.LLVM_VERSION }}"
|
||||
Get-Content -Path (Get-ChildItem -Path 'scripts/build*.ps1', 'scripts/all-dependencies.ps1', 'scripts/env.ps1' | Sort-Object -Property Name).FullName | Out-String
|
||||
echo 1
|
||||
})"
|
||||
$hash = ( -join ((New-Object -TypeName System.Security.Cryptography.SHA1CryptoServiceProvider).ComputeHash([System.Text.Encoding]::UTF8.GetBytes($data)) | ForEach-Object { $_.ToString("x2") } )).Substring(0, 10)
|
||||
echo "hash=${hash}" >> $env:GITHUB_OUTPUT
|
||||
- if: ${{ !inputs.no-cache }}
|
||||
name: Restore Cache
|
||||
id: cache
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: bun-deps
|
||||
key: bun-${{ inputs.tag }}-deps-${{ steps.hash.outputs.hash }}
|
||||
- if: ${{ inputs.no-cache || !steps.cache.outputs.cache-hit }}
|
||||
name: Install Ninja
|
||||
run: |
|
||||
choco install -y ninja
|
||||
choco install -y llvm --version=${{ env.LLVM_VERSION }} --force
|
||||
- if: ${{ inputs.no-cache || !steps.cache.outputs.cache-hit }}
|
||||
name: Clone Submodules
|
||||
run: |
|
||||
.\scripts\update-submodules.ps1
|
||||
- if: ${{ inputs.no-cache || !steps.cache.outputs.cache-hit }}
|
||||
name: Build Dependencies
|
||||
env:
|
||||
CPU_TARGET: ${{ inputs.cpu }}
|
||||
CCACHE_DIR: ccache
|
||||
USE_LTO: 1
|
||||
run: |
|
||||
.\scripts\env.ps1 ${{ contains(inputs.tag, '-baseline') && '-Baseline' || '' }}
|
||||
choco install -y nasm --version=2.16.01
|
||||
$env:BUN_DEPS_OUT_DIR = (mkdir -Force "./bun-deps")
|
||||
.\scripts\all-dependencies.ps1
|
||||
- name: Save Cache
|
||||
if: ${{ inputs.no-cache || !steps.cache.outputs.cache-hit }}
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
path: bun-deps
|
||||
key: ${{ steps.cache.outputs.cache-primary-key }}
|
||||
- name: Upload bun-${{ inputs.tag }}-deps
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bun-${{ inputs.tag }}-deps
|
||||
path: bun-deps
|
||||
if-no-files-found: error
|
||||
codegen:
|
||||
name: Codegen
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Setup Git
|
||||
run: |
|
||||
git config --global core.autocrlf false
|
||||
git config --global core.eol lf
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup Bun
|
||||
uses: ./.github/actions/setup-bun
|
||||
with:
|
||||
bun-version: ${{ inputs.bun-version }}
|
||||
- name: Codegen
|
||||
run: |
|
||||
./scripts/cross-compile-codegen.sh win32 x64
|
||||
- if: ${{ inputs.canary }}
|
||||
name: Calculate Revision
|
||||
run: |
|
||||
echo "canary_revision=$(GITHUB_TOKEN="${{ github.token }}"
|
||||
bash ./scripts/calculate-canary-revision.sh --raw)" > build-codegen-win32-x64/.canary_revision
|
||||
- name: Upload bun-${{ inputs.tag }}-codegen
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bun-${{ inputs.tag }}-codegen
|
||||
path: build-codegen-win32-x64
|
||||
if-no-files-found: error
|
||||
build-cpp:
|
||||
name: Build C++
|
||||
needs: codegen
|
||||
runs-on: ${{ inputs.runs-on }}
|
||||
steps:
|
||||
- name: Install VS2022 BuildTools 17.9.7
|
||||
run: choco install -y visualstudio2022buildtools --version=117.9.7.0 --params "--add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 --installChannelUri https://aka.ms/vs/17/release/180911598_-255012421/channel"
|
||||
- name: Setup Git
|
||||
run: |
|
||||
git config --global core.autocrlf false
|
||||
git config --global core.eol lf
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Install Ninja
|
||||
run: |
|
||||
choco install -y ninja
|
||||
choco install -y llvm --version=${{ env.LLVM_VERSION }} --force
|
||||
- name: Setup Bun
|
||||
uses: ./.github/actions/setup-bun
|
||||
with:
|
||||
bun-version: ${{ inputs.bun-version }}
|
||||
- if: ${{ !inputs.no-cache }}
|
||||
name: Restore Cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ccache
|
||||
key: bun-${{ inputs.tag }}-cpp-${{ hashFiles('Dockerfile', 'Makefile', 'CMakeLists.txt', 'build.zig', 'scripts/**', 'src/**', 'packages/bun-usockets/src/**', 'packages/bun-uws/src/**') }}
|
||||
restore-keys: |
|
||||
bun-${{ inputs.tag }}-cpp-
|
||||
- name: Download bun-${{ inputs.tag }}-codegen
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: bun-${{ inputs.tag }}-codegen
|
||||
path: build
|
||||
- name: Compile
|
||||
env:
|
||||
CPU_TARGET: ${{ inputs.cpu }}
|
||||
CCACHE_DIR: ccache
|
||||
USE_LTO: 1
|
||||
run: |
|
||||
# $CANARY_REVISION = if (Test-Path build/.canary_revision) { Get-Content build/.canary_revision } else { "0" }
|
||||
$CANARY_REVISION = 0
|
||||
.\scripts\env.ps1 ${{ contains(inputs.tag, '-baseline') && '-Baseline' || '' }}
|
||||
.\scripts\update-submodules.ps1
|
||||
.\scripts\build-libuv.ps1 -CloneOnly $True
|
||||
cd build
|
||||
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release `
|
||||
-DNO_CODEGEN=1 `
|
||||
-DUSE_LTO=1 `
|
||||
-DNO_CONFIGURE_DEPENDS=1 `
|
||||
"-DCANARY=${CANARY_REVISION}" `
|
||||
-DBUN_CPP_ONLY=1 ${{ contains(inputs.tag, '-baseline') && '-DUSE_BASELINE_BUILD=1' || '' }}
|
||||
if ($LASTEXITCODE -ne 0) { throw "CMake configuration failed" }
|
||||
.\compile-cpp-only.ps1 -v
|
||||
if ($LASTEXITCODE -ne 0) { throw "C++ compilation failed" }
|
||||
- name: Upload bun-${{ inputs.tag }}-cpp
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bun-${{ inputs.tag }}-cpp
|
||||
path: build/bun-cpp-objects.a
|
||||
if-no-files-found: error
|
||||
build-zig:
|
||||
name: Build Zig
|
||||
uses: ./.github/workflows/build-zig.yml
|
||||
with:
|
||||
os: windows
|
||||
zig-optimize: ReleaseSafe
|
||||
only-zig: true
|
||||
tag: ${{ inputs.tag }}
|
||||
arch: ${{ inputs.arch }}
|
||||
cpu: ${{ inputs.cpu }}
|
||||
assertions: ${{ inputs.assertions }}
|
||||
canary: ${{ inputs.canary }}
|
||||
no-cache: ${{ inputs.no-cache }}
|
||||
link:
|
||||
name: Link
|
||||
runs-on: ${{ inputs.runs-on }}
|
||||
needs:
|
||||
- build-submodules
|
||||
- build-cpp
|
||||
- build-zig
|
||||
- codegen
|
||||
steps:
|
||||
- name: Install VS2022 BuildTools 17.9.7
|
||||
run: choco install -y visualstudio2022buildtools --version=117.9.7.0 --params "--add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 --installChannelUri https://aka.ms/vs/17/release/180911598_-255012421/channel"
|
||||
- name: Setup Git
|
||||
run: |
|
||||
git config --global core.autocrlf false
|
||||
git config --global core.eol lf
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Install Ninja
|
||||
run: |
|
||||
choco install -y ninja
|
||||
choco install -y llvm --version=${{ env.LLVM_VERSION }} --force
|
||||
- name: Setup Bun
|
||||
uses: ./.github/actions/setup-bun
|
||||
with:
|
||||
bun-version: ${{ inputs.bun-version }}
|
||||
- name: Download bun-${{ inputs.tag }}-deps
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: bun-${{ inputs.tag }}-deps
|
||||
path: bun-deps
|
||||
- name: Download bun-${{ inputs.tag }}-cpp
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: bun-${{ inputs.tag }}-cpp
|
||||
path: bun-cpp
|
||||
- name: Download bun-${{ inputs.tag }}-zig
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: bun-${{ inputs.tag }}-zig
|
||||
path: bun-zig
|
||||
- name: Download bun-${{ inputs.tag }}-codegen
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: bun-${{ inputs.tag }}-codegen
|
||||
path: build
|
||||
- if: ${{ !inputs.no-cache }}
|
||||
name: Restore Cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ccache
|
||||
key: bun-${{ inputs.tag }}-cpp-${{ hashFiles('Dockerfile', 'Makefile', 'CMakeLists.txt', 'build.zig', 'scripts/**', 'src/**', 'packages/bun-usockets/src/**', 'packages/bun-uws/src/**') }}
|
||||
restore-keys: |
|
||||
bun-${{ inputs.tag }}-cpp-
|
||||
- name: Link
|
||||
env:
|
||||
CPU_TARGET: ${{ inputs.cpu }}
|
||||
CCACHE_DIR: ccache
|
||||
run: |
|
||||
.\scripts\update-submodules.ps1
|
||||
.\scripts\env.ps1 ${{ contains(inputs.tag, '-baseline') && '-Baseline' || '' }}
|
||||
Set-Location build
|
||||
# $CANARY_REVISION = if (Test-Path build/.canary_revision) { Get-Content build/.canary_revision } else { "0" }
|
||||
$CANARY_REVISION = 0
|
||||
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release `
|
||||
-DNO_CODEGEN=1 `
|
||||
-DNO_CONFIGURE_DEPENDS=1 `
|
||||
"-DCANARY=${CANARY_REVISION}" `
|
||||
-DBUN_LINK_ONLY=1 `
|
||||
-DUSE_LTO=1 `
|
||||
"-DBUN_DEPS_OUT_DIR=$(Resolve-Path ../bun-deps)" `
|
||||
"-DBUN_CPP_ARCHIVE=$(Resolve-Path ../bun-cpp/bun-cpp-objects.a)" `
|
||||
"-DBUN_ZIG_OBJ_DIR=$(Resolve-Path ../bun-zig)" `
|
||||
${{ contains(inputs.tag, '-baseline') && '-DUSE_BASELINE_BUILD=1' || '' }}
|
||||
if ($LASTEXITCODE -ne 0) { throw "CMake configuration failed" }
|
||||
ninja -v
|
||||
if ($LASTEXITCODE -ne 0) { throw "Link failed!" }
|
||||
- name: Prepare
|
||||
run: |
|
||||
$Dist = mkdir -Force "bun-${{ inputs.tag }}"
|
||||
cp -r build\bun.exe "$Dist\bun.exe"
|
||||
Compress-Archive -Force "$Dist" "${Dist}.zip"
|
||||
$Dist = "$Dist-profile"
|
||||
MkDir -Force "$Dist"
|
||||
cp -r build\bun.exe "$Dist\bun.exe"
|
||||
cp -r build\bun.pdb "$Dist\bun.pdb"
|
||||
Compress-Archive -Force "$Dist" "$Dist.zip"
|
||||
.\build\bun.exe --print "JSON.stringify(require('bun:internal-for-testing').crash_handler.getFeatureData())" > .\features.json
|
||||
- name: Upload bun-${{ inputs.tag }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bun-${{ inputs.tag }}
|
||||
path: bun-${{ inputs.tag }}.zip
|
||||
if-no-files-found: error
|
||||
- name: Upload bun-${{ inputs.tag }}-profile
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bun-${{ inputs.tag }}-profile
|
||||
path: bun-${{ inputs.tag }}-profile.zip
|
||||
if-no-files-found: error
|
||||
- name: Upload bun-feature-data
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bun-feature-data
|
||||
path: features.json
|
||||
if-no-files-found: error
|
||||
overwrite: true
|
||||
on-failure:
|
||||
if: ${{ github.repository_owner == 'oven-sh' && failure() }}
|
||||
name: On Failure
|
||||
needs: link
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Send Message
|
||||
uses: sarisia/actions-status-discord@v1
|
||||
with:
|
||||
webhook: ${{ secrets.DISCORD_WEBHOOK }}
|
||||
nodetail: true
|
||||
color: "#FF0000"
|
||||
title: ""
|
||||
description: |
|
||||
### ❌ [${{ github.event.pull_request.title }}](${{ github.event.pull_request.html_url }})
|
||||
|
||||
@${{ github.actor }}, the build for bun-${{ inputs.tag }} failed.
|
||||
|
||||
**[View logs](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})**
|
||||
122
.github/workflows/build-zig.yml
vendored
122
.github/workflows/build-zig.yml
vendored
@@ -1,122 +0,0 @@
|
||||
name: Build Zig
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
actions: write
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
runs-on:
|
||||
type: string
|
||||
default: ${{ github.repository_owner != 'oven-sh' && 'ubuntu-latest' || inputs.only-zig && 'namespace-profile-bun-ci-linux-x64' || inputs.arch == 'x64' && 'namespace-profile-bun-ci-linux-x64' || 'namespace-profile-bun-ci-linux-aarch64' }}
|
||||
tag:
|
||||
type: string
|
||||
required: true
|
||||
os:
|
||||
type: string
|
||||
required: true
|
||||
arch:
|
||||
type: string
|
||||
required: true
|
||||
cpu:
|
||||
type: string
|
||||
required: true
|
||||
assertions:
|
||||
type: boolean
|
||||
default: false
|
||||
zig-optimize:
|
||||
type: string # 'ReleaseSafe' or 'ReleaseFast'
|
||||
default: ReleaseFast
|
||||
canary:
|
||||
type: boolean
|
||||
default: ${{ github.ref == 'refs/heads/main' }}
|
||||
only-zig:
|
||||
type: boolean
|
||||
default: true
|
||||
no-cache:
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
build-zig:
|
||||
name: ${{ inputs.only-zig && 'Build Zig' || 'Build & Link' }}
|
||||
runs-on: ${{ inputs.runs-on }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Calculate Cache Key
|
||||
id: cache
|
||||
run: |
|
||||
echo "key=${{ hashFiles('Dockerfile', 'Makefile', 'CMakeLists.txt', 'build.zig', 'scripts/**', 'src/**', 'packages/bun-usockets/src/**', 'packages/bun-uws/src/**') }}" >> $GITHUB_OUTPUT
|
||||
- if: ${{ !inputs.no-cache }}
|
||||
name: Restore Cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
key: bun-${{ inputs.tag }}-docker-${{ steps.cache.outputs.key }}
|
||||
restore-keys: |
|
||||
bun-${{ inputs.tag }}-docker-
|
||||
path: |
|
||||
${{ runner.temp }}/dockercache
|
||||
- name: Setup Docker
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
install: true
|
||||
platforms: |
|
||||
linux/${{ runner.arch == 'X64' && 'amd64' || 'arm64' }}
|
||||
- name: Build
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
push: false
|
||||
target: ${{ inputs.only-zig && 'build_release_obj' || 'artifact' }}
|
||||
cache-from: |
|
||||
type=local,src=${{ runner.temp }}/dockercache
|
||||
cache-to: |
|
||||
type=local,dest=${{ runner.temp }}/dockercache,mode=max
|
||||
outputs: |
|
||||
type=local,dest=${{ runner.temp }}/release
|
||||
platforms: |
|
||||
linux/${{ runner.arch == 'X64' && 'amd64' || 'arm64' }}
|
||||
build-args: |
|
||||
GIT_SHA=${{ github.event.workflow_run.head_sha || github.sha }}
|
||||
TRIPLET=${{ inputs.os == 'darwin' && format('{0}-macos-none', inputs.arch == 'x64' && 'x86_64' || 'aarch64') || inputs.os == 'windows' && format('{0}-windows-msvc', inputs.arch == 'x64' && 'x86_64' || 'aarch64') || format('{0}-linux-gnu', inputs.arch == 'x64' && 'x86_64' || 'aarch64') }}
|
||||
ARCH=${{ inputs.arch == 'x64' && 'x86_64' || 'aarch64' }}
|
||||
BUILDARCH=${{ inputs.arch == 'x64' && 'amd64' || 'arm64' }}
|
||||
BUILD_MACHINE_ARCH=${{ inputs.arch == 'x64' && 'x86_64' || 'aarch64' }}
|
||||
CPU_TARGET=${{ inputs.arch == 'x64' && inputs.cpu || 'native' }}
|
||||
ASSERTIONS=${{ inputs.assertions && 'ON' || 'OFF' }}
|
||||
ZIG_OPTIMIZE=${{ inputs.zig-optimize }}
|
||||
CANARY=${{ inputs.canary && '1' || '0' }}
|
||||
- if: ${{ inputs.only-zig }}
|
||||
name: Upload bun-${{ inputs.tag }}-zig
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bun-${{ inputs.tag }}-zig
|
||||
path: ${{ runner.temp }}/release/bun-zig.o
|
||||
if-no-files-found: error
|
||||
- if: ${{ !inputs.only-zig }}
|
||||
name: Prepare
|
||||
run: |
|
||||
cd ${{ runner.temp }}/release
|
||||
chmod +x bun-profile bun
|
||||
mkdir bun-${{ inputs.tag }}-profile
|
||||
mkdir bun-${{ inputs.tag }}
|
||||
strip bun
|
||||
mv bun-profile bun-${{ inputs.tag }}-profile/bun-profile
|
||||
mv bun bun-${{ inputs.tag }}/bun
|
||||
zip -r bun-${{ inputs.tag }}-profile.zip bun-${{ inputs.tag }}-profile
|
||||
zip -r bun-${{ inputs.tag }}.zip bun-${{ inputs.tag }}
|
||||
- if: ${{ !inputs.only-zig }}
|
||||
name: Upload bun-${{ inputs.tag }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bun-${{ inputs.tag }}
|
||||
path: ${{ runner.temp }}/release/bun-${{ inputs.tag }}.zip
|
||||
if-no-files-found: error
|
||||
- if: ${{ !inputs.only-zig }}
|
||||
name: Upload bun-${{ inputs.tag }}-profile
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bun-${{ inputs.tag }}-profile
|
||||
path: ${{ runner.temp }}/release/bun-${{ inputs.tag }}-profile.zip
|
||||
if-no-files-found: error
|
||||
245
.github/workflows/ci.yml
vendored
245
.github/workflows/ci.yml
vendored
@@ -1,245 +0,0 @@
|
||||
name: CI
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
actions: write
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event_name == 'workflow_dispatch' && inputs.run-id || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
run-id:
|
||||
type: string
|
||||
description: The workflow ID to download artifacts (skips the build step)
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- .vscode/**/*
|
||||
- docs/**/*
|
||||
- examples/**/*
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths-ignore:
|
||||
- .vscode/**/*
|
||||
- docs/**/*
|
||||
- examples/**/*
|
||||
|
||||
jobs:
|
||||
format:
|
||||
if: ${{ !inputs.run-id }}
|
||||
name: Format
|
||||
uses: ./.github/workflows/run-format.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
zig-version: 0.13.0
|
||||
permissions:
|
||||
contents: write
|
||||
lint:
|
||||
if: ${{ !inputs.run-id }}
|
||||
name: Lint
|
||||
uses: ./.github/workflows/run-lint.yml
|
||||
secrets: inherit
|
||||
linux-x64:
|
||||
if: ${{ !inputs.run-id }}
|
||||
name: Build linux-x64
|
||||
uses: ./.github/workflows/build-linux.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
runs-on: ${{ github.repository_owner == 'oven-sh' && 'namespace-profile-bun-ci-linux-x64' || 'ubuntu-latest' }}
|
||||
tag: linux-x64
|
||||
arch: x64
|
||||
cpu: haswell
|
||||
canary: true
|
||||
no-cache: true
|
||||
linux-x64-baseline:
|
||||
if: ${{ !inputs.run-id }}
|
||||
name: Build linux-x64-baseline
|
||||
uses: ./.github/workflows/build-linux.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
runs-on: ${{ github.repository_owner == 'oven-sh' && 'namespace-profile-bun-ci-linux-x64' || 'ubuntu-latest' }}
|
||||
tag: linux-x64-baseline
|
||||
arch: x64
|
||||
cpu: nehalem
|
||||
canary: true
|
||||
no-cache: true
|
||||
linux-aarch64:
|
||||
if: ${{ !inputs.run-id && github.repository_owner == 'oven-sh' }}
|
||||
name: Build linux-aarch64
|
||||
uses: ./.github/workflows/build-linux.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
runs-on: namespace-profile-bun-ci-linux-aarch64
|
||||
tag: linux-aarch64
|
||||
arch: aarch64
|
||||
cpu: native
|
||||
canary: true
|
||||
no-cache: true
|
||||
darwin-x64:
|
||||
if: ${{ !inputs.run-id }}
|
||||
name: Build darwin-x64
|
||||
uses: ./.github/workflows/build-darwin.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
runs-on: ${{ github.repository_owner == 'oven-sh' && 'macos-12-large' || 'macos-12' }}
|
||||
tag: darwin-x64
|
||||
arch: x64
|
||||
cpu: haswell
|
||||
canary: true
|
||||
darwin-x64-baseline:
|
||||
if: ${{ !inputs.run-id }}
|
||||
name: Build darwin-x64-baseline
|
||||
uses: ./.github/workflows/build-darwin.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
runs-on: ${{ github.repository_owner == 'oven-sh' && 'macos-12-large' || 'macos-12' }}
|
||||
tag: darwin-x64-baseline
|
||||
arch: x64
|
||||
cpu: nehalem
|
||||
canary: true
|
||||
darwin-aarch64:
|
||||
if: ${{ !inputs.run-id }}
|
||||
name: Build darwin-aarch64
|
||||
uses: ./.github/workflows/build-darwin.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
runs-on: ${{ github.repository_owner == 'oven-sh' && 'namespace-profile-bun-ci-darwin-aarch64' || 'macos-12' }}
|
||||
tag: darwin-aarch64
|
||||
arch: aarch64
|
||||
cpu: native
|
||||
canary: true
|
||||
windows-x64:
|
||||
if: ${{ !inputs.run-id }}
|
||||
name: Build windows-x64
|
||||
uses: ./.github/workflows/build-windows.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
runs-on: windows
|
||||
tag: windows-x64
|
||||
arch: x64
|
||||
cpu: haswell
|
||||
canary: true
|
||||
windows-x64-baseline:
|
||||
if: ${{ !inputs.run-id }}
|
||||
name: Build windows-x64-baseline
|
||||
uses: ./.github/workflows/build-windows.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
runs-on: windows
|
||||
tag: windows-x64-baseline
|
||||
arch: x64
|
||||
cpu: nehalem
|
||||
canary: true
|
||||
linux-x64-test:
|
||||
if: ${{ inputs.run-id || github.event_name == 'pull_request' }}
|
||||
name: Test linux-x64
|
||||
needs: linux-x64
|
||||
uses: ./.github/workflows/run-test.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
run-id: ${{ inputs.run-id }}
|
||||
pr-number: ${{ github.event.number }}
|
||||
runs-on: ${{ github.repository_owner == 'oven-sh' && 'namespace-profile-bun-ci-linux-x64' || 'ubuntu-latest' }}
|
||||
tag: linux-x64
|
||||
linux-x64-baseline-test:
|
||||
if: ${{ inputs.run-id || github.event_name == 'pull_request' }}
|
||||
name: Test linux-x64-baseline
|
||||
needs: linux-x64-baseline
|
||||
uses: ./.github/workflows/run-test.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
run-id: ${{ inputs.run-id }}
|
||||
pr-number: ${{ github.event.number }}
|
||||
runs-on: ${{ github.repository_owner == 'oven-sh' && 'namespace-profile-bun-ci-linux-x64' || 'ubuntu-latest' }}
|
||||
tag: linux-x64-baseline
|
||||
linux-aarch64-test:
|
||||
if: ${{ inputs.run-id || github.event_name == 'pull_request' && github.repository_owner == 'oven-sh'}}
|
||||
name: Test linux-aarch64
|
||||
needs: linux-aarch64
|
||||
uses: ./.github/workflows/run-test.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
run-id: ${{ inputs.run-id }}
|
||||
pr-number: ${{ github.event.number }}
|
||||
runs-on: namespace-profile-bun-ci-linux-aarch64
|
||||
tag: linux-aarch64
|
||||
darwin-x64-test:
|
||||
if: ${{ inputs.run-id || github.event_name == 'pull_request' }}
|
||||
name: Test darwin-x64
|
||||
needs: darwin-x64
|
||||
uses: ./.github/workflows/run-test.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
run-id: ${{ inputs.run-id }}
|
||||
pr-number: ${{ github.event.number }}
|
||||
runs-on: ${{ github.repository_owner == 'oven-sh' && 'macos-12-large' || 'macos-12' }}
|
||||
tag: darwin-x64
|
||||
darwin-x64-baseline-test:
|
||||
if: ${{ inputs.run-id || github.event_name == 'pull_request' }}
|
||||
name: Test darwin-x64-baseline
|
||||
needs: darwin-x64-baseline
|
||||
uses: ./.github/workflows/run-test.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
run-id: ${{ inputs.run-id }}
|
||||
pr-number: ${{ github.event.number }}
|
||||
runs-on: ${{ github.repository_owner == 'oven-sh' && 'macos-12-large' || 'macos-12' }}
|
||||
tag: darwin-x64-baseline
|
||||
darwin-aarch64-test:
|
||||
if: ${{ inputs.run-id || github.event_name == 'pull_request' }}
|
||||
name: Test darwin-aarch64
|
||||
needs: darwin-aarch64
|
||||
uses: ./.github/workflows/run-test.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
run-id: ${{ inputs.run-id }}
|
||||
pr-number: ${{ github.event.number }}
|
||||
runs-on: ${{ github.repository_owner == 'oven-sh' && 'namespace-profile-bun-ci-darwin-aarch64' || 'macos-12' }}
|
||||
tag: darwin-aarch64
|
||||
windows-x64-test:
|
||||
if: ${{ inputs.run-id || github.event_name == 'pull_request' }}
|
||||
name: Test windows-x64
|
||||
needs: windows-x64
|
||||
uses: ./.github/workflows/run-test.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
run-id: ${{ inputs.run-id }}
|
||||
pr-number: ${{ github.event.number }}
|
||||
runs-on: windows
|
||||
tag: windows-x64
|
||||
windows-x64-baseline-test:
|
||||
if: ${{ inputs.run-id || github.event_name == 'pull_request' }}
|
||||
name: Test windows-x64-baseline
|
||||
needs: windows-x64-baseline
|
||||
uses: ./.github/workflows/run-test.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
run-id: ${{ inputs.run-id }}
|
||||
pr-number: ${{ github.event.number }}
|
||||
runs-on: windows
|
||||
tag: windows-x64-baseline
|
||||
cleanup:
|
||||
if: ${{ always() }}
|
||||
name: Cleanup
|
||||
needs:
|
||||
- linux-x64
|
||||
- linux-x64-baseline
|
||||
- linux-aarch64
|
||||
- darwin-x64
|
||||
- darwin-x64-baseline
|
||||
- darwin-aarch64
|
||||
- windows-x64
|
||||
- windows-x64-baseline
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Cleanup Artifacts
|
||||
uses: geekyeggo/delete-artifact@v5
|
||||
with:
|
||||
name: |
|
||||
bun-*-cpp
|
||||
bun-*-zig
|
||||
bun-*-deps
|
||||
bun-*-codegen
|
||||
55
.github/workflows/comment.yml
vendored
55
.github/workflows/comment.yml
vendored
@@ -1,55 +0,0 @@
|
||||
name: Comment
|
||||
|
||||
permissions:
|
||||
actions: read
|
||||
pull-requests: write
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows:
|
||||
- CI
|
||||
types:
|
||||
- completed
|
||||
|
||||
jobs:
|
||||
comment:
|
||||
if: ${{ github.repository_owner == 'oven-sh' }}
|
||||
name: Comment
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download Tests
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: bun
|
||||
pattern: bun-*-tests
|
||||
github-token: ${{ github.token }}
|
||||
run-id: ${{ github.event.workflow_run.id }}
|
||||
- name: Setup Environment
|
||||
id: env
|
||||
shell: bash
|
||||
run: |
|
||||
echo "pr-number=$(<bun/bun-linux-x64-tests/pr-number.txt)" >> $GITHUB_OUTPUT
|
||||
- name: Generate Comment
|
||||
run: |
|
||||
cat bun/bun-*-tests/comment.md > comment.md
|
||||
if [ -s comment.md ]; then
|
||||
echo -e "❌ @${{ github.actor }}, your commit has failing tests :(\n\n$(cat comment.md)" > comment.md
|
||||
else
|
||||
echo -e "✅ @${{ github.actor }}, all tests passed!" > comment.md
|
||||
fi
|
||||
echo -e "\n**[View logs](https://github.com/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }})**" >> comment.md
|
||||
echo -e "<!-- generated-comment workflow=${{ github.workflow }} -->" >> comment.md
|
||||
- name: Find Comment
|
||||
id: comment
|
||||
uses: peter-evans/find-comment@v3
|
||||
with:
|
||||
issue-number: ${{ steps.env.outputs.pr-number }}
|
||||
comment-author: github-actions[bot]
|
||||
body-includes: <!-- generated-comment workflow=${{ github.workflow }} -->
|
||||
- name: Write Comment
|
||||
uses: peter-evans/create-or-update-comment@v4
|
||||
with:
|
||||
comment-id: ${{ steps.comment.outputs.comment-id }}
|
||||
issue-number: ${{ steps.env.outputs.pr-number }}
|
||||
body-path: comment.md
|
||||
edit-mode: replace
|
||||
183
.github/workflows/create-release-build.yml
vendored
183
.github/workflows/create-release-build.yml
vendored
@@ -1,183 +0,0 @@
|
||||
name: Create Release Build
|
||||
run-name: Compile Bun v${{ inputs.version }} by ${{ github.actor }}
|
||||
|
||||
concurrency:
|
||||
group: release
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
actions: write
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
type: string
|
||||
required: true
|
||||
description: "Release version. Example: 1.1.4. Exclude the 'v' prefix."
|
||||
tag:
|
||||
type: string
|
||||
required: true
|
||||
description: "GitHub tag to use"
|
||||
clobber:
|
||||
type: boolean
|
||||
required: false
|
||||
default: false
|
||||
description: "Overwrite existing release artifacts?"
|
||||
release:
|
||||
types:
|
||||
- created
|
||||
|
||||
jobs:
|
||||
notify-start:
|
||||
if: ${{ github.repository_owner == 'oven-sh' }}
|
||||
name: Notify Start
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Send Message
|
||||
uses: sarisia/actions-status-discord@v1
|
||||
with:
|
||||
webhook: ${{ secrets.DISCORD_WEBHOOK_PUBLIC }}
|
||||
nodetail: true
|
||||
color: "#1F6FEB"
|
||||
title: "Bun v${{ inputs.version }} is compiling"
|
||||
description: |
|
||||
### @${{ github.actor }} started compiling Bun v${{inputs.version}}
|
||||
- name: Send Message
|
||||
uses: sarisia/actions-status-discord@v1
|
||||
with:
|
||||
webhook: ${{ secrets.BUN_DISCORD_GITHUB_CHANNEL_WEBHOOK }}
|
||||
nodetail: true
|
||||
color: "#1F6FEB"
|
||||
title: "Bun v${{ inputs.version }} is compiling"
|
||||
description: |
|
||||
### @${{ github.actor }} started compiling Bun v${{inputs.version}}
|
||||
|
||||
**[View logs](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})**
|
||||
linux-x64:
|
||||
name: Build linux-x64
|
||||
uses: ./.github/workflows/build-linux.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
runs-on: ${{ github.repository_owner == 'oven-sh' && 'namespace-profile-bun-ci-linux-x64' || 'ubuntu-latest' }}
|
||||
tag: linux-x64
|
||||
arch: x64
|
||||
cpu: haswell
|
||||
canary: false
|
||||
linux-x64-baseline:
|
||||
name: Build linux-x64-baseline
|
||||
uses: ./.github/workflows/build-linux.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
runs-on: ${{ github.repository_owner == 'oven-sh' && 'namespace-profile-bun-ci-linux-x64' || 'ubuntu-latest' }}
|
||||
tag: linux-x64-baseline
|
||||
arch: x64
|
||||
cpu: nehalem
|
||||
canary: false
|
||||
linux-aarch64:
|
||||
name: Build linux-aarch64
|
||||
uses: ./.github/workflows/build-linux.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
runs-on: namespace-profile-bun-ci-linux-aarch64
|
||||
tag: linux-aarch64
|
||||
arch: aarch64
|
||||
cpu: native
|
||||
canary: false
|
||||
darwin-x64:
|
||||
name: Build darwin-x64
|
||||
uses: ./.github/workflows/build-darwin.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
runs-on: ${{ github.repository_owner == 'oven-sh' && 'macos-12-large' || 'macos-12' }}
|
||||
tag: darwin-x64
|
||||
arch: x64
|
||||
cpu: haswell
|
||||
canary: false
|
||||
darwin-x64-baseline:
|
||||
name: Build darwin-x64-baseline
|
||||
uses: ./.github/workflows/build-darwin.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
runs-on: ${{ github.repository_owner == 'oven-sh' && 'macos-12-large' || 'macos-12' }}
|
||||
tag: darwin-x64-baseline
|
||||
arch: x64
|
||||
cpu: nehalem
|
||||
canary: false
|
||||
darwin-aarch64:
|
||||
name: Build darwin-aarch64
|
||||
uses: ./.github/workflows/build-darwin.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
runs-on: ${{ github.repository_owner == 'oven-sh' && 'namespace-profile-bun-ci-darwin-aarch64' || 'macos-12' }}
|
||||
tag: darwin-aarch64
|
||||
arch: aarch64
|
||||
cpu: native
|
||||
canary: false
|
||||
windows-x64:
|
||||
name: Build windows-x64
|
||||
uses: ./.github/workflows/build-windows.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
runs-on: windows
|
||||
tag: windows-x64
|
||||
arch: x64
|
||||
cpu: haswell
|
||||
canary: false
|
||||
windows-x64-baseline:
|
||||
name: Build windows-x64-baseline
|
||||
uses: ./.github/workflows/build-windows.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
runs-on: windows
|
||||
tag: windows-x64-baseline
|
||||
arch: x64
|
||||
cpu: nehalem
|
||||
canary: false
|
||||
|
||||
upload-artifacts:
|
||||
needs:
|
||||
- linux-x64
|
||||
- linux-x64-baseline
|
||||
- linux-aarch64
|
||||
- darwin-x64
|
||||
- darwin-x64-baseline
|
||||
- darwin-aarch64
|
||||
- windows-x64
|
||||
- windows-x64-baseline
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: bun-releases
|
||||
pattern: bun-*
|
||||
merge-multiple: true
|
||||
github-token: ${{ github.token }}
|
||||
- name: Check for Artifacts
|
||||
run: |
|
||||
if [ ! -d "bun-releases" ] || [ -z "$(ls -A bun-releases)" ]; then
|
||||
echo "Error: No artifacts were downloaded or 'bun-releases' directory does not exist."
|
||||
exit 1 # Fail the job if the condition is met
|
||||
else
|
||||
echo "Artifacts downloaded successfully."
|
||||
fi
|
||||
- name: Send Message
|
||||
uses: sarisia/actions-status-discord@v1
|
||||
with:
|
||||
webhook: ${{ secrets.DISCORD_WEBHOOK }}
|
||||
nodetail: true
|
||||
color: "#FF0000"
|
||||
title: "Bun v${{ inputs.version }} release artifacts uploaded"
|
||||
- name: "Upload Artifacts"
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
# Unzip one level deep each artifact
|
||||
cd bun-releases
|
||||
for f in *.zip; do
|
||||
unzip -o $f
|
||||
done
|
||||
cd ..
|
||||
gh release upload --repo=${{ github.repository }} ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.tag || github.event.release.id }} ${{ inputs.clobber && '--clobber' || '' }} bun-releases/*.zip
|
||||
29
.github/workflows/release.yml
vendored
29
.github/workflows/release.yml
vendored
@@ -1,3 +1,6 @@
|
||||
# TODO: Move this to bash scripts intead of Github Actions
|
||||
# so it can be run from Buildkite, see: .buildkite/scripts/release.sh
|
||||
|
||||
name: Release
|
||||
concurrency: release
|
||||
|
||||
@@ -63,7 +66,7 @@ jobs:
|
||||
- name: Setup Bun
|
||||
uses: ./.github/actions/setup-bun
|
||||
with:
|
||||
bun-version: "1.0.21"
|
||||
bun-version: "1.1.20"
|
||||
- name: Install Dependencies
|
||||
run: bun install
|
||||
- name: Sign Release
|
||||
@@ -88,7 +91,7 @@ jobs:
|
||||
- name: Setup Bun
|
||||
uses: ./.github/actions/setup-bun
|
||||
with:
|
||||
bun-version: "1.0.21"
|
||||
bun-version: "1.1.20"
|
||||
- name: Install Dependencies
|
||||
run: bun install
|
||||
- name: Release
|
||||
@@ -117,7 +120,7 @@ jobs:
|
||||
if: ${{ env.BUN_VERSION != 'canary' }}
|
||||
uses: ./.github/actions/setup-bun
|
||||
with:
|
||||
bun-version: "1.0.21"
|
||||
bun-version: "1.1.20"
|
||||
- name: Setup Bun
|
||||
if: ${{ env.BUN_VERSION == 'canary' }}
|
||||
uses: ./.github/actions/setup-bun
|
||||
@@ -259,7 +262,7 @@ jobs:
|
||||
- name: Setup Bun
|
||||
uses: ./.github/actions/setup-bun
|
||||
with:
|
||||
bun-version: "1.0.21"
|
||||
bun-version: "1.1.20"
|
||||
- name: Install Dependencies
|
||||
run: bun install
|
||||
- name: Release
|
||||
@@ -270,6 +273,24 @@ jobs:
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY}}
|
||||
AWS_ENDPOINT: ${{ secrets.AWS_ENDPOINT }}
|
||||
AWS_BUCKET: bun
|
||||
|
||||
notify-sentry:
|
||||
name: Notify Sentry
|
||||
runs-on: ubuntu-latest
|
||||
needs: s3
|
||||
steps:
|
||||
- name: Notify Sentry
|
||||
uses: getsentry/action-release@v1.7.0
|
||||
env:
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
|
||||
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
|
||||
with:
|
||||
ignore_missing: true
|
||||
ignore_empty: true
|
||||
version: ${{ env.BUN_VERSION }}
|
||||
environment: production
|
||||
|
||||
bump:
|
||||
name: "Bump version"
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
4
.github/workflows/run-format.yml
vendored
4
.github/workflows/run-format.yml
vendored
@@ -29,9 +29,9 @@ jobs:
|
||||
- name: Setup Bun
|
||||
uses: ./.github/actions/setup-bun
|
||||
with:
|
||||
bun-version: "1.1.8"
|
||||
bun-version: "1.1.20"
|
||||
- name: Setup Zig
|
||||
uses: goto-bus-stop/setup-zig@c7b6cdd3adba8f8b96984640ff172c37c93f73ee
|
||||
uses: mlugg/setup-zig@v1
|
||||
with:
|
||||
version: ${{ inputs.zig-version }}
|
||||
- name: Install Dependencies
|
||||
|
||||
4
.github/workflows/run-lint-cpp.yml
vendored
4
.github/workflows/run-lint-cpp.yml
vendored
@@ -3,7 +3,7 @@ name: lint-cpp
|
||||
permissions:
|
||||
contents: read
|
||||
env:
|
||||
LLVM_VERSION: 16
|
||||
LLVM_VERSION: 18
|
||||
LC_CTYPE: "en_US.UTF-8"
|
||||
LC_ALL: "en_US.UTF-8"
|
||||
|
||||
@@ -17,7 +17,7 @@ on:
|
||||
jobs:
|
||||
lint-cpp:
|
||||
name: Lint C++
|
||||
runs-on: ${{ github.repository_owner == 'oven-sh' && 'macos-13-xlarge' || 'macos-12' }}
|
||||
runs-on: ${{ github.repository_owner == 'oven-sh' && 'macos-13-xlarge' || 'macos-13' }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
224
.github/workflows/run-test.yml
vendored
224
.github/workflows/run-test.yml
vendored
@@ -1,224 +0,0 @@
|
||||
name: Test
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
actions: read
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
runs-on:
|
||||
type: string
|
||||
required: true
|
||||
tag:
|
||||
type: string
|
||||
required: true
|
||||
pr-number:
|
||||
type: string
|
||||
required: true
|
||||
run-id:
|
||||
type: string
|
||||
default: ${{ github.run_id }}
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Tests
|
||||
runs-on: ${{ inputs.runs-on }}
|
||||
steps:
|
||||
- if: ${{ runner.os == 'Windows' }}
|
||||
name: Setup Git
|
||||
run: |
|
||||
git config --global core.autocrlf false
|
||||
git config --global core.eol lf
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: |
|
||||
package.json
|
||||
bun.lockb
|
||||
test
|
||||
packages/bun-internal-test
|
||||
packages/bun-types
|
||||
- name: Setup Environment
|
||||
shell: bash
|
||||
run: |
|
||||
echo "${{ inputs.pr-number }}" > pr-number.txt
|
||||
- name: Download Bun
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: bun-${{ inputs.tag }}
|
||||
path: bun
|
||||
github-token: ${{ github.token }}
|
||||
run-id: ${{ inputs.run-id || github.run_id }}
|
||||
- name: Download pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 8
|
||||
- if: ${{ runner.os != 'Windows' }}
|
||||
name: Setup Bun
|
||||
shell: bash
|
||||
run: |
|
||||
unzip bun/bun-*.zip
|
||||
cd bun-*
|
||||
pwd >> $GITHUB_PATH
|
||||
- if: ${{ runner.os == 'Windows' }}
|
||||
name: Setup Cygwin
|
||||
uses: secondlife/setup-cygwin@v3
|
||||
with:
|
||||
packages: bash
|
||||
- if: ${{ runner.os == 'Windows' }}
|
||||
name: Setup Bun (Windows)
|
||||
run: |
|
||||
unzip bun/bun-*.zip
|
||||
cd bun-*
|
||||
pwd >> $env:GITHUB_PATH
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
- name: Install Dependencies
|
||||
timeout-minutes: 5
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
bun install
|
||||
- name: Install Dependencies (test)
|
||||
timeout-minutes: 5
|
||||
run: |
|
||||
bun install --cwd test
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Install Dependencies (runner)
|
||||
timeout-minutes: 5
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
bun install --cwd packages/bun-internal-test
|
||||
- name: Run Tests
|
||||
id: test
|
||||
timeout-minutes: 90
|
||||
shell: bash
|
||||
env:
|
||||
IS_BUN_CI: 1
|
||||
TMPDIR: ${{ runner.temp }}
|
||||
BUN_TAG: ${{ inputs.tag }}
|
||||
BUN_FEATURE_FLAG_INTERNAL_FOR_TESTING: "true"
|
||||
SMTP_SENDGRID_SENDER: ${{ secrets.SMTP_SENDGRID_SENDER }}
|
||||
TLS_MONGODB_DATABASE_URL: ${{ secrets.TLS_MONGODB_DATABASE_URL }}
|
||||
TLS_POSTGRES_DATABASE_URL: ${{ secrets.TLS_POSTGRES_DATABASE_URL }}
|
||||
TEST_INFO_STRIPE: ${{ secrets.TEST_INFO_STRIPE }}
|
||||
TEST_INFO_AZURE_SERVICE_BUS: ${{ secrets.TEST_INFO_AZURE_SERVICE_BUS }}
|
||||
SHELLOPTS: igncr
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
node packages/bun-internal-test/src/runner.node.mjs $(which bun)
|
||||
- if: ${{ always() }}
|
||||
name: Upload Results
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bun-${{ inputs.tag }}-tests
|
||||
path: |
|
||||
test-report.*
|
||||
comment.md
|
||||
pr-number.txt
|
||||
if-no-files-found: error
|
||||
overwrite: true
|
||||
- if: ${{ always() && steps.test.outputs.failing_tests != '' && github.event.pull_request && github.repository_owner == 'oven-sh' }}
|
||||
name: Send Message
|
||||
uses: sarisia/actions-status-discord@v1
|
||||
with:
|
||||
webhook: ${{ secrets.DISCORD_WEBHOOK }}
|
||||
nodetail: true
|
||||
color: "#FF0000"
|
||||
title: ""
|
||||
description: |
|
||||
### ❌ [${{ github.event.pull_request.title }}](${{ github.event.pull_request.html_url }})
|
||||
|
||||
@${{ github.actor }}, there are ${{ steps.test.outputs.failing_tests_count || 'some' }} failing tests on bun-${{ inputs.tag }}.
|
||||
|
||||
${{ steps.test.outputs.failing_tests }}
|
||||
|
||||
**[View logs](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})**
|
||||
- name: Fail
|
||||
if: ${{ failure() || always() && steps.test.outputs.failing_tests != '' }}
|
||||
run: |
|
||||
echo "There are ${{ steps.test.outputs.failing_tests_count || 'some' }} failing tests on bun-${{ inputs.tag }}."
|
||||
exit 1
|
||||
test-node:
|
||||
name: Node.js Tests
|
||||
# TODO: enable when we start paying attention to the results. In the meantime, this causes CI to queue jobs wasting developer time.
|
||||
if: 0
|
||||
runs-on: ${{ inputs.runs-on }}
|
||||
steps:
|
||||
- if: ${{ runner.os == 'Windows' }}
|
||||
name: Setup Git
|
||||
run: |
|
||||
git config --global core.autocrlf false
|
||||
git config --global core.eol lf
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: |
|
||||
test/node.js
|
||||
- name: Setup Environment
|
||||
shell: bash
|
||||
run: |
|
||||
echo "${{ inputs.pr-number }}" > pr-number.txt
|
||||
- name: Download Bun
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: bun-${{ inputs.tag }}
|
||||
path: bun
|
||||
github-token: ${{ github.token }}
|
||||
run-id: ${{ inputs.run-id || github.run_id }}
|
||||
- if: ${{ runner.os != 'Windows' }}
|
||||
name: Setup Bun
|
||||
shell: bash
|
||||
run: |
|
||||
unzip bun/bun-*.zip
|
||||
cd bun-*
|
||||
pwd >> $GITHUB_PATH
|
||||
- if: ${{ runner.os == 'Windows' }}
|
||||
name: Setup Cygwin
|
||||
uses: secondlife/setup-cygwin@v3
|
||||
with:
|
||||
packages: bash
|
||||
- if: ${{ runner.os == 'Windows' }}
|
||||
name: Setup Bun (Windows)
|
||||
run: |
|
||||
unzip bun/bun-*.zip
|
||||
cd bun-*
|
||||
pwd >> $env:GITHUB_PATH
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
- name: Checkout Tests
|
||||
shell: bash
|
||||
working-directory: test/node.js
|
||||
run: |
|
||||
node runner.mjs --pull
|
||||
- name: Install Dependencies
|
||||
timeout-minutes: 5
|
||||
shell: bash
|
||||
working-directory: test/node.js
|
||||
run: |
|
||||
bun install
|
||||
- name: Run Tests
|
||||
timeout-minutes: 10 # Increase when more tests are added
|
||||
shell: bash
|
||||
working-directory: test/node.js
|
||||
env:
|
||||
TMPDIR: ${{ runner.temp }}
|
||||
BUN_GARBAGE_COLLECTOR_LEVEL: "0"
|
||||
BUN_FEATURE_FLAG_INTERNAL_FOR_TESTING: "true"
|
||||
run: |
|
||||
node runner.mjs
|
||||
- name: Upload Results
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bun-${{ inputs.tag }}-node-tests
|
||||
path: |
|
||||
test/node.js/summary/*.json
|
||||
if-no-files-found: error
|
||||
overwrite: true
|
||||
82
.github/workflows/upload.yml
vendored
82
.github/workflows/upload.yml
vendored
@@ -1,82 +0,0 @@
|
||||
name: Upload Artifacts
|
||||
run-name: Canary release ${{github.sha}} upload
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows:
|
||||
- CI
|
||||
types:
|
||||
- completed
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
upload:
|
||||
if: ${{ github.repository_owner == 'oven-sh' }}
|
||||
name: Upload Artifacts
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: bun
|
||||
pattern: bun-*
|
||||
merge-multiple: true
|
||||
github-token: ${{ github.token }}
|
||||
run-id: ${{ github.event.workflow_run.id }}
|
||||
- name: Check for Artifacts
|
||||
run: |
|
||||
if [ ! -d "bun" ] || [ -z "$(ls -A bun)" ]; then
|
||||
echo "Error: No artifacts were downloaded or 'bun' directory does not exist."
|
||||
exit 1 # Fail the job if the condition is met
|
||||
else
|
||||
echo "Artifacts downloaded successfully."
|
||||
fi
|
||||
- name: Upload to GitHub Releases
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
tag: canary
|
||||
name: Canary (${{ github.sha }})
|
||||
prerelease: true
|
||||
body: This canary release of Bun corresponds to the commit [${{ github.sha }}]
|
||||
allowUpdates: true
|
||||
replacesArtifacts: true
|
||||
generateReleaseNotes: true
|
||||
artifactErrorsFailBuild: true
|
||||
artifacts: bun/**/bun-*.zip
|
||||
token: ${{ github.token }}
|
||||
- name: Upload to S3 (using SHA)
|
||||
uses: shallwefootball/s3-upload-action@4350529f410221787ccf424e50133cbc1b52704e
|
||||
with:
|
||||
endpoint: ${{ secrets.AWS_ENDPOINT }}
|
||||
aws_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY}}
|
||||
aws_bucket: ${{ secrets.AWS_BUCKET }}
|
||||
source_dir: bun
|
||||
destination_dir: releases/${{ github.event.workflow_run.head_sha || github.sha }}-canary
|
||||
- name: Upload to S3 (using tag)
|
||||
uses: shallwefootball/s3-upload-action@4350529f410221787ccf424e50133cbc1b52704e
|
||||
with:
|
||||
endpoint: ${{ secrets.AWS_ENDPOINT }}
|
||||
aws_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY}}
|
||||
aws_bucket: ${{ secrets.AWS_BUCKET }}
|
||||
source_dir: bun
|
||||
destination_dir: releases/canary
|
||||
- name: Announce on Discord
|
||||
uses: sarisia/actions-status-discord@v1
|
||||
with:
|
||||
webhook: ${{ secrets.BUN_DISCORD_GITHUB_CHANNEL_WEBHOOK }}
|
||||
nodetail: true
|
||||
color: "#1F6FEB"
|
||||
title: "New Bun Canary available"
|
||||
url: https://github.com/oven-sh/bun/commit/${{ github.sha }}
|
||||
description: |
|
||||
A new canary build of Bun has been automatically uploaded. To upgrade, run:
|
||||
```sh
|
||||
bun upgrade --canary
|
||||
# bun upgrade --stable <- to downgrade
|
||||
```
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -145,3 +145,4 @@ zig-cache
|
||||
zig-out
|
||||
test/node.js/upstream
|
||||
.zig-cache
|
||||
scripts/env.local
|
||||
|
||||
4
.gitmodules
vendored
4
.gitmodules
vendored
@@ -82,3 +82,7 @@ url = https://github.com/oven-sh/zig
|
||||
depth = 1
|
||||
shallow = true
|
||||
fetchRecurseSubmodules = false
|
||||
[submodule "src/deps/libdeflate"]
|
||||
path = src/deps/libdeflate
|
||||
url = https://github.com/ebiggers/libdeflate
|
||||
ignore = "dirty"
|
||||
|
||||
4
.lldbinit
Normal file
4
.lldbinit
Normal file
@@ -0,0 +1,4 @@
|
||||
command script import src/deps/zig/tools/lldb_pretty_printers.py
|
||||
command script import src/bun.js/WebKit/Tools/lldb/lldb_webkit.py
|
||||
|
||||
# type summary add --summary-string "${var} | inner=${var[0-30]}, source=${var[33-64]}, tag=${var[31-32]}" "unsigned long"
|
||||
1
.vscode/launch.json
generated
vendored
1
.vscode/launch.json
generated
vendored
@@ -17,6 +17,7 @@
|
||||
"cwd": "${workspaceFolder}/test",
|
||||
"env": {
|
||||
"FORCE_COLOR": "1",
|
||||
"BUN_DEBUG_QUIET_LOGS": "1",
|
||||
"BUN_GARBAGE_COLLECTOR_LEVEL": "1",
|
||||
},
|
||||
"console": "internalConsole",
|
||||
|
||||
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@@ -42,8 +42,11 @@
|
||||
"editor.defaultFormatter": "ziglang.vscode-zig",
|
||||
},
|
||||
|
||||
// C++
|
||||
// lldb
|
||||
"lldb.launch.initCommands": ["command source ${workspaceFolder}/.lldbinit"],
|
||||
"lldb.verboseLogging": false,
|
||||
|
||||
// C++
|
||||
"cmake.configureOnOpen": false,
|
||||
"C_Cpp.errorSquiggles": "enabled",
|
||||
"[cpp]": {
|
||||
|
||||
259
CMakeLists.txt
259
CMakeLists.txt
@@ -3,8 +3,8 @@ cmake_policy(SET CMP0091 NEW)
|
||||
cmake_policy(SET CMP0067 NEW)
|
||||
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0069 NEW)
|
||||
set(Bun_VERSION "1.1.19")
|
||||
set(WEBKIT_TAG 615e8585f96aa718b0f5158210259b83fe8440ea)
|
||||
set(Bun_VERSION "1.1.22")
|
||||
set(WEBKIT_TAG a060f087c2232fb20d82c321d21e074e735d3261)
|
||||
|
||||
set(BUN_WORKDIR "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
message(STATUS "Configuring Bun ${Bun_VERSION} in ${BUN_WORKDIR}")
|
||||
@@ -15,7 +15,19 @@ set(CMAKE_C_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
|
||||
# Should not start with v
|
||||
option(ZIG_CACHE_DIR "Path to the Zig cache directory" "")
|
||||
|
||||
if(NOT ZIG_CACHE_DIR)
|
||||
SET(ZIG_CACHE_DIR "${BUN_WORKDIR}")
|
||||
cmake_path(APPEND ZIG_CACHE_DIR "zig-cache")
|
||||
endif()
|
||||
|
||||
set(LOCAL_ZIG_CACHE_DIR "${ZIG_CACHE_DIR}")
|
||||
set(GLOBAL_ZIG_CACHE_DIR "${ZIG_CACHE_DIR}")
|
||||
|
||||
cmake_path(APPEND LOCAL_ZIG_CACHE_DIR "local")
|
||||
cmake_path(APPEND GLOBAL_ZIG_CACHE_DIR "global")
|
||||
|
||||
# Used in process.version, process.versions.node, napi, and elsewhere
|
||||
set(REPORTED_NODEJS_VERSION "22.3.0")
|
||||
|
||||
@@ -23,6 +35,7 @@ set(REPORTED_NODEJS_VERSION "22.3.0")
|
||||
# If we do not set this, it will crash at startup on the first memory allocation.
|
||||
if(NOT WIN32 AND NOT APPLE)
|
||||
set(CMAKE_CXX_EXTENSIONS ON)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE FALSE)
|
||||
endif()
|
||||
|
||||
# --- Build Type ---
|
||||
@@ -39,6 +52,13 @@ else()
|
||||
message(STATUS "The CMake build type is: ${CMAKE_BUILD_TYPE}")
|
||||
endif()
|
||||
|
||||
if(WIN32 AND NOT CMAKE_CL_SHOWINCLUDES_PREFIX)
|
||||
# workaround until cmake fix is shipped https://github.com/ninja-build/ninja/issues/2280
|
||||
# './build/.ninja_deps' may need to be deleted, the bug is "Note: including file: ..." is saved
|
||||
# as part of some file paths
|
||||
set(CMAKE_CL_SHOWINCLUDES_PREFIX "Note: including file:")
|
||||
endif()
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(DEBUG ON)
|
||||
set(DEFAULT_ZIG_OPTIMIZE "Debug")
|
||||
@@ -51,11 +71,8 @@ elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
set(DEFAULT_ZIG_OPTIMIZE "ReleaseFast")
|
||||
|
||||
if(WIN32)
|
||||
# lld-link will strip it for you, so we can build directly to bun.exe
|
||||
# Debug symbols are in a separate file: bun.pdb
|
||||
set(bun "bun")
|
||||
|
||||
# TODO(@paperdave): Remove this
|
||||
# it is enabled for the time being to make sure to catch more bugs in the experimental windows builds
|
||||
set(DEFAULT_ZIG_OPTIMIZE "ReleaseSafe")
|
||||
else()
|
||||
if(ZIG_OPTIMIZE STREQUAL "Debug")
|
||||
@@ -68,7 +85,7 @@ endif()
|
||||
|
||||
# --- MacOS SDK ---
|
||||
if(APPLE AND DEFINED ENV{CI})
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "12.0")
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "13.0")
|
||||
endif()
|
||||
|
||||
if(APPLE AND NOT CMAKE_OSX_DEPLOYMENT_TARGET)
|
||||
@@ -112,7 +129,11 @@ endif()
|
||||
# we do some extra work afterwards to double-check, and we will rerun BUN_FIND_LLVM if the compiler did not match.
|
||||
#
|
||||
# If the user passes -DLLVM_PREFIX, most of this logic is skipped, but we still warn if invalid.
|
||||
set(LLVM_VERSION 16)
|
||||
if(WIN32 OR APPLE)
|
||||
set(LLVM_VERSION 18)
|
||||
else()
|
||||
set(LLVM_VERSION 16)
|
||||
endif()
|
||||
|
||||
macro(BUN_FIND_LLVM)
|
||||
find_program(
|
||||
@@ -146,11 +167,12 @@ macro(BUN_FIND_LLVM)
|
||||
PATHS ENV PATH ${PLATFORM_LLVM_SEARCH_PATHS}
|
||||
DOC "Path to LLVM ${LLVM_VERSION}'s llvm-strip binary"
|
||||
)
|
||||
|
||||
find_program(
|
||||
STRIP
|
||||
NAMES strip
|
||||
PATHS ENV PATH ${PLATFORM_LLVM_SEARCH_PATHS}
|
||||
DOC "Path to LLVM ${LLVM_VERSION}'s llvm-strip binary"
|
||||
DOC "Path to strip binary"
|
||||
)
|
||||
find_program(
|
||||
DSYMUTIL
|
||||
@@ -301,6 +323,7 @@ endif()
|
||||
# -- Build Flags --
|
||||
option(USE_STATIC_SQLITE "Statically link SQLite?" ${DEFAULT_ON_UNLESS_APPLE})
|
||||
option(USE_CUSTOM_ZLIB "Use Bun's recommended version of zlib" ON)
|
||||
option(USE_CUSTOM_LIBDEFLATE "Use Bun's recommended version of libdeflate" ON)
|
||||
option(USE_CUSTOM_BORINGSSL "Use Bun's recommended version of BoringSSL" ON)
|
||||
option(USE_CUSTOM_LIBARCHIVE "Use Bun's recommended version of libarchive" ON)
|
||||
option(USE_CUSTOM_MIMALLOC "Use Bun's recommended version of Mimalloc" ON)
|
||||
@@ -322,6 +345,11 @@ option(USE_STATIC_LIBATOMIC "Statically link libatomic, requires the presence of
|
||||
|
||||
option(USE_LTO "Enable Link-Time Optimization" ${DEFAULT_LTO})
|
||||
|
||||
if(APPLE AND USE_LTO)
|
||||
set(USE_LTO OFF)
|
||||
message(FATAL_ERROR "Link-Time Optimization is not supported on macOS because it requires -fuse-ld=lld and lld causes many segfaults on macOS (likely related to stack size)")
|
||||
endif()
|
||||
|
||||
if(WIN32 AND USE_LTO)
|
||||
set(CMAKE_LINKER_TYPE LLD)
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION OFF)
|
||||
@@ -448,6 +476,8 @@ elseif(NOT BUN_CPP_ONLY AND NOT BUN_LINK_ONLY AND NOT BUN_TIDY_ONLY AND NOT BUN_
|
||||
|
||||
message(STATUS "Installed Zig Compiler: ${ZIG_COMPILER}")
|
||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "build.zig")
|
||||
|
||||
message(STATUS "Using zig cache directory: ${ZIG_CACHE_DIR}")
|
||||
endif()
|
||||
|
||||
# Bun
|
||||
@@ -472,7 +502,7 @@ if(USE_UNIFIED_SOURCES)
|
||||
endif()
|
||||
|
||||
# CCache
|
||||
find_program(CCACHE_PROGRAM sccache)
|
||||
# find_program(CCACHE_PROGRAM sccache)
|
||||
find_program(CCACHE_PROGRAM ccache)
|
||||
|
||||
if(CCACHE_PROGRAM)
|
||||
@@ -638,16 +668,6 @@ file(GLOB BUN_CPP ${CONFIGURE_DEPENDS}
|
||||
)
|
||||
list(APPEND BUN_RAW_SOURCES ${BUN_CPP})
|
||||
|
||||
# -- Brotli --
|
||||
set(BROTLI_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/deps/brotli")
|
||||
file(GLOB BROTLI_FILES ${CONFIGURE_DEPENDS}
|
||||
"${BROTLI_SRC}/common/*.c"
|
||||
"${BROTLI_SRC}/enc/*.c"
|
||||
"${BROTLI_SRC}/dec/*.c"
|
||||
)
|
||||
list(APPEND BUN_RAW_SOURCES ${BROTLI_FILES})
|
||||
include_directories("${BUN_DEPS_DIR}/brotli/include")
|
||||
|
||||
# -- uSockets --
|
||||
set(USOCKETS_SRC "${CMAKE_CURRENT_SOURCE_DIR}/packages/bun-usockets/src")
|
||||
file(GLOB USOCKETS_FILES ${CONFIGURE_DEPENDS}
|
||||
@@ -684,6 +704,32 @@ add_custom_command(
|
||||
)
|
||||
list(APPEND BUN_RAW_SOURCES "${BUN_WORKDIR}/codegen/ZigGeneratedClasses.cpp")
|
||||
|
||||
if(NOT NO_CODEGEN)
|
||||
# --- ErrorCode Generator ---
|
||||
file(GLOB NODE_ERRORS_TS ${CONFIGURE_DEPENDS}
|
||||
"${BUN_SRC}/bun.js/bindings/ErrorCode.ts"
|
||||
)
|
||||
add_custom_command(
|
||||
OUTPUT "${BUN_WORKDIR}/codegen/ErrorCode+List.h" "${BUN_WORKDIR}/codegen/ErrorCode+Data.h" "${BUN_WORKDIR}/codegen/ErrorCode.zig"
|
||||
COMMAND ${BUN_EXECUTABLE} run "${BUN_CODEGEN_SRC}/generate-node-errors.ts" "${BUN_WORKDIR}/codegen"
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
MAIN_DEPENDENCY "${BUN_CODEGEN_SRC}/generate-node-errors.ts"
|
||||
DEPENDS ${NODE_ERRORS_TS}
|
||||
VERBATIM
|
||||
COMMENT "Generating ErrorCode.zig"
|
||||
)
|
||||
|
||||
# This needs something to force it to be regenerated
|
||||
WEBKIT_ADD_SOURCE_DEPENDENCIES(
|
||||
"${BUN_SRC}/bun.js/bindings/ErrorCode.cpp"
|
||||
"${BUN_WORKDIR}/codegen/ErrorCode+List.h"
|
||||
)
|
||||
WEBKIT_ADD_SOURCE_DEPENDENCIES(
|
||||
"${BUN_SRC}/bun.js/bindings/ErrorCode.h"
|
||||
"${BUN_WORKDIR}/codegen/ErrorCode+Data.h"
|
||||
)
|
||||
endif()
|
||||
|
||||
# --- JSSink Generator ---
|
||||
add_custom_command(
|
||||
OUTPUT "${BUN_WORKDIR}/codegen/JSSink.cpp"
|
||||
@@ -757,7 +803,7 @@ if(NOT NO_CODEGEN)
|
||||
OUTPUT ${BUN_IDENTIFIER_CACHE_OUT}
|
||||
MAIN_DEPENDENCY "${BUN_SRC}/js_lexer/identifier_data.zig"
|
||||
DEPENDS "${BUN_SRC}/js_lexer/identifier_cache.zig"
|
||||
COMMAND ${ZIG_COMPILER} run "--zig-lib-dir" "${ZIG_LIB_DIR}" "${BUN_SRC}/js_lexer/identifier_data.zig"
|
||||
COMMAND ${ZIG_COMPILER} run "--zig-lib-dir" "${ZIG_LIB_DIR}" "--cache-dir" "${LOCAL_ZIG_CACHE_DIR}" "--global-cache-dir" "${GLOBAL_ZIG_CACHE_DIR}" "${BUN_SRC}/js_lexer/identifier_data.zig"
|
||||
VERBATIM
|
||||
COMMENT "Building Identifier Cache"
|
||||
)
|
||||
@@ -778,6 +824,8 @@ if(NOT NO_CODEGEN)
|
||||
"${BUN_SRC}/js/thirdparty/*.ts"
|
||||
"${BUN_SRC}/js/internal/*.js"
|
||||
"${BUN_SRC}/js/internal/*.ts"
|
||||
"${BUN_SRC}/js/internal/util/*.js"
|
||||
"${BUN_SRC}/js/internal/fs/*.ts"
|
||||
"${BUN_SRC}/js/node/*.js"
|
||||
"${BUN_SRC}/js/node/*.ts"
|
||||
"${BUN_SRC}/js/thirdparty/*.js"
|
||||
@@ -861,13 +909,24 @@ file(GLOB ZIG_FILES
|
||||
"${BUN_SRC}/*/*/*/*/*.zig"
|
||||
)
|
||||
|
||||
if(NOT BUN_ZIG_OBJ_FORMAT)
|
||||
# To use LLVM bitcode from Zig, more work needs to be done. Currently, an install of
|
||||
# LLVM 18.1.7 does not compatible with what bitcode Zig 0.13 outputs (has LLVM 18.1.7)
|
||||
# Change to "bc" to experiment, "Invalid record" means it is not valid output.
|
||||
set(BUN_ZIG_OBJ_FORMAT "obj")
|
||||
endif()
|
||||
|
||||
if(NOT BUN_ZIG_OBJ_DIR)
|
||||
set(BUN_ZIG_OBJ_DIR "${BUN_WORKDIR}/CMakeFiles")
|
||||
endif()
|
||||
|
||||
get_filename_component(BUN_ZIG_OBJ_DIR "${BUN_ZIG_OBJ_DIR}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
|
||||
|
||||
set(BUN_ZIG_OBJ "${BUN_ZIG_OBJ_DIR}/bun-zig.o")
|
||||
if(WIN32)
|
||||
set(BUN_ZIG_OBJ "${BUN_ZIG_OBJ_DIR}/bun-zig.o")
|
||||
else()
|
||||
set(BUN_ZIG_OBJ "${BUN_ZIG_OBJ_DIR}/bun-zig.o")
|
||||
endif()
|
||||
|
||||
set(USES_TERMINAL_NOT_IN_CI "")
|
||||
|
||||
@@ -882,6 +941,7 @@ if(NOT BUN_LINK_ONLY AND NOT BUN_CPP_ONLY)
|
||||
"${ZIG_COMPILER}" "build" "obj"
|
||||
"--zig-lib-dir" "${ZIG_LIB_DIR}"
|
||||
"--prefix" "${BUN_ZIG_OBJ_DIR}"
|
||||
"--verbose"
|
||||
"-Dgenerated-code=${BUN_WORKDIR}/codegen"
|
||||
"-freference-trace=10"
|
||||
"-Dversion=${Bun_VERSION}"
|
||||
@@ -891,10 +951,14 @@ if(NOT BUN_LINK_ONLY AND NOT BUN_CPP_ONLY)
|
||||
"-Dtarget=${ZIG_TARGET}"
|
||||
"-Denable_logs=${ENABLE_LOGS}"
|
||||
"-Dreported_nodejs_version=${REPORTED_NODEJS_VERSION}"
|
||||
"-Dobj_format=${BUN_ZIG_OBJ_FORMAT}"
|
||||
"--cache-dir" "${LOCAL_ZIG_CACHE_DIR}"
|
||||
"--global-cache-dir" "${GLOBAL_ZIG_CACHE_DIR}"
|
||||
DEPENDS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/build.zig"
|
||||
"${ZIG_FILES}"
|
||||
"${BUN_WORKDIR}/codegen/ZigGeneratedClasses.zig"
|
||||
"${BUN_WORKDIR}/codegen/ErrorCode.zig"
|
||||
"${BUN_WORKDIR}/codegen/ResolvedSourceTag.zig"
|
||||
"${BUN_IDENTIFIER_CACHE_OUT}"
|
||||
"${BUN_SRC}/api/schema.zig"
|
||||
@@ -980,8 +1044,20 @@ add_compile_definitions(
|
||||
)
|
||||
|
||||
if(NOT ASSERT_ENABLED)
|
||||
if(APPLE)
|
||||
add_compile_definitions("_LIBCXX_ENABLE_ASSERTIONS=0")
|
||||
add_compile_definitions("_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE")
|
||||
endif()
|
||||
|
||||
add_compile_definitions("NDEBUG=1")
|
||||
else()
|
||||
if(APPLE)
|
||||
add_compile_definitions("_LIBCXX_ENABLE_ASSERTIONS=1")
|
||||
add_compile_definitions("_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG")
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
add_compile_definitions("_GLIBCXX_ASSERTIONS=1")
|
||||
endif()
|
||||
|
||||
add_compile_definitions("ASSERT_ENABLED=1")
|
||||
endif()
|
||||
|
||||
@@ -1051,12 +1127,25 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
-Werror=uninitialized
|
||||
-Werror=conditional-uninitialized
|
||||
-Werror=suspicious-memaccess
|
||||
-Werror=int-conversion
|
||||
-Werror=nonnull
|
||||
-Werror=move
|
||||
-Werror=sometimes-uninitialized
|
||||
-Werror=unused
|
||||
-Wno-unused-function
|
||||
-Wno-nullability-completeness
|
||||
-Werror
|
||||
-fsanitize=null
|
||||
-fsanitize-recover=all
|
||||
-fsanitize=bounds
|
||||
-fsanitize=return
|
||||
-fsanitize=nullability-arg
|
||||
-fsanitize=nullability-assign
|
||||
-fsanitize=nullability-return
|
||||
-fsanitize=returns-nonnull-attribute
|
||||
-fsanitize=unreachable
|
||||
)
|
||||
target_link_libraries(${bun} PRIVATE -fsanitize=null)
|
||||
else()
|
||||
target_compile_options(${bun} PUBLIC /Od /Z7)
|
||||
endif()
|
||||
@@ -1067,7 +1156,7 @@ elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
|
||||
if(NOT WIN32)
|
||||
if(USE_LTO)
|
||||
list(APPEND LTO_FLAG "-flto=full" "-emit-llvm")
|
||||
list(APPEND LTO_FLAG "-flto=full" "-emit-llvm" "-fwhole-program-vtables" "-fforce-emit-vtables")
|
||||
endif()
|
||||
|
||||
# Leave -Werror=unused off in release builds so we avoid errors from being used in ASSERT
|
||||
@@ -1078,8 +1167,11 @@ elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
-Werror=uninitialized
|
||||
-Werror=conditional-uninitialized
|
||||
-Werror=suspicious-memaccess
|
||||
-Werror=int-conversion
|
||||
-Werror=nonnull
|
||||
-Werror=move
|
||||
-Werror=sometimes-uninitialized
|
||||
-Wno-nullability-completeness
|
||||
-Werror
|
||||
)
|
||||
else()
|
||||
@@ -1088,13 +1180,36 @@ elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
if(USE_LTO)
|
||||
target_compile_options(${bun} PUBLIC -Xclang -emit-llvm-bc)
|
||||
|
||||
# -emit-llvm seems to not be supported or under a different name on Windows.
|
||||
list(APPEND LTO_FLAG "-flto=full")
|
||||
list(APPEND LTO_LINK_FLAG "-flto=full")
|
||||
list(APPEND LTO_LINK_FLAG "/LTCG")
|
||||
list(APPEND LTO_LINK_FLAG "/OPT:REF")
|
||||
list(APPEND LTO_LINK_FLAG "/OPT:NOICF")
|
||||
endif()
|
||||
|
||||
target_compile_options(${bun} PUBLIC /O2 ${LTO_FLAG})
|
||||
target_link_options(${bun} PUBLIC ${LTO_LINK_FLAG} /DEBUG:FULL)
|
||||
target_compile_options(${bun} PUBLIC
|
||||
/O2
|
||||
${LTO_FLAG}
|
||||
/Gy
|
||||
/Gw
|
||||
/GF
|
||||
/GA
|
||||
)
|
||||
target_link_options(${bun} PUBLIC
|
||||
${LTO_LINK_FLAG}
|
||||
/DEBUG:FULL
|
||||
|
||||
/delayload:ole32.dll
|
||||
/delayload:WINMM.dll
|
||||
/delayload:dbghelp.dll
|
||||
/delayload:VCRUNTIME140_1.dll
|
||||
|
||||
# libuv loads these two immediately, but for some reason it seems to still be slightly faster to delayload them
|
||||
/delayload:WS2_32.dll
|
||||
/delayload:WSOCK32.dll
|
||||
/delayload:ADVAPI32.dll
|
||||
/delayload:IPHLPAPI.dll
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -1112,6 +1227,11 @@ else()
|
||||
# On arm macOS, we can set it to a minimum of the M1 cpu set. this might be the default already.
|
||||
target_compile_options(${bun} PUBLIC "-mcpu=apple-m1")
|
||||
endif()
|
||||
|
||||
if(NOT WIN32 AND NOT APPLE AND ARCH STREQUAL "aarch64")
|
||||
# on arm64 linux, we set a minimum of armv8
|
||||
target_compile_options(${bun} PUBLIC -march=armv8-a+crc -mtune=ampere1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_compile_options(${bun} PUBLIC -ferror-limit=${ERROR_LIMIT})
|
||||
@@ -1125,24 +1245,29 @@ if(WIN32)
|
||||
"BORINGSSL_NO_CXX=1" # lol
|
||||
)
|
||||
|
||||
# set_property(TARGET ${bun} PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded")
|
||||
set_property(TARGET ${bun} PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreadedDLL")
|
||||
# set_property(TARGET ${bun} PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
set_property(TARGET ${bun} PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded")
|
||||
|
||||
target_compile_options(${bun} PUBLIC "/EHsc" "/GR-")
|
||||
target_compile_options(${bun} PUBLIC "/EHsc" "/GR-" -Xclang -fno-c++-static-destructors)
|
||||
|
||||
target_link_options(${bun} PUBLIC "/STACK:0x1200000,0x100000" "/DEF:${BUN_SRC}/symbols.def" "/errorlimit:0")
|
||||
else()
|
||||
target_compile_options(${bun} PUBLIC
|
||||
-fPIC
|
||||
-mtune=${CPU_TARGET}
|
||||
-fconstexpr-steps=2542484
|
||||
-fconstexpr-depth=54
|
||||
-fno-exceptions
|
||||
-fno-asynchronous-unwind-tables
|
||||
-fno-unwind-tables
|
||||
-fno-c++-static-destructors
|
||||
-fvisibility=hidden
|
||||
-fvisibility-inlines-hidden
|
||||
-fno-rtti
|
||||
-fno-omit-frame-pointer
|
||||
-mno-omit-leaf-frame-pointer
|
||||
-fno-pic
|
||||
-fno-pie
|
||||
-faddrsig
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -1158,10 +1283,12 @@ endif()
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
target_link_options(${bun} PUBLIC
|
||||
"-fuse-ld=lld"
|
||||
"-static-libstdc++"
|
||||
"-static-libgcc"
|
||||
"-Wl,-z,now"
|
||||
-fuse-ld=lld-${LLVM_VERSION}
|
||||
-fno-pic
|
||||
-static-libstdc++
|
||||
-static-libgcc
|
||||
"-Wl,-no-pie"
|
||||
"-Wl,-icf=safe"
|
||||
"-Wl,--as-needed"
|
||||
"-Wl,--gc-sections"
|
||||
"-Wl,-z,stack-size=12800000"
|
||||
@@ -1190,6 +1317,8 @@ if(UNIX AND NOT APPLE)
|
||||
"-rdynamic"
|
||||
"-Wl,--dynamic-list=${BUN_SRC}/symbols.dyn"
|
||||
"-Wl,--version-script=${BUN_SRC}/linker.lds"
|
||||
-Wl,-z,lazy
|
||||
-Wl,-z,norelro
|
||||
)
|
||||
|
||||
target_link_libraries(${bun} PRIVATE "c")
|
||||
@@ -1223,12 +1352,16 @@ endif()
|
||||
|
||||
# --- Stripped Binary "bun"
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Release" AND NOT WIN32 AND NOT ASSERT_ENABLED)
|
||||
# add_custom_command(
|
||||
# TARGET ${bun}
|
||||
# POST_BUILD
|
||||
# COMMAND ${DSYMUTIL} -o ${BUN_WORKDIR}/bun.dSYM ${BUN_WORKDIR}/${bun}
|
||||
# COMMENT "Stripping Symbols"
|
||||
# )
|
||||
# if(CI AND APPLE)
|
||||
if(APPLE)
|
||||
add_custom_command(
|
||||
TARGET ${bun}
|
||||
POST_BUILD
|
||||
COMMAND ${DSYMUTIL} -o ${BUN_WORKDIR}/${bun}.dSYM ${BUN_WORKDIR}/${bun}
|
||||
COMMENT "Generating .dSYM"
|
||||
)
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
TARGET ${bun}
|
||||
POST_BUILD
|
||||
@@ -1298,6 +1431,19 @@ else()
|
||||
target_link_libraries(${bun} PRIVATE LibArchive::LibArchive)
|
||||
endif()
|
||||
|
||||
if(USE_CUSTOM_LIBDEFLATE)
|
||||
include_directories(${BUN_DEPS_DIR}/libdeflate)
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/deflate.lib")
|
||||
else()
|
||||
target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/libdeflate.a")
|
||||
endif()
|
||||
else()
|
||||
find_package(LibDeflate REQUIRED)
|
||||
target_link_libraries(${bun} PRIVATE LibDeflate::LibDeflate)
|
||||
endif()
|
||||
|
||||
if(USE_CUSTOM_MIMALLOC)
|
||||
include_directories(${BUN_DEPS_DIR}/mimalloc/include)
|
||||
|
||||
@@ -1396,6 +1542,11 @@ if(USE_STATIC_SQLITE)
|
||||
"SQLITE_ENABLE_JSON1=1"
|
||||
"SQLITE_ENABLE_MATH_FUNCTIONS=1"
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
target_compile_options(sqlite3 PRIVATE /MT /U_DLL)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${bun} PRIVATE sqlite3)
|
||||
message(STATUS "Using static sqlite3")
|
||||
target_compile_definitions(${bun} PRIVATE "LAZY_LOAD_SQLITE=0")
|
||||
@@ -1404,6 +1555,24 @@ else()
|
||||
target_compile_definitions(${bun} PRIVATE "LAZY_LOAD_SQLITE=1")
|
||||
endif()
|
||||
|
||||
# -- Brotli --
|
||||
set(BROTLI_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/deps/brotli")
|
||||
file(GLOB BROTLI_FILES ${CONFIGURE_DEPENDS}
|
||||
"${BROTLI_SRC}/common/*.c"
|
||||
"${BROTLI_SRC}/enc/*.c"
|
||||
"${BROTLI_SRC}/dec/*.c"
|
||||
)
|
||||
add_library(brotli STATIC ${BROTLI_FILES})
|
||||
target_include_directories(brotli PRIVATE "${BROTLI_SRC}/include")
|
||||
target_compile_definitions(brotli PRIVATE "BROTLI_STATIC")
|
||||
|
||||
if(WIN32)
|
||||
target_compile_options(brotli PRIVATE /MT /U_DLL)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${bun} PRIVATE brotli)
|
||||
include_directories("${BUN_DEPS_DIR}/brotli/include")
|
||||
|
||||
if(USE_CUSTOM_LSHPACK)
|
||||
include_directories(${BUN_DEPS_DIR}/ls-hpack)
|
||||
|
||||
@@ -1421,9 +1590,11 @@ endif()
|
||||
if(NOT WIN32)
|
||||
target_link_libraries(${bun} PRIVATE "${WEBKIT_LIB_DIR}/libWTF.a")
|
||||
target_link_libraries(${bun} PRIVATE "${WEBKIT_LIB_DIR}/libJavaScriptCore.a")
|
||||
target_link_libraries(${bun} PRIVATE "${WEBKIT_LIB_DIR}/libbmalloc.a")
|
||||
|
||||
if(NOT APPLE OR EXISTS "${WEBKIT_LIB_DIR}/libbmalloc.a")
|
||||
target_link_libraries(${bun} PRIVATE "${WEBKIT_LIB_DIR}/libbmalloc.a")
|
||||
endif()
|
||||
else()
|
||||
target_link_options(${bun} PRIVATE "-static")
|
||||
target_link_libraries(${bun} PRIVATE
|
||||
"${WEBKIT_LIB_DIR}/WTF.lib"
|
||||
"${WEBKIT_LIB_DIR}/JavaScriptCore.lib"
|
||||
@@ -1433,10 +1604,10 @@ else()
|
||||
winmm
|
||||
bcrypt
|
||||
ntdll
|
||||
ucrt
|
||||
userenv
|
||||
dbghelp
|
||||
wsock32 # ws2_32 required by TransmitFile aka sendfile on windows
|
||||
delayimp.lib
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ If you are using Windows, please refer to [this guide](/docs/project/building-wi
|
||||
{% details summary="For Ubuntu users" %}
|
||||
TL;DR: Ubuntu 22.04 is suggested.
|
||||
Bun currently requires `glibc >=2.32` in development which means if you're on Ubuntu 20.04 (glibc == 2.31), you may likely meet `error: undefined symbol: __libc_single_threaded `. You need to take extra configurations. Also, according to this [issue](https://github.com/llvm/llvm-project/issues/97314), LLVM 16 is no longer maintained on Ubuntu 24.04 (noble). And instead, you might want `brew` to install LLVM 16 for your Ubuntu 24.04.
|
||||
{% /details %}
|
||||
|
||||
## Install Dependencies
|
||||
|
||||
|
||||
72
Dockerfile
72
Dockerfile
@@ -52,11 +52,8 @@ ENV CI 1
|
||||
ENV CPU_TARGET=${CPU_TARGET}
|
||||
ENV BUILDARCH=${BUILDARCH}
|
||||
ENV BUN_DEPS_OUT_DIR=${BUN_DEPS_OUT_DIR}
|
||||
ENV USE_LTO 1
|
||||
|
||||
ENV CXX=clang++-${LLVM_VERSION}
|
||||
ENV CC=clang-${LLVM_VERSION}
|
||||
ENV AR=/usr/bin/llvm-ar-${LLVM_VERSION}
|
||||
ENV LD=lld-${LLVM_VERSION}
|
||||
ENV LC_CTYPE=en_US.UTF-8
|
||||
ENV LC_ALL=en_US.UTF-8
|
||||
|
||||
@@ -93,6 +90,8 @@ RUN install_packages \
|
||||
clangd-${LLVM_VERSION} \
|
||||
libc++-${LLVM_VERSION}-dev \
|
||||
libc++abi-${LLVM_VERSION}-dev \
|
||||
llvm-${LLVM_VERSION}-runtime \
|
||||
llvm-${LLVM_VERSION}-dev \
|
||||
make \
|
||||
cmake \
|
||||
ninja-build \
|
||||
@@ -119,6 +118,15 @@ RUN install_packages \
|
||||
&& ln -sf /usr/bin/lldb-${LLVM_VERSION} /usr/bin/lldb \
|
||||
&& ln -sf /usr/bin/clangd-${LLVM_VERSION} /usr/bin/clangd \
|
||||
&& ln -sf /usr/bin/llvm-ar-${LLVM_VERSION} /usr/bin/llvm-ar \
|
||||
&& ln -sf /usr/bin/ld.lld /usr/bin/ld \
|
||||
&& ln -sf /usr/bin/llvm-ranlib-${LLVM_VERSION} /usr/bin/ranlib \
|
||||
&& ln -sf /usr/bin/clang /usr/bin/cc \
|
||||
&& ln -sf /usr/bin/clang /usr/bin/c89 \
|
||||
&& ln -sf /usr/bin/clang /usr/bin/c99 \
|
||||
&& ln -sf /usr/bin/clang++ /usr/bin/c++ \
|
||||
&& ln -sf /usr/bin/clang++ /usr/bin/g++ \
|
||||
&& ln -sf /usr/bin/llvm-ar /usr/bin/ar \
|
||||
&& ln -sf /usr/bin/clang /usr/bin/gcc \
|
||||
&& arch="$(dpkg --print-architecture)" \
|
||||
&& case "${arch##*-}" in \
|
||||
amd64) variant="x64";; \
|
||||
@@ -131,6 +139,7 @@ RUN install_packages \
|
||||
&& ln -s /usr/bin/bun /usr/bin/bunx \
|
||||
&& rm -rf bun-linux-${variant} bun-linux-${variant}.zip \
|
||||
&& mkdir -p ${BUN_DIR} ${BUN_DEPS_OUT_DIR}
|
||||
|
||||
# && if [ -n "${SCCACHE_BUCKET}" ]; then \
|
||||
# echo "Setting up sccache" \
|
||||
# && wget https://github.com/mozilla/sccache/releases/download/v0.5.4/sccache-v0.5.4-${BUILD_MACHINE_ARCH}-unknown-linux-musl.tar.gz \
|
||||
@@ -167,13 +176,14 @@ ENV CCACHE_DIR=${CCACHE_DIR}
|
||||
|
||||
COPY Makefile ${BUN_DIR}/Makefile
|
||||
COPY src/deps/c-ares ${BUN_DIR}/src/deps/c-ares
|
||||
COPY scripts ${BUN_DIR}/scripts
|
||||
|
||||
WORKDIR $BUN_DIR
|
||||
|
||||
RUN --mount=type=cache,target=${CCACHE_DIR} \
|
||||
cd $BUN_DIR \
|
||||
&& make c-ares \
|
||||
&& rm -rf ${BUN_DIR}/src/deps/c-ares ${BUN_DIR}/Makefile
|
||||
&& bash ./scripts/build-cares.sh \
|
||||
&& rm -rf ${BUN_DIR}/src/deps/c-ares ${BUN_DIR}/Makefile ${BUN_DIR}/scripts
|
||||
|
||||
FROM bun-base as lolhtml
|
||||
|
||||
@@ -204,13 +214,14 @@ ENV CPU_TARGET=${CPU_TARGET}
|
||||
|
||||
COPY Makefile ${BUN_DIR}/Makefile
|
||||
COPY src/deps/mimalloc ${BUN_DIR}/src/deps/mimalloc
|
||||
COPY scripts ${BUN_DIR}/scripts
|
||||
|
||||
ARG CCACHE_DIR=/ccache
|
||||
ENV CCACHE_DIR=${CCACHE_DIR}
|
||||
|
||||
RUN --mount=type=cache,target=${CCACHE_DIR} \
|
||||
cd ${BUN_DIR} \
|
||||
&& make mimalloc \
|
||||
&& bash ./scripts/build-mimalloc.sh \
|
||||
&& rm -rf src/deps/mimalloc Makefile
|
||||
|
||||
FROM bun-base as mimalloc-debug
|
||||
@@ -240,14 +251,38 @@ ARG CCACHE_DIR=/ccache
|
||||
ENV CCACHE_DIR=${CCACHE_DIR}
|
||||
|
||||
COPY Makefile ${BUN_DIR}/Makefile
|
||||
COPY CMakeLists.txt ${BUN_DIR}/CMakeLists.txt
|
||||
COPY scripts ${BUN_DIR}/scripts
|
||||
COPY src/deps/zlib ${BUN_DIR}/src/deps/zlib
|
||||
COPY package.json bun.lockb Makefile .gitmodules ${BUN_DIR}/
|
||||
|
||||
WORKDIR $BUN_DIR
|
||||
|
||||
RUN --mount=type=cache,target=${CCACHE_DIR} \
|
||||
cd $BUN_DIR \
|
||||
&& make zlib \
|
||||
&& rm -rf src/deps/zlib Makefile
|
||||
&& bash ./scripts/build-zlib.sh && rm -rf src/deps/zlib scripts
|
||||
|
||||
|
||||
FROM bun-base as libdeflate
|
||||
|
||||
ARG BUN_DIR
|
||||
ARG CPU_TARGET
|
||||
ENV CPU_TARGET=${CPU_TARGET}
|
||||
ARG CCACHE_DIR=/ccache
|
||||
ENV CCACHE_DIR=${CCACHE_DIR}
|
||||
|
||||
COPY Makefile ${BUN_DIR}/Makefile
|
||||
COPY CMakeLists.txt ${BUN_DIR}/CMakeLists.txt
|
||||
COPY scripts ${BUN_DIR}/scripts
|
||||
COPY src/deps/libdeflate ${BUN_DIR}/src/deps/libdeflate
|
||||
COPY package.json bun.lockb Makefile .gitmodules ${BUN_DIR}/
|
||||
|
||||
WORKDIR $BUN_DIR
|
||||
|
||||
RUN --mount=type=cache,target=${CCACHE_DIR} \
|
||||
cd $BUN_DIR \
|
||||
&& bash ./scripts/build-libdeflate.sh && rm -rf src/deps/libdeflate scripts
|
||||
|
||||
|
||||
FROM bun-base as libarchive
|
||||
|
||||
@@ -286,6 +321,7 @@ ARG CPU_TARGET
|
||||
ENV CPU_TARGET=${CPU_TARGET}
|
||||
|
||||
COPY Makefile ${BUN_DIR}/Makefile
|
||||
COPY scripts ${BUN_DIR}/scripts
|
||||
COPY src/deps/boringssl ${BUN_DIR}/src/deps/boringssl
|
||||
|
||||
WORKDIR $BUN_DIR
|
||||
@@ -295,7 +331,7 @@ ENV CCACHE_DIR=${CCACHE_DIR}
|
||||
|
||||
RUN --mount=type=cache,target=${CCACHE_DIR} \
|
||||
cd ${BUN_DIR} \
|
||||
&& make boringssl \
|
||||
&& bash ./scripts/build-boringssl.sh \
|
||||
&& rm -rf src/deps/boringssl Makefile
|
||||
|
||||
|
||||
@@ -311,12 +347,14 @@ ENV CCACHE_DIR=${CCACHE_DIR}
|
||||
|
||||
COPY Makefile ${BUN_DIR}/Makefile
|
||||
COPY src/deps/zstd ${BUN_DIR}/src/deps/zstd
|
||||
COPY scripts ${BUN_DIR}/scripts
|
||||
|
||||
WORKDIR $BUN_DIR
|
||||
|
||||
RUN --mount=type=cache,target=${CCACHE_DIR} \
|
||||
cd $BUN_DIR \
|
||||
&& make zstd
|
||||
&& bash ./scripts/build-zstd.sh \
|
||||
&& rm -rf src/deps/zstd scripts
|
||||
|
||||
FROM bun-base as ls-hpack
|
||||
|
||||
@@ -330,12 +368,14 @@ ENV CCACHE_DIR=${CCACHE_DIR}
|
||||
|
||||
COPY Makefile ${BUN_DIR}/Makefile
|
||||
COPY src/deps/ls-hpack ${BUN_DIR}/src/deps/ls-hpack
|
||||
COPY scripts ${BUN_DIR}/scripts
|
||||
|
||||
WORKDIR $BUN_DIR
|
||||
|
||||
RUN --mount=type=cache,target=${CCACHE_DIR} \
|
||||
cd $BUN_DIR \
|
||||
&& make lshpack
|
||||
&& bash ./scripts/build-lshpack.sh \
|
||||
&& rm -rf src/deps/ls-hpack scripts
|
||||
|
||||
FROM bun-base-with-zig as bun-identifier-cache
|
||||
|
||||
@@ -393,6 +433,9 @@ COPY src ${BUN_DIR}/src
|
||||
COPY CMakeLists.txt ${BUN_DIR}/CMakeLists.txt
|
||||
COPY src/deps/boringssl/include ${BUN_DIR}/src/deps/boringssl/include
|
||||
|
||||
# for uWebSockets
|
||||
COPY src/deps/libdeflate ${BUN_DIR}/src/deps/libdeflate
|
||||
|
||||
ARG CCACHE_DIR=/ccache
|
||||
ENV CCACHE_DIR=${CCACHE_DIR}
|
||||
|
||||
@@ -491,11 +534,13 @@ RUN mkdir -p build bun-webkit
|
||||
|
||||
# lol
|
||||
COPY src/bun.js/bindings/sqlite/sqlite3.c ${BUN_DIR}/src/bun.js/bindings/sqlite/sqlite3.c
|
||||
COPY src/deps/brotli ${BUN_DIR}/src/deps/brotli
|
||||
|
||||
COPY src/symbols.dyn src/linker.lds ${BUN_DIR}/src/
|
||||
|
||||
COPY CMakeLists.txt ${BUN_DIR}/CMakeLists.txt
|
||||
COPY --from=zlib ${BUN_DEPS_OUT_DIR}/* ${BUN_DEPS_OUT_DIR}/
|
||||
COPY --from=libdeflate ${BUN_DEPS_OUT_DIR}/* ${BUN_DEPS_OUT_DIR}/
|
||||
COPY --from=libarchive ${BUN_DEPS_OUT_DIR}/* ${BUN_DEPS_OUT_DIR}/
|
||||
COPY --from=boringssl ${BUN_DEPS_OUT_DIR}/* ${BUN_DEPS_OUT_DIR}/
|
||||
COPY --from=lolhtml ${BUN_DEPS_OUT_DIR}/* ${BUN_DEPS_OUT_DIR}/
|
||||
@@ -505,7 +550,8 @@ COPY --from=tinycc ${BUN_DEPS_OUT_DIR}/* ${BUN_DEPS_OUT_DIR}/
|
||||
COPY --from=c-ares ${BUN_DEPS_OUT_DIR}/* ${BUN_DEPS_OUT_DIR}/
|
||||
COPY --from=ls-hpack ${BUN_DEPS_OUT_DIR}/* ${BUN_DEPS_OUT_DIR}/
|
||||
COPY --from=bun-compile-zig-obj /tmp/bun-zig.o ${BUN_DIR}/build/bun-zig.o
|
||||
COPY --from=bun-cpp-objects ${BUN_DIR}/build/bun-cpp-objects.a ${BUN_DIR}/build/bun-cpp-objects.a
|
||||
COPY --from=bun-cpp-objects ${BUN_DIR}/build/*.a ${BUN_DIR}/build/
|
||||
COPY --from=bun-cpp-objects ${BUN_DIR}/build/*.o ${BUN_DIR}/build/
|
||||
COPY --from=bun-cpp-objects ${BUN_DIR}/bun-webkit/lib ${BUN_DIR}/bun-webkit/lib
|
||||
|
||||
WORKDIR $BUN_DIR/build
|
||||
|
||||
@@ -34,6 +34,8 @@ Bun statically links these libraries:
|
||||
| [`c-ares`](https://github.com/c-ares/c-ares) | MIT licensed |
|
||||
| [`libicu`](https://github.com/unicode-org/icu) 72 | [license here](https://github.com/unicode-org/icu/blob/main/icu4c/LICENSE) |
|
||||
| [`libbase64`](https://github.com/aklomp/base64/blob/master/LICENSE) | BSD 2-Clause |
|
||||
| [`libuv`](https://github.com/libuv/libuv) (on Windows) | MIT |
|
||||
| [`libdeflate`](https://github.com/ebiggers/libdeflate) | MIT |
|
||||
| A fork of [`uWebsockets`](https://github.com/jarred-sumner/uwebsockets) | Apache 2.0 licensed |
|
||||
| Parts of [Tigerbeetle's IO code](https://github.com/tigerbeetle/tigerbeetle/blob/532c8b70b9142c17e07737ab6d3da68d7500cbca/src/io/windows.zig#L1) | Apache 2.0 licensed |
|
||||
|
||||
|
||||
17
Makefile
17
Makefile
@@ -26,8 +26,11 @@ ifeq ($(ARCH_NAME_RAW),arm64)
|
||||
ARCH_NAME = aarch64
|
||||
DOCKER_BUILDARCH = arm64
|
||||
BREW_PREFIX_PATH = /opt/homebrew
|
||||
DEFAULT_MIN_MACOS_VERSION = 11.0
|
||||
DEFAULT_MIN_MACOS_VERSION = 13.0
|
||||
MARCH_NATIVE = -mtune=$(CPU_TARGET)
|
||||
ifeq ($(OS_NAME),linux)
|
||||
MARCH_NATIVE = -march=armv8-a+crc -mtune=ampere1
|
||||
endif
|
||||
else
|
||||
ARCH_NAME = x64
|
||||
DOCKER_BUILDARCH = amd64
|
||||
@@ -154,7 +157,12 @@ CMAKE_FLAGS_WITHOUT_RELEASE = -DCMAKE_C_COMPILER=$(CC) \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=$(MIN_MACOS_VERSION) \
|
||||
$(CMAKE_CXX_COMPILER_LAUNCHER_FLAG) \
|
||||
-DCMAKE_AR=$(AR) \
|
||||
-DCMAKE_RANLIB=$(which llvm-16-ranlib 2>/dev/null || which llvm-ranlib 2>/dev/null)
|
||||
-DCMAKE_RANLIB=$(which llvm-16-ranlib 2>/dev/null || which llvm-ranlib 2>/dev/null) \
|
||||
-DCMAKE_CXX_STANDARD=20 \
|
||||
-DCMAKE_C_STANDARD=17 \
|
||||
-DCMAKE_CXX_STANDARD_REQUIRED=ON \
|
||||
-DCMAKE_C_STANDARD_REQUIRED=ON \
|
||||
-DCMAKE_CXX_EXTENSIONS=ON
|
||||
|
||||
|
||||
|
||||
@@ -181,8 +189,8 @@ endif
|
||||
|
||||
OPTIMIZATION_LEVEL=-O3 $(MARCH_NATIVE)
|
||||
DEBUG_OPTIMIZATION_LEVEL= -O1 $(MARCH_NATIVE) -gdwarf-4
|
||||
CFLAGS_WITHOUT_MARCH = $(MACOS_MIN_FLAG) $(OPTIMIZATION_LEVEL) -fno-exceptions -fvisibility=hidden -fvisibility-inlines-hidden
|
||||
BUN_CFLAGS = $(MACOS_MIN_FLAG) $(MARCH_NATIVE) $(OPTIMIZATION_LEVEL) -fno-exceptions -fvisibility=hidden -fvisibility-inlines-hidden
|
||||
CFLAGS_WITHOUT_MARCH = $(MACOS_MIN_FLAG) $(OPTIMIZATION_LEVEL) -fno-exceptions -fvisibility=hidden -fvisibility-inlines-hidden -mno-omit-leaf-frame-pointer -fno-omit-frame-pointer -fno-asynchronous-unwind-tables -fno-unwind-tables -fno-pie -fno-pic
|
||||
BUN_CFLAGS = $(MACOS_MIN_FLAG) $(MARCH_NATIVE) $(OPTIMIZATION_LEVEL) -fno-exceptions -fvisibility=hidden -fvisibility-inlines-hidden -mno-omit-leaf-frame-pointer -fno-omit-frame-pointer -fno-asynchronous-unwind-tables -fno-unwind-tables -fno-pie -fno-pic
|
||||
BUN_TMP_DIR := /tmp/make-bun
|
||||
CFLAGS=$(CFLAGS_WITHOUT_MARCH) $(MARCH_NATIVE)
|
||||
|
||||
@@ -1301,6 +1309,7 @@ jsc-build-mac-compile-debug:
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DUSE_THIN_ARCHIVES=OFF \
|
||||
-DENABLE_FTL_JIT=ON \
|
||||
-DENABLE_MALLOC_HEAP_BREAKDOWN=ON \
|
||||
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
||||
-DUSE_BUN_JSC_ADDITIONS=ON \
|
||||
-DENABLE_BUN_SKIP_FAILING_ASSERTIONS=ON \
|
||||
|
||||
@@ -1,20 +1,43 @@
|
||||
import { run, bench } from "mitata";
|
||||
import { run, bench, group } from "mitata";
|
||||
import { gzipSync, gunzipSync } from "bun";
|
||||
|
||||
const data = new TextEncoder().encode("Hello World!".repeat(9999));
|
||||
const data = await Bun.file(require.resolve("@babel/standalone/babel.min.js")).arrayBuffer();
|
||||
|
||||
const compressed = gzipSync(data);
|
||||
|
||||
bench(`roundtrip - "Hello World!".repeat(9999))`, () => {
|
||||
gunzipSync(gzipSync(data));
|
||||
const libraries = ["zlib"];
|
||||
if (Bun.semver.satisfies(Bun.version.replaceAll("-debug", ""), ">=1.1.21")) {
|
||||
libraries.push("libdeflate");
|
||||
}
|
||||
const options = { library: undefined };
|
||||
const benchFn = (name, fn) => {
|
||||
if (libraries.length > 1) {
|
||||
group(name, () => {
|
||||
for (const library of libraries) {
|
||||
bench(library, () => {
|
||||
options.library = library;
|
||||
fn();
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
options.library = libraries[0];
|
||||
bench(name, () => {
|
||||
fn();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
benchFn(`roundtrip - @babel/standalone/babel.min.js`, () => {
|
||||
gunzipSync(gzipSync(data, options), options);
|
||||
});
|
||||
|
||||
bench(`gzipSync("Hello World!".repeat(9999)))`, () => {
|
||||
gzipSync(data);
|
||||
benchFn(`gzipSync(@babel/standalone/babel.min.js`, () => {
|
||||
gzipSync(data, options);
|
||||
});
|
||||
|
||||
bench(`gunzipSync("Hello World!".repeat(9999)))`, () => {
|
||||
gunzipSync(compressed);
|
||||
benchFn(`gunzipSync(@babel/standalone/babel.min.js`, () => {
|
||||
gunzipSync(compressed, options);
|
||||
});
|
||||
|
||||
await run();
|
||||
|
||||
BIN
bench/gzip/bun.lockb
Executable file
BIN
bench/gzip/bun.lockb
Executable file
Binary file not shown.
@@ -1,19 +1,22 @@
|
||||
import { run, bench } from "mitata";
|
||||
import { gzipSync, gunzipSync } from "zlib";
|
||||
import { createRequire } from "module";
|
||||
import { readFileSync } from "fs";
|
||||
|
||||
const data = new TextEncoder().encode("Hello World!".repeat(9999));
|
||||
const require = createRequire(import.meta.url);
|
||||
const data = readFileSync(require.resolve("@babel/standalone/babel.min.js"));
|
||||
|
||||
const compressed = gzipSync(data);
|
||||
|
||||
bench(`roundtrip - "Hello World!".repeat(9999))`, () => {
|
||||
bench(`roundtrip - @babel/standalone/babel.min.js)`, () => {
|
||||
gunzipSync(gzipSync(data));
|
||||
});
|
||||
|
||||
bench(`gzipSync("Hello World!".repeat(9999)))`, () => {
|
||||
bench(`gzipSync(@babel/standalone/babel.min.js))`, () => {
|
||||
gzipSync(data);
|
||||
});
|
||||
|
||||
bench(`gunzipSync("Hello World!".repeat(9999)))`, () => {
|
||||
bench(`gunzipSync(@babel/standalone/babel.min.js))`, () => {
|
||||
gunzipSync(compressed);
|
||||
});
|
||||
|
||||
|
||||
@@ -7,5 +7,8 @@
|
||||
"bench:node": "$NODE node.mjs",
|
||||
"bench:deno": "$DENO run -A --unstable deno.js",
|
||||
"bench": "bun run bench:bun && bun run bench:node && bun run bench:deno"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/standalone": "7.24.10"
|
||||
}
|
||||
}
|
||||
|
||||
31
bench/sqlite/better-sqlite3.mjs
Normal file
31
bench/sqlite/better-sqlite3.mjs
Normal file
@@ -0,0 +1,31 @@
|
||||
import { run, bench } from "mitata";
|
||||
import { createRequire } from "module";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const db = require("better-sqlite3")("./src/northwind.sqlite");
|
||||
|
||||
{
|
||||
const sql = db.prepare(`SELECT * FROM "Order"`);
|
||||
|
||||
bench('SELECT * FROM "Order"', () => {
|
||||
sql.all();
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
const sql = db.prepare(`SELECT * FROM "Product"`);
|
||||
|
||||
bench('SELECT * FROM "Product"', () => {
|
||||
sql.all();
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
const sql = db.prepare(`SELECT * FROM "OrderDetail"`);
|
||||
|
||||
bench('SELECT * FROM "OrderDetail"', () => {
|
||||
sql.all();
|
||||
});
|
||||
}
|
||||
|
||||
await run();
|
||||
@@ -1,8 +1,9 @@
|
||||
// Run `node --experimental-sqlite bench/sqlite/node.mjs` to run the script.
|
||||
// You will need `--experimental-sqlite` flag to run this script and node v22.5.0 or higher.
|
||||
import { run, bench } from "mitata";
|
||||
import { createRequire } from "module";
|
||||
import { DatabaseSync as Database } from "node:sqlite";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const db = require("better-sqlite3")("./src/northwind.sqlite");
|
||||
const db = new Database("./src/northwind.sqlite");
|
||||
|
||||
{
|
||||
const sql = db.prepare(`SELECT * FROM "Order"`);
|
||||
|
||||
211
build.zig
211
build.zig
@@ -33,8 +33,6 @@ comptime {
|
||||
}
|
||||
}
|
||||
|
||||
const default_reported_nodejs_version = "22.3.0";
|
||||
|
||||
const zero_sha = "0000000000000000000000000000000000000000";
|
||||
|
||||
const BunBuildOptions = struct {
|
||||
@@ -48,9 +46,10 @@ const BunBuildOptions = struct {
|
||||
sha: []const u8,
|
||||
enable_logs: bool = false,
|
||||
tracy_callstack_depth: u16,
|
||||
reported_nodejs_version: []const u8 = default_reported_nodejs_version,
|
||||
reported_nodejs_version: Version,
|
||||
|
||||
generated_code_dir: []const u8,
|
||||
no_llvm: bool,
|
||||
|
||||
cached_options_module: ?*Module = null,
|
||||
windows_shim: ?WindowsShim = null,
|
||||
@@ -73,14 +72,7 @@ const BunBuildOptions = struct {
|
||||
opts.addOption([:0]const u8, "sha", b.allocator.dupeZ(u8, this.sha) catch @panic("OOM"));
|
||||
opts.addOption(bool, "baseline", this.isBaseline());
|
||||
opts.addOption(bool, "enable_logs", this.enable_logs);
|
||||
opts.addOption([:0]const u8, "reported_nodejs_version", b.allocator.dupeZ(u8, this.reported_nodejs_version) catch @panic("OOM"));
|
||||
if (this.reported_nodejs_version.len > 0 and this.reported_nodejs_version[0] == 'v') {
|
||||
@panic("Node.js version should not start with 'v'");
|
||||
}
|
||||
|
||||
if (this.reported_nodejs_version.len == 0) {
|
||||
@panic("Node.js version should not be empty");
|
||||
}
|
||||
opts.addOption([]const u8, "reported_nodejs_version", b.fmt("{}", .{this.reported_nodejs_version}));
|
||||
|
||||
const mod = opts.createModule();
|
||||
this.cached_options_module = mod;
|
||||
@@ -122,6 +114,23 @@ pub fn getOSGlibCVersion(os: OperatingSystem) ?Version {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getCpuModel(os: OperatingSystem, arch: Arch) ?Target.Query.CpuModel {
|
||||
// https://github.com/oven-sh/bun/issues/12076
|
||||
if (os == .linux and arch == .aarch64) {
|
||||
return .{ .explicit = &Target.aarch64.cpu.cortex_a35 };
|
||||
}
|
||||
|
||||
// Be explicit and ensure we do not accidentally target a newer M-series chip
|
||||
if (os == .mac and arch == .aarch64) {
|
||||
return .{ .explicit = &Target.aarch64.cpu.apple_m1 };
|
||||
}
|
||||
|
||||
// note: x86_64 is dealt with in the CMake config and passed in.
|
||||
// the reason for the explicit handling on aarch64 is due to troubles
|
||||
// passing the exact target in via flags.
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn build(b: *Build) !void {
|
||||
std.log.info("zig compiler v{s}", .{builtin.zig_version_string});
|
||||
|
||||
@@ -147,6 +156,14 @@ pub fn build(b: *Build) !void {
|
||||
break :brk .{ os, arch };
|
||||
};
|
||||
|
||||
// target must be refined to support older but very popular devices on
|
||||
// aarch64, this means moving the minimum supported CPU to support certain
|
||||
// raspberry PIs. there are also a number of cloud hosts that use virtual
|
||||
// machines with surprisingly out of date versions of glibc.
|
||||
if (getCpuModel(os, arch)) |cpu_model| {
|
||||
target_query.cpu_model = cpu_model;
|
||||
}
|
||||
|
||||
target_query.os_version_min = getOSVersionMin(os);
|
||||
target_query.glibc_version = getOSGlibCVersion(os);
|
||||
|
||||
@@ -163,6 +180,10 @@ pub fn build(b: *Build) !void {
|
||||
break :ref_trace if (trace == 0) null else trace;
|
||||
};
|
||||
|
||||
const obj_format = b.option(ObjectFormat, "obj_format", "Output file for object files") orelse .obj;
|
||||
|
||||
const no_llvm = b.option(bool, "no_llvm", "Experiment with Zig self hosted backends. No stability guaranteed") orelse false;
|
||||
|
||||
var build_options = BunBuildOptions{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
@@ -171,6 +192,7 @@ pub fn build(b: *Build) !void {
|
||||
.arch = arch,
|
||||
|
||||
.generated_code_dir = generated_code_dir,
|
||||
.no_llvm = no_llvm,
|
||||
|
||||
.version = try Version.parse(bun_version),
|
||||
.canary_revision = canary: {
|
||||
@@ -178,7 +200,10 @@ pub fn build(b: *Build) !void {
|
||||
break :canary if (rev == 0) null else rev;
|
||||
},
|
||||
|
||||
.reported_nodejs_version = b.option([]const u8, "reported_nodejs_version", "Reported Node.js version") orelse default_reported_nodejs_version,
|
||||
.reported_nodejs_version = try Version.parse(
|
||||
b.option([]const u8, "reported_nodejs_version", "Reported Node.js version") orelse
|
||||
"0.0.0-unset",
|
||||
),
|
||||
|
||||
.sha = sha: {
|
||||
const sha = b.option([]const u8, "sha", "Force the git sha") orelse
|
||||
@@ -224,7 +249,7 @@ pub fn build(b: *Build) !void {
|
||||
var step = b.step("obj", "Build Bun's Zig code as a .o file");
|
||||
var bun_obj = addBunObject(b, &build_options);
|
||||
step.dependOn(&bun_obj.step);
|
||||
step.dependOn(&b.addInstallFile(bun_obj.getEmittedBin(), "bun-zig.o").step);
|
||||
step.dependOn(addInstallObjectFile(b, bun_obj, "bun-zig", obj_format));
|
||||
}
|
||||
|
||||
// zig build windows-shim
|
||||
@@ -252,95 +277,60 @@ pub fn build(b: *Build) !void {
|
||||
|
||||
// zig build check-all
|
||||
{
|
||||
var step = b.step("check-all", "Check for semantic analysis errors on all supported platforms");
|
||||
inline for (.{
|
||||
const step = b.step("check-all", "Check for semantic analysis errors on all supported platforms");
|
||||
addMultiCheck(b, step, build_options, &.{
|
||||
.{ .os = .windows, .arch = .x86_64 },
|
||||
.{ .os = .mac, .arch = .x86_64 },
|
||||
.{ .os = .mac, .arch = .aarch64 },
|
||||
.{ .os = .linux, .arch = .x86_64 },
|
||||
.{ .os = .linux, .arch = .aarch64 },
|
||||
}) |check| {
|
||||
inline for (.{ .Debug, .ReleaseFast }) |mode| {
|
||||
const check_target = b.resolveTargetQuery(.{
|
||||
.os_tag = OperatingSystem.stdOSTag(check.os),
|
||||
.cpu_arch = check.arch,
|
||||
.os_version_min = getOSVersionMin(check.os),
|
||||
.glibc_version = getOSGlibCVersion(check.os),
|
||||
});
|
||||
|
||||
var options = BunBuildOptions{
|
||||
.target = check_target,
|
||||
.os = check.os,
|
||||
.arch = check_target.result.cpu.arch,
|
||||
.optimize = mode,
|
||||
|
||||
.canary_revision = build_options.canary_revision,
|
||||
.sha = build_options.sha,
|
||||
.tracy_callstack_depth = build_options.tracy_callstack_depth,
|
||||
.version = build_options.version,
|
||||
.reported_nodejs_version = build_options.reported_nodejs_version,
|
||||
.generated_code_dir = build_options.generated_code_dir,
|
||||
};
|
||||
var obj = addBunObject(b, &options);
|
||||
obj.generated_bin = null;
|
||||
step.dependOn(&obj.step);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// zig build check-windows
|
||||
{
|
||||
var step = b.step("check-windows", "Check for semantic analysis errors on Windows x64");
|
||||
inline for (.{
|
||||
const step = b.step("check-windows", "Check for semantic analysis errors on Windows");
|
||||
addMultiCheck(b, step, build_options, &.{
|
||||
.{ .os = .windows, .arch = .x86_64 },
|
||||
}) |check| {
|
||||
inline for (.{ .Debug, .ReleaseFast }) |mode| {
|
||||
const check_target = b.resolveTargetQuery(.{
|
||||
.os_tag = OperatingSystem.stdOSTag(check.os),
|
||||
.cpu_arch = check.arch,
|
||||
.os_version_min = getOSVersionMin(check.os),
|
||||
.glibc_version = getOSGlibCVersion(check.os),
|
||||
});
|
||||
|
||||
var options = BunBuildOptions{
|
||||
.target = check_target,
|
||||
.os = check.os,
|
||||
.arch = check_target.result.cpu.arch,
|
||||
.optimize = mode,
|
||||
|
||||
.canary_revision = build_options.canary_revision,
|
||||
.sha = build_options.sha,
|
||||
.tracy_callstack_depth = build_options.tracy_callstack_depth,
|
||||
.version = build_options.version,
|
||||
.reported_nodejs_version = build_options.reported_nodejs_version,
|
||||
.generated_code_dir = build_options.generated_code_dir,
|
||||
};
|
||||
var obj = addBunObject(b, &options);
|
||||
obj.generated_bin = null;
|
||||
step.dependOn(&obj.step);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Running `zig build` with no arguments is almost always a mistake.
|
||||
// TODO: revive this error. cannot right now since ZLS runs zig build without arguments
|
||||
{
|
||||
// const mistake_message = b.addSystemCommand(&.{
|
||||
// "echo",
|
||||
// \\
|
||||
// \\To build Bun from source, please use `bun run setup` instead of `zig build`"
|
||||
// \\For more info, see https://bun.sh/docs/project/contributing
|
||||
// \\
|
||||
// \\If you want to build the zig code in isolation, run:
|
||||
// \\ 'zig build obj -Dgenerated-code=./build/codegen [...opts]'
|
||||
// \\
|
||||
// \\If you want to test a compile without emitting an object:
|
||||
// \\ 'zig build check'
|
||||
// \\ 'zig build check-all' (run linux+mac+windows)
|
||||
// \\
|
||||
// });
|
||||
pub inline fn addMultiCheck(
|
||||
b: *Build,
|
||||
parent_step: *Step,
|
||||
root_build_options: BunBuildOptions,
|
||||
to_check: []const struct { os: OperatingSystem, arch: Arch },
|
||||
) void {
|
||||
inline for (to_check) |check| {
|
||||
inline for (.{ .Debug, .ReleaseFast }) |mode| {
|
||||
const check_target = b.resolveTargetQuery(.{
|
||||
.os_tag = OperatingSystem.stdOSTag(check.os),
|
||||
.cpu_arch = check.arch,
|
||||
.cpu_model = getCpuModel(check.os, check.arch) orelse .determined_by_cpu_arch,
|
||||
.os_version_min = getOSVersionMin(check.os),
|
||||
.glibc_version = getOSGlibCVersion(check.os),
|
||||
});
|
||||
|
||||
// b.default_step.dependOn(&mistake_message.step);
|
||||
var options: BunBuildOptions = .{
|
||||
.target = check_target,
|
||||
.os = check.os,
|
||||
.arch = check_target.result.cpu.arch,
|
||||
.optimize = mode,
|
||||
|
||||
.canary_revision = root_build_options.canary_revision,
|
||||
.sha = root_build_options.sha,
|
||||
.tracy_callstack_depth = root_build_options.tracy_callstack_depth,
|
||||
.version = root_build_options.version,
|
||||
.reported_nodejs_version = root_build_options.reported_nodejs_version,
|
||||
.generated_code_dir = root_build_options.generated_code_dir,
|
||||
.no_llvm = root_build_options.no_llvm,
|
||||
};
|
||||
|
||||
var obj = addBunObject(b, &options);
|
||||
obj.generated_bin = null;
|
||||
parent_step.dependOn(&obj.step);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,10 +343,15 @@ pub fn addBunObject(b: *Build, opts: *BunBuildOptions) *Compile {
|
||||
},
|
||||
.target = opts.target,
|
||||
.optimize = opts.optimize,
|
||||
.use_llvm = !opts.no_llvm,
|
||||
.use_lld = if (opts.os == .mac) false else !opts.no_llvm,
|
||||
|
||||
// https://github.com/ziglang/zig/issues/17430
|
||||
.pic = true,
|
||||
|
||||
.omit_frame_pointer = false,
|
||||
.strip = false, // stripped at the end
|
||||
});
|
||||
|
||||
obj.bundle_compiler_rt = false;
|
||||
obj.formatted_panics = true;
|
||||
obj.root_module.omit_frame_pointer = false;
|
||||
@@ -374,9 +369,10 @@ pub fn addBunObject(b: *Build, opts: *BunBuildOptions) *Compile {
|
||||
}
|
||||
|
||||
if (opts.os == .linux) {
|
||||
obj.link_emit_relocs = true;
|
||||
obj.link_eh_frame_hdr = true;
|
||||
obj.link_emit_relocs = false;
|
||||
obj.link_eh_frame_hdr = false;
|
||||
obj.link_function_sections = true;
|
||||
obj.link_data_sections = true;
|
||||
|
||||
if (opts.optimize == .Debug) {
|
||||
obj.root_module.valgrind = true;
|
||||
@@ -387,6 +383,25 @@ pub fn addBunObject(b: *Build, opts: *BunBuildOptions) *Compile {
|
||||
return obj;
|
||||
}
|
||||
|
||||
const ObjectFormat = enum {
|
||||
bc,
|
||||
obj,
|
||||
};
|
||||
|
||||
pub fn addInstallObjectFile(
|
||||
b: *Build,
|
||||
compile: *Compile,
|
||||
name: []const u8,
|
||||
out_mode: ObjectFormat,
|
||||
) *Step {
|
||||
// bin always needed to be computed or else the compilation will do nothing. zig build system bug?
|
||||
const bin = compile.getEmittedBin();
|
||||
return &b.addInstallFile(switch (out_mode) {
|
||||
.obj => bin,
|
||||
.bc => compile.getEmittedLlvmBc(),
|
||||
}, b.fmt("{s}.o", .{name})).step;
|
||||
}
|
||||
|
||||
fn exists(path: []const u8) bool {
|
||||
const file = std.fs.openFileAbsolute(path, .{ .mode = .read_only }) catch return false;
|
||||
file.close();
|
||||
@@ -438,6 +453,12 @@ fn addInternalPackages(b: *Build, obj: *Compile, opts: *BunBuildOptions) void {
|
||||
.root_source_file = .{ .cwd_relative = resolved_source_tag_path },
|
||||
});
|
||||
|
||||
const error_code_path = b.pathJoin(&.{ opts.generated_code_dir, "ErrorCode.zig" });
|
||||
validateGeneratedPath(error_code_path);
|
||||
obj.root_module.addAnonymousImport("ErrorCode", .{
|
||||
.root_source_file = .{ .cwd_relative = error_code_path },
|
||||
});
|
||||
|
||||
if (os == .windows) {
|
||||
obj.root_module.addAnonymousImport("bun_shim_impl.exe", .{
|
||||
.root_source_file = opts.windowsShim(b).exe.getEmittedBin(),
|
||||
@@ -447,7 +468,11 @@ fn addInternalPackages(b: *Build, obj: *Compile, opts: *BunBuildOptions) void {
|
||||
|
||||
fn validateGeneratedPath(path: []const u8) void {
|
||||
if (!exists(path)) {
|
||||
std.debug.panic("{s} does not exist in generated code directory!", .{std.fs.path.basename(path)});
|
||||
std.debug.panic(
|
||||
\\Generated file '{s}' is missing!
|
||||
\\
|
||||
\\Make sure to use CMake and Ninja, or pass a manual codegen folder with '-Dgenerated-code=...'
|
||||
, .{path});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -425,6 +425,7 @@ _bun_run_completion() {
|
||||
'--external[Exclude module from transpilation (can use * wildcards). ex: -e react]:external' \
|
||||
'-e[Exclude module from transpilation (can use * wildcards). ex: -e react]:external' \
|
||||
'--loader[Parse files with .ext:loader, e.g. --loader .js:jsx. Valid loaders: js, jsx, ts, tsx, json, toml, text, file, wasm, napi]:loader' \
|
||||
'--packages[Exclude dependencies from bundle, e.g. --packages external. Valid options: bundle, external]:packages' \
|
||||
'-l[Parse files with .ext:loader, e.g. --loader .js:jsx. Valid loaders: js, jsx, ts, tsx, json, toml, text, file, wasm, napi]:loader' \
|
||||
'--origin[Rewrite import URLs to start with --origin. Default: ""]:origin' \
|
||||
'-u[Rewrite import URLs to start with --origin. Default: ""]:origin' \
|
||||
|
||||
308
docs/api/fetch.md
Normal file
308
docs/api/fetch.md
Normal file
@@ -0,0 +1,308 @@
|
||||
Bun implements the WHATWG `fetch` standard, with some extensions to meet the needs of server-side JavaScript.
|
||||
|
||||
Bun also implements `node:http`, but `fetch` is generally recommended instead.
|
||||
|
||||
## Sending an HTTP request
|
||||
|
||||
To send an HTTP request, use `fetch`
|
||||
|
||||
```ts
|
||||
const response = await fetch("http://example.com");
|
||||
|
||||
console.log(response.status); // => 200
|
||||
|
||||
const text = await response.text(); // or response.json(), response.formData(), etc.
|
||||
```
|
||||
|
||||
`fetch` also works with HTTPS URLs.
|
||||
|
||||
```ts
|
||||
const response = await fetch("https://example.com");
|
||||
```
|
||||
|
||||
You can also pass `fetch` a [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) object.
|
||||
|
||||
```ts
|
||||
const request = new Request("http://example.com", {
|
||||
method: "POST",
|
||||
body: "Hello, world!",
|
||||
});
|
||||
|
||||
const response = await fetch(request);
|
||||
```
|
||||
|
||||
### Sending a POST request
|
||||
|
||||
To send a POST request, pass an object with the `method` property set to `"POST"`.
|
||||
|
||||
```ts
|
||||
const response = await fetch("http://example.com", {
|
||||
method: "POST",
|
||||
body: "Hello, world!",
|
||||
});
|
||||
```
|
||||
|
||||
`body` can be a string, a `FormData` object, an `ArrayBuffer`, a `Blob`, and more. See the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/Body/body) for more information.
|
||||
|
||||
### Proxying requests
|
||||
|
||||
To proxy a request, pass an object with the `proxy` property set to a URL.
|
||||
|
||||
```ts
|
||||
const response = await fetch("http://example.com", {
|
||||
proxy: "http://proxy.com",
|
||||
});
|
||||
```
|
||||
|
||||
### Custom headers
|
||||
|
||||
To set custom headers, pass an object with the `headers` property set to an object.
|
||||
|
||||
```ts
|
||||
const response = await fetch("http://example.com", {
|
||||
headers: {
|
||||
"X-Custom-Header": "value",
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
You can also set headers using the [Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers) object.
|
||||
|
||||
```ts
|
||||
const headers = new Headers();
|
||||
headers.append("X-Custom-Header", "value");
|
||||
|
||||
const response = await fetch("http://example.com", {
|
||||
headers,
|
||||
});
|
||||
```
|
||||
|
||||
### Response bodies
|
||||
|
||||
To read the response body, use one of the following methods:
|
||||
|
||||
- `response.text(): Promise<string>`: Returns a promise that resolves with the response body as a string.
|
||||
- `response.json(): Promise<any>`: Returns a promise that resolves with the response body as a JSON object.
|
||||
- `response.formData(): Promise<FormData>`: Returns a promise that resolves with the response body as a `FormData` object.
|
||||
- `response.bytes(): Promise<Uint8Array>`: Returns a promise that resolves with the response body as a `Uint8Array`.
|
||||
- `response.arrayBuffer(): Promise<ArrayBuffer>`: Returns a promise that resolves with the response body as an `ArrayBuffer`.
|
||||
- `response.blob(): Promise<Blob>`: Returns a promise that resolves with the response body as a `Blob`.
|
||||
|
||||
#### Streaming response bodies
|
||||
|
||||
You can use async iterators to stream the response body.
|
||||
|
||||
```ts
|
||||
const response = await fetch("http://example.com");
|
||||
|
||||
for await (const chunk of response.body) {
|
||||
console.log(chunk);
|
||||
}
|
||||
```
|
||||
|
||||
You can also more directly access the `ReadableStream` object.
|
||||
|
||||
```ts
|
||||
const response = await fetch("http://example.com");
|
||||
|
||||
const stream = response.body;
|
||||
|
||||
const reader = stream.getReader();
|
||||
const { value, done } = await reader.read();
|
||||
```
|
||||
|
||||
### Fetching a URL with a timeout
|
||||
|
||||
To fetch a URL with a timeout, use `AbortSignal.timeout`:
|
||||
|
||||
```ts
|
||||
const response = await fetch("http://example.com", {
|
||||
signal: AbortSignal.timeout(1000),
|
||||
});
|
||||
```
|
||||
|
||||
#### Canceling a request
|
||||
|
||||
To cancel a request, use an `AbortController`:
|
||||
|
||||
```ts
|
||||
const controller = new AbortController();
|
||||
|
||||
const response = await fetch("http://example.com", {
|
||||
signal: controller.signal,
|
||||
});
|
||||
|
||||
controller.abort();
|
||||
```
|
||||
|
||||
### Unix domain sockets
|
||||
|
||||
To fetch a URL using a Unix domain socket, use the `unix: string` option:
|
||||
|
||||
```ts
|
||||
const response = await fetch("https://hostname/a/path", {
|
||||
unix: "/var/run/path/to/unix.sock",
|
||||
method: "POST",
|
||||
body: JSON.stringify({ message: "Hello from Bun!" }),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### TLS
|
||||
|
||||
To use a client certificate, use the `tls` option:
|
||||
|
||||
```ts
|
||||
await fetch("https://example.com", {
|
||||
tls: {
|
||||
key: Bun.file("/path/to/key.pem"),
|
||||
cert: Bun.file("/path/to/cert.pem"),
|
||||
// ca: [Bun.file("/path/to/ca.pem")],
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
#### Custom TLS Validation
|
||||
|
||||
To customize the TLS validation, use the `checkServerIdentity` option in `tls`
|
||||
|
||||
```ts
|
||||
await fetch("https://example.com", {
|
||||
tls: {
|
||||
checkServerIdentity: (hostname, peerCertificate) => {
|
||||
// Return an error if the certificate is invalid
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
This is similar to how it works in Node's `net` module.
|
||||
|
||||
## Debugging
|
||||
|
||||
To help with debugging, you can pass `verbose: true` to `fetch`:
|
||||
|
||||
```ts
|
||||
const response = await fetch("http://example.com", {
|
||||
verbose: true,
|
||||
});
|
||||
```
|
||||
|
||||
This will print the request and response headers to your terminal:
|
||||
|
||||
```sh
|
||||
[fetch] > HTTP/1.1 GET http://example.com/
|
||||
[fetch] > Connection: keep-alive
|
||||
[fetch] > User-Agent: Bun/1.1.21
|
||||
[fetch] > Accept: */*
|
||||
[fetch] > Host: example.com
|
||||
[fetch] > Accept-Encoding: gzip, deflate, br
|
||||
|
||||
[fetch] < 200 OK
|
||||
[fetch] < Content-Encoding: gzip
|
||||
[fetch] < Age: 201555
|
||||
[fetch] < Cache-Control: max-age=604800
|
||||
[fetch] < Content-Type: text/html; charset=UTF-8
|
||||
[fetch] < Date: Sun, 21 Jul 2024 02:41:14 GMT
|
||||
[fetch] < Etag: "3147526947+gzip"
|
||||
[fetch] < Expires: Sun, 28 Jul 2024 02:41:14 GMT
|
||||
[fetch] < Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
|
||||
[fetch] < Server: ECAcc (sac/254F)
|
||||
[fetch] < Vary: Accept-Encoding
|
||||
[fetch] < X-Cache: HIT
|
||||
[fetch] < Content-Length: 648
|
||||
```
|
||||
|
||||
Note: `verbose: boolean` is not part of the Web standard `fetch` API and is specific to Bun.
|
||||
|
||||
## Performance
|
||||
|
||||
Before an HTTP request can be sent, the DNS lookup must be performed. This can take a significant amount of time, especially if the DNS server is slow or the network connection is poor.
|
||||
|
||||
After the DNS lookup, the TCP socket must be connected and the TLS handshake might need to be performed. This can also take a significant amount of time.
|
||||
|
||||
After the request completes, consuming the response body can also take a significant amount of time and memory.
|
||||
|
||||
At every step of the way, Bun provides APIs to help you optimize the performance of your application.
|
||||
|
||||
### DNS prefetching
|
||||
|
||||
To prefetch a DNS entry, you can use the `dns.prefetch` API. This API is useful when you know you'll need to connect to a host soon and want to avoid the initial DNS lookup.
|
||||
|
||||
```ts
|
||||
import { dns } from "bun";
|
||||
|
||||
dns.prefetch("bun.sh", 443);
|
||||
```
|
||||
|
||||
#### DNS caching
|
||||
|
||||
By default, Bun caches and deduplicates DNS queries in-memory for up to 30 seconds. You can see the cache stats by calling `dns.getCacheStats()`:
|
||||
|
||||
To learn more about DNS caching in Bun, see the [DNS caching](/docs/api/dns) documentation.
|
||||
|
||||
### Preconnect to a host
|
||||
|
||||
To preconnect to a host, you can use the `fetch.preconnect` API. This API is useful when you know you'll need to connect to a host soon and want to start the initial DNS lookup, TCP socket connection, and TLS handshake early.
|
||||
|
||||
```ts
|
||||
import { fetch } from "bun";
|
||||
|
||||
fetch.preconnect("https://bun.sh");
|
||||
```
|
||||
|
||||
Note: calling `fetch` immediately after `fetch.preconnect` will not make your request faster. Preconnecting only helps if you know you'll need to connect to a host soon, but you're not ready to make the request yet.
|
||||
|
||||
#### Preconnect at startup
|
||||
|
||||
To preconnect to a host at startup, you can pass `--fetch-preconnect`:
|
||||
|
||||
```sh
|
||||
$ bun --fetch-preconnect https://bun.sh ./my-script.ts
|
||||
```
|
||||
|
||||
This is sort of like `<link rel="preconnect">` in HTML.
|
||||
|
||||
This feature is not implemented on Windows yet. If you're interested in using this feature on Windows, please file an issue and we can implement support for it on Windows.
|
||||
|
||||
### Connection pooling & HTTP keep-alive
|
||||
|
||||
Bun automatically reuses connections to the same host. This is known as connection pooling. This can significantly reduce the time it takes to establish a connection. You don't need to do anything to enable this; it's automatic.
|
||||
|
||||
#### Simultaneous connection limit
|
||||
|
||||
By default, Bun limits the maximum number of simultaneous `fetch` requests to 256. We do this for several reasons:
|
||||
|
||||
- It improves overall system stability. Operating systems have an upper limit on the number of simultaneous open TCP sockets, usually in the low thousands. Nearing this limit causes your entire computer to behave strangely. Applications hang and crash.
|
||||
- It encourages HTTP Keep-Alive connection reuse. For short-lived HTTP requests, the slowest step is often the initial connection setup. Reusing connections can save a lot of time.
|
||||
|
||||
When the limit is exceeded, the requests are queued and sent as soon as the next request ends.
|
||||
|
||||
You can increase the maximum number of simultaneous connections via the `BUN_CONFIG_MAX_HTTP_REQUESTS` environment variable:
|
||||
|
||||
```sh
|
||||
$ BUN_CONFIG_MAX_HTTP_REQUESTS=512 bun ./my-script.ts
|
||||
```
|
||||
|
||||
The max value for this limit is currently set to 65,336. The maximum port number is 65,535, so it's quite difficult for any one computer to exceed this limit.
|
||||
|
||||
### Response buffering
|
||||
|
||||
Bun goes to great lengths to optimize the performance of reading the response body. The fastest way to read the response body is to use one of these methods:
|
||||
|
||||
- `response.text(): Promise<string>`
|
||||
- `response.json(): Promise<any>`
|
||||
- `response.formData(): Promise<FormData>`
|
||||
- `response.bytes(): Promise<Uint8Array>`
|
||||
- `response.arrayBuffer(): Promise<ArrayBuffer>`
|
||||
- `response.blob(): Promise<Blob>`
|
||||
|
||||
You can also use `Bun.write` to write the response body to a file on disk:
|
||||
|
||||
```ts
|
||||
import { write } from "bun";
|
||||
|
||||
await write("output.txt", response);
|
||||
```
|
||||
@@ -756,6 +756,25 @@ $ bun build ./index.tsx --outdir ./out --external '*'
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
### `packages`
|
||||
|
||||
Control whatever package dependencies are included to bundle or not. Possible values: `bundle` (default), `external`. Bun threats any import which path do not start with `.`, `..` or `/` as package.
|
||||
|
||||
{% codetabs group="a" %}
|
||||
|
||||
```ts#JavaScript
|
||||
await Bun.build({
|
||||
entrypoints: ['./index.ts'],
|
||||
packages: 'external',
|
||||
})
|
||||
```
|
||||
|
||||
```bash#CLI
|
||||
$ bun build ./index.ts --packages external
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
### `naming`
|
||||
|
||||
Customizes the generated file names. Defaults to `./[dir]/[name].[ext]`.
|
||||
|
||||
@@ -94,8 +94,8 @@ In Bun's CLI, simple boolean flags like `--minify` do not accept an argument. Ot
|
||||
---
|
||||
|
||||
- `--packages`
|
||||
- n/a
|
||||
- Not supported
|
||||
- `--packages`
|
||||
- No differences
|
||||
|
||||
---
|
||||
|
||||
@@ -208,8 +208,7 @@ In Bun's CLI, simple boolean flags like `--minify` do not accept an argument. Ot
|
||||
---
|
||||
|
||||
- `--ignore-annotations`
|
||||
- n/a
|
||||
- Not supported
|
||||
- `--ignore-dce-annotations`
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ name: Define and replace static globals & constants
|
||||
The `--define` flag lets you declare statically-analyzable constants and globals. It replace all usages of an identifier or property in a JavaScript or TypeScript file with a constant value. This feature is supported at runtime and also in `bun build`. This is sort of similar to `#define` in C/C++, except for JavaScript.
|
||||
|
||||
```ts
|
||||
bun --define:process.env.NODE_ENV="'production'" src/index.ts # Runtime
|
||||
bun build --define:process.env.NODE_ENV="'production'" src/index.ts # Build
|
||||
bun --define process.env.NODE_ENV="'production'" src/index.ts # Runtime
|
||||
bun build --define process.env.NODE_ENV="'production'" src/index.ts # Build
|
||||
```
|
||||
|
||||
---
|
||||
@@ -95,7 +95,7 @@ To replace all usages of `AWS` with the JSON object `{"ACCESS_KEY":"abc","SECRET
|
||||
|
||||
```sh
|
||||
# JSON
|
||||
bun --define:AWS='{"ACCESS_KEY":"abc","SECRET_KEY":"def"}' src/index.ts
|
||||
bun --define AWS='{"ACCESS_KEY":"abc","SECRET_KEY":"def"}' src/index.ts
|
||||
```
|
||||
|
||||
Those will be transformed into the equivalent JavaScript code.
|
||||
@@ -119,7 +119,7 @@ You can also pass properties to the `--define` flag.
|
||||
For example, to replace all usages of `console.write` with `console.log`, you can use the following command (requires Bun v1.1.5 or later)
|
||||
|
||||
```sh
|
||||
bun --define:console.write=console.log src/index.ts
|
||||
bun --define console.write=console.log src/index.ts
|
||||
```
|
||||
|
||||
That transforms the following input:
|
||||
|
||||
@@ -27,6 +27,28 @@ data.version; // => "1.0.0"
|
||||
data.author.name; // => "John Dough"
|
||||
```
|
||||
|
||||
Bun also supports [Import Attributes](https://github.com/tc39/proposal-import-attributes/) and [JSON modules](https://github.com/tc39/proposal-json-modules) syntax.
|
||||
|
||||
```ts
|
||||
import data from "./package.json" with { type: "json" };
|
||||
|
||||
data.name; // => "bun"
|
||||
data.version; // => "1.0.0"
|
||||
data.author.name; // => "John Dough"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Bun also supports [Import Attributes](https://github.com/tc39/proposal-import-attributes/) and [JSON modules](https://github.com/tc39/proposal-json-modules) syntax.
|
||||
|
||||
```ts
|
||||
import data from "./package.json" with { type: "json" };
|
||||
|
||||
data.name; // => "bun"
|
||||
data.version; // => "1.0.0"
|
||||
data.author.name; // => "John Dough"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
See [Docs > Runtime > TypeScript](/docs/runtime/typescript) for more information on using TypeScript with Bun.
|
||||
|
||||
@@ -2,7 +2,7 @@ Bun supports loading configuration options from [`.npmrc`](https://docs.npmjs.co
|
||||
|
||||
{% callout %}
|
||||
|
||||
**NOTE**: We recommend migrating your `.npmrc` file to Bun's [`bunfig.toml`](/docs/runtime/bunfig) format, as it provides more flexible options and can let you configure Bun-specific configuration options.
|
||||
**NOTE**: We recommend migrating your `.npmrc` file to Bun's [`bunfig.toml`](/docs/runtime/bunfig) format, as it provides more flexible options and can let you configure Bun-specific options.
|
||||
|
||||
{% /callout %}
|
||||
|
||||
@@ -50,16 +50,22 @@ Allows you to set options for a specific registry:
|
||||
|
||||
|
||||
# or you could set a username and password
|
||||
# note that the password is base64 encoded
|
||||
//http://localhost:4873/:username=myusername
|
||||
|
||||
//http://localhost:4873/:_password=${NPM_PASSWORD}
|
||||
|
||||
# or use _auth, which is your username and password
|
||||
# combined into a single string, which is then base 64 encoded
|
||||
//http://localhost:4873/:_auth=${NPM_AUTH}
|
||||
```
|
||||
|
||||
The following options are supported:
|
||||
|
||||
- `_authToken`
|
||||
- `username`
|
||||
- `_password`
|
||||
- `_password` (base64 encoded password)
|
||||
- `_auth` (base64 encoded username:password, e.g. `btoa(username + ":" + password)`)
|
||||
|
||||
The equivalent `bunfig.toml` option is to add a key in [`install.scopes`](/docs/runtime/bunfig#install-registry):
|
||||
|
||||
|
||||
@@ -287,8 +287,11 @@ export default {
|
||||
|
||||
divider("API"),
|
||||
page("api/http", "HTTP server", {
|
||||
description: `Bun implements Web-standard fetch, plus a Bun-native API for building fast HTTP servers.`,
|
||||
description: `Bun implements a fast HTTP server built on Request/Response objects, along with supporting node:http APIs.`,
|
||||
}), // "`Bun.serve`"),
|
||||
page("api/fetch", "HTTP client", {
|
||||
description: `Bun implements Web-standard fetch with some Bun-native extensions.`,
|
||||
}), // "fetch"),
|
||||
page("api/websockets", "WebSockets", {
|
||||
description: `Bun supports server-side WebSockets with on-the-fly compression, TLS support, and a Bun-native pubsub API.`,
|
||||
}), // "`Bun.serve`"),
|
||||
|
||||
@@ -171,6 +171,8 @@ Once imported, you should see something like this:
|
||||
|
||||
{% image alt="Viewing heap snapshot in Safari" src="https://user-images.githubusercontent.com/709451/204429337-b0d8935f-3509-4071-b991-217794d1fb27.png" caption="Viewing heap snapshot in Safari Dev Tools" /%}
|
||||
|
||||
> The [web debugger](https://bun.sh/docs/runtime/debugger#inspect) also offers the timeline feature which allows you to track and examine the memory usage of the running debug session.
|
||||
|
||||
### Native heap stats
|
||||
|
||||
Bun uses mimalloc for the other heap. To report a summary of non-JavaScript memory usage, set the `MIMALLOC_SHOW_STATS=1` environment variable. and stats will print on exit.
|
||||
|
||||
@@ -60,7 +60,7 @@ Visual Studio can be installed graphically using the wizard or through WinGet:
|
||||
|
||||
After Visual Studio, you need the following:
|
||||
|
||||
- LLVM 16
|
||||
- LLVM 18.1.8
|
||||
- Go
|
||||
- Rust
|
||||
- NASM
|
||||
@@ -78,14 +78,14 @@ After Visual Studio, you need the following:
|
||||
|
||||
```ps1#WinGet
|
||||
## Select "Add LLVM to the system PATH for all users" in the LLVM installer
|
||||
> winget install -i LLVM.LLVM -v 16.0.6 && winget install GoLang.Go Rustlang.Rustup NASM.NASM StrawberryPerl.StrawberryPerl RubyInstallerTeam.Ruby.3.2 OpenJS.NodeJS.LTS
|
||||
> winget install -i LLVM.LLVM -v 18.1.8 && winget install GoLang.Go Rustlang.Rustup NASM.NASM StrawberryPerl.StrawberryPerl RubyInstallerTeam.Ruby.3.2 OpenJS.NodeJS.LTS
|
||||
```
|
||||
|
||||
```ps1#Scoop
|
||||
> irm https://get.scoop.sh | iex
|
||||
> scoop install nodejs-lts go rust nasm ruby perl
|
||||
# scoop seems to be buggy if you install llvm and the rest at the same time
|
||||
> scoop install llvm@16.0.6
|
||||
> scoop install llvm@18.1.8
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
@@ -153,7 +153,7 @@ Some methods are not optimized yet.
|
||||
|
||||
### [`node:util`](https://nodejs.org/api/util.html)
|
||||
|
||||
🟡 Missing `MIMEParams` `MIMEType` `aborted` `debug` `getSystemErrorMap` `getSystemErrorName` `transferableAbortController` `transferableAbortSignal` `stripVTControlCharacters`
|
||||
🟡 Missing `MIMEParams` `MIMEType` `aborted` `debug` `getSystemErrorMap` `transferableAbortController` `transferableAbortSignal` `stripVTControlCharacters`
|
||||
|
||||
### [`node:v8`](https://nodejs.org/api/v8.html)
|
||||
|
||||
|
||||
@@ -7,22 +7,36 @@ The following Web APIs are partially or completely supported.
|
||||
---
|
||||
|
||||
- HTTP
|
||||
- [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/fetch) [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers) [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal)
|
||||
- [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/fetch)
|
||||
[`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
|
||||
[`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request)
|
||||
[`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers)
|
||||
[`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController)
|
||||
[`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal)
|
||||
|
||||
---
|
||||
|
||||
- URLs
|
||||
- [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL) [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)
|
||||
- [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL)
|
||||
[`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)
|
||||
|
||||
---
|
||||
|
||||
- Web Workers
|
||||
- [`Worker`](https://developer.mozilla.org/en-US/docs/Web/API/Worker) [`self.postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/DedicatedWorkerGlobalScope/postMessage) [`structuredClone`](https://developer.mozilla.org/en-US/docs/Web/API/structuredClone) [`MessagePort`](https://developer.mozilla.org/en-US/docs/Web/API/MessagePort) [`MessageChannel`](https://developer.mozilla.org/en-US/docs/Web/API/MessageChannel), [`BroadcastChannel`](https://developer.mozilla.org/en-US/docs/Web/API/BroadcastChannel).
|
||||
- [`Worker`](https://developer.mozilla.org/en-US/docs/Web/API/Worker)
|
||||
[`self.postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/DedicatedWorkerGlobalScope/postMessage)
|
||||
[`structuredClone`](https://developer.mozilla.org/en-US/docs/Web/API/structuredClone)
|
||||
[`MessagePort`](https://developer.mozilla.org/en-US/docs/Web/API/MessagePort)
|
||||
[`MessageChannel`](https://developer.mozilla.org/en-US/docs/Web/API/MessageChannel), [`BroadcastChannel`](https://developer.mozilla.org/en-US/docs/Web/API/BroadcastChannel).
|
||||
|
||||
---
|
||||
|
||||
- Streams
|
||||
- [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) [`WritableStream`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream) [`TransformStream`](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream) [`ByteLengthQueuingStrategy`](https://developer.mozilla.org/en-US/docs/Web/API/ByteLengthQueuingStrategy) [`CountQueuingStrategy`](https://developer.mozilla.org/en-US/docs/Web/API/CountQueuingStrategy) and associated classes
|
||||
- [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)
|
||||
[`WritableStream`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream)
|
||||
[`TransformStream`](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream)
|
||||
[`ByteLengthQueuingStrategy`](https://developer.mozilla.org/en-US/docs/Web/API/ByteLengthQueuingStrategy)
|
||||
[`CountQueuingStrategy`](https://developer.mozilla.org/en-US/docs/Web/API/CountQueuingStrategy) and associated classes
|
||||
|
||||
---
|
||||
|
||||
@@ -37,7 +51,10 @@ The following Web APIs are partially or completely supported.
|
||||
---
|
||||
|
||||
- Encoding and decoding
|
||||
- [`atob`](https://developer.mozilla.org/en-US/docs/Web/API/atob) [`btoa`](https://developer.mozilla.org/en-US/docs/Web/API/btoa) [`TextEncoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder) [`TextDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder)
|
||||
- [`atob`](https://developer.mozilla.org/en-US/docs/Web/API/atob)
|
||||
[`btoa`](https://developer.mozilla.org/en-US/docs/Web/API/btoa)
|
||||
[`TextEncoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder)
|
||||
[`TextDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder)
|
||||
|
||||
---
|
||||
|
||||
@@ -47,7 +64,8 @@ The following Web APIs are partially or completely supported.
|
||||
---
|
||||
|
||||
- Timeouts
|
||||
- [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout) [`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout)
|
||||
- [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout)
|
||||
[`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout)
|
||||
|
||||
---
|
||||
|
||||
@@ -57,14 +75,16 @@ The following Web APIs are partially or completely supported.
|
||||
---
|
||||
|
||||
- Crypto
|
||||
- [`crypto`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto) [`SubtleCrypto`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto)
|
||||
- [`crypto`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto)
|
||||
[`SubtleCrypto`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto)
|
||||
[`CryptoKey`](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey)
|
||||
|
||||
---
|
||||
|
||||
- Debugging
|
||||
|
||||
- [`console`](https://developer.mozilla.org/en-US/docs/Web/API/console) [`performance`](https://developer.mozilla.org/en-US/docs/Web/API/Performance)
|
||||
- [`console`](https://developer.mozilla.org/en-US/docs/Web/API/console)
|
||||
[`performance`](https://developer.mozilla.org/en-US/docs/Web/API/Performance)
|
||||
|
||||
---
|
||||
|
||||
@@ -79,7 +99,9 @@ The following Web APIs are partially or completely supported.
|
||||
---
|
||||
|
||||
- User interaction
|
||||
- [`alert`](https://developer.mozilla.org/en-US/docs/Web/API/Window/alert) [`confirm`](https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm) [`prompt`](https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt) (intended for interactive CLIs)
|
||||
- [`alert`](https://developer.mozilla.org/en-US/docs/Web/API/Window/alert)
|
||||
[`confirm`](https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm)
|
||||
[`prompt`](https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt) (intended for interactive CLIs)
|
||||
|
||||
<!-- - Blocking. Prints the alert message to terminal and awaits `[ENTER]` before proceeding. -->
|
||||
<!-- - Blocking. Prints confirmation message and awaits `[y/N]` input from user. Returns `true` if user entered `y` or `Y`, `false` otherwise.
|
||||
@@ -94,7 +116,10 @@ The following Web APIs are partially or completely supported.
|
||||
|
||||
- Events
|
||||
- [`EventTarget`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget)
|
||||
[`Event`](https://developer.mozilla.org/en-US/docs/Web/API/Event) [`ErrorEvent`](https://developer.mozilla.org/en-US/docs/Web/API/ErrorEvent) [`CloseEvent`](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent) [`MessageEvent`](https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent)
|
||||
[`Event`](https://developer.mozilla.org/en-US/docs/Web/API/Event)
|
||||
[`ErrorEvent`](https://developer.mozilla.org/en-US/docs/Web/API/ErrorEvent)
|
||||
[`CloseEvent`](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent)
|
||||
[`MessageEvent`](https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -196,3 +196,41 @@ As of Bun v1.0.19, Bun automatically resolves the `specifier` argument to `mock.
|
||||
After resolution, the mocked module is stored in the ES Module registry **and** the CommonJS require cache. This means that you can use `import` and `require` interchangeably for mocked modules.
|
||||
|
||||
The callback function is called lazily, only if the module is imported or required. This means that you can use `mock.module()` to mock modules that don't exist yet, and it means that you can use `mock.module()` to mock modules that are imported by other modules.
|
||||
|
||||
## Restore all function mocks to their original values with `mock.restore()`
|
||||
|
||||
Instead of manually restoring each mock individually with `mockFn.mockRestore()`, restore all mocks with one command by calling `mock.restore()`. Doing so does not reset the value of modules overridden with `mock.module()`.
|
||||
|
||||
Using `mock.restore()` can reduce the amount of code in your tests by adding it to `afterEach` blocks in each test file or even in your [test preload code](https://bun.sh/docs/runtime/bunfig#test-preload).
|
||||
|
||||
```ts
|
||||
import { expect, mock, spyOn, test } from "bun:test";
|
||||
|
||||
import * as fooModule from './foo.ts';
|
||||
import * as barModule from './bar.ts';
|
||||
import * as bazModule from './baz.ts';
|
||||
|
||||
test('foo, bar, baz', () => {
|
||||
const fooSpy = spyOn(fooModule, 'foo');
|
||||
const barSpy = spyOn(barModule, 'bar');
|
||||
const bazSpy = spyOn(bazModule, 'baz');
|
||||
|
||||
expect(fooSpy).toBe('foo');
|
||||
expect(barSpy).toBe('bar');
|
||||
expect(bazSpy).toBe('baz');
|
||||
|
||||
fooSpy.mockImplementation(() => 42);
|
||||
barSpy.mockImplementation(() => 43);
|
||||
bazSpy.mockImplementation(() => 44);
|
||||
|
||||
expect(fooSpy).toBe(42);
|
||||
expect(barSpy).toBe(43);
|
||||
expect(bazSpy).toBe(44);
|
||||
|
||||
mock.restore();
|
||||
|
||||
expect(fooSpy).toBe('foo');
|
||||
expect(barSpy).toBe('bar');
|
||||
expect(bazSpy).toBe('baz');
|
||||
});
|
||||
```
|
||||
|
||||
@@ -195,7 +195,6 @@ pub fn main() anyerror!void {
|
||||
args.headers_buf,
|
||||
response_body_string,
|
||||
args.body,
|
||||
0,
|
||||
HTTP.FetchRedirect.follow,
|
||||
),
|
||||
};
|
||||
|
||||
@@ -31,7 +31,6 @@ const params = [_]clap.Param(clap.Help){
|
||||
clap.parseParam("-b, --body <STR> HTTP request body as a string") catch unreachable,
|
||||
clap.parseParam("-f, --file <STR> File path to load as body") catch unreachable,
|
||||
clap.parseParam("-n, --count <INT> How many runs? Default 10") catch unreachable,
|
||||
clap.parseParam("-t, --timeout <INT> Max duration per request") catch unreachable,
|
||||
clap.parseParam("-r, --retry <INT> Max retry count") catch unreachable,
|
||||
clap.parseParam("--no-gzip Disable gzip") catch unreachable,
|
||||
clap.parseParam("--no-deflate Disable deflate") catch unreachable,
|
||||
@@ -75,7 +74,6 @@ pub const Arguments = struct {
|
||||
body: string = "",
|
||||
turbo: bool = false,
|
||||
count: usize = 10,
|
||||
timeout: usize = 0,
|
||||
repeat: usize = 0,
|
||||
concurrency: u16 = 32,
|
||||
|
||||
@@ -165,10 +163,6 @@ pub const Arguments = struct {
|
||||
// .keep_alive = !args.flag("--no-keep-alive"),
|
||||
.concurrency = std.fmt.parseInt(u16, args.option("--max-concurrency") orelse "32", 10) catch 32,
|
||||
.turbo = args.flag("--turbo"),
|
||||
.timeout = std.fmt.parseInt(usize, args.option("--timeout") orelse "0", 10) catch |err| {
|
||||
Output.prettyErrorln("<r><red>{s}<r> parsing timeout", .{@errorName(err)});
|
||||
Global.exit(1);
|
||||
},
|
||||
.count = std.fmt.parseInt(usize, args.option("--count") orelse "10", 10) catch |err| {
|
||||
Output.prettyErrorln("<r><red>{s}<r> parsing count", .{@errorName(err)});
|
||||
Global.exit(1);
|
||||
@@ -225,7 +219,6 @@ pub fn main() anyerror!void {
|
||||
args.headers_buf,
|
||||
response_body,
|
||||
"",
|
||||
args.timeout,
|
||||
),
|
||||
};
|
||||
ctx.http.client.verbose = args.verbose;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"workspaces": [
|
||||
"./packages/bun-types"
|
||||
],
|
||||
"dependencies": {
|
||||
"devDependencies": {
|
||||
"@vscode/debugadapter": "^1.65.0",
|
||||
"esbuild": "^0.21.4",
|
||||
"eslint": "^9.4.0",
|
||||
@@ -15,9 +15,7 @@
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"source-map-js": "^1.2.0",
|
||||
"typescript": "^5.4.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.4.5",
|
||||
"@types/bun": "^1.1.3",
|
||||
"@types/react": "^18.3.3",
|
||||
"@typescript-eslint/eslint-plugin": "^7.11.0",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"std.debug.assert": "Use bun.assert instead",
|
||||
"std.debug.dumpStackTrace": "Use bun.handleErrorReturnTrace or bun.crash_handler.dumpStackTrace instead",
|
||||
"std.debug.print": "Don't let this be committed",
|
||||
"std.mem.indexOfAny(": "Use bun.strings.indexOfAny",
|
||||
"std.mem.indexOfAny(u8": "Use bun.strings.indexOfAny",
|
||||
"undefined != ": "This is by definition Undefined Behavior.",
|
||||
"undefined == ": "This is by definition Undefined Behavior.",
|
||||
"bun.toFD(std.fs.cwd().fd)": "Use bun.FD.cwd()",
|
||||
@@ -13,5 +13,6 @@
|
||||
"std.StringArrayHashMap(": "bun.StringArrayHashMap has a faster `eql`",
|
||||
"std.StringHashMapUnmanaged(": "bun.StringHashMapUnmanaged has a faster `eql`",
|
||||
"std.StringHashMap(": "bun.StringHashMaphas a faster `eql`",
|
||||
"std.enums.tagName(": "Use bun.tagName instead",
|
||||
"": ""
|
||||
}
|
||||
|
||||
@@ -239,7 +239,7 @@ Starting "${testFileName}"
|
||||
GITHUB_ACTIONS: process.env.GITHUB_ACTIONS ?? "true",
|
||||
BUN_DEBUG_QUIET_LOGS: "1",
|
||||
BUN_INSTALL_CACHE_DIR: join(TMPDIR, ".bun-install-cache"),
|
||||
BUN_ENABLE_CRASH_REPORTING: "1",
|
||||
BUN_ENABLE_CRASH_REPORTING: "0",
|
||||
[windows ? "TEMP" : "TMPDIR"]: TMPDIR,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -22,10 +22,10 @@ bun upgrade
|
||||
- [Linux, arm64](https://www.npmjs.com/package/@oven/bun-linux-aarch64)
|
||||
- [Linux, x64](https://www.npmjs.com/package/@oven/bun-linux-x64)
|
||||
- [Linux, x64 (without AVX2 instructions)](https://www.npmjs.com/package/@oven/bun-linux-x64-baseline)
|
||||
- [Windows (using Windows Subsystem for Linux, aka. "WSL")](https://relatablecode.com/how-to-set-up-bun-on-a-windows-machine)
|
||||
- [Windows](https://www.npmjs.com/package/@oven/bun-windows-x64)
|
||||
- [Windows (without AVX2 instructions)](https://www.npmjs.com/package/@oven/bun-windows-x64-baseline)
|
||||
|
||||
### Future Platforms
|
||||
|
||||
- [Windows](https://github.com/oven-sh/bun/issues/43)
|
||||
- Unix-like variants such as FreeBSD, OpenBSD, etc.
|
||||
- Android and iOS
|
||||
|
||||
48
packages/bun-types/bun.d.ts
vendored
48
packages/bun-types/bun.d.ts
vendored
@@ -1455,7 +1455,7 @@ declare module "bun" {
|
||||
* ```js
|
||||
* const {imports, exports} = transpiler.scan(`
|
||||
* import {foo} from "baz";
|
||||
* const hello = "hi!";
|
||||
* export const hello = "hi!";
|
||||
* `);
|
||||
*
|
||||
* console.log(imports); // ["baz"]
|
||||
@@ -1516,6 +1516,7 @@ declare module "bun" {
|
||||
plugins?: BunPlugin[];
|
||||
// manifest?: boolean; // whether to return manifest
|
||||
external?: string[];
|
||||
packages?: "bundle" | "external";
|
||||
publicPath?: string;
|
||||
define?: Record<string, string>;
|
||||
// origin?: string; // e.g. http://mydomain.com
|
||||
@@ -1536,6 +1537,16 @@ declare module "bun" {
|
||||
syntax?: boolean;
|
||||
identifiers?: boolean;
|
||||
};
|
||||
/**
|
||||
* Ignore dead code elimination/tree-shaking annotations such as @__PURE__ and package.json
|
||||
* "sideEffects" fields. This should only be used as a temporary workaround for incorrect
|
||||
* annotations in libraries.
|
||||
*/
|
||||
ignoreDCEAnnotations?: boolean;
|
||||
/**
|
||||
* Force emitting @__PURE__ annotations even if minify.whitespace is true.
|
||||
*/
|
||||
emitDCEAnnotations?: boolean;
|
||||
// treeshaking?: boolean;
|
||||
|
||||
// jsx?:
|
||||
@@ -3099,6 +3110,10 @@ declare module "bun" {
|
||||
*/
|
||||
function openInEditor(path: string, options?: EditorOptions): void;
|
||||
|
||||
const fetch: typeof globalThis.fetch & {
|
||||
preconnect(url: string): void;
|
||||
};
|
||||
|
||||
interface EditorOptions {
|
||||
editor?: "vscode" | "subl";
|
||||
line?: number;
|
||||
@@ -3476,6 +3491,13 @@ declare module "bun" {
|
||||
* Filtered data consists mostly of small values with a somewhat random distribution.
|
||||
*/
|
||||
strategy?: number;
|
||||
|
||||
library?: "zlib";
|
||||
}
|
||||
|
||||
interface LibdeflateCompressionOptions {
|
||||
level?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
|
||||
library?: "libdeflate";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3484,26 +3506,38 @@ declare module "bun" {
|
||||
* @param options Compression options to use
|
||||
* @returns The output buffer with the compressed data
|
||||
*/
|
||||
function deflateSync(data: Uint8Array | string | ArrayBuffer, options?: ZlibCompressionOptions): Uint8Array;
|
||||
function deflateSync(
|
||||
data: Uint8Array | string | ArrayBuffer,
|
||||
options?: ZlibCompressionOptions | LibdeflateCompressionOptions,
|
||||
): Uint8Array;
|
||||
/**
|
||||
* Compresses a chunk of data with `zlib` GZIP algorithm.
|
||||
* @param data The buffer of data to compress
|
||||
* @param options Compression options to use
|
||||
* @returns The output buffer with the compressed data
|
||||
*/
|
||||
function gzipSync(data: Uint8Array | string | ArrayBuffer, options?: ZlibCompressionOptions): Uint8Array;
|
||||
function gzipSync(
|
||||
data: Uint8Array | string | ArrayBuffer,
|
||||
options?: ZlibCompressionOptions | LibdeflateCompressionOptions,
|
||||
): Uint8Array;
|
||||
/**
|
||||
* Decompresses a chunk of data with `zlib` INFLATE algorithm.
|
||||
* @param data The buffer of data to decompress
|
||||
* @returns The output buffer with the decompressed data
|
||||
*/
|
||||
function inflateSync(data: Uint8Array | string | ArrayBuffer): Uint8Array;
|
||||
function inflateSync(
|
||||
data: Uint8Array | string | ArrayBuffer,
|
||||
options?: ZlibCompressionOptions | LibdeflateCompressionOptions,
|
||||
): Uint8Array;
|
||||
/**
|
||||
* Decompresses a chunk of data with `zlib` GUNZIP algorithm.
|
||||
* @param data The buffer of data to decompress
|
||||
* @returns The output buffer with the decompressed data
|
||||
*/
|
||||
function gunzipSync(data: Uint8Array | string | ArrayBuffer): Uint8Array;
|
||||
function gunzipSync(
|
||||
data: Uint8Array | string | ArrayBuffer,
|
||||
options?: ZlibCompressionOptions | LibdeflateCompressionOptions,
|
||||
): Uint8Array;
|
||||
|
||||
type Target =
|
||||
/**
|
||||
@@ -3823,7 +3857,7 @@ declare module "bun" {
|
||||
*/
|
||||
const isMainThread: boolean;
|
||||
|
||||
interface Socket<Data = undefined> {
|
||||
interface Socket<Data = undefined> extends Disposable {
|
||||
/**
|
||||
* Write `data` to the socket
|
||||
*
|
||||
@@ -4105,7 +4139,7 @@ declare module "bun" {
|
||||
setMaxSendFragment(size: number): boolean;
|
||||
}
|
||||
|
||||
interface SocketListener<Data = undefined> {
|
||||
interface SocketListener<Data = undefined> extends Disposable {
|
||||
stop(closeActiveConnections?: boolean): void;
|
||||
ref(): void;
|
||||
unref(): void;
|
||||
|
||||
54
packages/bun-types/globals.d.ts
vendored
54
packages/bun-types/globals.d.ts
vendored
@@ -907,26 +907,42 @@ declare global {
|
||||
new (): ShadowRealm;
|
||||
};
|
||||
|
||||
/**
|
||||
* Send a HTTP(s) request
|
||||
*
|
||||
* @param request Request object
|
||||
* @param init A structured value that contains settings for the fetch() request.
|
||||
*
|
||||
* @returns A promise that resolves to {@link Response} object.
|
||||
*/
|
||||
interface Fetch {
|
||||
/**
|
||||
* Send a HTTP(s) request
|
||||
*
|
||||
* @param request Request object
|
||||
* @param init A structured value that contains settings for the fetch() request.
|
||||
*
|
||||
* @returns A promise that resolves to {@link Response} object.
|
||||
*/
|
||||
(request: Request, init?: RequestInit): Promise<Response>;
|
||||
|
||||
// tslint:disable-next-line:unified-signatures
|
||||
function fetch(request: Request, init?: RequestInit): Promise<Response>;
|
||||
/**
|
||||
* Send a HTTP(s) request
|
||||
*
|
||||
* @param url URL string
|
||||
* @param init A structured value that contains settings for the fetch() request.
|
||||
*
|
||||
* @returns A promise that resolves to {@link Response} object.
|
||||
*/
|
||||
function fetch(url: string | URL | Request, init?: FetchRequestInit): Promise<Response>;
|
||||
/**
|
||||
* Send a HTTP(s) request
|
||||
*
|
||||
* @param url URL string
|
||||
* @param init A structured value that contains settings for the fetch() request.
|
||||
*
|
||||
* @returns A promise that resolves to {@link Response} object.
|
||||
*/
|
||||
(url: string | URL | Request, init?: FetchRequestInit): Promise<Response>;
|
||||
|
||||
(input: string | URL | globalThis.Request, init?: RequestInit): Promise<Response>;
|
||||
|
||||
/**
|
||||
* Start the DNS resolution, TCP connection, and TLS handshake for a request
|
||||
* before the request is actually sent.
|
||||
*
|
||||
* This can reduce the latency of a request when you know there's some
|
||||
* long-running task that will delay the request starting.
|
||||
*
|
||||
* This is a bun-specific API and is not part of the Fetch API specification.
|
||||
*/
|
||||
preconnect(url: string | URL): void;
|
||||
}
|
||||
|
||||
var fetch: Fetch;
|
||||
|
||||
function queueMicrotask(callback: (...args: any[]) => void): void;
|
||||
/**
|
||||
|
||||
@@ -26,6 +26,10 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
// Necessary for the stdint include
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
@@ -38,8 +42,8 @@
|
||||
#include <mstcpip.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) && defined(__aarch64__)
|
||||
#define HAS_MSGX
|
||||
#if defined(__APPLE__)
|
||||
extern int Bun__doesMacOSVersionSupportSendRecvMsgX();
|
||||
#endif
|
||||
|
||||
|
||||
@@ -73,32 +77,30 @@ int bsd_sendmmsg(LIBUS_SOCKET_DESCRIPTOR fd, struct udp_sendbuf* sendbuf, int fl
|
||||
}
|
||||
return sendbuf->num;
|
||||
#elif defined(__APPLE__)
|
||||
// TODO figure out why sendmsg_x fails when one of the messages is empty
|
||||
// so that we can get rid of this code.
|
||||
// One of the weird things is that once a non-empty message has been sent on the socket,
|
||||
// empty messages start working as well. Bizzare.
|
||||
#ifdef HAS_MSGX
|
||||
if (sendbuf->has_empty) {
|
||||
#endif
|
||||
for (int i = 0; i < sendbuf->num; i++) {
|
||||
while (1) {
|
||||
ssize_t ret = sendmsg(fd, &sendbuf->msgvec[i].msg_hdr, flags);
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) return i;
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// sendmsg_x does not support addresses.
|
||||
if (!sendbuf->has_empty && !sendbuf->has_addresses && Bun__doesMacOSVersionSupportSendRecvMsgX()) {
|
||||
while (1) {
|
||||
int ret = sendmsg_x(fd, sendbuf->msgvec, sendbuf->num, flags);
|
||||
if (ret >= 0) return ret;
|
||||
// If we receive EMMSGSIZE, we should use the fallback code.
|
||||
if (errno == EMSGSIZE) break;
|
||||
if (errno != EINTR) return ret;
|
||||
}
|
||||
return sendbuf->num;
|
||||
#ifdef HAS_MSGX
|
||||
}
|
||||
while (1) {
|
||||
int ret = sendmsg_x(fd, sendbuf->msgvec, sendbuf->num, flags);
|
||||
if (ret >= 0 || errno != EINTR) return ret;
|
||||
|
||||
for (size_t i = 0, count = sendbuf->num; i < count; i++) {
|
||||
while (1) {
|
||||
ssize_t ret = sendmsg(fd, &sendbuf->msgvec[i].msg_hdr, flags);
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) return i;
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return sendbuf->num;
|
||||
#else
|
||||
while (1) {
|
||||
int ret = sendmmsg(fd, sendbuf->msgvec, sendbuf->num, flags | MSG_NOSIGNAL);
|
||||
@@ -120,12 +122,13 @@ int bsd_recvmmsg(LIBUS_SOCKET_DESCRIPTOR fd, struct udp_recvbuf *recvbuf, int fl
|
||||
return 1;
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
#ifdef HAS_MSGX
|
||||
while (1) {
|
||||
int ret = recvmsg_x(fd, recvbuf->msgvec, LIBUS_UDP_RECV_COUNT, flags);
|
||||
if (ret >= 0 || errno != EINTR) return ret;
|
||||
if (Bun__doesMacOSVersionSupportSendRecvMsgX()) {
|
||||
while (1) {
|
||||
int ret = recvmsg_x(fd, recvbuf->msgvec, LIBUS_UDP_RECV_COUNT, flags);
|
||||
if (ret >= 0 || errno != EINTR) return ret;
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
for (int i = 0; i < LIBUS_UDP_RECV_COUNT; ++i) {
|
||||
while (1) {
|
||||
ssize_t ret = recvmsg(fd, &recvbuf->msgvec[i].msg_hdr, flags);
|
||||
@@ -139,7 +142,6 @@ int bsd_recvmmsg(LIBUS_SOCKET_DESCRIPTOR fd, struct udp_recvbuf *recvbuf, int fl
|
||||
}
|
||||
}
|
||||
return LIBUS_UDP_RECV_COUNT;
|
||||
#endif
|
||||
#else
|
||||
while (1) {
|
||||
int ret = recvmmsg(fd, (struct mmsghdr *)&recvbuf->msgvec, LIBUS_UDP_RECV_COUNT, flags, 0);
|
||||
@@ -154,19 +156,20 @@ void bsd_udp_setup_recvbuf(struct udp_recvbuf *recvbuf, void *databuf, size_t da
|
||||
recvbuf->buflen = databuflen;
|
||||
#else
|
||||
// assert(databuflen > LIBUS_UDP_MAX_SIZE * LIBUS_UDP_RECV_COUNT);
|
||||
|
||||
for (int i = 0; i < LIBUS_UDP_RECV_COUNT; i++) {
|
||||
memset(recvbuf, 0, sizeof(struct udp_recvbuf));
|
||||
for (size_t i = 0; i < LIBUS_UDP_RECV_COUNT; i++) {
|
||||
recvbuf->iov[i].iov_base = (char*)databuf + i * LIBUS_UDP_MAX_SIZE;
|
||||
recvbuf->iov[i].iov_len = LIBUS_UDP_MAX_SIZE;
|
||||
|
||||
recvbuf->msgvec[i].msg_hdr.msg_name = &recvbuf->addr[i];
|
||||
recvbuf->msgvec[i].msg_hdr.msg_namelen = sizeof(struct sockaddr_storage);
|
||||
|
||||
recvbuf->msgvec[i].msg_hdr.msg_iov = &recvbuf->iov[i];
|
||||
recvbuf->msgvec[i].msg_hdr.msg_iovlen = 1;
|
||||
|
||||
recvbuf->msgvec[i].msg_hdr.msg_control = recvbuf->control[i];
|
||||
recvbuf->msgvec[i].msg_hdr.msg_controllen = 256;
|
||||
struct msghdr mh = {};
|
||||
memset(&mh, 0, sizeof(struct msghdr));
|
||||
mh.msg_name = &recvbuf->addr[i];
|
||||
mh.msg_namelen = sizeof(struct sockaddr_storage);
|
||||
mh.msg_iov = &recvbuf->iov[i];
|
||||
mh.msg_iovlen = 1;
|
||||
mh.msg_control = recvbuf->control[i];
|
||||
mh.msg_controllen = sizeof(recvbuf->control[i]);
|
||||
recvbuf->msgvec[i].msg_hdr = mh;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -179,7 +182,12 @@ int bsd_udp_setup_sendbuf(struct udp_sendbuf *buf, size_t bufsize, void** payloa
|
||||
buf->num = num;
|
||||
return num;
|
||||
#else
|
||||
// TODO: can we skip empty messages altogether? Do we really need to send 0-length messages?
|
||||
buf->has_empty = 0;
|
||||
|
||||
// sendmsg_x docs states it does not support addresses.
|
||||
buf->has_addresses = 0;
|
||||
|
||||
struct mmsghdr *msgvec = buf->msgvec;
|
||||
// todo check this math
|
||||
size_t count = (bufsize - sizeof(struct udp_sendbuf)) / (sizeof(struct mmsghdr) + sizeof(struct iovec));
|
||||
@@ -194,6 +202,9 @@ int bsd_udp_setup_sendbuf(struct udp_sendbuf *buf, size_t bufsize, void** payloa
|
||||
addr_len = addr->sa_family == AF_INET ? sizeof(struct sockaddr_in)
|
||||
: addr->sa_family == AF_INET6 ? sizeof(struct sockaddr_in6)
|
||||
: 0;
|
||||
if (addr_len > 0) {
|
||||
buf->has_addresses = 1;
|
||||
}
|
||||
}
|
||||
iov[i].iov_base = payloads[i];
|
||||
iov[i].iov_len = lengths[i];
|
||||
@@ -206,6 +217,7 @@ int bsd_udp_setup_sendbuf(struct udp_sendbuf *buf, size_t bufsize, void** payloa
|
||||
msgvec[i].msg_hdr.msg_flags = 0;
|
||||
msgvec[i].msg_len = 0;
|
||||
|
||||
|
||||
if (lengths[i] == 0) {
|
||||
buf->has_empty = 1;
|
||||
}
|
||||
@@ -882,7 +894,7 @@ int bsd_connect_udp_socket(LIBUS_SOCKET_DESCRIPTOR fd, const char *host, int por
|
||||
}
|
||||
|
||||
freeaddrinfo(result);
|
||||
return LIBUS_SOCKET_ERROR;
|
||||
return (int)LIBUS_SOCKET_ERROR;
|
||||
}
|
||||
|
||||
int bsd_disconnect_udp_socket(LIBUS_SOCKET_DESCRIPTOR fd) {
|
||||
|
||||
@@ -15,18 +15,17 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "libusockets.h"
|
||||
#include "internal/internal.h"
|
||||
#include "libusockets.h"
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#define CONCURRENT_CONNECTIONS 2
|
||||
|
||||
// clang-format off
|
||||
int default_is_low_prio_handler(struct us_socket_t *s) {
|
||||
return 0;
|
||||
}
|
||||
@@ -44,7 +43,7 @@ int us_raw_root_certs(struct us_cert_string_t**out){
|
||||
void us_listen_socket_close(int ssl, struct us_listen_socket_t *ls) {
|
||||
/* us_listen_socket_t extends us_socket_t so we close in similar ways */
|
||||
if (!us_socket_is_closed(0, &ls->s)) {
|
||||
us_internal_socket_context_unlink_listen_socket(ls->s.context, ls);
|
||||
us_internal_socket_context_unlink_listen_socket(ssl, ls->s.context, ls);
|
||||
us_poll_stop((struct us_poll_t *) &ls->s, ls->s.context->loop);
|
||||
bsd_close_socket(us_poll_fd((struct us_poll_t *) &ls->s));
|
||||
|
||||
@@ -65,6 +64,7 @@ void us_socket_context_close(int ssl, struct us_socket_context_t *context) {
|
||||
while (ls) {
|
||||
struct us_listen_socket_t *nextLS = (struct us_listen_socket_t *) ls->s.next;
|
||||
us_listen_socket_close(ssl, ls);
|
||||
|
||||
ls = nextLS;
|
||||
}
|
||||
|
||||
@@ -72,12 +72,12 @@ void us_socket_context_close(int ssl, struct us_socket_context_t *context) {
|
||||
struct us_socket_t *s = context->head_sockets;
|
||||
while (s) {
|
||||
struct us_socket_t *nextS = s->next;
|
||||
us_socket_close(ssl, s, 0, 0);
|
||||
us_socket_close(ssl, s, LIBUS_SOCKET_CLOSE_CODE_CLEAN_SHUTDOWN, 0);
|
||||
s = nextS;
|
||||
}
|
||||
}
|
||||
|
||||
void us_internal_socket_context_unlink_listen_socket(struct us_socket_context_t *context, struct us_listen_socket_t *ls) {
|
||||
void us_internal_socket_context_unlink_listen_socket(int ssl, struct us_socket_context_t *context, struct us_listen_socket_t *ls) {
|
||||
/* We have to properly update the iterator used to sweep sockets for timeouts */
|
||||
if (ls == (struct us_listen_socket_t *) context->iterator) {
|
||||
context->iterator = ls->s.next;
|
||||
@@ -95,9 +95,10 @@ void us_internal_socket_context_unlink_listen_socket(struct us_socket_context_t
|
||||
ls->s.next->prev = ls->s.prev;
|
||||
}
|
||||
}
|
||||
us_socket_context_unref(ssl, context);
|
||||
}
|
||||
|
||||
void us_internal_socket_context_unlink_socket(struct us_socket_context_t *context, struct us_socket_t *s) {
|
||||
void us_internal_socket_context_unlink_socket(int ssl, struct us_socket_context_t *context, struct us_socket_t *s) {
|
||||
/* We have to properly update the iterator used to sweep sockets for timeouts */
|
||||
if (s == context->iterator) {
|
||||
context->iterator = s->next;
|
||||
@@ -115,6 +116,7 @@ void us_internal_socket_context_unlink_socket(struct us_socket_context_t *contex
|
||||
s->next->prev = s->prev;
|
||||
}
|
||||
}
|
||||
us_socket_context_unref(ssl, context);
|
||||
}
|
||||
|
||||
/* We always add in the top, so we don't modify any s.next */
|
||||
@@ -126,6 +128,7 @@ void us_internal_socket_context_link_listen_socket(struct us_socket_context_t *c
|
||||
context->head_listen_sockets->s.prev = &ls->s;
|
||||
}
|
||||
context->head_listen_sockets = ls;
|
||||
context->ref_count++;
|
||||
}
|
||||
|
||||
/* We always add in the top, so we don't modify any s.next */
|
||||
@@ -137,6 +140,7 @@ void us_internal_socket_context_link_socket(struct us_socket_context_t *context,
|
||||
context->head_sockets->prev = s;
|
||||
}
|
||||
context->head_sockets = s;
|
||||
context->ref_count++;
|
||||
}
|
||||
|
||||
struct us_loop_t *us_socket_context_loop(int ssl, struct us_socket_context_t *context) {
|
||||
@@ -231,6 +235,7 @@ struct us_socket_context_t *us_create_socket_context(int ssl, struct us_loop_t *
|
||||
struct us_socket_context_t *context = us_calloc(1, sizeof(struct us_socket_context_t) + context_ext_size);
|
||||
context->loop = loop;
|
||||
context->is_low_prio = default_is_low_prio_handler;
|
||||
context->ref_count = 1;
|
||||
|
||||
us_internal_loop_link(loop, context);
|
||||
|
||||
@@ -252,6 +257,7 @@ struct us_socket_context_t *us_create_bun_socket_context(int ssl, struct us_loop
|
||||
struct us_socket_context_t *context = us_calloc(1, sizeof(struct us_socket_context_t) + context_ext_size);
|
||||
context->loop = loop;
|
||||
context->is_low_prio = default_is_low_prio_handler;
|
||||
context->ref_count = 1;
|
||||
|
||||
us_internal_loop_link(loop, context);
|
||||
|
||||
@@ -272,7 +278,8 @@ struct us_bun_verify_error_t us_socket_verify_error(int ssl, struct us_socket_t
|
||||
}
|
||||
|
||||
|
||||
void us_socket_context_free(int ssl, struct us_socket_context_t *context) {
|
||||
|
||||
void us_internal_socket_context_free(int ssl, struct us_socket_context_t *context) {
|
||||
#ifndef LIBUS_NO_SSL
|
||||
if (ssl) {
|
||||
/* This function will call us again with SSL=false */
|
||||
@@ -285,7 +292,23 @@ void us_socket_context_free(int ssl, struct us_socket_context_t *context) {
|
||||
* This is the opposite order compared to when creating the context - SSL code is cleaning up before non-SSL */
|
||||
|
||||
us_internal_loop_unlink(context->loop, context);
|
||||
us_free(context);
|
||||
/* Link this context to the close-list and let it be deleted after this iteration */
|
||||
context->next = context->loop->data.closed_context_head;
|
||||
context->loop->data.closed_context_head = context;
|
||||
}
|
||||
|
||||
void us_socket_context_ref(int ssl, struct us_socket_context_t *context) {
|
||||
context->ref_count++;
|
||||
}
|
||||
|
||||
void us_socket_context_unref(int ssl, struct us_socket_context_t *context) {
|
||||
if (--context->ref_count == 0) {
|
||||
us_internal_socket_context_free(ssl, context);
|
||||
}
|
||||
}
|
||||
|
||||
void us_socket_context_free(int ssl, struct us_socket_context_t *context) {
|
||||
us_socket_context_unref(ssl, context);
|
||||
}
|
||||
|
||||
struct us_listen_socket_t *us_socket_context_listen(int ssl, struct us_socket_context_t *context, const char *host, int port, int options, int socket_ext_size) {
|
||||
@@ -703,13 +726,15 @@ struct us_socket_t *us_socket_context_adopt_socket(int ssl, struct us_socket_con
|
||||
#endif
|
||||
|
||||
/* Cannot adopt a closed socket */
|
||||
if (us_socket_is_closed(ssl, s)) {
|
||||
if (us_socket_is_closed(ssl, s) || us_socket_is_shut_down(ssl, s)) {
|
||||
return s;
|
||||
}
|
||||
|
||||
if (s->low_prio_state != 1) {
|
||||
/* We need to be sure that we still holding a reference*/
|
||||
us_socket_context_ref(ssl, context);
|
||||
/* This properly updates the iterator if in on_timeout */
|
||||
us_internal_socket_context_unlink_socket(s->context, s);
|
||||
us_internal_socket_context_unlink_socket(ssl, s->context, s);
|
||||
}
|
||||
|
||||
|
||||
@@ -734,6 +759,7 @@ struct us_socket_t *us_socket_context_adopt_socket(int ssl, struct us_socket_con
|
||||
if (new_s->next) new_s->next->prev = new_s;
|
||||
} else {
|
||||
us_internal_socket_context_link_socket(context, new_s);
|
||||
us_socket_context_unref(ssl, context);
|
||||
}
|
||||
|
||||
return new_s;
|
||||
|
||||
@@ -14,8 +14,14 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// clang-format off
|
||||
#if (defined(LIBUS_USE_OPENSSL) || defined(LIBUS_USE_WOLFSSL))
|
||||
|
||||
|
||||
#include "internal/internal.h"
|
||||
#include "libusockets.h"
|
||||
#include <string.h>
|
||||
|
||||
/* These are in sni_tree.cpp */
|
||||
void *sni_new();
|
||||
void sni_free(void *sni, void (*cb)(void *));
|
||||
@@ -23,10 +29,6 @@ int sni_add(void *sni, const char *hostname, void *user);
|
||||
void *sni_remove(void *sni, const char *hostname);
|
||||
void *sni_find(void *sni, const char *hostname);
|
||||
|
||||
#include "internal/internal.h"
|
||||
#include "libusockets.h"
|
||||
#include <string.h>
|
||||
|
||||
/* This module contains the entire OpenSSL implementation
|
||||
* of the SSL socket and socket context interfaces. */
|
||||
#ifdef LIBUS_USE_OPENSSL
|
||||
@@ -71,10 +73,6 @@ struct us_internal_ssl_socket_context_t {
|
||||
// socket context
|
||||
SSL_CTX *ssl_context;
|
||||
int is_parent;
|
||||
#if ALLOW_SERVER_RENEGOTIATION
|
||||
unsigned int client_renegotiation_limit;
|
||||
unsigned int client_renegotiation_window;
|
||||
#endif
|
||||
/* These decorate the base implementation */
|
||||
struct us_internal_ssl_socket_t *(*on_open)(struct us_internal_ssl_socket_t *,
|
||||
int is_client, char *ip,
|
||||
@@ -86,6 +84,10 @@ struct us_internal_ssl_socket_context_t {
|
||||
struct us_internal_ssl_socket_t *(*on_close)(
|
||||
struct us_internal_ssl_socket_t *, int code, void *reason);
|
||||
|
||||
struct us_internal_ssl_socket_t *(*on_timeout)(
|
||||
struct us_internal_ssl_socket_t *);
|
||||
struct us_internal_ssl_socket_t *(*on_long_timeout)(struct us_internal_ssl_socket_t *);
|
||||
|
||||
/* Called for missing SNI hostnames, if not NULL */
|
||||
void (*on_server_name)(struct us_internal_ssl_socket_context_t *,
|
||||
const char *hostname);
|
||||
@@ -108,15 +110,10 @@ enum {
|
||||
struct us_internal_ssl_socket_t {
|
||||
struct us_socket_t s;
|
||||
SSL *ssl; // this _must_ be the first member after s
|
||||
#if ALLOW_SERVER_RENEGOTIATION
|
||||
unsigned int client_pending_renegotiations;
|
||||
uint64_t last_ssl_renegotiation;
|
||||
unsigned int is_client : 1;
|
||||
#endif
|
||||
unsigned int ssl_write_wants_read : 1; // we use this for now
|
||||
unsigned int ssl_read_wants_write : 1;
|
||||
unsigned int handshake_state : 2;
|
||||
unsigned int received_ssl_shutdown : 1;
|
||||
unsigned int fatal_error : 1;
|
||||
};
|
||||
|
||||
int passphrase_cb(char *buf, int size, int rwflag, void *u) {
|
||||
@@ -182,10 +179,9 @@ int BIO_s_custom_read(BIO *bio, char *dst, int length) {
|
||||
return length;
|
||||
}
|
||||
|
||||
struct us_internal_ssl_socket_t *ssl_on_open(struct us_internal_ssl_socket_t *s,
|
||||
int is_client, char *ip,
|
||||
int ip_length) {
|
||||
|
||||
struct loop_ssl_data * us_internal_set_loop_ssl_data(struct us_internal_ssl_socket_t *s) {
|
||||
// note: this context can change when we adopt the socket!
|
||||
struct us_internal_ssl_socket_context_t *context =
|
||||
(struct us_internal_ssl_socket_context_t *)us_socket_context(0, &s->s);
|
||||
|
||||
@@ -193,17 +189,31 @@ struct us_internal_ssl_socket_t *ssl_on_open(struct us_internal_ssl_socket_t *s,
|
||||
struct loop_ssl_data *loop_ssl_data =
|
||||
(struct loop_ssl_data *)loop->data.ssl_data;
|
||||
|
||||
s->ssl = SSL_new(context->ssl_context);
|
||||
#if ALLOW_SERVER_RENEGOTIATION
|
||||
s->client_pending_renegotiations = context->client_renegotiation_limit;
|
||||
s->last_ssl_renegotiation = 0;
|
||||
s->is_client = is_client ? 1 : 0;
|
||||
// note: if we put data here we should never really clear it (not in write
|
||||
// either, it still should be available for SSL_write to read from!)
|
||||
|
||||
#endif
|
||||
loop_ssl_data->ssl_read_input_length = 0;
|
||||
loop_ssl_data->ssl_read_input_offset = 0;
|
||||
loop_ssl_data->ssl_socket = &s->s;
|
||||
loop_ssl_data->msg_more = 0;
|
||||
return loop_ssl_data;
|
||||
}
|
||||
|
||||
struct us_internal_ssl_socket_t *ssl_on_open(struct us_internal_ssl_socket_t *s,
|
||||
int is_client, char *ip,
|
||||
int ip_length) {
|
||||
|
||||
struct us_internal_ssl_socket_context_t *context =
|
||||
(struct us_internal_ssl_socket_context_t *)us_socket_context(0, &s->s);
|
||||
|
||||
struct loop_ssl_data *loop_ssl_data = us_internal_set_loop_ssl_data(s);
|
||||
|
||||
s->ssl = SSL_new(context->ssl_context);
|
||||
s->ssl_write_wants_read = 0;
|
||||
s->ssl_read_wants_write = 0;
|
||||
s->fatal_error = 0;
|
||||
s->handshake_state = HANDSHAKE_PENDING;
|
||||
s->received_ssl_shutdown = 0;
|
||||
|
||||
|
||||
SSL_set_bio(s->ssl, loop_ssl_data->shared_rbio, loop_ssl_data->shared_wbio);
|
||||
// if we allow renegotiation, we need to set the mode here
|
||||
@@ -213,24 +223,18 @@ struct us_internal_ssl_socket_t *ssl_on_open(struct us_internal_ssl_socket_t *s,
|
||||
// this can be a DoS vector for servers, so we enable it using a limit
|
||||
// we do not use ssl_renegotiate_freely, since ssl_renegotiate_explicit is
|
||||
// more performant when using BoringSSL
|
||||
#if ALLOW_SERVER_RENEGOTIATION
|
||||
if (context->client_renegotiation_limit) {
|
||||
SSL_set_renegotiate_mode(s->ssl, ssl_renegotiate_explicit);
|
||||
} else {
|
||||
SSL_set_renegotiate_mode(s->ssl, ssl_renegotiate_never);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
BIO_up_ref(loop_ssl_data->shared_rbio);
|
||||
BIO_up_ref(loop_ssl_data->shared_wbio);
|
||||
|
||||
if (is_client) {
|
||||
#if ALLOW_SERVER_RENEGOTIATION == 0
|
||||
SSL_set_renegotiate_mode(s->ssl, ssl_renegotiate_explicit);
|
||||
#endif
|
||||
SSL_set_connect_state(s->ssl);
|
||||
} else {
|
||||
SSL_set_accept_state(s->ssl);
|
||||
// we do not allow renegotiation on the server side (should be the default for BoringSSL, but we set to make openssl compatible)
|
||||
SSL_set_renegotiate_mode(s->ssl, ssl_renegotiate_never);
|
||||
}
|
||||
|
||||
struct us_internal_ssl_socket_t *result =
|
||||
@@ -246,6 +250,43 @@ struct us_internal_ssl_socket_t *ssl_on_open(struct us_internal_ssl_socket_t *s,
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @brief Complete the shutdown or do a fast shutdown when needed, this should only be called before closing the socket
|
||||
/// @param s
|
||||
int us_internal_handle_shutdown(struct us_internal_ssl_socket_t *s, int force_fast_shutdown) {
|
||||
// if we are already shutdown or in the middle of a handshake we dont need to do anything
|
||||
if(us_internal_ssl_socket_is_shut_down(s) || s->fatal_error) return 1;
|
||||
|
||||
|
||||
// we are closing the socket but did not sent a shutdown yet
|
||||
int state = SSL_get_shutdown(s->ssl);
|
||||
int sent_shutdown = state & SSL_SENT_SHUTDOWN;
|
||||
int received_shutdown = state & SSL_RECEIVED_SHUTDOWN;
|
||||
// if we are missing a shutdown call, we need to do a fast shutdown here
|
||||
if(!sent_shutdown || !received_shutdown) {
|
||||
// make sure that the ssl loop data is set
|
||||
us_internal_set_loop_ssl_data(s);
|
||||
// Zero means that we should wait for the peer to close the connection
|
||||
// but we are already closing the connection so we do a fast shutdown here
|
||||
int ret = SSL_shutdown(s->ssl);
|
||||
if(ret == 0 && force_fast_shutdown) {
|
||||
// do a fast shutdown (dont wait for peer)
|
||||
ret = SSL_shutdown(s->ssl);
|
||||
}
|
||||
if(ret < 0) {
|
||||
// we got some error here, but we dont care about it, we are closing the socket
|
||||
int err = SSL_get_error(s->ssl, ret);
|
||||
if (err == SSL_ERROR_SSL || err == SSL_ERROR_SYSCALL) {
|
||||
// clear
|
||||
ERR_clear_error();
|
||||
s->fatal_error = 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return ret == 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void us_internal_on_ssl_handshake(
|
||||
struct us_internal_ssl_socket_context_t *context,
|
||||
void (*on_handshake)(struct us_internal_ssl_socket_t *, int success,
|
||||
@@ -256,9 +297,17 @@ void us_internal_on_ssl_handshake(
|
||||
context->handshake_data = custom_data;
|
||||
}
|
||||
|
||||
int us_internal_ssl_socket_is_closed(struct us_internal_ssl_socket_t *s) {
|
||||
return us_socket_is_closed(0, &s->s);
|
||||
}
|
||||
|
||||
struct us_internal_ssl_socket_t *
|
||||
us_internal_ssl_socket_close(struct us_internal_ssl_socket_t *s, int code,
|
||||
void *reason) {
|
||||
|
||||
// check if we are already closed
|
||||
if (us_internal_ssl_socket_is_closed(s)) return s;
|
||||
|
||||
if (s->handshake_state != HANDSHAKE_COMPLETED) {
|
||||
// if we have some pending handshake we cancel it and try to check the
|
||||
// latest handshake error this way we will always call on_handshake with the
|
||||
@@ -269,8 +318,14 @@ us_internal_ssl_socket_close(struct us_internal_ssl_socket_t *s, int code,
|
||||
us_internal_trigger_handshake_callback(s, 0);
|
||||
}
|
||||
|
||||
return (struct us_internal_ssl_socket_t *)us_socket_close(
|
||||
0, (struct us_socket_t *)s, code, reason);
|
||||
// if we are in the middle of a close_notify we need to finish it (code != 0 forces a fast shutdown)
|
||||
int can_close = s->ssl && us_internal_handle_shutdown(s, code != 0);
|
||||
|
||||
// only close the socket if we are not in the middle of a handshake
|
||||
if(can_close) {
|
||||
return (struct us_internal_ssl_socket_t *)us_socket_close(0, (struct us_socket_t *)s, code, reason);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void us_internal_trigger_handshake_callback(struct us_internal_ssl_socket_t *s,
|
||||
@@ -292,26 +347,7 @@ int us_internal_ssl_renegotiate(struct us_internal_ssl_socket_t *s) {
|
||||
// if is a server and we have no pending renegotiation we can check
|
||||
// the limits
|
||||
s->handshake_state = HANDSHAKE_RENEGOTIATION_PENDING;
|
||||
#if ALLOW_SERVER_RENEGOTIATION
|
||||
if (!s->is_client && !SSL_renegotiate_pending(s->ssl)) {
|
||||
uint64_t now = time(NULL);
|
||||
struct us_internal_ssl_socket_context_t *context =
|
||||
(struct us_internal_ssl_socket_context_t *)us_socket_context(0, &s->s);
|
||||
// if is not the first time we negotiate and we are outside the time
|
||||
// window, reset the limits
|
||||
if (s->last_ssl_renegotiation && (now - s->last_ssl_renegotiation) >=
|
||||
context->client_renegotiation_window) {
|
||||
// reset the limits
|
||||
s->client_pending_renegotiations = context->client_renegotiation_limit;
|
||||
}
|
||||
// if we have no more renegotiations, we should close the connection
|
||||
if (s->client_pending_renegotiations == 0) {
|
||||
return 0;
|
||||
}
|
||||
s->last_ssl_renegotiation = now;
|
||||
s->client_pending_renegotiations--;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!SSL_renegotiate(s->ssl)) {
|
||||
// we failed to renegotiate
|
||||
us_internal_trigger_handshake_callback(s, 0);
|
||||
@@ -321,24 +357,13 @@ int us_internal_ssl_renegotiate(struct us_internal_ssl_socket_t *s) {
|
||||
}
|
||||
|
||||
void us_internal_update_handshake(struct us_internal_ssl_socket_t *s) {
|
||||
struct us_internal_ssl_socket_context_t *context =
|
||||
(struct us_internal_ssl_socket_context_t *)us_socket_context(0, &s->s);
|
||||
|
||||
// nothing todo here, renegotiation must be handled in SSL_read
|
||||
if (s->handshake_state != HANDSHAKE_PENDING)
|
||||
return;
|
||||
|
||||
struct us_loop_t *loop = us_socket_context_loop(0, &context->sc);
|
||||
struct loop_ssl_data *loop_ssl_data =
|
||||
(struct loop_ssl_data *)loop->data.ssl_data;
|
||||
|
||||
loop_ssl_data->ssl_read_input_length = 0;
|
||||
loop_ssl_data->ssl_read_input_offset = 0;
|
||||
loop_ssl_data->ssl_socket = &s->s;
|
||||
loop_ssl_data->msg_more = 0;
|
||||
|
||||
if (us_socket_is_closed(0, &s->s) || us_internal_ssl_socket_is_shut_down(s) ||
|
||||
SSL_get_shutdown(s->ssl) & SSL_RECEIVED_SHUTDOWN) {
|
||||
|
||||
if (us_internal_ssl_socket_is_closed(s) || us_internal_ssl_socket_is_shut_down(s) ||
|
||||
(s->ssl && SSL_get_shutdown(s->ssl) & SSL_RECEIVED_SHUTDOWN)) {
|
||||
|
||||
us_internal_trigger_handshake_callback(s, 0);
|
||||
return;
|
||||
@@ -347,7 +372,6 @@ void us_internal_update_handshake(struct us_internal_ssl_socket_t *s) {
|
||||
int result = SSL_do_handshake(s->ssl);
|
||||
|
||||
if (SSL_get_shutdown(s->ssl) & SSL_RECEIVED_SHUTDOWN) {
|
||||
s->received_ssl_shutdown = 1;
|
||||
us_internal_ssl_socket_close(s, 0, NULL);
|
||||
return;
|
||||
}
|
||||
@@ -356,30 +380,23 @@ void us_internal_update_handshake(struct us_internal_ssl_socket_t *s) {
|
||||
int err = SSL_get_error(s->ssl, result);
|
||||
// as far as I know these are the only errors we want to handle
|
||||
if (err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) {
|
||||
us_internal_trigger_handshake_callback(s, 1);
|
||||
|
||||
// clear per thread error queue if it may contain something
|
||||
if (err == SSL_ERROR_SSL || err == SSL_ERROR_SYSCALL) {
|
||||
ERR_clear_error();
|
||||
s->fatal_error = 1;
|
||||
}
|
||||
us_internal_trigger_handshake_callback(s, 0);
|
||||
|
||||
return;
|
||||
}
|
||||
s->handshake_state = HANDSHAKE_PENDING;
|
||||
// Ensure that we'll cycle through internal openssl's state
|
||||
if (!us_socket_is_closed(0, &s->s) &&
|
||||
!us_internal_ssl_socket_is_shut_down(s)) {
|
||||
us_socket_write(1, loop_ssl_data->ssl_socket, "\0", 0, 0);
|
||||
}
|
||||
s->ssl_write_wants_read = 1;
|
||||
|
||||
return;
|
||||
}
|
||||
// success
|
||||
us_internal_trigger_handshake_callback(s, 1);
|
||||
// Ensure that we'll cycle through internal openssl's state
|
||||
if (!us_socket_is_closed(0, &s->s) &&
|
||||
!us_internal_ssl_socket_is_shut_down(s)) {
|
||||
us_socket_write(1, loop_ssl_data->ssl_socket, "\0", 0, 0);
|
||||
}
|
||||
s->ssl_write_wants_read = 1;
|
||||
}
|
||||
|
||||
struct us_internal_ssl_socket_t *
|
||||
@@ -387,16 +404,33 @@ ssl_on_close(struct us_internal_ssl_socket_t *s, int code, void *reason) {
|
||||
struct us_internal_ssl_socket_context_t *context =
|
||||
(struct us_internal_ssl_socket_context_t *)us_socket_context(0, &s->s);
|
||||
|
||||
SSL_free(s->ssl);
|
||||
us_internal_set_loop_ssl_data(s);
|
||||
struct us_internal_ssl_socket_t * ret = context->on_close(s, code, reason);
|
||||
SSL_free(s->ssl); // free SSL after on_close
|
||||
s->ssl = NULL; // set to NULL
|
||||
return ret;
|
||||
}
|
||||
|
||||
return context->on_close(s, code, reason);
|
||||
struct us_internal_ssl_socket_t * ssl_on_timeout(struct us_internal_ssl_socket_t *s) {
|
||||
struct us_internal_ssl_socket_context_t *context =
|
||||
(struct us_internal_ssl_socket_context_t *)us_socket_context(0, &s->s);
|
||||
|
||||
us_internal_set_loop_ssl_data(s);
|
||||
return context->on_timeout(s);
|
||||
}
|
||||
|
||||
struct us_internal_ssl_socket_t * ssl_on_long_timeout(struct us_internal_ssl_socket_t *s) {
|
||||
struct us_internal_ssl_socket_context_t *context =
|
||||
(struct us_internal_ssl_socket_context_t *)us_socket_context(0, &s->s);
|
||||
|
||||
us_internal_set_loop_ssl_data(s);
|
||||
return context->on_long_timeout(s);
|
||||
}
|
||||
|
||||
struct us_internal_ssl_socket_t *
|
||||
ssl_on_end(struct us_internal_ssl_socket_t *s) {
|
||||
us_internal_set_loop_ssl_data(s);
|
||||
// whatever state we are in, a TCP FIN is always an answered shutdown
|
||||
|
||||
/* Todo: this should report CLEANLY SHUTDOWN as reason */
|
||||
return us_internal_ssl_socket_close(s, 0, NULL);
|
||||
}
|
||||
|
||||
@@ -408,43 +442,20 @@ struct us_internal_ssl_socket_t *ssl_on_data(struct us_internal_ssl_socket_t *s,
|
||||
struct us_internal_ssl_socket_context_t *context =
|
||||
(struct us_internal_ssl_socket_context_t *)us_socket_context(0, &s->s);
|
||||
|
||||
struct us_loop_t *loop = us_socket_context_loop(0, &context->sc);
|
||||
struct loop_ssl_data *loop_ssl_data =
|
||||
(struct loop_ssl_data *)loop->data.ssl_data;
|
||||
struct loop_ssl_data *loop_ssl_data = us_internal_set_loop_ssl_data(s);
|
||||
|
||||
// note: if we put data here we should never really clear it (not in write
|
||||
// either, it still should be available for SSL_write to read from!)
|
||||
loop_ssl_data->ssl_read_input = data;
|
||||
loop_ssl_data->ssl_read_input_length = length;
|
||||
loop_ssl_data->ssl_read_input_offset = 0;
|
||||
loop_ssl_data->ssl_socket = &s->s;
|
||||
loop_ssl_data->msg_more = 0;
|
||||
|
||||
if (us_socket_is_closed(0, &s->s) || s->received_ssl_shutdown) {
|
||||
if (us_internal_ssl_socket_is_closed(s)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (us_internal_ssl_socket_is_shut_down(s)) {
|
||||
|
||||
int ret = 0;
|
||||
if ((ret = SSL_shutdown(s->ssl)) == 1) {
|
||||
// two phase shutdown is complete here
|
||||
|
||||
/* Todo: this should also report some kind of clean shutdown */
|
||||
return us_internal_ssl_socket_close(s, 0, NULL);
|
||||
} else if (ret < 0) {
|
||||
|
||||
int err = SSL_get_error(s->ssl, ret);
|
||||
|
||||
if (err == SSL_ERROR_SSL || err == SSL_ERROR_SYSCALL) {
|
||||
// we need to clear the error queue in case these added to the thread
|
||||
// local queue
|
||||
ERR_clear_error();
|
||||
}
|
||||
}
|
||||
|
||||
// no further processing of data when in shutdown state
|
||||
return s;
|
||||
us_internal_ssl_socket_close(s, 0, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// bug checking: this loop needs a lot of attention and clean-ups and
|
||||
@@ -452,17 +463,12 @@ struct us_internal_ssl_socket_t *ssl_on_data(struct us_internal_ssl_socket_t *s,
|
||||
int read = 0;
|
||||
restart:
|
||||
// read until shutdown
|
||||
while (!s->received_ssl_shutdown) {
|
||||
while (1) {
|
||||
int just_read = SSL_read(s->ssl,
|
||||
loop_ssl_data->ssl_read_output +
|
||||
LIBUS_RECV_BUFFER_PADDING + read,
|
||||
LIBUS_RECV_BUFFER_LENGTH - read);
|
||||
// we need to check if we received a shutdown here
|
||||
if (SSL_get_shutdown(s->ssl) & SSL_RECEIVED_SHUTDOWN) {
|
||||
s->received_ssl_shutdown = 1;
|
||||
// we will only close after we handle the data and errors
|
||||
}
|
||||
|
||||
|
||||
if (just_read <= 0) {
|
||||
int err = SSL_get_error(s->ssl, just_read);
|
||||
// as far as I know these are the only errors we want to handle
|
||||
@@ -477,8 +483,9 @@ restart:
|
||||
// clean and close renegotiation failed
|
||||
err = SSL_ERROR_SSL;
|
||||
} else if (err == SSL_ERROR_ZERO_RETURN) {
|
||||
// zero return can be EOF/FIN, if we have data just signal on_data and
|
||||
// close
|
||||
// Remotely-Initiated Shutdown
|
||||
// See: https://www.openssl.org/docs/manmaster/man3/SSL_shutdown.html
|
||||
|
||||
if (read) {
|
||||
context =
|
||||
(struct us_internal_ssl_socket_context_t *)us_socket_context(
|
||||
@@ -487,21 +494,24 @@ restart:
|
||||
s = context->on_data(
|
||||
s, loop_ssl_data->ssl_read_output + LIBUS_RECV_BUFFER_PADDING,
|
||||
read);
|
||||
if (!s || us_socket_is_closed(0, &s->s)) {
|
||||
return s;
|
||||
if (!s || us_internal_ssl_socket_is_closed(s)) {
|
||||
return NULL; // stop processing data
|
||||
}
|
||||
}
|
||||
// terminate connection here
|
||||
return us_internal_ssl_socket_close(s, 0, NULL);
|
||||
us_internal_ssl_socket_close(s, 0, NULL);
|
||||
return NULL; // stop processing data
|
||||
}
|
||||
|
||||
if (err == SSL_ERROR_SSL || err == SSL_ERROR_SYSCALL) {
|
||||
// clear per thread error queue if it may contain something
|
||||
ERR_clear_error();
|
||||
s->fatal_error = 1;
|
||||
}
|
||||
|
||||
// terminate connection here
|
||||
return us_internal_ssl_socket_close(s, 0, NULL);
|
||||
us_internal_ssl_socket_close(s, 0, NULL);
|
||||
return NULL; // stop processing data
|
||||
} else {
|
||||
// emit the data we have and exit
|
||||
|
||||
@@ -526,8 +536,8 @@ restart:
|
||||
s = context->on_data(
|
||||
s, loop_ssl_data->ssl_read_output + LIBUS_RECV_BUFFER_PADDING,
|
||||
read);
|
||||
if (!s || us_socket_is_closed(0, &s->s)) {
|
||||
return s;
|
||||
if (!s || us_internal_ssl_socket_is_closed(s)) {
|
||||
return NULL; // stop processing data
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -549,20 +559,14 @@ restart:
|
||||
// emit data and restart
|
||||
s = context->on_data(
|
||||
s, loop_ssl_data->ssl_read_output + LIBUS_RECV_BUFFER_PADDING, read);
|
||||
if (!s || us_socket_is_closed(0, &s->s)) {
|
||||
return s;
|
||||
if (!s || us_internal_ssl_socket_is_closed(s)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
read = 0;
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
|
||||
// we received the shutdown after reading so we close
|
||||
if (s->received_ssl_shutdown) {
|
||||
us_internal_ssl_socket_close(s, 0, NULL);
|
||||
return NULL;
|
||||
}
|
||||
// trigger writable if we failed last write with want read
|
||||
if (s->ssl_write_wants_read) {
|
||||
s->ssl_write_wants_read = 0;
|
||||
@@ -575,8 +579,8 @@ restart:
|
||||
s = (struct us_internal_ssl_socket_t *)context->sc.on_writable(
|
||||
&s->s); // cast here!
|
||||
// if we are closed here, then exit
|
||||
if (!s || us_socket_is_closed(0, &s->s)) {
|
||||
return s;
|
||||
if (!s || us_internal_ssl_socket_is_closed(s)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -585,6 +589,7 @@ restart:
|
||||
|
||||
struct us_internal_ssl_socket_t *
|
||||
ssl_on_writable(struct us_internal_ssl_socket_t *s) {
|
||||
us_internal_set_loop_ssl_data(s);
|
||||
us_internal_update_handshake(s);
|
||||
|
||||
struct us_internal_ssl_socket_context_t *context =
|
||||
@@ -606,8 +611,8 @@ ssl_on_writable(struct us_internal_ssl_socket_t *s) {
|
||||
}
|
||||
// Do not call on_writable if the socket is closed.
|
||||
// on close means the socket data is no longer accessible
|
||||
if (!s || us_socket_is_closed(0, &s->s)) {
|
||||
return 0;
|
||||
if (!s || us_internal_ssl_socket_is_closed(s) || us_internal_ssl_socket_is_shut_down(s)) {
|
||||
return s;
|
||||
}
|
||||
|
||||
if (s->handshake_state == HANDSHAKE_COMPLETED) {
|
||||
@@ -1032,7 +1037,7 @@ long us_internal_verify_peer_certificate( // NOLINT(runtime/int)
|
||||
|
||||
struct us_bun_verify_error_t
|
||||
us_internal_verify_error(struct us_internal_ssl_socket_t *s) {
|
||||
if (us_socket_is_closed(0, &s->s) || us_internal_ssl_socket_is_shut_down(s)) {
|
||||
if (us_internal_ssl_socket_is_closed(s) || us_internal_ssl_socket_is_shut_down(s)) {
|
||||
return (struct us_bun_verify_error_t){
|
||||
.error = 0, .code = NULL, .reason = NULL};
|
||||
}
|
||||
@@ -1317,10 +1322,6 @@ void us_bun_internal_ssl_socket_context_add_server_name(
|
||||
|
||||
/* We do not want to hold any nullptr's in our SNI tree */
|
||||
if (ssl_context) {
|
||||
#if ALLOW_SERVER_RENEGOTIATION
|
||||
context->client_renegotiation_limit = options.client_renegotiation_limit;
|
||||
context->client_renegotiation_window = options.client_renegotiation_window;
|
||||
#endif
|
||||
if (sni_add(context->sni, hostname_pattern, ssl_context)) {
|
||||
/* If we already had that name, ignore */
|
||||
free_ssl_context(ssl_context);
|
||||
@@ -1469,10 +1470,6 @@ us_internal_bun_create_ssl_socket_context(
|
||||
|
||||
context->on_handshake = NULL;
|
||||
context->handshake_data = NULL;
|
||||
#if ALLOW_SERVER_RENEGOTIATION
|
||||
context->client_renegotiation_limit = options.client_renegotiation_limit;
|
||||
context->client_renegotiation_window = options.client_renegotiation_window;
|
||||
#endif
|
||||
/* We, as parent context, may ignore data */
|
||||
context->sc.is_low_prio = (int (*)(struct us_socket_t *))ssl_is_low_prio;
|
||||
|
||||
@@ -1503,7 +1500,7 @@ void us_internal_ssl_socket_context_free(
|
||||
sni_free(context->sni, sni_hostname_destructor);
|
||||
}
|
||||
|
||||
us_socket_context_free(0, &context->sc);
|
||||
us_internal_socket_context_free(0, &context->sc);
|
||||
}
|
||||
|
||||
struct us_listen_socket_t *us_internal_ssl_socket_context_listen(
|
||||
@@ -1592,7 +1589,8 @@ void us_internal_ssl_socket_context_on_timeout(
|
||||
struct us_internal_ssl_socket_t *s)) {
|
||||
us_socket_context_on_timeout(0, (struct us_socket_context_t *)context,
|
||||
(struct us_socket_t * (*)(struct us_socket_t *))
|
||||
on_timeout);
|
||||
ssl_on_timeout);
|
||||
context->on_timeout = on_timeout;
|
||||
}
|
||||
|
||||
void us_internal_ssl_socket_context_on_long_timeout(
|
||||
@@ -1601,7 +1599,8 @@ void us_internal_ssl_socket_context_on_long_timeout(
|
||||
struct us_internal_ssl_socket_t *s)) {
|
||||
us_socket_context_on_long_timeout(
|
||||
0, (struct us_socket_context_t *)context,
|
||||
(struct us_socket_t * (*)(struct us_socket_t *)) on_long_timeout);
|
||||
(struct us_socket_t * (*)(struct us_socket_t *)) ssl_on_long_timeout);
|
||||
context->on_long_timeout = on_long_timeout;
|
||||
}
|
||||
|
||||
/* We do not really listen to passed FIN-handler, we entirely override it with
|
||||
@@ -1656,8 +1655,8 @@ int us_internal_ssl_socket_raw_write(struct us_internal_ssl_socket_t *s,
|
||||
|
||||
int us_internal_ssl_socket_write(struct us_internal_ssl_socket_t *s,
|
||||
const char *data, int length, int msg_more) {
|
||||
|
||||
if (us_socket_is_closed(0, &s->s) || us_internal_ssl_socket_is_shut_down(s)) {
|
||||
|
||||
if (us_socket_is_closed(0, &s->s) || us_internal_ssl_socket_is_shut_down(s) || length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1697,6 +1696,7 @@ int us_internal_ssl_socket_write(struct us_internal_ssl_socket_t *s,
|
||||
// these two errors may add to the error queue, which is per thread and
|
||||
// must be cleared
|
||||
ERR_clear_error();
|
||||
s->fatal_error = 1;
|
||||
|
||||
// all errors here except for want write are critical and should not
|
||||
// happen
|
||||
@@ -1714,12 +1714,12 @@ void *us_internal_connecting_ssl_socket_ext(struct us_connecting_socket_t *s) {
|
||||
}
|
||||
|
||||
int us_internal_ssl_socket_is_shut_down(struct us_internal_ssl_socket_t *s) {
|
||||
return us_socket_is_shut_down(0, &s->s) ||
|
||||
SSL_get_shutdown(s->ssl) & SSL_SENT_SHUTDOWN;
|
||||
return !s->ssl || us_socket_is_shut_down(0, &s->s) ||
|
||||
SSL_get_shutdown(s->ssl) & SSL_SENT_SHUTDOWN || s->fatal_error;
|
||||
}
|
||||
|
||||
void us_internal_ssl_socket_shutdown(struct us_internal_ssl_socket_t *s) {
|
||||
if (!us_socket_is_closed(0, &s->s) &&
|
||||
if (!us_internal_ssl_socket_is_closed(s) &&
|
||||
!us_internal_ssl_socket_is_shut_down(s)) {
|
||||
struct us_internal_ssl_socket_context_t *context =
|
||||
(struct us_internal_ssl_socket_context_t *)us_socket_context(0, &s->s);
|
||||
@@ -1740,19 +1740,22 @@ void us_internal_ssl_socket_shutdown(struct us_internal_ssl_socket_t *s) {
|
||||
loop_ssl_data->ssl_socket = &s->s;
|
||||
|
||||
loop_ssl_data->msg_more = 0;
|
||||
|
||||
// sets SSL_SENT_SHUTDOWN no matter what (not actually true if error!)
|
||||
// sets SSL_SENT_SHUTDOWN and waits for the other side to do the same
|
||||
int ret = SSL_shutdown(s->ssl);
|
||||
if (ret == 0) {
|
||||
ret = SSL_shutdown(s->ssl);
|
||||
|
||||
if (SSL_in_init(s->ssl) || SSL_get_quiet_shutdown(s->ssl)) {
|
||||
// when SSL_in_init or quiet shutdown in BoringSSL, we call shutdown
|
||||
// directly
|
||||
us_socket_shutdown(0, &s->s);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
|
||||
int err = SSL_get_error(s->ssl, ret);
|
||||
if (err == SSL_ERROR_SSL || err == SSL_ERROR_SYSCALL) {
|
||||
// clear
|
||||
ERR_clear_error();
|
||||
s->fatal_error = 1;
|
||||
}
|
||||
|
||||
// we get here if we are shutting down while still in init
|
||||
@@ -2043,8 +2046,8 @@ us_socket_context_on_socket_connect_error(
|
||||
socket->ssl = NULL;
|
||||
socket->ssl_write_wants_read = 0;
|
||||
socket->ssl_read_wants_write = 0;
|
||||
socket->fatal_error = 0;
|
||||
socket->handshake_state = HANDSHAKE_PENDING;
|
||||
socket->received_ssl_shutdown = 0;
|
||||
return socket;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// clang-format off
|
||||
#pragma once
|
||||
#ifndef INTERNAL_H
|
||||
#define INTERNAL_H
|
||||
@@ -100,6 +101,9 @@ struct addrinfo_result {
|
||||
int error;
|
||||
};
|
||||
|
||||
#define us_internal_ssl_socket_context_r struct us_internal_ssl_socket_context_t *nonnull_arg
|
||||
#define us_internal_ssl_socket_r struct us_internal_ssl_socket_t *nonnull_arg
|
||||
|
||||
extern int Bun__addrinfo_get(struct us_loop_t* loop, const char* host, struct addrinfo_request** ptr);
|
||||
extern int Bun__addrinfo_set(struct addrinfo_request* ptr, struct us_connecting_socket_t* socket);
|
||||
extern void Bun__addrinfo_freeRequest(struct addrinfo_request* addrinfo_req, int error);
|
||||
@@ -109,19 +113,19 @@ extern struct addrinfo_result *Bun__addrinfo_getRequestResult(struct addrinfo_re
|
||||
/* Loop related */
|
||||
void us_internal_dispatch_ready_poll(struct us_poll_t *p, int error,
|
||||
int events);
|
||||
void us_internal_timer_sweep(struct us_loop_t *loop);
|
||||
void us_internal_free_closed_sockets(struct us_loop_t *loop);
|
||||
void us_internal_timer_sweep(us_loop_r loop);
|
||||
void us_internal_free_closed_sockets(us_loop_r loop);
|
||||
void us_internal_loop_link(struct us_loop_t *loop,
|
||||
struct us_socket_context_t *context);
|
||||
void us_internal_loop_unlink(struct us_loop_t *loop,
|
||||
struct us_socket_context_t *context);
|
||||
void us_internal_loop_data_init(struct us_loop_t *loop,
|
||||
void (*wakeup_cb)(struct us_loop_t *loop),
|
||||
void (*pre_cb)(struct us_loop_t *loop),
|
||||
void (*post_cb)(struct us_loop_t *loop));
|
||||
void us_internal_loop_data_free(struct us_loop_t *loop);
|
||||
void us_internal_loop_pre(struct us_loop_t *loop);
|
||||
void us_internal_loop_post(struct us_loop_t *loop);
|
||||
void (*wakeup_cb)(us_loop_r loop),
|
||||
void (*pre_cb)(us_loop_r loop),
|
||||
void (*post_cb)(us_loop_r loop));
|
||||
void us_internal_loop_data_free(us_loop_r loop);
|
||||
void us_internal_loop_pre(us_loop_r loop);
|
||||
void us_internal_loop_post(us_loop_r loop);
|
||||
|
||||
/* Asyncs (old) */
|
||||
struct us_internal_async *us_internal_create_async(struct us_loop_t *loop,
|
||||
@@ -138,18 +142,22 @@ int us_internal_poll_type(struct us_poll_t *p);
|
||||
void us_internal_poll_set_type(struct us_poll_t *p, int poll_type);
|
||||
|
||||
/* SSL loop data */
|
||||
void us_internal_init_loop_ssl_data(struct us_loop_t *loop);
|
||||
void us_internal_free_loop_ssl_data(struct us_loop_t *loop);
|
||||
void us_internal_init_loop_ssl_data(us_loop_r loop);
|
||||
void us_internal_free_loop_ssl_data(us_loop_r loop);
|
||||
|
||||
/* Socket context related */
|
||||
void us_internal_socket_context_link_socket(struct us_socket_context_t *context,
|
||||
struct us_socket_t *s);
|
||||
void us_internal_socket_context_unlink_socket(
|
||||
struct us_socket_context_t *context, struct us_socket_t *s);
|
||||
void us_internal_socket_context_link_socket(us_socket_context_r context,
|
||||
us_socket_r s);
|
||||
void us_internal_socket_context_unlink_socket(int ssl,
|
||||
us_socket_context_r context, us_socket_r s);
|
||||
|
||||
void us_internal_socket_after_resolve(struct us_connecting_socket_t *s);
|
||||
void us_internal_socket_after_open(struct us_socket_t *s, int error);
|
||||
int us_internal_handle_dns_results(struct us_loop_t *loop);
|
||||
void us_internal_socket_after_open(us_socket_r s, int error);
|
||||
struct us_internal_ssl_socket_t *
|
||||
us_internal_ssl_socket_close(us_internal_ssl_socket_r s, int code,
|
||||
void *reason);
|
||||
|
||||
int us_internal_handle_dns_results(us_loop_r loop);
|
||||
|
||||
/* Sockets are polls */
|
||||
struct us_socket_t {
|
||||
@@ -243,13 +251,14 @@ struct us_listen_socket_t {
|
||||
|
||||
/* Listen sockets are keps in their own list */
|
||||
void us_internal_socket_context_link_listen_socket(
|
||||
struct us_socket_context_t *context, struct us_listen_socket_t *s);
|
||||
void us_internal_socket_context_unlink_listen_socket(
|
||||
struct us_socket_context_t *context, struct us_listen_socket_t *s);
|
||||
us_socket_context_r context, struct us_listen_socket_t *s);
|
||||
void us_internal_socket_context_unlink_listen_socket(int ssl,
|
||||
us_socket_context_r context, struct us_listen_socket_t *s);
|
||||
|
||||
struct us_socket_context_t {
|
||||
alignas(LIBUS_EXT_ALIGNMENT) struct us_loop_t *loop;
|
||||
uint32_t global_tick;
|
||||
uint32_t ref_count;
|
||||
unsigned char timestamp;
|
||||
unsigned char long_timestamp;
|
||||
struct us_socket_t *head_sockets;
|
||||
@@ -280,34 +289,35 @@ struct us_internal_ssl_socket_t;
|
||||
typedef void (*us_internal_on_handshake_t)(
|
||||
struct us_internal_ssl_socket_t *, int success,
|
||||
struct us_bun_verify_error_t verify_error, void *custom_data);
|
||||
|
||||
|
||||
void us_internal_socket_context_free(int ssl, struct us_socket_context_t *context);
|
||||
/* SNI functions */
|
||||
void us_internal_ssl_socket_context_add_server_name(
|
||||
struct us_internal_ssl_socket_context_t *context,
|
||||
us_internal_ssl_socket_context_r context,
|
||||
const char *hostname_pattern, struct us_socket_context_options_t options,
|
||||
void *user);
|
||||
void us_bun_internal_ssl_socket_context_add_server_name(
|
||||
struct us_internal_ssl_socket_context_t *context,
|
||||
us_internal_ssl_socket_context_r context,
|
||||
const char *hostname_pattern,
|
||||
struct us_bun_socket_context_options_t options, void *user);
|
||||
void us_internal_ssl_socket_context_remove_server_name(
|
||||
struct us_internal_ssl_socket_context_t *context,
|
||||
us_internal_ssl_socket_context_r context,
|
||||
const char *hostname_pattern);
|
||||
void us_internal_ssl_socket_context_on_server_name(
|
||||
struct us_internal_ssl_socket_context_t *context,
|
||||
us_internal_ssl_socket_context_r context,
|
||||
void (*cb)(struct us_internal_ssl_socket_context_t *, const char *));
|
||||
void *
|
||||
us_internal_ssl_socket_get_sni_userdata(struct us_internal_ssl_socket_t *s);
|
||||
us_internal_ssl_socket_get_sni_userdata(us_internal_ssl_socket_r s);
|
||||
void *us_internal_ssl_socket_context_find_server_name_userdata(
|
||||
struct us_internal_ssl_socket_context_t *context,
|
||||
us_internal_ssl_socket_context_r context,
|
||||
const char *hostname_pattern);
|
||||
|
||||
void *
|
||||
us_internal_ssl_socket_get_native_handle(struct us_internal_ssl_socket_t *s);
|
||||
us_internal_ssl_socket_get_native_handle(us_internal_ssl_socket_r s);
|
||||
void *us_internal_ssl_socket_context_get_native_handle(
|
||||
struct us_internal_ssl_socket_context_t *context);
|
||||
us_internal_ssl_socket_context_r context);
|
||||
struct us_bun_verify_error_t
|
||||
us_internal_verify_error(struct us_internal_ssl_socket_t *s);
|
||||
us_internal_verify_error(us_internal_ssl_socket_r s);
|
||||
struct us_internal_ssl_socket_context_t *us_internal_create_ssl_socket_context(
|
||||
struct us_loop_t *loop, int context_ext_size,
|
||||
struct us_socket_context_options_t options);
|
||||
@@ -317,108 +327,109 @@ us_internal_bun_create_ssl_socket_context(
|
||||
struct us_bun_socket_context_options_t options);
|
||||
|
||||
void us_internal_ssl_socket_context_free(
|
||||
struct us_internal_ssl_socket_context_t *context);
|
||||
us_internal_ssl_socket_context_r context);
|
||||
void us_internal_ssl_socket_context_on_open(
|
||||
struct us_internal_ssl_socket_context_t *context,
|
||||
us_internal_ssl_socket_context_r context,
|
||||
struct us_internal_ssl_socket_t *(*on_open)(
|
||||
struct us_internal_ssl_socket_t *s, int is_client, char *ip,
|
||||
us_internal_ssl_socket_r s, int is_client, char *ip,
|
||||
int ip_length));
|
||||
|
||||
void us_internal_ssl_socket_context_on_close(
|
||||
struct us_internal_ssl_socket_context_t *context,
|
||||
us_internal_ssl_socket_context_r context,
|
||||
struct us_internal_ssl_socket_t *(*on_close)(
|
||||
struct us_internal_ssl_socket_t *s, int code, void *reason));
|
||||
us_internal_ssl_socket_r s, int code, void *reason));
|
||||
|
||||
void us_internal_ssl_socket_context_on_data(
|
||||
struct us_internal_ssl_socket_context_t *context,
|
||||
us_internal_ssl_socket_context_r context,
|
||||
struct us_internal_ssl_socket_t *(*on_data)(
|
||||
struct us_internal_ssl_socket_t *s, char *data, int length));
|
||||
us_internal_ssl_socket_r s, char *data, int length));
|
||||
|
||||
void us_internal_update_handshake(struct us_internal_ssl_socket_t *s);
|
||||
int us_internal_renegotiate(struct us_internal_ssl_socket_t *s);
|
||||
void us_internal_trigger_handshake_callback(struct us_internal_ssl_socket_t *s,
|
||||
void us_internal_update_handshake(us_internal_ssl_socket_r s);
|
||||
int us_internal_renegotiate(us_internal_ssl_socket_r s);
|
||||
void us_internal_trigger_handshake_callback(us_internal_ssl_socket_r s,
|
||||
int success);
|
||||
void us_internal_on_ssl_handshake(
|
||||
struct us_internal_ssl_socket_context_t *context,
|
||||
us_internal_ssl_socket_context_r context,
|
||||
us_internal_on_handshake_t onhandshake, void *custom_data);
|
||||
|
||||
void us_internal_ssl_socket_context_on_writable(
|
||||
struct us_internal_ssl_socket_context_t *context,
|
||||
us_internal_ssl_socket_context_r context,
|
||||
struct us_internal_ssl_socket_t *(*on_writable)(
|
||||
struct us_internal_ssl_socket_t *s));
|
||||
us_internal_ssl_socket_r s));
|
||||
|
||||
void us_internal_ssl_socket_context_on_timeout(
|
||||
struct us_internal_ssl_socket_context_t *context,
|
||||
us_internal_ssl_socket_context_r context,
|
||||
struct us_internal_ssl_socket_t *(*on_timeout)(
|
||||
struct us_internal_ssl_socket_t *s));
|
||||
us_internal_ssl_socket_r s));
|
||||
|
||||
void us_internal_ssl_socket_context_on_long_timeout(
|
||||
struct us_internal_ssl_socket_context_t *context,
|
||||
us_internal_ssl_socket_context_r context,
|
||||
struct us_internal_ssl_socket_t *(*on_timeout)(
|
||||
struct us_internal_ssl_socket_t *s));
|
||||
us_internal_ssl_socket_r s));
|
||||
|
||||
void us_internal_ssl_socket_context_on_end(
|
||||
struct us_internal_ssl_socket_context_t *context,
|
||||
us_internal_ssl_socket_context_r context,
|
||||
struct us_internal_ssl_socket_t *(*on_end)(
|
||||
struct us_internal_ssl_socket_t *s));
|
||||
us_internal_ssl_socket_r s));
|
||||
|
||||
void us_internal_ssl_socket_context_on_connect_error(
|
||||
struct us_internal_ssl_socket_context_t *context,
|
||||
us_internal_ssl_socket_context_r context,
|
||||
struct us_internal_ssl_socket_t *(*on_connect_error)(
|
||||
struct us_internal_ssl_socket_t *s, int code));
|
||||
us_internal_ssl_socket_r s, int code));
|
||||
|
||||
void us_internal_ssl_socket_context_on_socket_connect_error(
|
||||
struct us_internal_ssl_socket_context_t *context,
|
||||
us_internal_ssl_socket_context_r context,
|
||||
struct us_internal_ssl_socket_t *(*on_socket_connect_error)(
|
||||
struct us_internal_ssl_socket_t *s, int code));
|
||||
us_internal_ssl_socket_r s, int code));
|
||||
|
||||
struct us_listen_socket_t *us_internal_ssl_socket_context_listen(
|
||||
struct us_internal_ssl_socket_context_t *context, const char *host,
|
||||
us_internal_ssl_socket_context_r context, const char *host,
|
||||
int port, int options, int socket_ext_size);
|
||||
|
||||
struct us_listen_socket_t *us_internal_ssl_socket_context_listen_unix(
|
||||
struct us_internal_ssl_socket_context_t *context, const char *path,
|
||||
us_internal_ssl_socket_context_r context, const char *path,
|
||||
size_t pathlen, int options, int socket_ext_size);
|
||||
|
||||
struct us_connecting_socket_t *us_internal_ssl_socket_context_connect(
|
||||
struct us_internal_ssl_socket_context_t *context, const char *host,
|
||||
us_internal_ssl_socket_context_r context, const char *host,
|
||||
int port, int options, int socket_ext_size, int* is_resolved);
|
||||
|
||||
struct us_internal_ssl_socket_t *us_internal_ssl_socket_context_connect_unix(
|
||||
struct us_internal_ssl_socket_context_t *context, const char *server_path,
|
||||
us_internal_ssl_socket_context_r context, const char *server_path,
|
||||
size_t pathlen, int options, int socket_ext_size);
|
||||
|
||||
int us_internal_ssl_socket_write(struct us_internal_ssl_socket_t *s,
|
||||
int us_internal_ssl_socket_write(us_internal_ssl_socket_r s,
|
||||
const char *data, int length, int msg_more);
|
||||
int us_internal_ssl_socket_raw_write(struct us_internal_ssl_socket_t *s,
|
||||
int us_internal_ssl_socket_raw_write(us_internal_ssl_socket_r s,
|
||||
const char *data, int length,
|
||||
int msg_more);
|
||||
|
||||
void us_internal_ssl_socket_timeout(struct us_internal_ssl_socket_t *s,
|
||||
void us_internal_ssl_socket_timeout(us_internal_ssl_socket_r s,
|
||||
unsigned int seconds);
|
||||
void *
|
||||
us_internal_ssl_socket_context_ext(struct us_internal_ssl_socket_context_t *s);
|
||||
struct us_internal_ssl_socket_context_t *
|
||||
us_internal_ssl_socket_get_context(struct us_internal_ssl_socket_t *s);
|
||||
void *us_internal_ssl_socket_ext(struct us_internal_ssl_socket_t *s);
|
||||
us_internal_ssl_socket_get_context(us_internal_ssl_socket_r s);
|
||||
void *us_internal_ssl_socket_ext(us_internal_ssl_socket_r s);
|
||||
void *us_internal_connecting_ssl_socket_ext(struct us_connecting_socket_t *c);
|
||||
int us_internal_ssl_socket_is_shut_down(struct us_internal_ssl_socket_t *s);
|
||||
void us_internal_ssl_socket_shutdown(struct us_internal_ssl_socket_t *s);
|
||||
int us_internal_ssl_socket_is_shut_down(us_internal_ssl_socket_r s);
|
||||
int us_internal_ssl_socket_is_closed(us_internal_ssl_socket_r s);
|
||||
void us_internal_ssl_socket_shutdown(us_internal_ssl_socket_r s);
|
||||
|
||||
struct us_internal_ssl_socket_t *us_internal_ssl_socket_context_adopt_socket(
|
||||
struct us_internal_ssl_socket_context_t *context,
|
||||
struct us_internal_ssl_socket_t *s, int ext_size);
|
||||
us_internal_ssl_socket_context_r context,
|
||||
us_internal_ssl_socket_r s, int ext_size);
|
||||
|
||||
struct us_internal_ssl_socket_t *us_internal_ssl_socket_wrap_with_tls(
|
||||
struct us_socket_t *s, struct us_bun_socket_context_options_t options,
|
||||
us_socket_r s, struct us_bun_socket_context_options_t options,
|
||||
struct us_socket_events_t events, int socket_ext_size);
|
||||
struct us_internal_ssl_socket_context_t *
|
||||
us_internal_create_child_ssl_socket_context(
|
||||
struct us_internal_ssl_socket_context_t *context, int context_ext_size);
|
||||
us_internal_ssl_socket_context_r context, int context_ext_size);
|
||||
struct us_loop_t *us_internal_ssl_socket_context_loop(
|
||||
struct us_internal_ssl_socket_context_t *context);
|
||||
us_internal_ssl_socket_context_r context);
|
||||
struct us_internal_ssl_socket_t *
|
||||
us_internal_ssl_socket_open(struct us_internal_ssl_socket_t *s, int is_client,
|
||||
us_internal_ssl_socket_open(us_internal_ssl_socket_r s, int is_client,
|
||||
char *ip, int ip_length);
|
||||
|
||||
int us_raw_root_certs(struct us_cert_string_t **out);
|
||||
|
||||
@@ -27,6 +27,7 @@ struct us_internal_loop_data_t {
|
||||
int last_write_failed;
|
||||
struct us_socket_context_t *head;
|
||||
struct us_socket_context_t *iterator;
|
||||
struct us_socket_context_t *closed_context_head;
|
||||
char *recv_buf;
|
||||
char *send_buf;
|
||||
void *ssl_data;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#ifndef BSD_H
|
||||
#define BSD_H
|
||||
#pragma once
|
||||
|
||||
// top-most wrapper of bsd-like syscalls
|
||||
|
||||
@@ -25,7 +26,7 @@
|
||||
|
||||
#include "libusockets.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
@@ -34,7 +35,7 @@
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
#define SETSOCKOPT_PTR_TYPE const char *
|
||||
#define LIBUS_SOCKET_ERROR INVALID_SOCKET
|
||||
#else
|
||||
#else /* POSIX */
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
@@ -64,14 +65,76 @@ struct bsd_addr_t {
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
// a.k.a msghdr_x
|
||||
struct mmsghdr {
|
||||
/*
|
||||
* Extended version for sendmsg_x() and recvmsg_x() calls
|
||||
*/
|
||||
struct mmsghdr {
|
||||
struct msghdr msg_hdr;
|
||||
size_t msg_len; /* byte length of buffer in msg_iov */
|
||||
};
|
||||
/*
|
||||
* recvmsg_x() is a system call similar to recvmsg(2) to receive
|
||||
* several datagrams at once in the array of message headers "msgp".
|
||||
*
|
||||
* recvmsg_x() can be used only with protocols handlers that have been specially
|
||||
* modified to support sending and receiving several datagrams at once.
|
||||
*
|
||||
* The size of the array "msgp" is given by the argument "cnt".
|
||||
*
|
||||
* The "flags" arguments supports only the value MSG_DONTWAIT.
|
||||
*
|
||||
* Each member of "msgp" array is of type "struct msghdr_x".
|
||||
*
|
||||
* The "msg_iov" and "msg_iovlen" are input parameters that describe where to
|
||||
* store a datagram in a scatter gather locations of buffers -- see recvmsg(2).
|
||||
* On output the field "msg_datalen" gives the length of the received datagram.
|
||||
*
|
||||
* The field "msg_flags" must be set to zero on input. On output, "msg_flags"
|
||||
* may have MSG_TRUNC set to indicate the trailing portion of the datagram was
|
||||
* discarded because the datagram was larger than the buffer supplied.
|
||||
* recvmsg_x() returns as soon as a datagram is truncated.
|
||||
*
|
||||
* recvmsg_x() may return with less than "cnt" datagrams received based on
|
||||
* the low water mark and the amount of data pending in the socket buffer.
|
||||
*
|
||||
* recvmsg_x() returns the number of datagrams that have been received,
|
||||
* or -1 if an error occurred.
|
||||
*
|
||||
* NOTE: This a private system call, the API is subject to change.
|
||||
*/
|
||||
ssize_t recvmsg_x(int s, const struct mmsghdr *msgp, u_int cnt, int flags);
|
||||
|
||||
ssize_t sendmsg_x(int s, struct mmsghdr *msgp, u_int cnt, int flags);
|
||||
ssize_t recvmsg_x(int s, struct mmsghdr *msgp, u_int cnt, int flags);
|
||||
/*
|
||||
* sendmsg_x() is a system call similar to send(2) to send
|
||||
* several datagrams at once in the array of message headers "msgp".
|
||||
*
|
||||
* sendmsg_x() can be used only with protocols handlers that have been specially
|
||||
* modified to support sending and receiving several datagrams at once.
|
||||
*
|
||||
* The size of the array "msgp" is given by the argument "cnt".
|
||||
*
|
||||
* The "flags" arguments supports only the value MSG_DONTWAIT.
|
||||
*
|
||||
* Each member of "msgp" array is of type "struct msghdr_x".
|
||||
*
|
||||
* The "msg_iov" and "msg_iovlen" are input parameters that specify the
|
||||
* data to be sent in a scatter gather locations of buffers -- see sendmsg(2).
|
||||
*
|
||||
* sendmsg_x() fails with EMSGSIZE if the sum of the length of the datagrams
|
||||
* is greater than the high water mark.
|
||||
*
|
||||
* Address and ancillary data are not supported so the following fields
|
||||
* must be set to zero on input:
|
||||
* "msg_name", "msg_namelen", "msg_control" and "msg_controllen".
|
||||
*
|
||||
* The field "msg_flags" and "msg_datalen" must be set to zero on input.
|
||||
*
|
||||
* sendmsg_x() returns the number of datagrams that have been sent,
|
||||
* or -1 if an error occurred.
|
||||
*
|
||||
* NOTE: This a private system call, the API is subject to change.
|
||||
*/
|
||||
ssize_t sendmsg_x(int s, const struct mmsghdr *msgp, u_int cnt, int flags);
|
||||
#endif
|
||||
|
||||
struct udp_recvbuf {
|
||||
@@ -95,8 +158,9 @@ struct udp_sendbuf {
|
||||
void **addresses;
|
||||
int num;
|
||||
#else
|
||||
int num;
|
||||
char has_empty;
|
||||
unsigned int has_empty : 1;
|
||||
unsigned int has_addresses : 1;
|
||||
unsigned int num;
|
||||
struct mmsghdr msgvec[];
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
// clang-format off
|
||||
|
||||
#pragma once
|
||||
#ifndef us_calloc
|
||||
#define us_calloc calloc
|
||||
#endif
|
||||
@@ -35,6 +35,25 @@
|
||||
#ifndef LIBUSOCKETS_H
|
||||
#define LIBUSOCKETS_H
|
||||
|
||||
#ifdef BUN_DEBUG
|
||||
#define nonnull_arg _Nonnull
|
||||
#else
|
||||
#define nonnull_arg
|
||||
#endif
|
||||
|
||||
#ifdef BUN_DEBUG
|
||||
#define nonnull_fn_decl
|
||||
#else
|
||||
#ifndef nonnull_fn_decl
|
||||
#define nonnull_fn_decl __attribute__((nonnull))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define us_loop_r struct us_loop_t *nonnull_arg
|
||||
#define us_socket_r struct us_socket_t *nonnull_arg
|
||||
#define us_poll_r struct us_poll_t *nonnull_arg
|
||||
#define us_socket_context_r struct us_socket_context_t *nonnull_arg
|
||||
|
||||
|
||||
/* 512kb shared receive buffer */
|
||||
#define LIBUS_RECV_BUFFER_LENGTH 524288
|
||||
@@ -49,6 +68,7 @@
|
||||
#define LIBUS_EXT_ALIGNMENT 16
|
||||
#define ALLOW_SERVER_RENEGOTIATION 0
|
||||
|
||||
#define LIBUS_SOCKET_CLOSE_CODE_CLEAN_SHUTDOWN 0
|
||||
#define LIBUS_SOCKET_CLOSE_CODE_CONNECTION_RESET 1
|
||||
|
||||
/* Define what a socket descriptor is based on platform */
|
||||
@@ -123,11 +143,11 @@ struct us_udp_packet_buffer_t *us_create_udp_packet_buffer();
|
||||
/* Creates a (heavy-weight) UDP socket with a user space ring buffer. Again, this one is heavy weight and
|
||||
* shoud be reused. One entire QUIC server can be implemented using only one single UDP socket so weight
|
||||
* is not a concern as is the case for TCP sockets which are 1-to-1 with TCP connections. */
|
||||
//struct us_udp_socket_t *us_create_udp_socket(struct us_loop_t *loop, void (*read_cb)(struct us_udp_socket_t *), unsigned short port);
|
||||
//struct us_udp_socket_t *us_create_udp_socket(us_loop_r loop, void (*read_cb)(struct us_udp_socket_t *), unsigned short port);
|
||||
|
||||
//struct us_udp_socket_t *us_create_udp_socket(struct us_loop_t *loop, void (*data_cb)(struct us_udp_socket_t *, struct us_udp_packet_buffer_t *, int), void (*drain_cb)(struct us_udp_socket_t *), char *host, unsigned short port);
|
||||
//struct us_udp_socket_t *us_create_udp_socket(us_loop_r loop, void (*data_cb)(struct us_udp_socket_t *, struct us_udp_packet_buffer_t *, int), void (*drain_cb)(struct us_udp_socket_t *), char *host, unsigned short port);
|
||||
|
||||
struct us_udp_socket_t *us_create_udp_socket(struct us_loop_t *loop, void (*data_cb)(struct us_udp_socket_t *, void *, int), void (*drain_cb)(struct us_udp_socket_t *), void (*close_cb)(struct us_udp_socket_t *), const char *host, unsigned short port, void *user);
|
||||
struct us_udp_socket_t *us_create_udp_socket(us_loop_r loop, void (*data_cb)(struct us_udp_socket_t *, void *, int), void (*drain_cb)(struct us_udp_socket_t *), void (*close_cb)(struct us_udp_socket_t *), const char *host, unsigned short port, void *user);
|
||||
|
||||
void us_udp_socket_close(struct us_udp_socket_t *s);
|
||||
|
||||
@@ -140,7 +160,7 @@ int us_udp_socket_bind(struct us_udp_socket_t *s, const char *hostname, unsigned
|
||||
/* Public interfaces for timers */
|
||||
|
||||
/* Create a new high precision, low performance timer. May fail and return null */
|
||||
struct us_timer_t *us_create_timer(struct us_loop_t *loop, int fallthrough, unsigned int ext_size);
|
||||
struct us_timer_t *us_create_timer(us_loop_r loop, int fallthrough, unsigned int ext_size);
|
||||
|
||||
/* Returns user data extension for this timer */
|
||||
void *us_timer_ext(struct us_timer_t *timer);
|
||||
@@ -174,17 +194,17 @@ struct us_bun_verify_error_t {
|
||||
};
|
||||
|
||||
struct us_socket_events_t {
|
||||
struct us_socket_t *(*on_open)(struct us_socket_t *, int is_client, char *ip, int ip_length);
|
||||
struct us_socket_t *(*on_data)(struct us_socket_t *, char *data, int length);
|
||||
struct us_socket_t *(*on_writable)(struct us_socket_t *);
|
||||
struct us_socket_t *(*on_close)(struct us_socket_t *, int code, void *reason);
|
||||
struct us_socket_t *(*on_open)(us_socket_r, int is_client, char *ip, int ip_length);
|
||||
struct us_socket_t *(*on_data)(us_socket_r, char *data, int length);
|
||||
struct us_socket_t *(*on_writable)(us_socket_r);
|
||||
struct us_socket_t *(*on_close)(us_socket_r, int code, void *reason);
|
||||
//void (*on_timeout)(struct us_socket_context *);
|
||||
struct us_socket_t *(*on_timeout)(struct us_socket_t *);
|
||||
struct us_socket_t *(*on_long_timeout)(struct us_socket_t *);
|
||||
struct us_socket_t *(*on_end)(struct us_socket_t *);
|
||||
struct us_socket_t *(*on_timeout)(us_socket_r);
|
||||
struct us_socket_t *(*on_long_timeout)(us_socket_r);
|
||||
struct us_socket_t *(*on_end)(us_socket_r);
|
||||
struct us_connecting_socket_t *(*on_connect_error)(struct us_connecting_socket_t *, int code);
|
||||
struct us_socket_t *(*on_connecting_socket_error)(struct us_socket_t *, int code);
|
||||
void (*on_handshake)(struct us_socket_t*, int success, struct us_bun_verify_error_t verify_error, void* custom_data);
|
||||
struct us_socket_t *(*on_connecting_socket_error)(us_socket_r, int code);
|
||||
void (*on_handshake)(us_socket_r, int success, struct us_bun_verify_error_t verify_error, void* custom_data);
|
||||
};
|
||||
|
||||
|
||||
@@ -210,67 +230,70 @@ struct us_bun_socket_context_options_t {
|
||||
};
|
||||
|
||||
/* Return 15-bit timestamp for this context */
|
||||
unsigned short us_socket_context_timestamp(int ssl, struct us_socket_context_t *context);
|
||||
unsigned short us_socket_context_timestamp(int ssl, us_socket_context_r context) nonnull_fn_decl;
|
||||
|
||||
/* Adds SNI domain and cert in asn1 format */
|
||||
void us_socket_context_add_server_name(int ssl, struct us_socket_context_t *context, const char *hostname_pattern, struct us_socket_context_options_t options, void *user);
|
||||
void us_bun_socket_context_add_server_name(int ssl, struct us_socket_context_t *context, const char *hostname_pattern, struct us_bun_socket_context_options_t options, void *user);
|
||||
void us_socket_context_remove_server_name(int ssl, struct us_socket_context_t *context, const char *hostname_pattern);
|
||||
void us_socket_context_on_server_name(int ssl, struct us_socket_context_t *context, void (*cb)(struct us_socket_context_t *, const char *hostname));
|
||||
void *us_socket_server_name_userdata(int ssl, struct us_socket_t *s);
|
||||
void *us_socket_context_find_server_name_userdata(int ssl, struct us_socket_context_t *context, const char *hostname_pattern);
|
||||
void us_socket_context_add_server_name(int ssl, us_socket_context_r context, const char *hostname_pattern, struct us_socket_context_options_t options, void *user);
|
||||
void us_bun_socket_context_add_server_name(int ssl, us_socket_context_r context, const char *hostname_pattern, struct us_bun_socket_context_options_t options, void *user);
|
||||
void us_socket_context_remove_server_name(int ssl, us_socket_context_r context, const char *hostname_pattern);
|
||||
void us_socket_context_on_server_name(int ssl, us_socket_context_r context, void (*cb)(us_socket_context_r context, const char *hostname));
|
||||
void *us_socket_server_name_userdata(int ssl, us_socket_r s);
|
||||
void *us_socket_context_find_server_name_userdata(int ssl, us_socket_context_r context, const char *hostname_pattern);
|
||||
|
||||
/* Returns the underlying SSL native handle, such as SSL_CTX or nullptr */
|
||||
void *us_socket_context_get_native_handle(int ssl, struct us_socket_context_t *context);
|
||||
void *us_socket_context_get_native_handle(int ssl, us_socket_context_r context);
|
||||
|
||||
/* A socket context holds shared callbacks and user data extension for associated sockets */
|
||||
struct us_socket_context_t *us_create_socket_context(int ssl, struct us_loop_t *loop,
|
||||
int ext_size, struct us_socket_context_options_t options);
|
||||
struct us_socket_context_t *us_create_socket_context(int ssl, us_loop_r loop,
|
||||
int ext_size, struct us_socket_context_options_t options) nonnull_fn_decl;
|
||||
struct us_socket_context_t *us_create_bun_socket_context(int ssl, struct us_loop_t *loop,
|
||||
int ext_size, struct us_bun_socket_context_options_t options);
|
||||
int ext_size, struct us_bun_socket_context_options_t options) nonnull_fn_decl;
|
||||
|
||||
/* Delete resources allocated at creation time (will call unref now and only free when ref count == 0). */
|
||||
void us_socket_context_free(int ssl, us_socket_context_r context) nonnull_fn_decl;
|
||||
void us_socket_context_ref(int ssl, us_socket_context_r context) nonnull_fn_decl;
|
||||
void us_socket_context_unref(int ssl, us_socket_context_r context) nonnull_fn_decl;
|
||||
|
||||
/* Delete resources allocated at creation time. */
|
||||
void us_socket_context_free(int ssl, struct us_socket_context_t *context);
|
||||
struct us_bun_verify_error_t us_socket_verify_error(int ssl, struct us_socket_t *context);
|
||||
/* Setters of various async callbacks */
|
||||
void us_socket_context_on_open(int ssl, struct us_socket_context_t *context,
|
||||
struct us_socket_t *(*on_open)(struct us_socket_t *s, int is_client, char *ip, int ip_length));
|
||||
void us_socket_context_on_close(int ssl, struct us_socket_context_t *context,
|
||||
struct us_socket_t *(*on_close)(struct us_socket_t *s, int code, void *reason));
|
||||
void us_socket_context_on_data(int ssl, struct us_socket_context_t *context,
|
||||
struct us_socket_t *(*on_data)(struct us_socket_t *s, char *data, int length));
|
||||
void us_socket_context_on_writable(int ssl, struct us_socket_context_t *context,
|
||||
struct us_socket_t *(*on_writable)(struct us_socket_t *s));
|
||||
void us_socket_context_on_timeout(int ssl, struct us_socket_context_t *context,
|
||||
struct us_socket_t *(*on_timeout)(struct us_socket_t *s));
|
||||
void us_socket_context_on_long_timeout(int ssl, struct us_socket_context_t *context,
|
||||
struct us_socket_t *(*on_timeout)(struct us_socket_t *s));
|
||||
void us_socket_context_on_open(int ssl, us_socket_context_r context,
|
||||
struct us_socket_t *(*on_open)(us_socket_r s, int is_client, char *ip, int ip_length));
|
||||
void us_socket_context_on_close(int ssl, us_socket_context_r context,
|
||||
struct us_socket_t *(*on_close)(us_socket_r s, int code, void *reason));
|
||||
void us_socket_context_on_data(int ssl, us_socket_context_r context,
|
||||
struct us_socket_t *(*on_data)(us_socket_r s, char *data, int length));
|
||||
void us_socket_context_on_writable(int ssl, us_socket_context_r context,
|
||||
struct us_socket_t *(*on_writable)(us_socket_r s));
|
||||
void us_socket_context_on_timeout(int ssl, us_socket_context_r context,
|
||||
struct us_socket_t *(*on_timeout)(us_socket_r s));
|
||||
void us_socket_context_on_long_timeout(int ssl, us_socket_context_r context,
|
||||
struct us_socket_t *(*on_timeout)(us_socket_r s));
|
||||
/* This one is only used for when a connecting socket fails in a late stage. */
|
||||
void us_socket_context_on_connect_error(int ssl, struct us_socket_context_t *context,
|
||||
void us_socket_context_on_connect_error(int ssl, us_socket_context_r context,
|
||||
struct us_connecting_socket_t *(*on_connect_error)(struct us_connecting_socket_t *s, int code));
|
||||
void us_socket_context_on_socket_connect_error(int ssl, struct us_socket_context_t *context,
|
||||
struct us_socket_t *(*on_connect_error)(struct us_socket_t *s, int code));
|
||||
void us_socket_context_on_socket_connect_error(int ssl, us_socket_context_r context,
|
||||
struct us_socket_t *(*on_connect_error)(us_socket_r s, int code));
|
||||
|
||||
void us_socket_context_on_handshake(int ssl, struct us_socket_context_t *context, void (*on_handshake)(struct us_socket_t *, int success, struct us_bun_verify_error_t verify_error, void* custom_data), void* custom_data);
|
||||
void us_socket_context_on_handshake(int ssl, us_socket_context_r context, void (*on_handshake)(struct us_socket_t *, int success, struct us_bun_verify_error_t verify_error, void* custom_data), void* custom_data);
|
||||
|
||||
/* Emitted when a socket has been half-closed */
|
||||
void us_socket_context_on_end(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_end)(struct us_socket_t *s));
|
||||
void us_socket_context_on_end(int ssl, us_socket_context_r context, struct us_socket_t *(*on_end)(us_socket_r s));
|
||||
|
||||
/* Returns user data extension for this socket context */
|
||||
void *us_socket_context_ext(int ssl, struct us_socket_context_t *context);
|
||||
void *us_socket_context_ext(int ssl, us_socket_context_r context);
|
||||
|
||||
/* Closes all open sockets, including listen sockets. Does not invalidate the socket context. */
|
||||
void us_socket_context_close(int ssl, struct us_socket_context_t *context);
|
||||
void us_socket_context_close(int ssl, us_socket_context_r context);
|
||||
|
||||
/* Listen for connections. Acts as the main driving cog in a server. Will call set async callbacks. */
|
||||
struct us_listen_socket_t *us_socket_context_listen(int ssl, struct us_socket_context_t *context,
|
||||
struct us_listen_socket_t *us_socket_context_listen(int ssl, us_socket_context_r context,
|
||||
const char *host, int port, int options, int socket_ext_size);
|
||||
|
||||
struct us_listen_socket_t *us_socket_context_listen_unix(int ssl, struct us_socket_context_t *context,
|
||||
struct us_listen_socket_t *us_socket_context_listen_unix(int ssl, us_socket_context_r context,
|
||||
const char *path, size_t pathlen, int options, int socket_ext_size);
|
||||
|
||||
/* listen_socket.c/.h */
|
||||
void us_listen_socket_close(int ssl, struct us_listen_socket_t *ls);
|
||||
void us_listen_socket_close(int ssl, struct us_listen_socket_t *ls) nonnull_fn_decl;
|
||||
|
||||
/*
|
||||
Returns one of
|
||||
@@ -281,156 +304,156 @@ void us_listen_socket_close(int ssl, struct us_listen_socket_t *ls);
|
||||
This is the slow path where we must either go through DNS resolution or create multiple sockets
|
||||
per the happy eyeballs algorithm
|
||||
*/
|
||||
void *us_socket_context_connect(int ssl, struct us_socket_context_t *context,
|
||||
const char *host, int port, int options, int socket_ext_size, int *is_connecting);
|
||||
void *us_socket_context_connect(int ssl, struct us_socket_context_t * nonnull_arg context,
|
||||
const char *host, int port, int options, int socket_ext_size, int *is_connecting) __attribute__((nonnull(2)));
|
||||
|
||||
struct us_socket_t *us_socket_context_connect_unix(int ssl, struct us_socket_context_t *context,
|
||||
const char *server_path, size_t pathlen, int options, int socket_ext_size);
|
||||
struct us_socket_t *us_socket_context_connect_unix(int ssl, us_socket_context_r context,
|
||||
const char *server_path, size_t pathlen, int options, int socket_ext_size) __attribute__((nonnull(2)));
|
||||
|
||||
/* Is this socket established? Can be used to check if a connecting socket has fired the on_open event yet.
|
||||
* Can also be used to determine if a socket is a listen_socket or not, but you probably know that already. */
|
||||
int us_socket_is_established(int ssl, struct us_socket_t *s);
|
||||
int us_socket_is_established(int ssl, us_socket_r s) nonnull_fn_decl;
|
||||
|
||||
void us_connecting_socket_free(struct us_connecting_socket_t *c);
|
||||
void us_connecting_socket_free(struct us_connecting_socket_t *c) nonnull_fn_decl;
|
||||
|
||||
/* Cancel a connecting socket. Can be used together with us_socket_timeout to limit connection times.
|
||||
* Entirely destroys the socket - this function works like us_socket_close but does not trigger on_close event since
|
||||
* you never got the on_open event first. */
|
||||
void us_connecting_socket_close(int ssl, struct us_connecting_socket_t *c);
|
||||
void us_connecting_socket_close(int ssl, struct us_connecting_socket_t *c) nonnull_fn_decl;
|
||||
|
||||
/* Returns the loop for this socket context. */
|
||||
struct us_loop_t *us_socket_context_loop(int ssl, struct us_socket_context_t *context);
|
||||
struct us_loop_t *us_socket_context_loop(int ssl, us_socket_context_r context) nonnull_fn_decl __attribute((returns_nonnull));
|
||||
|
||||
/* Invalidates passed socket, returning a new resized socket which belongs to a different socket context.
|
||||
* Used mainly for "socket upgrades" such as when transitioning from HTTP to WebSocket. */
|
||||
struct us_socket_t *us_socket_context_adopt_socket(int ssl, struct us_socket_context_t *context, struct us_socket_t *s, int ext_size);
|
||||
struct us_socket_t *us_socket_context_adopt_socket(int ssl, us_socket_context_r context, us_socket_r s, int ext_size);
|
||||
|
||||
/* Create a child socket context which acts much like its own socket context with its own callbacks yet still relies on the
|
||||
* parent socket context for some shared resources. Child socket contexts should be used together with socket adoptions and nothing else. */
|
||||
struct us_socket_context_t *us_create_child_socket_context(int ssl, struct us_socket_context_t *context, int context_ext_size);
|
||||
struct us_socket_context_t *us_create_child_socket_context(int ssl, us_socket_context_r context, int context_ext_size);
|
||||
|
||||
/* Public interfaces for loops */
|
||||
|
||||
/* Returns a new event loop with user data extension */
|
||||
struct us_loop_t *us_create_loop(void *hint, void (*wakeup_cb)(struct us_loop_t *loop),
|
||||
void (*pre_cb)(struct us_loop_t *loop), void (*post_cb)(struct us_loop_t *loop), unsigned int ext_size);
|
||||
struct us_loop_t *us_create_loop(void *hint, void (*wakeup_cb)(us_loop_r loop),
|
||||
void (*pre_cb)(us_loop_r loop), void (*post_cb)(us_loop_r loop), unsigned int ext_size);
|
||||
|
||||
/* Frees the loop immediately */
|
||||
void us_loop_free(struct us_loop_t *loop);
|
||||
void us_loop_free(us_loop_r loop) nonnull_fn_decl;
|
||||
|
||||
/* Returns the loop user data extension */
|
||||
void *us_loop_ext(struct us_loop_t *loop);
|
||||
void *us_loop_ext(us_loop_r loop) nonnull_fn_decl;
|
||||
|
||||
/* Blocks the calling thread and drives the event loop until no more non-fallthrough polls are scheduled */
|
||||
void us_loop_run(struct us_loop_t *loop);
|
||||
void us_loop_run(us_loop_r loop) nonnull_fn_decl;
|
||||
|
||||
|
||||
/* Signals the loop from any thread to wake up and execute its wakeup handler from the loop's own running thread.
|
||||
* This is the only fully thread-safe function and serves as the basis for thread safety */
|
||||
void us_wakeup_loop(struct us_loop_t *loop);
|
||||
void us_wakeup_loop(us_loop_r loop) nonnull_fn_decl;
|
||||
|
||||
/* Hook up timers in existing loop */
|
||||
void us_loop_integrate(struct us_loop_t *loop);
|
||||
void us_loop_integrate(us_loop_r loop) nonnull_fn_decl;
|
||||
|
||||
/* Returns the loop iteration number */
|
||||
long long us_loop_iteration_number(struct us_loop_t *loop);
|
||||
long long us_loop_iteration_number(us_loop_r loop) nonnull_fn_decl;
|
||||
|
||||
/* Public interfaces for polls */
|
||||
|
||||
/* A fallthrough poll does not keep the loop running, it falls through */
|
||||
struct us_poll_t *us_create_poll(struct us_loop_t *loop, int fallthrough, unsigned int ext_size);
|
||||
struct us_poll_t *us_create_poll(us_loop_r loop, int fallthrough, unsigned int ext_size);
|
||||
|
||||
/* After stopping a poll you must manually free the memory */
|
||||
void us_poll_free(struct us_poll_t *p, struct us_loop_t *loop);
|
||||
void us_poll_free(us_poll_r p, struct us_loop_t *loop);
|
||||
|
||||
/* Associate this poll with a socket descriptor and poll type */
|
||||
void us_poll_init(struct us_poll_t *p, LIBUS_SOCKET_DESCRIPTOR fd, int poll_type);
|
||||
void us_poll_init(us_poll_r p, LIBUS_SOCKET_DESCRIPTOR fd, int poll_type);
|
||||
|
||||
/* Start, change and stop polling for events */
|
||||
void us_poll_start(struct us_poll_t *p, struct us_loop_t *loop, int events);
|
||||
void us_poll_change(struct us_poll_t *p, struct us_loop_t *loop, int events);
|
||||
void us_poll_stop(struct us_poll_t *p, struct us_loop_t *loop);
|
||||
void us_poll_start(us_poll_r p, us_loop_r loop, int events) nonnull_fn_decl;
|
||||
void us_poll_change(us_poll_r p, us_loop_r loop, int events) nonnull_fn_decl;
|
||||
void us_poll_stop(us_poll_r p, struct us_loop_t *loop) nonnull_fn_decl;
|
||||
|
||||
/* Return what events we are polling for */
|
||||
int us_poll_events(struct us_poll_t *p);
|
||||
int us_poll_events(us_poll_r p) nonnull_fn_decl;
|
||||
|
||||
/* Returns the user data extension of this poll */
|
||||
void *us_poll_ext(struct us_poll_t *p);
|
||||
void *us_poll_ext(us_poll_r p) nonnull_fn_decl;
|
||||
|
||||
/* Get associated socket descriptor from a poll */
|
||||
LIBUS_SOCKET_DESCRIPTOR us_poll_fd(struct us_poll_t *p);
|
||||
LIBUS_SOCKET_DESCRIPTOR us_poll_fd(us_poll_r p) nonnull_fn_decl;
|
||||
|
||||
/* Resize an active poll */
|
||||
struct us_poll_t *us_poll_resize(struct us_poll_t *p, struct us_loop_t *loop, unsigned int ext_size);
|
||||
struct us_poll_t *us_poll_resize(us_poll_r p, us_loop_r loop, unsigned int ext_size) nonnull_fn_decl;
|
||||
|
||||
/* Public interfaces for sockets */
|
||||
|
||||
/* Returns the underlying native handle for a socket, such as SSL or file descriptor.
|
||||
* In the case of file descriptor, the value of pointer is fd. */
|
||||
void *us_socket_get_native_handle(int ssl, struct us_socket_t *s);
|
||||
void *us_socket_get_native_handle(int ssl, us_socket_r s) nonnull_fn_decl;
|
||||
|
||||
/* Write up to length bytes of data. Returns actual bytes written.
|
||||
* Will call the on_writable callback of active socket context on failure to write everything off in one go.
|
||||
* Set hint msg_more if you have more immediate data to write. */
|
||||
int us_socket_write(int ssl, struct us_socket_t *s, const char *data, int length, int msg_more);
|
||||
int us_socket_write(int ssl, us_socket_r s, const char * nonnull_arg data, int length, int msg_more) nonnull_fn_decl;
|
||||
|
||||
/* Special path for non-SSL sockets. Used to send header and payload in one go. Works like us_socket_write. */
|
||||
int us_socket_write2(int ssl, struct us_socket_t *s, const char *header, int header_length, const char *payload, int payload_length);
|
||||
int us_socket_write2(int ssl, us_socket_r s, const char *header, int header_length, const char *payload, int payload_length) nonnull_fn_decl;
|
||||
|
||||
/* Set a low precision, high performance timer on a socket. A socket can only have one single active timer
|
||||
* at any given point in time. Will remove any such pre set timer */
|
||||
void us_socket_timeout(int ssl, struct us_socket_t *s, unsigned int seconds);
|
||||
void us_socket_timeout(int ssl, us_socket_r s, unsigned int seconds) nonnull_fn_decl;
|
||||
|
||||
/* Set a low precision, high performance timer on a socket. Suitable for per-minute precision. */
|
||||
void us_socket_long_timeout(int ssl, struct us_socket_t *s, unsigned int minutes);
|
||||
void us_socket_long_timeout(int ssl, us_socket_r s, unsigned int minutes) nonnull_fn_decl;
|
||||
|
||||
/* Return the user data extension of this socket */
|
||||
void *us_socket_ext(int ssl, struct us_socket_t *s);
|
||||
void *us_connecting_socket_ext(int ssl, struct us_connecting_socket_t *c);
|
||||
void *us_socket_ext(int ssl, us_socket_r s) nonnull_fn_decl;
|
||||
void *us_connecting_socket_ext(int ssl, struct us_connecting_socket_t *c) nonnull_fn_decl;
|
||||
|
||||
/* Return the socket context of this socket */
|
||||
struct us_socket_context_t *us_socket_context(int ssl, struct us_socket_t *s);
|
||||
struct us_socket_context_t *us_socket_context(int ssl, us_socket_r s) nonnull_fn_decl __attribute__((returns_nonnull));
|
||||
|
||||
/* Withdraw any msg_more status and flush any pending data */
|
||||
void us_socket_flush(int ssl, struct us_socket_t *s);
|
||||
void us_socket_flush(int ssl, us_socket_r s) nonnull_fn_decl;
|
||||
|
||||
/* Shuts down the connection by sending FIN and/or close_notify */
|
||||
void us_socket_shutdown(int ssl, struct us_socket_t *s);
|
||||
void us_socket_shutdown(int ssl, us_socket_r s) nonnull_fn_decl;
|
||||
|
||||
/* Shuts down the connection in terms of read, meaning next event loop
|
||||
* iteration will catch the socket being closed. Can be used to defer closing
|
||||
* to next event loop iteration. */
|
||||
void us_socket_shutdown_read(int ssl, struct us_socket_t *s);
|
||||
void us_socket_shutdown_read(int ssl, us_socket_r s) nonnull_fn_decl;
|
||||
|
||||
/* Returns whether the socket has been shut down or not */
|
||||
int us_socket_is_shut_down(int ssl, struct us_socket_t *s);
|
||||
int us_socket_is_shut_down(int ssl, us_socket_r s) nonnull_fn_decl;
|
||||
|
||||
/* Returns whether this socket has been closed. Only valid if memory has not yet been released. */
|
||||
int us_socket_is_closed(int ssl, struct us_socket_t *s);
|
||||
int us_socket_is_closed(int ssl, us_socket_r s) nonnull_fn_decl;
|
||||
|
||||
/* Immediately closes the socket */
|
||||
struct us_socket_t *us_socket_close(int ssl, struct us_socket_t *s, int code, void *reason);
|
||||
struct us_socket_t *us_socket_close(int ssl, us_socket_r s, int code, void *reason) __attribute__((nonnull(2)));
|
||||
|
||||
/* Returns local port or -1 on failure. */
|
||||
int us_socket_local_port(int ssl, struct us_socket_t *s);
|
||||
int us_socket_local_port(int ssl, us_socket_r s) nonnull_fn_decl;
|
||||
|
||||
/* Copy remote (IP) address of socket, or fail with zero length. */
|
||||
void us_socket_remote_address(int ssl, struct us_socket_t *s, char *buf, int *length);
|
||||
void us_socket_local_address(int ssl, struct us_socket_t *s, char *buf, int *length);
|
||||
void us_socket_remote_address(int ssl, us_socket_r s, char *nonnull_arg buf, int *nonnull_arg length) nonnull_fn_decl;
|
||||
void us_socket_local_address(int ssl, us_socket_r s, char *nonnull_arg buf, int *nonnull_arg length) nonnull_fn_decl;
|
||||
|
||||
/* Bun extras */
|
||||
struct us_socket_t *us_socket_pair(struct us_socket_context_t *ctx, int socket_ext_size, LIBUS_SOCKET_DESCRIPTOR* fds);
|
||||
struct us_socket_t *us_socket_from_fd(struct us_socket_context_t *ctx, int socket_ext_size, LIBUS_SOCKET_DESCRIPTOR fd);
|
||||
struct us_socket_t *us_socket_attach(int ssl, LIBUS_SOCKET_DESCRIPTOR client_fd, struct us_socket_context_t *ctx, int flags, int socket_ext_size);
|
||||
struct us_socket_t *us_socket_wrap_with_tls(int ssl, struct us_socket_t *s, struct us_bun_socket_context_options_t options, struct us_socket_events_t events, int socket_ext_size);
|
||||
int us_socket_raw_write(int ssl, struct us_socket_t *s, const char *data, int length, int msg_more);
|
||||
struct us_socket_t *us_socket_wrap_with_tls(int ssl, us_socket_r s, struct us_bun_socket_context_options_t options, struct us_socket_events_t events, int socket_ext_size);
|
||||
int us_socket_raw_write(int ssl, us_socket_r s, const char *data, int length, int msg_more);
|
||||
struct us_socket_t* us_socket_open(int ssl, struct us_socket_t * s, int is_client, char* ip, int ip_length);
|
||||
int us_raw_root_certs(struct us_cert_string_t**out);
|
||||
unsigned int us_get_remote_address_info(char *buf, struct us_socket_t *s, const char **dest, int *port, int *is_ipv6);
|
||||
int us_socket_get_error(int ssl, struct us_socket_t *s);
|
||||
unsigned int us_get_remote_address_info(char *buf, us_socket_r s, const char **dest, int *port, int *is_ipv6);
|
||||
int us_socket_get_error(int ssl, us_socket_r s);
|
||||
|
||||
void us_socket_ref(struct us_socket_t *s);
|
||||
void us_socket_unref(struct us_socket_t *s);
|
||||
void us_socket_ref(us_socket_r s);
|
||||
void us_socket_unref(us_socket_r s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -47,6 +47,8 @@ void us_internal_loop_data_init(struct us_loop_t *loop, void (*wakeup_cb)(struct
|
||||
loop->data.parent_ptr = 0;
|
||||
loop->data.parent_tag = 0;
|
||||
|
||||
loop->data.closed_context_head = 0;
|
||||
|
||||
loop->data.wakeup_async = us_internal_create_async(loop, 1, 0);
|
||||
us_internal_async_set(loop->data.wakeup_async, (void (*)(struct us_internal_async *)) wakeup_cb);
|
||||
}
|
||||
@@ -234,6 +236,15 @@ void us_internal_free_closed_sockets(struct us_loop_t *loop) {
|
||||
loop->data.closed_connecting_head = 0;
|
||||
}
|
||||
|
||||
void us_internal_free_closed_contexts(struct us_loop_t *loop) {
|
||||
for (struct us_socket_context_t *ctx = loop->data.closed_context_head; ctx; ) {
|
||||
struct us_socket_context_t *next = ctx->next;
|
||||
us_free(ctx);
|
||||
ctx = next;
|
||||
}
|
||||
loop->data.closed_context_head = 0;
|
||||
}
|
||||
|
||||
void sweep_timer_cb(struct us_internal_callback_t *cb) {
|
||||
us_internal_timer_sweep(cb->loop);
|
||||
}
|
||||
@@ -253,6 +264,7 @@ void us_internal_loop_pre(struct us_loop_t *loop) {
|
||||
void us_internal_loop_post(struct us_loop_t *loop) {
|
||||
us_internal_handle_dns_results(loop);
|
||||
us_internal_free_closed_sockets(loop);
|
||||
us_internal_free_closed_contexts(loop);
|
||||
loop->data.post_cb(loop);
|
||||
}
|
||||
|
||||
@@ -356,7 +368,8 @@ void us_internal_dispatch_ready_poll(struct us_poll_t *p, int error, int events)
|
||||
s->context->loop->data.low_prio_budget--; /* Still having budget for this iteration - do normal processing */
|
||||
} else {
|
||||
us_poll_change(&s->p, us_socket_context(0, s)->loop, us_poll_events(&s->p) & LIBUS_SOCKET_WRITABLE);
|
||||
us_internal_socket_context_unlink_socket(s->context, s);
|
||||
us_socket_context_ref(0, s->context);
|
||||
us_internal_socket_context_unlink_socket(0, s->context, s);
|
||||
|
||||
/* Link this socket to the low-priority queue - we use a LIFO queue, to prioritize newer clients that are
|
||||
* maybe not already timeouted - sounds unfair, but works better in real-life with smaller client-timeouts
|
||||
@@ -411,7 +424,8 @@ void us_internal_dispatch_ready_poll(struct us_poll_t *p, int error, int events)
|
||||
if (us_socket_is_shut_down(0, s)) {
|
||||
/* We got FIN back after sending it */
|
||||
/* Todo: We should give "CLEAN SHUTDOWN" as reason here */
|
||||
s = us_socket_close(0, s, 0, NULL);
|
||||
s = us_socket_close(0, s, LIBUS_SOCKET_CLOSE_CODE_CLEAN_SHUTDOWN, NULL);
|
||||
return;
|
||||
} else {
|
||||
/* We got FIN, so stop polling for readable */
|
||||
us_poll_change(&s->p, us_socket_context(0, s)->loop, us_poll_events(&s->p) & LIBUS_SOCKET_WRITABLE);
|
||||
@@ -419,7 +433,7 @@ void us_internal_dispatch_ready_poll(struct us_poll_t *p, int error, int events)
|
||||
}
|
||||
} else if (length == LIBUS_SOCKET_ERROR && !bsd_would_block()) {
|
||||
/* Todo: decide also here what kind of reason we should give */
|
||||
s = us_socket_close(0, s, 0, NULL);
|
||||
s = us_socket_close(0, s, LIBUS_SOCKET_CLOSE_CODE_CLEAN_SHUTDOWN, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <fcntl.h>
|
||||
@@ -113,6 +114,9 @@ void us_socket_flush(int ssl, struct us_socket_t *s) {
|
||||
}
|
||||
|
||||
int us_socket_is_closed(int ssl, struct us_socket_t *s) {
|
||||
if(ssl) {
|
||||
return us_internal_ssl_socket_is_closed((struct us_internal_ssl_socket_t *) s);
|
||||
}
|
||||
return s->prev == (struct us_socket_t *) s->context;
|
||||
}
|
||||
|
||||
@@ -137,7 +141,7 @@ void us_connecting_socket_close(int ssl, struct us_connecting_socket_t *c) {
|
||||
c->closed = 1;
|
||||
|
||||
for (struct us_socket_t *s = c->connecting_head; s; s = s->connect_next) {
|
||||
us_internal_socket_context_unlink_socket(s->context, s);
|
||||
us_internal_socket_context_unlink_socket(ssl, s->context, s);
|
||||
us_poll_stop((struct us_poll_t *) s, s->context->loop);
|
||||
bsd_close_socket(us_poll_fd((struct us_poll_t *) s));
|
||||
|
||||
@@ -157,6 +161,9 @@ void us_connecting_socket_close(int ssl, struct us_connecting_socket_t *c) {
|
||||
}
|
||||
|
||||
struct us_socket_t *us_socket_close(int ssl, struct us_socket_t *s, int code, void *reason) {
|
||||
if(ssl) {
|
||||
return (struct us_socket_t *)us_internal_ssl_socket_close((struct us_internal_ssl_socket_t *) s, code, reason);
|
||||
}
|
||||
if (!us_socket_is_closed(0, s)) {
|
||||
if (s->low_prio_state == 1) {
|
||||
/* Unlink this socket from the low-priority queue */
|
||||
@@ -168,8 +175,10 @@ struct us_socket_t *us_socket_close(int ssl, struct us_socket_t *s, int code, vo
|
||||
s->prev = 0;
|
||||
s->next = 0;
|
||||
s->low_prio_state = 0;
|
||||
us_socket_context_unref(ssl, s->context);
|
||||
|
||||
} else {
|
||||
us_internal_socket_context_unlink_socket(s->context, s);
|
||||
us_internal_socket_context_unlink_socket(ssl, s->context, s);
|
||||
}
|
||||
#ifdef LIBUS_USE_KQUEUE
|
||||
// kqueue automatically removes the fd from the set on close
|
||||
@@ -218,8 +227,10 @@ struct us_socket_t *us_socket_detach(int ssl, struct us_socket_t *s) {
|
||||
s->prev = 0;
|
||||
s->next = 0;
|
||||
s->low_prio_state = 0;
|
||||
us_socket_context_unref(ssl, s->context);
|
||||
|
||||
} else {
|
||||
us_internal_socket_context_unlink_socket(s->context, s);
|
||||
us_internal_socket_context_unlink_socket(ssl, s->context, s);
|
||||
}
|
||||
us_poll_stop((struct us_poll_t *) s, s->context->loop);
|
||||
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
CAPI_EXAMPLE_FILES := HelloWorld HelloWorldAsync ServerName UpgradeSync UpgradeAsync EchoServer Broadcast BroadcastEchoServer
|
||||
RUST_EXAMPLE_FILES := RustHelloWorld
|
||||
LIBRARY_NAME := libuwebsockets
|
||||
|
||||
default:
|
||||
$(MAKE) capi
|
||||
$(CXX) -O3 -flto -I ../src -I ../uSockets/src examples/HelloWorld.c *.o -lz -luv -lssl -lcrypto -lstdc++ ../uSockets/uSockets.a -o HelloWorld
|
||||
|
||||
capi:
|
||||
$(MAKE) clean
|
||||
cd ../uSockets && $(CC) -pthread -DUWS_WITH_PROXY -DLIBUS_USE_OPENSSL -DLIBUS_USE_LIBUV -std=c11 -Isrc -flto -fPIC -O3 -c src/*.c src/eventing/*.c src/crypto/*.c
|
||||
cd ../uSockets && $(CXX) -std=c++17 -flto -fPIC -O3 -c src/crypto/*.cpp
|
||||
cd ../uSockets && $(AR) rvs uSockets.a *.o
|
||||
|
||||
$(CXX) -DUWS_WITH_PROXY -c -O3 -std=c++17 -lz -luv -flto -fPIC -I ../src -I ../uSockets/src $(LIBRARY_NAME).cpp
|
||||
$(AR) rvs $(LIBRARY_NAME).a $(LIBRARY_NAME).o ../uSockets/uSockets.a
|
||||
shared:
|
||||
$(MAKE) clean
|
||||
|
||||
cd ../uSockets && $(CC) -pthread -DUWS_WITH_PROXY -DLIBUS_USE_OPENSSL -DLIBUS_USE_LIBUV -std=c11 -Isrc -flto -fPIC -O3 -c src/*.c src/eventing/*.c src/crypto/*.c
|
||||
cd ../uSockets && $(CXX) -std=c++17 -flto -fPIC -O3 -c src/crypto/*.cpp
|
||||
cd ../uSockets && $(AR) rvs uSockets.a *.o
|
||||
|
||||
$(CXX) -DUWS_WITH_PROXY -c -O3 -std=c++17 -lz -luv -flto -fPIC -I ../src -I ../uSockets/src $(LIBRARY_NAME).cpp
|
||||
$(CXX) -shared -o $(LIBRARY_NAME).so $(LIBRARY_NAME).o ../uSockets/uSockets.a -fPIC -lz -luv -lssl -lcrypto
|
||||
misc:
|
||||
mkdir -p ../misc && openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -passout pass:1234 -keyout ../misc/key.pem -out ../misc/cert.pem
|
||||
rust:
|
||||
$(MAKE) capi
|
||||
rustc -C link-arg=$(LIBRARY_NAME).a -C link-args="-lstdc++ -luv" -C opt-level=3 -C lto -L all=. examples/RustHelloWorld.rs -o RustHelloWorld
|
||||
|
||||
clean:
|
||||
rm -f *.o $(CAPI_EXAMPLE_FILES) $(RUST_EXAMPLE_FILES) $(LIBRARY_NAME).a $(LIBRARY_NAME).so
|
||||
|
||||
all:
|
||||
for FILE in $(CAPI_EXAMPLE_FILES); do $(CXX) -O3 -flto -I ../src -I ../uSockets/src examples/$$FILE.c *.o -luv -lstdc++ ../uSockets/uSockets.a -o $$FILE & done; \
|
||||
wait
|
||||
|
||||
@@ -1,157 +0,0 @@
|
||||
#include "../libuwebsockets.h"
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#define SSL 1
|
||||
|
||||
|
||||
//Timer close helper
|
||||
void uws_timer_close(struct us_timer_t *timer)
|
||||
{
|
||||
struct us_timer_t *t = (struct us_timer_t *)timer;
|
||||
struct timer_handler_data *data;
|
||||
memcpy(&data, us_timer_ext(t), sizeof(struct timer_handler_data *));
|
||||
free(data);
|
||||
us_timer_close(t, 0);
|
||||
}
|
||||
//Timer create helper
|
||||
struct us_timer_t *uws_create_timer(int ms, int repeat_ms, void (*handler)(void *data), void *data)
|
||||
{
|
||||
struct us_loop_t *loop = uws_get_loop();
|
||||
struct us_timer_t *delayTimer = us_create_timer(loop, 0, sizeof(void *));
|
||||
|
||||
struct timer_handler_data
|
||||
{
|
||||
void *data;
|
||||
void (*handler)(void *data);
|
||||
bool repeat;
|
||||
};
|
||||
|
||||
struct timer_handler_data *timer_data = (struct timer_handler_data *)malloc(sizeof(timer_handler_data));
|
||||
timer_data->data = data;
|
||||
timer_data->handler = handler;
|
||||
timer_data->repeat = repeat_ms > 0;
|
||||
memcpy(us_timer_ext(delayTimer), &timer_data, sizeof(struct timer_handler_data *));
|
||||
|
||||
us_timer_set(
|
||||
delayTimer, [](struct us_timer_t *t)
|
||||
{
|
||||
/* We wrote the pointer to the timer's extension */
|
||||
struct timer_handler_data *data;
|
||||
memcpy(&data, us_timer_ext(t), sizeof(struct timer_handler_data *));
|
||||
|
||||
data->handler(data->data);
|
||||
|
||||
if (!data->repeat)
|
||||
{
|
||||
free(data);
|
||||
us_timer_close(t, 0);
|
||||
}
|
||||
},
|
||||
ms, repeat_ms);
|
||||
|
||||
return (struct us_timer_t *)delayTimer;
|
||||
}
|
||||
|
||||
/* This is a simple WebSocket "sync" upgrade example.
|
||||
* You may compile it with "WITH_OPENSSL=1 make" or with "make" */
|
||||
|
||||
/* ws->getUserData returns one of these */
|
||||
struct PerSocketData {
|
||||
/* Fill with user data */
|
||||
};
|
||||
|
||||
int buffer_size(const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int result = vsnprintf(NULL, 0, format, args);
|
||||
va_end(args);
|
||||
return result + 1; // safe byte for \0
|
||||
}
|
||||
|
||||
void listen_handler(struct us_listen_socket_t *listen_socket, uws_app_listen_config_t config, void* user_data)
|
||||
{
|
||||
if (listen_socket){
|
||||
printf("Listening on port wss://localhost:%d\n", config.port);
|
||||
}
|
||||
}
|
||||
|
||||
void open_handler(uws_websocket_t* ws){
|
||||
|
||||
/* Open event here, you may access uws_ws_get_user_data(WS) which points to a PerSocketData struct */
|
||||
uws_ws_subscribe(SSL, ws, "broadcast", 9);
|
||||
}
|
||||
|
||||
void message_handler(uws_websocket_t* ws, const char* message, size_t length, uws_opcode_t opcode){
|
||||
}
|
||||
|
||||
void close_handler(uws_websocket_t* ws, int code, const char* message, size_t length){
|
||||
/* You may access uws_ws_get_user_data(ws) here, but sending or
|
||||
* doing any kind of I/O with the socket is not valid. */
|
||||
}
|
||||
|
||||
void drain_handler(uws_websocket_t* ws){
|
||||
/* Check uws_ws_get_buffered_amount(ws) here */
|
||||
}
|
||||
|
||||
void ping_handler(uws_websocket_t* ws, const char* message, size_t length){
|
||||
/* You don't need to handle this one, we automatically respond to pings as per standard */
|
||||
}
|
||||
|
||||
void pong_handler(uws_websocket_t* ws, const char* message, size_t length){
|
||||
|
||||
/* You don't need to handle this one either */
|
||||
}
|
||||
|
||||
void on_timer_interval(void* data){
|
||||
|
||||
// broadcast the unix time as millis
|
||||
|
||||
uws_app_t * app = (uws_app_t *)data;
|
||||
struct timespec ts;
|
||||
timespec_get(&ts, TIME_UTC);
|
||||
|
||||
int64_t millis = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
|
||||
|
||||
|
||||
char* message = (char*)malloc((size_t)buffer_size("%ld", millis));
|
||||
size_t message_length = sprintf(message, "%ld", millis);
|
||||
|
||||
uws_publish(SSL, app, "broadcast", 9, message, message_length, uws_opcode_t::TEXT, false);
|
||||
free(message);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
|
||||
uws_app_t *app = uws_create_app(SSL, (struct us_socket_context_options_t){
|
||||
/* There are example certificates in uWebSockets.js repo */
|
||||
.key_file_name = "../misc/key.pem",
|
||||
.cert_file_name = "../misc/cert.pem",
|
||||
.passphrase = "1234"
|
||||
});
|
||||
|
||||
uws_ws(SSL, app, "/*", (uws_socket_behavior_t){
|
||||
.compression = uws_compress_options_t::SHARED_COMPRESSOR,
|
||||
.maxPayloadLength = 16 * 1024,
|
||||
.idleTimeout = 12,
|
||||
.maxBackpressure = 1 * 1024 * 1024,
|
||||
.upgrade = NULL,
|
||||
.open = open_handler,
|
||||
.message = message_handler,
|
||||
.drain = drain_handler,
|
||||
.ping = ping_handler,
|
||||
.pong = pong_handler,
|
||||
.close = close_handler,
|
||||
});
|
||||
|
||||
uws_app_listen(SSL, app, 9001, listen_handler, NULL);
|
||||
|
||||
// broadcast the unix time as millis every 8 millis
|
||||
uws_create_timer(8, 8, on_timer_interval, app);
|
||||
|
||||
uws_app_run(SSL, app);
|
||||
}
|
||||
@@ -1,175 +0,0 @@
|
||||
#include "../libuwebsockets.h"
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define SSL 1
|
||||
|
||||
|
||||
/* This is a simple WebSocket "sync" upgrade example.
|
||||
* You may compile it with "WITH_OPENSSL=1 make" or with "make" */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t length;
|
||||
char *name;
|
||||
} topic_t;
|
||||
|
||||
/* ws->getUserData returns one of these */
|
||||
struct PerSocketData
|
||||
{
|
||||
/* Fill with user data */
|
||||
topic_t **topics;
|
||||
int topics_quantity;
|
||||
int nr;
|
||||
};
|
||||
|
||||
uws_app_t *app;
|
||||
|
||||
int buffer_size(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int result = vsnprintf(NULL, 0, format, args);
|
||||
va_end(args);
|
||||
return result + 1; // safe byte for \0
|
||||
}
|
||||
|
||||
void listen_handler(struct us_listen_socket_t *listen_socket, uws_app_listen_config_t config, void* user_data)
|
||||
{
|
||||
if (listen_socket)
|
||||
{
|
||||
printf("Listening on port wss://localhost:%d\n", config.port);
|
||||
}
|
||||
}
|
||||
|
||||
void upgrade_handler(uws_res_t *response, uws_req_t *request, uws_socket_context_t *context)
|
||||
{
|
||||
|
||||
/* You may read from req only here, and COPY whatever you need into your PerSocketData.
|
||||
* PerSocketData is valid from .open to .close event, accessed with uws_ws_get_user_data(ws).
|
||||
* HttpRequest (req) is ONLY valid in this very callback, so any data you will need later
|
||||
* has to be COPIED into PerSocketData here. */
|
||||
|
||||
/* Immediately upgrading without doing anything "async" before, is simple */
|
||||
|
||||
struct PerSocketData *data = (struct PerSocketData *)malloc(sizeof(struct PerSocketData));
|
||||
data->topics = (topic_t **)calloc(32, sizeof(topic_t *));
|
||||
data->topics_quantity = 32;
|
||||
data->nr = 0;
|
||||
|
||||
const char *ws_key = NULL;
|
||||
const char *ws_protocol = NULL;
|
||||
const char *ws_extensions = NULL;
|
||||
|
||||
size_t ws_key_length = uws_req_get_header(request, "sec-websocket-key", 17, &ws_key);
|
||||
size_t ws_protocol_length = uws_req_get_header(request, "sec-websocket-protocol", 22, &ws_protocol);
|
||||
size_t ws_extensions_length = uws_req_get_header(request, "sec-websocket-extensions", 24, &ws_extensions);
|
||||
|
||||
uws_res_upgrade(SSL,
|
||||
response,
|
||||
(void *)data,
|
||||
ws_key,
|
||||
ws_key_length,
|
||||
ws_protocol,
|
||||
ws_protocol_length,
|
||||
ws_extensions,
|
||||
ws_extensions_length,
|
||||
context);
|
||||
}
|
||||
|
||||
void open_handler(uws_websocket_t *ws)
|
||||
{
|
||||
|
||||
/* Open event here, you may access uws_ws_get_user_data(ws) which points to a PerSocketData struct */
|
||||
struct PerSocketData *data = (struct PerSocketData *)uws_ws_get_user_data(SSL, ws);
|
||||
for (int i = 0; i < data->topics_quantity; i++)
|
||||
{
|
||||
|
||||
char *topic = (char *)malloc((size_t)buffer_size("%ld-%d", (uintptr_t)ws, i));
|
||||
size_t topic_length = sprintf(topic, "%ld-%d", (uintptr_t)ws, i);
|
||||
|
||||
topic_t *new_topic = (topic_t*) malloc(sizeof(topic_t));
|
||||
new_topic->length = topic_length;
|
||||
new_topic->name = topic;
|
||||
data->topics[i] = new_topic;
|
||||
uws_ws_subscribe(SSL, ws, topic, topic_length);
|
||||
}
|
||||
}
|
||||
|
||||
void message_handler(uws_websocket_t *ws, const char *message, size_t length, uws_opcode_t opcode)
|
||||
{
|
||||
struct PerSocketData *data = (struct PerSocketData *)uws_ws_get_user_data(SSL, ws);
|
||||
topic_t *topic = data->topics[(size_t)(++data->nr % data->topics_quantity)];
|
||||
uws_publish(SSL, app, topic->name, topic->length, message, length, opcode, false);
|
||||
|
||||
topic = data->topics[(size_t)(++data->nr % data->topics_quantity)];
|
||||
uws_ws_publish(SSL, ws, topic->name, topic->length, message, length);
|
||||
}
|
||||
|
||||
void close_handler(uws_websocket_t *ws, int code, const char *message, size_t length)
|
||||
{
|
||||
/* You may access uws_ws_get_user_data(ws) here, but sending or
|
||||
* doing any kind of I/O with the socket is not valid. */
|
||||
struct PerSocketData *data = (struct PerSocketData *)uws_ws_get_user_data(SSL, ws);
|
||||
if (data)
|
||||
{
|
||||
for (int i = 0; i < data->topics_quantity; i++)
|
||||
{
|
||||
|
||||
topic_t* topic = data->topics[i];
|
||||
free(topic->name);
|
||||
free(topic);
|
||||
}
|
||||
free(data->topics);
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
|
||||
void drain_handler(uws_websocket_t *ws)
|
||||
{
|
||||
/* Check uws_ws_get_buffered_amount(ws) here */
|
||||
}
|
||||
|
||||
void ping_handler(uws_websocket_t *ws, const char *message, size_t length)
|
||||
{
|
||||
/* You don't need to handle this one, we automatically respond to pings as per standard */
|
||||
}
|
||||
|
||||
void pong_handler(uws_websocket_t *ws, const char *message, size_t length)
|
||||
{
|
||||
|
||||
/* You don't need to handle this one either */
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
|
||||
uws_app_t *app = uws_create_app(SSL, (struct us_socket_context_options_t){
|
||||
/* There are example certificates in uWebSockets.js repo */
|
||||
.key_file_name = "../misc/key.pem",
|
||||
.cert_file_name = "../misc/cert.pem",
|
||||
.passphrase = "1234"
|
||||
});
|
||||
|
||||
uws_ws(SSL, app, "/*", (uws_socket_behavior_t){
|
||||
.compression = uws_compress_options_t::SHARED_COMPRESSOR,
|
||||
.maxPayloadLength = 16 * 1024,
|
||||
.idleTimeout = 12,
|
||||
.maxBackpressure = 1 * 1024 * 1024,
|
||||
.upgrade = upgrade_handler,
|
||||
.open = open_handler,
|
||||
.message = message_handler,
|
||||
.drain = drain_handler,
|
||||
.ping = ping_handler,
|
||||
.pong = pong_handler,
|
||||
.close = close_handler,
|
||||
});
|
||||
|
||||
uws_app_listen(SSL, app, 9001, listen_handler, NULL);
|
||||
|
||||
uws_app_run(SSL, app);
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
#include "../libuwebsockets.h"
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#define SSL 1
|
||||
|
||||
|
||||
/* This is a simple WebSocket "sync" upgrade example.
|
||||
* You may compile it with "WITH_OPENSSL=1 make" or with "make" */
|
||||
|
||||
/* ws->getUserData returns one of these */
|
||||
struct PerSocketData {
|
||||
/* Fill with user data */
|
||||
};
|
||||
|
||||
void listen_handler(struct us_listen_socket_t *listen_socket, uws_app_listen_config_t config, void* user_data)
|
||||
{
|
||||
if (listen_socket){
|
||||
printf("Listening on port wss://localhost:%d\n", config.port);
|
||||
}
|
||||
}
|
||||
|
||||
void open_handler(uws_websocket_t* ws){
|
||||
|
||||
/* Open event here, you may access uws_ws_get_user_data(WS) which points to a PerSocketData struct */
|
||||
}
|
||||
|
||||
void message_handler(uws_websocket_t* ws, const char* message, size_t length, uws_opcode_t opcode){
|
||||
uws_ws_send(SSL, ws, message, length, opcode);
|
||||
}
|
||||
|
||||
void close_handler(uws_websocket_t* ws, int code, const char* message, size_t length){
|
||||
|
||||
/* You may access uws_ws_get_user_data(ws) here, but sending or
|
||||
* doing any kind of I/O with the socket is not valid. */
|
||||
}
|
||||
|
||||
void drain_handler(uws_websocket_t* ws){
|
||||
/* Check uws_ws_get_buffered_amount(ws) here */
|
||||
}
|
||||
|
||||
void ping_handler(uws_websocket_t* ws, const char* message, size_t length){
|
||||
/* You don't need to handle this one, we automatically respond to pings as per standard */
|
||||
}
|
||||
|
||||
void pong_handler(uws_websocket_t* ws, const char* message, size_t length){
|
||||
|
||||
/* You don't need to handle this one either */
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
|
||||
uws_app_t *app = uws_create_app(SSL, (struct us_socket_context_options_t){
|
||||
/* There are example certificates in uWebSockets.js repo */
|
||||
.key_file_name = "../misc/key.pem",
|
||||
.cert_file_name = "../misc/cert.pem",
|
||||
.passphrase = "1234"
|
||||
});
|
||||
|
||||
uws_ws(SSL, app, "/*", (uws_socket_behavior_t){
|
||||
.compression = uws_compress_options_t::SHARED_COMPRESSOR,
|
||||
.maxPayloadLength = 16 * 1024,
|
||||
.idleTimeout = 12,
|
||||
.maxBackpressure = 1 * 1024 * 1024,
|
||||
.upgrade = NULL,
|
||||
.open = open_handler,
|
||||
.message = message_handler,
|
||||
.drain = drain_handler,
|
||||
.ping = ping_handler,
|
||||
.pong = pong_handler,
|
||||
.close = close_handler,
|
||||
});
|
||||
|
||||
uws_app_listen(SSL,app, 9001, listen_handler, NULL);
|
||||
|
||||
|
||||
uws_app_run(SSL, app);
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
#include "../libuwebsockets.h"
|
||||
#include "libusockets.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define SSL 1
|
||||
|
||||
void get_handler(uws_res_t *res, uws_req_t *req, void *user_data)
|
||||
{
|
||||
uws_res_end(SSL, res, "Hello CAPI!", 11, false);
|
||||
}
|
||||
|
||||
void listen_handler(struct us_listen_socket_t *listen_socket, uws_app_listen_config_t config, void *user_data)
|
||||
{
|
||||
if (listen_socket)
|
||||
{
|
||||
printf("Listening on port https://localhost:%d now\n", config.port);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
/* Overly simple hello world app */
|
||||
|
||||
uws_app_t *app = uws_create_app(SSL, (struct us_socket_context_options_t){
|
||||
/* There are example certificates in uWebSockets.js repo */
|
||||
.key_file_name = "../misc/key.pem",
|
||||
.cert_file_name = "../misc/cert.pem",
|
||||
.passphrase = "1234"
|
||||
});
|
||||
uws_app_get(SSL, app, "/*", get_handler, NULL);
|
||||
uws_app_listen(SSL, app, 3000, listen_handler, NULL);
|
||||
uws_app_run(SSL, app);
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
#include "../libuwebsockets.h"
|
||||
#include "libusockets.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
|
||||
#define SSL 0
|
||||
|
||||
typedef struct {
|
||||
uws_res_t* res;
|
||||
bool aborted;
|
||||
} async_request_t;
|
||||
|
||||
//Timer close helper
|
||||
void uws_timer_close(struct us_timer_t *timer)
|
||||
{
|
||||
struct us_timer_t *t = (struct us_timer_t *)timer;
|
||||
struct timer_handler_data *data;
|
||||
memcpy(&data, us_timer_ext(t), sizeof(struct timer_handler_data *));
|
||||
free(data);
|
||||
us_timer_close(t, 0);
|
||||
}
|
||||
//Timer create helper
|
||||
struct us_timer_t *uws_create_timer(int ms, int repeat_ms, void (*handler)(void *data), void *data)
|
||||
{
|
||||
struct us_loop_t *loop = uws_get_loop();
|
||||
struct us_timer_t *delayTimer = us_create_timer(loop, 0, sizeof(void *));
|
||||
|
||||
struct timer_handler_data
|
||||
{
|
||||
void *data;
|
||||
void (*handler)(void *data);
|
||||
bool repeat;
|
||||
};
|
||||
|
||||
struct timer_handler_data *timer_data = (struct timer_handler_data *)malloc(sizeof(timer_handler_data));
|
||||
timer_data->data = data;
|
||||
timer_data->handler = handler;
|
||||
timer_data->repeat = repeat_ms > 0;
|
||||
memcpy(us_timer_ext(delayTimer), &timer_data, sizeof(struct timer_handler_data *));
|
||||
|
||||
us_timer_set(
|
||||
delayTimer, [](struct us_timer_t *t)
|
||||
{
|
||||
/* We wrote the pointer to the timer's extension */
|
||||
struct timer_handler_data *data;
|
||||
memcpy(&data, us_timer_ext(t), sizeof(struct timer_handler_data *));
|
||||
|
||||
data->handler(data->data);
|
||||
|
||||
if (!data->repeat)
|
||||
{
|
||||
free(data);
|
||||
us_timer_close(t, 0);
|
||||
}
|
||||
},
|
||||
ms, repeat_ms);
|
||||
|
||||
return (struct us_timer_t *)delayTimer;
|
||||
}
|
||||
|
||||
void on_res_aborted(uws_res_t *response, void* data){
|
||||
async_request_t* request_data = (async_request_t*)data;
|
||||
/* We don't implement any kind of cancellation here,
|
||||
* so simply flag us as aborted */
|
||||
request_data->aborted = true;
|
||||
}
|
||||
|
||||
void on_res_corked(uws_res_t *response, void* data){
|
||||
uws_res_end(SSL, response, "Hello CAPI!", 11, false);
|
||||
}
|
||||
void on_timer_done(void *data){
|
||||
async_request_t* request_data = (async_request_t*)data;
|
||||
/* Were'nt we aborted before our async task finished? Okay, send a message! */
|
||||
if(!request_data->aborted){
|
||||
|
||||
uws_res_cork(SSL, request_data->res,on_res_corked, request_data);
|
||||
}
|
||||
}
|
||||
|
||||
void get_handler(uws_res_t *res, uws_req_t *req, void* user_data)
|
||||
{
|
||||
|
||||
/* We have to attach an abort handler for us to be aware
|
||||
* of disconnections while we perform async tasks */
|
||||
async_request_t* request_data = (async_request_t*) malloc(sizeof(async_request_t));
|
||||
request_data->res = res;
|
||||
request_data->aborted = false;
|
||||
|
||||
uws_res_on_aborted(SSL, res, on_res_aborted, request_data);
|
||||
|
||||
/* Simulate checking auth for 5 seconds. This looks like crap, never write
|
||||
* code that utilize us_timer_t like this; they are high-cost and should
|
||||
* not be created and destroyed more than rarely!
|
||||
* Either way, here we go!*/
|
||||
uws_create_timer(1, 0, on_timer_done, request_data);
|
||||
}
|
||||
|
||||
|
||||
void listen_handler(struct us_listen_socket_t *listen_socket, uws_app_listen_config_t config, void* user_data)
|
||||
{
|
||||
if (listen_socket)
|
||||
{
|
||||
printf("Listening on port https://localhost:%d now\n", config.port);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
/* Overly simple hello world app with async response */
|
||||
|
||||
|
||||
uws_app_t *app = uws_create_app(SSL, (struct us_socket_context_options_t){
|
||||
/* There are example certificates in uWebSockets.js repo */
|
||||
.key_file_name = "../misc/key.pem",
|
||||
.cert_file_name = "../misc/cert.pem",
|
||||
.passphrase = "1234"
|
||||
});
|
||||
uws_app_get(SSL, app, "/*", get_handler, NULL);
|
||||
uws_app_listen(SSL, app, 3000, listen_handler, NULL);
|
||||
uws_app_run(SSL, app);
|
||||
}
|
||||
@@ -1,309 +0,0 @@
|
||||
/* automatically generated by rust-bindgen 0.59.2 */
|
||||
use std::convert::TryInto;
|
||||
use std::ffi::CString;
|
||||
|
||||
pub type SizeT = ::std::os::raw::c_ulong;
|
||||
pub type WcharT = ::std::os::raw::c_uint;
|
||||
#[repr(C)]
|
||||
#[repr(align(16))]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct max_align_t {
|
||||
pub __clang_max_align_nonce1: ::std::os::raw::c_longlong,
|
||||
pub __bindgen_padding_0: u64,
|
||||
pub __clang_max_align_nonce2: u128,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_max_align_t() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<max_align_t>(),
|
||||
32usize,
|
||||
concat!("Size of: ", stringify!(max_align_t))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<max_align_t>(),
|
||||
16usize,
|
||||
concat!("Alignment of ", stringify!(max_align_t))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<max_align_t>())).__clang_max_align_nonce1 as *const _ as usize
|
||||
},
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(max_align_t),
|
||||
"::",
|
||||
stringify!(__clang_max_align_nonce1)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<max_align_t>())).__clang_max_align_nonce2 as *const _ as usize
|
||||
},
|
||||
16usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(max_align_t),
|
||||
"::",
|
||||
stringify!(__clang_max_align_nonce2)
|
||||
)
|
||||
);
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct uws_app_s {
|
||||
_unused: [u8; 0],
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct uws_req_s {
|
||||
_unused: [u8; 0],
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct uws_res_s {
|
||||
_unused: [u8; 0],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct uws_app_listen_config_s {
|
||||
port: ::std::os::raw::c_int,
|
||||
host: *const ::std::os::raw::c_char,
|
||||
options: ::std::os::raw::c_int,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct us_socket_context_options_s {
|
||||
key_file_name: *const ::std::os::raw::c_char,
|
||||
cert_file_name: *const ::std::os::raw::c_char,
|
||||
passphrase: *const ::std::os::raw::c_char,
|
||||
dh_params_file_name: *const ::std::os::raw::c_char,
|
||||
ca_file_name: *const ::std::os::raw::c_char,
|
||||
ssl_prefer_low_memory_usage: ::std::os::raw::c_int,
|
||||
}
|
||||
|
||||
pub type UwsAppListenConfigT = uws_app_listen_config_s;
|
||||
pub type UsSocketContextOptionsT = us_socket_context_options_s;
|
||||
pub struct UsSocketContextOptions<'a> {
|
||||
key_file_name: &'a str,
|
||||
cert_file_name: &'a str,
|
||||
passphrase: &'a str,
|
||||
dh_params_file_name: &'a str,
|
||||
ca_file_name: &'a str,
|
||||
ssl_prefer_low_memory_usage: i32,
|
||||
}
|
||||
pub type UwsAppT = uws_app_s;
|
||||
pub type UwsReqT = uws_req_s;
|
||||
pub type UwsResT = uws_res_s;
|
||||
extern "C" {
|
||||
pub fn uws_create_app(
|
||||
ssl: ::std::os::raw::c_int,
|
||||
options: UsSocketContextOptionsT,
|
||||
) -> *mut UwsAppT;
|
||||
pub fn uws_app_get(
|
||||
ssl: ::std::os::raw::c_int,
|
||||
app: *mut UwsAppT,
|
||||
pattern: *const ::std::os::raw::c_char,
|
||||
handler: ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
res: *mut UwsResT,
|
||||
req: *mut UwsReqT,
|
||||
user_data: *mut ::std::os::raw::c_void,
|
||||
),
|
||||
>,
|
||||
user_data: *mut ::std::os::raw::c_void,
|
||||
);
|
||||
pub fn uws_app_run(ssl: ::std::os::raw::c_int, app: *mut UwsAppT);
|
||||
|
||||
pub fn uws_app_listen(
|
||||
ssl: ::std::os::raw::c_int,
|
||||
app: *mut UwsAppT,
|
||||
port: ::std::os::raw::c_int,
|
||||
handler: ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
listen_socket: *mut ::std::os::raw::c_void,
|
||||
config: UwsAppListenConfigT,
|
||||
user_data: *mut ::std::os::raw::c_void,
|
||||
),
|
||||
>,
|
||||
user_data: *mut ::std::os::raw::c_void,
|
||||
);
|
||||
pub fn uws_res_end(
|
||||
ssl: ::std::os::raw::c_int,
|
||||
res: *mut UwsResT,
|
||||
data: *const ::std::os::raw::c_char,
|
||||
length: SizeT,
|
||||
close_connection: bool,
|
||||
);
|
||||
}
|
||||
|
||||
pub struct AppResponse<const SSL: i32> {
|
||||
native: *mut UwsResT,
|
||||
}
|
||||
pub struct AppRequest {
|
||||
native: *mut UwsReqT,
|
||||
}
|
||||
impl AppRequest {
|
||||
pub fn new(native: *mut UwsReqT) -> AppRequest {
|
||||
AppRequest { native: native }
|
||||
}
|
||||
}
|
||||
impl<const SSL: i32> AppResponse<SSL> {
|
||||
pub fn new(native: *mut UwsResT) -> AppResponse<SSL> {
|
||||
AppResponse::<SSL> { native: native }
|
||||
}
|
||||
fn end(self, message: &str) -> AppResponse<SSL> {
|
||||
unsafe {
|
||||
let c_message =
|
||||
::std::ffi::CString::new(message).expect("Failed to create message CString");
|
||||
//This will now const fold :/ performance impact needs refactor
|
||||
uws_res_end(
|
||||
SSL,
|
||||
self.native,
|
||||
c_message.as_ptr(),
|
||||
message.len().try_into().unwrap(),
|
||||
false,
|
||||
);
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub type UwsMethodHandler<const SSL: i32> = fn(res: AppResponse<SSL>, req: AppRequest);
|
||||
pub type UwsListenHandler =
|
||||
fn(listen_socket: *mut ::std::os::raw::c_void, config: UwsAppListenConfigT);
|
||||
|
||||
pub struct TemplateApp<const SSL: i32> {
|
||||
native: *mut UwsAppT,
|
||||
}
|
||||
|
||||
extern "C" fn uws_generic_listen_handler(
|
||||
listen_socket: *mut ::std::os::raw::c_void,
|
||||
config: UwsAppListenConfigT,
|
||||
user_data: *mut ::std::os::raw::c_void,
|
||||
) {
|
||||
unsafe {
|
||||
let callback = &mut *(user_data as *mut UwsListenHandler);
|
||||
callback(listen_socket, config);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn uws_generic_method_handler(
|
||||
res: *mut UwsResT,
|
||||
req: *mut UwsReqT,
|
||||
user_data: *mut ::std::os::raw::c_void,
|
||||
) {
|
||||
unsafe {
|
||||
let response = AppResponse::<0>::new(res);
|
||||
let request = AppRequest::new(req);
|
||||
let callback = &mut *(user_data as *mut UwsMethodHandler<0>);
|
||||
callback(response, request);
|
||||
}
|
||||
}
|
||||
extern "C" fn uws_ssl_generic_method_handler(
|
||||
res: *mut UwsResT,
|
||||
req: *mut UwsReqT,
|
||||
user_data: *mut ::std::os::raw::c_void,
|
||||
) {
|
||||
unsafe {
|
||||
let response = AppResponse::<1>::new(res);
|
||||
let request = AppRequest::new(req);
|
||||
let callback = &mut *(user_data as *mut UwsMethodHandler<1>);
|
||||
callback(response, request);
|
||||
}
|
||||
}
|
||||
|
||||
impl<const SSL: i32> TemplateApp<SSL> {
|
||||
pub fn new(config: UsSocketContextOptions) -> TemplateApp<SSL> {
|
||||
unsafe {
|
||||
let key_file_name_s =
|
||||
CString::new(config.key_file_name).expect("Failed to create key_file_name CString");
|
||||
let cert_file_name_s = CString::new(config.cert_file_name)
|
||||
.expect("Failed to create cert_file_name CString");
|
||||
let passphrase_s =
|
||||
CString::new(config.passphrase).expect("Failed to create passphrase CString");
|
||||
let dh_params_file_name_s = CString::new(config.dh_params_file_name)
|
||||
.expect("Failed to create dh_params_file_name CString");
|
||||
let ca_file_name_s =
|
||||
CString::new(config.ca_file_name).expect("Failed to create ca_file_name CString");
|
||||
|
||||
let native_options = UsSocketContextOptionsT {
|
||||
key_file_name: key_file_name_s.as_ptr(),
|
||||
cert_file_name: cert_file_name_s.as_ptr(),
|
||||
passphrase: passphrase_s.as_ptr(),
|
||||
dh_params_file_name: dh_params_file_name_s.as_ptr(),
|
||||
ca_file_name: ca_file_name_s.as_ptr(),
|
||||
ssl_prefer_low_memory_usage: config.ssl_prefer_low_memory_usage,
|
||||
};
|
||||
TemplateApp::<SSL> {
|
||||
native: uws_create_app(SSL, native_options),
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn get(self, route: &str, mut handler: UwsMethodHandler<SSL>) -> TemplateApp<SSL> {
|
||||
unsafe {
|
||||
let c_route = ::std::ffi::CString::new(route).expect("Failed to create route CString");
|
||||
if SSL == 1 {
|
||||
uws_app_get(
|
||||
SSL,
|
||||
self.native,
|
||||
c_route.as_ptr(),
|
||||
std::option::Option::Some(uws_ssl_generic_method_handler),
|
||||
&mut handler as *mut _ as *mut ::std::os::raw::c_void,
|
||||
);
|
||||
} else {
|
||||
uws_app_get(
|
||||
SSL,
|
||||
self.native,
|
||||
c_route.as_ptr(),
|
||||
std::option::Option::Some(uws_generic_method_handler),
|
||||
&mut handler as *mut _ as *mut ::std::os::raw::c_void,
|
||||
);
|
||||
}
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn listen(self, port: i32, mut handler: UwsListenHandler) -> TemplateApp<SSL> {
|
||||
unsafe {
|
||||
uws_app_listen(
|
||||
SSL,
|
||||
self.native,
|
||||
port,
|
||||
::std::option::Option::Some(uws_generic_listen_handler),
|
||||
&mut handler as *mut _ as *mut ::std::os::raw::c_void,
|
||||
);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn run(self) -> TemplateApp<SSL> {
|
||||
unsafe {
|
||||
uws_app_run(SSL, self.native);
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
pub type App = TemplateApp<0>;
|
||||
pub type SSLApp = TemplateApp<1>;
|
||||
|
||||
fn main() {
|
||||
let config = UsSocketContextOptions {
|
||||
key_file_name: "../misc/key.pem",
|
||||
cert_file_name: "../misc/cert.pem",
|
||||
passphrase: "1234",
|
||||
ca_file_name: "",
|
||||
dh_params_file_name: "",
|
||||
ssl_prefer_low_memory_usage: 0,
|
||||
};
|
||||
|
||||
SSLApp::new(config)
|
||||
.get("/", |res, _req| {
|
||||
res.end("Hello Rust!");
|
||||
})
|
||||
.listen(3000, |_listen_socket, config| {
|
||||
println!("Listening on port https://127.0.0.1:{}", config.port);
|
||||
})
|
||||
.run();
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
#include "../libuwebsockets.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#define SSL 1
|
||||
|
||||
|
||||
struct us_listen_socket_t *globalListenSocket;
|
||||
uws_app_t *app;
|
||||
void get_handler(uws_res_t *res, uws_req_t *req, void* user_data)
|
||||
{
|
||||
|
||||
uws_res_end(SSL, res, "Hello CAPI!", 11, false);
|
||||
}
|
||||
|
||||
void exit_handler(uws_res_t *res, uws_req_t *req, void* user_data)
|
||||
{
|
||||
uws_res_end(SSL, res, "Shutting down!",14, false);
|
||||
/* We use this to check graceful closedown */
|
||||
us_listen_socket_close(false, globalListenSocket);
|
||||
}
|
||||
|
||||
void missing_server_name_handler(const char *hostname, void* user_data){
|
||||
printf("We are missing server name: <%s>\n", hostname);
|
||||
|
||||
/* Assume it is localhost, so add it */
|
||||
uws_add_server_name(SSL, app, "localhost");
|
||||
}
|
||||
|
||||
void listen_handler(struct us_listen_socket_t *listen_socket, uws_app_listen_config_t config, void* user_data)
|
||||
{
|
||||
if (listen_socket){
|
||||
printf("Listening on port https://localhost:%d\n", config.port);
|
||||
globalListenSocket = listen_socket;
|
||||
}else{
|
||||
printf("Failed to listen on port https://localhost:%d\n", config.port);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
/* Overly simple hello world app (SNI)*/
|
||||
|
||||
app = uws_create_app(SSL, (struct us_socket_context_options_t){
|
||||
/* There are example certificates in uWebSockets.js repo */
|
||||
.key_file_name = "../misc/key.pem",
|
||||
.cert_file_name = "../misc/cert.pem",
|
||||
.passphrase = "1234"
|
||||
});
|
||||
uws_missing_server_name(SSL, app, missing_server_name_handler, NULL);
|
||||
uws_app_get(SSL, app, "/*", get_handler, NULL);
|
||||
uws_app_get(SSL, app, "/exit", exit_handler, NULL);
|
||||
uws_app_listen(SSL, app, 3000, listen_handler, NULL);
|
||||
|
||||
/* Let's add a wildcard SNI to begin with */
|
||||
uws_add_server_name(SSL, app, "*.google.*");
|
||||
|
||||
uws_app_run(SSL, app);
|
||||
}
|
||||
@@ -1,255 +0,0 @@
|
||||
#include "../libuwebsockets.h"
|
||||
#include "libusockets.h"
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
/* This is a simple WebSocket "sync" upgrade example.
|
||||
* You may compile it with "WITH_OPENSSL=1 make" or with "make" */
|
||||
|
||||
#define SSL 1
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *value;
|
||||
size_t length;
|
||||
} header_t;
|
||||
struct PerSocketData
|
||||
{
|
||||
/* Define your user data */
|
||||
int something;
|
||||
};
|
||||
|
||||
struct UpgradeData
|
||||
{
|
||||
header_t *secWebSocketKey;
|
||||
header_t *secWebSocketProtocol;
|
||||
header_t *secWebSocketExtensions;
|
||||
uws_socket_context_t *context;
|
||||
uws_res_t *response;
|
||||
bool aborted;
|
||||
};
|
||||
|
||||
header_t *create_header(size_t length, const char* value)
|
||||
{
|
||||
header_t *header = (header_t *)malloc(sizeof(header_t));
|
||||
if(length > 0){
|
||||
header->value = (char *)calloc(sizeof(char), length);
|
||||
header->length = length;
|
||||
memcpy(header->value, value, length);
|
||||
}else{
|
||||
header->value = NULL;
|
||||
header->length = 0;
|
||||
}
|
||||
return header;
|
||||
}
|
||||
void free_header(header_t *header)
|
||||
{
|
||||
|
||||
free(header->value);
|
||||
free(header);
|
||||
}
|
||||
void listen_handler(struct us_listen_socket_t *listen_socket, uws_app_listen_config_t config, void *user_data)
|
||||
{
|
||||
if (listen_socket)
|
||||
{
|
||||
printf("Listening on port wss://localhost:%d\n", config.port);
|
||||
}
|
||||
}
|
||||
//Timer close helper
|
||||
void uws_timer_close(struct us_timer_t *timer)
|
||||
{
|
||||
struct us_timer_t *t = (struct us_timer_t *)timer;
|
||||
struct timer_handler_data *data;
|
||||
memcpy(&data, us_timer_ext(t), sizeof(struct timer_handler_data *));
|
||||
free(data);
|
||||
us_timer_close(t, 0);
|
||||
}
|
||||
//Timer create helper
|
||||
struct us_timer_t *uws_create_timer(int ms, int repeat_ms, void (*handler)(void *data), void *data)
|
||||
{
|
||||
struct us_loop_t *loop = uws_get_loop();
|
||||
struct us_timer_t *delayTimer = us_create_timer(loop, 0, sizeof(void *));
|
||||
|
||||
struct timer_handler_data
|
||||
{
|
||||
void *data;
|
||||
void (*handler)(void *data);
|
||||
bool repeat;
|
||||
};
|
||||
|
||||
struct timer_handler_data *timer_data = (struct timer_handler_data *)malloc(sizeof(timer_handler_data));
|
||||
timer_data->data = data;
|
||||
timer_data->handler = handler;
|
||||
timer_data->repeat = repeat_ms > 0;
|
||||
memcpy(us_timer_ext(delayTimer), &timer_data, sizeof(struct timer_handler_data *));
|
||||
|
||||
us_timer_set(
|
||||
delayTimer, [](struct us_timer_t *t)
|
||||
{
|
||||
/* We wrote the pointer to the timer's extension */
|
||||
struct timer_handler_data *data;
|
||||
memcpy(&data, us_timer_ext(t), sizeof(struct timer_handler_data *));
|
||||
|
||||
data->handler(data->data);
|
||||
|
||||
if (!data->repeat)
|
||||
{
|
||||
free(data);
|
||||
us_timer_close(t, 0);
|
||||
}
|
||||
},
|
||||
ms, repeat_ms);
|
||||
|
||||
return (struct us_timer_t *)delayTimer;
|
||||
}
|
||||
void on_timer_done(void *data)
|
||||
{
|
||||
|
||||
struct UpgradeData *upgrade_data = (struct UpgradeData *)data;
|
||||
|
||||
/* Were'nt we aborted before our async task finished? Okay, upgrade then! */
|
||||
if (!upgrade_data->aborted)
|
||||
{
|
||||
struct PerSocketData *socket_data = (struct PerSocketData *)malloc(sizeof(struct PerSocketData));
|
||||
socket_data->something = 15;
|
||||
printf("Async task done, upgrading to WebSocket now!\n");
|
||||
|
||||
uws_res_upgrade(SSL,
|
||||
upgrade_data->response,
|
||||
(void *)socket_data,
|
||||
upgrade_data->secWebSocketKey->value,
|
||||
upgrade_data->secWebSocketKey->length,
|
||||
upgrade_data->secWebSocketProtocol->value,
|
||||
upgrade_data->secWebSocketProtocol->length,
|
||||
upgrade_data->secWebSocketExtensions->value,
|
||||
upgrade_data->secWebSocketExtensions->length,
|
||||
upgrade_data->context);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Async task done, but the HTTP socket was closed. Skipping upgrade to WebSocket!\n");
|
||||
}
|
||||
free_header(upgrade_data->secWebSocketKey);
|
||||
free_header(upgrade_data->secWebSocketProtocol);
|
||||
free_header(upgrade_data->secWebSocketExtensions);
|
||||
free(upgrade_data);
|
||||
}
|
||||
|
||||
void on_res_aborted(uws_res_t *response, void *data)
|
||||
{
|
||||
struct UpgradeData *upgrade_data = (struct UpgradeData *)data;
|
||||
/* We don't implement any kind of cancellation here,
|
||||
* so simply flag us as aborted */
|
||||
upgrade_data->aborted = true;
|
||||
}
|
||||
void upgrade_handler(uws_res_t *response, uws_req_t *request, uws_socket_context_t *context)
|
||||
{
|
||||
|
||||
/* HttpRequest (req) is only valid in this very callback, so we must COPY the headers
|
||||
* we need later on while upgrading to WebSocket. You must not access req after first return.
|
||||
* Here we create a heap allocated struct holding everything we will need later on. */
|
||||
|
||||
struct UpgradeData *data = (struct UpgradeData *)malloc(sizeof(struct UpgradeData));
|
||||
data->aborted = false;
|
||||
data->context = context;
|
||||
data->response = response;
|
||||
|
||||
const char *ws_key = NULL;
|
||||
const char *ws_protocol = NULL;
|
||||
const char *ws_extensions = NULL;
|
||||
|
||||
size_t ws_key_length = uws_req_get_header(request, "sec-websocket-key", 17, &ws_key);
|
||||
size_t ws_protocol_length = uws_req_get_header(request, "sec-websocket-protocol", 22, &ws_protocol);
|
||||
size_t ws_extensions_length = uws_req_get_header(request, "sec-websocket-extensions", 24, &ws_extensions);
|
||||
|
||||
|
||||
data->secWebSocketKey = create_header(ws_key_length, ws_key);
|
||||
data->secWebSocketProtocol = create_header(ws_protocol_length, ws_protocol);
|
||||
data->secWebSocketExtensions = create_header(ws_extensions_length, ws_extensions);
|
||||
|
||||
/* We have to attach an abort handler for us to be aware
|
||||
* of disconnections while we perform async tasks */
|
||||
|
||||
uws_res_on_aborted(SSL, response, on_res_aborted, data);
|
||||
|
||||
/* Simulate checking auth for 5 seconds. This looks like crap, never write
|
||||
* code that utilize us_timer_t like this; they are high-cost and should
|
||||
* not be created and destroyed more than rarely!
|
||||
* Either way, here we go!*/
|
||||
uws_create_timer(5000, 0, on_timer_done, data);
|
||||
}
|
||||
|
||||
void open_handler(uws_websocket_t *ws)
|
||||
{
|
||||
|
||||
/* Open event here, you may access uws_ws_get_user_data(ws) which points to a PerSocketData struct.
|
||||
* Here we simply validate that indeed, something == 15 as set in upgrade handler. */
|
||||
|
||||
struct PerSocketData *data = (struct PerSocketData *)uws_ws_get_user_data(SSL, ws);
|
||||
data->something = 15;
|
||||
printf("Something is: %d\n", data->something);
|
||||
}
|
||||
|
||||
void message_handler(uws_websocket_t *ws, const char *message, size_t length, uws_opcode_t opcode)
|
||||
{
|
||||
|
||||
/* We simply echo whatever data we get */
|
||||
uws_ws_send(SSL, ws, message, length, opcode);
|
||||
}
|
||||
|
||||
void close_handler(uws_websocket_t *ws, int code, const char *message, size_t length)
|
||||
{
|
||||
|
||||
/* You may access uws_ws_get_user_data(ws) here, but sending or
|
||||
* doing any kind of I/O with the socket is not valid. */
|
||||
struct PerSocketData *data = (struct PerSocketData *)uws_ws_get_user_data(SSL, ws);
|
||||
if (data)
|
||||
{
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
|
||||
void drain_handler(uws_websocket_t *ws)
|
||||
{
|
||||
/* Check uws_ws_get_buffered_amount(ws) here */
|
||||
}
|
||||
|
||||
void ping_handler(uws_websocket_t *ws, const char *message, size_t length)
|
||||
{
|
||||
/* You don't need to handle this one, we automatically respond to pings as per standard */
|
||||
}
|
||||
|
||||
void pong_handler(uws_websocket_t *ws, const char *message, size_t length)
|
||||
{
|
||||
|
||||
/* You don't need to handle this one either */
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
uws_app_t *app = uws_create_app(SSL, (struct us_socket_context_options_t){
|
||||
/* There are example certificates in uWebSockets.js repo */
|
||||
.key_file_name = "../misc/key.pem",
|
||||
.cert_file_name = "../misc/cert.pem",
|
||||
.passphrase = "1234"
|
||||
});
|
||||
|
||||
uws_ws(SSL, app, "/*", (uws_socket_behavior_t){
|
||||
.compression = uws_compress_options_t::SHARED_COMPRESSOR,
|
||||
.maxPayloadLength = 16 * 1024,
|
||||
.idleTimeout = 12,
|
||||
.maxBackpressure = 1 * 1024 * 1024,
|
||||
.upgrade = upgrade_handler,
|
||||
.open = open_handler,
|
||||
.message = message_handler,
|
||||
.drain = drain_handler,
|
||||
.ping = ping_handler,
|
||||
.pong = pong_handler,
|
||||
.close = close_handler,
|
||||
});
|
||||
|
||||
uws_app_listen(SSL, app, 9001, listen_handler, NULL);
|
||||
|
||||
uws_app_run(SSL, app);
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
#include "../libuwebsockets.h"
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#define SSL 1
|
||||
|
||||
/* This is a simple WebSocket "sync" upgrade example.
|
||||
* You may compile it with "WITH_OPENSSL=1 make" or with "make" */
|
||||
|
||||
/* uws_ws_get_user_data(ws) returns one of these */
|
||||
|
||||
struct PerSocketData
|
||||
{
|
||||
/* Define your user data */
|
||||
int something;
|
||||
};
|
||||
|
||||
void listen_handler(struct us_listen_socket_t *listen_socket, uws_app_listen_config_t config, void *user_data)
|
||||
{
|
||||
if (listen_socket)
|
||||
{
|
||||
printf("Listening on port wss://localhost:%d\n", config.port);
|
||||
}
|
||||
}
|
||||
|
||||
void upgrade_handler(uws_res_t *response, uws_req_t *request, uws_socket_context_t *context)
|
||||
{
|
||||
|
||||
/* You may read from req only here, and COPY whatever you need into your PerSocketData.
|
||||
* PerSocketData is valid from .open to .close event, accessed with uws_ws_get_user_data(ws).
|
||||
* HttpRequest (req) is ONLY valid in this very callback, so any data you will need later
|
||||
* has to be COPIED into PerSocketData here. */
|
||||
|
||||
/* Immediately upgrading without doing anything "async" before, is simple */
|
||||
|
||||
struct PerSocketData *data = (struct PerSocketData *)malloc(sizeof(struct PerSocketData));
|
||||
data->something = 15;
|
||||
|
||||
const char *ws_key = NULL;
|
||||
const char *ws_protocol = NULL;
|
||||
const char *ws_extensions = NULL;
|
||||
|
||||
size_t ws_key_length = uws_req_get_header(request, "sec-websocket-key", 17, &ws_key);
|
||||
size_t ws_protocol_length = uws_req_get_header(request, "sec-websocket-protocol", 22, &ws_protocol);
|
||||
size_t ws_extensions_length = uws_req_get_header(request, "sec-websocket-extensions", 24, &ws_extensions);
|
||||
|
||||
uws_res_upgrade(SSL,
|
||||
response,
|
||||
(void *)data,
|
||||
ws_key,
|
||||
ws_key_length,
|
||||
ws_protocol,
|
||||
ws_protocol_length,
|
||||
ws_extensions,
|
||||
ws_extensions_length,
|
||||
context);
|
||||
}
|
||||
|
||||
void open_handler(uws_websocket_t *ws)
|
||||
{
|
||||
|
||||
/* Open event here, you may access uws_ws_get_user_data(ws) which points to a PerSocketData struct.
|
||||
* Here we simply validate that indeed, something == 15 as set in upgrade handler. */
|
||||
|
||||
struct PerSocketData *data = (struct PerSocketData *)uws_ws_get_user_data(SSL, ws);
|
||||
data->something = 15;
|
||||
printf("Something is: %d\n", data->something);
|
||||
}
|
||||
|
||||
void message_handler(uws_websocket_t *ws, const char *message, size_t length, uws_opcode_t opcode)
|
||||
{
|
||||
/* We simply echo whatever data we get */
|
||||
uws_ws_send(SSL, ws, message, length, opcode);
|
||||
}
|
||||
|
||||
void close_handler(uws_websocket_t *ws, int code, const char *message, size_t length)
|
||||
{
|
||||
|
||||
/* You may access uws_ws_get_user_data(ws) here, but sending or
|
||||
* doing any kind of I/O with the socket is not valid. */
|
||||
struct PerSocketData *data = (struct PerSocketData *)uws_ws_get_user_data(SSL, ws);
|
||||
if (data)
|
||||
free(data);
|
||||
}
|
||||
|
||||
void drain_handler(uws_websocket_t *ws)
|
||||
{
|
||||
/* Check uws_ws_get_buffered_amount(ws) here */
|
||||
}
|
||||
|
||||
void ping_handler(uws_websocket_t *ws, const char *message, size_t length)
|
||||
{
|
||||
/* You don't need to handle this one, we automatically respond to pings as per standard */
|
||||
}
|
||||
|
||||
void pong_handler(uws_websocket_t *ws, const char *message, size_t length)
|
||||
{
|
||||
|
||||
/* You don't need to handle this one either */
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
uws_app_t *app = uws_create_app(SSL, (struct us_socket_context_options_t){
|
||||
/* There are example certificates in uWebSockets.js repo */
|
||||
.key_file_name = "../misc/key.pem",
|
||||
.cert_file_name = "../misc/cert.pem",
|
||||
.passphrase = "1234"
|
||||
});
|
||||
|
||||
uws_ws(SSL, app, "/*", (uws_socket_behavior_t){.compression = uws_compress_options_t::SHARED_COMPRESSOR, .maxPayloadLength = 16 * 1024, .idleTimeout = 12, .maxBackpressure = 1 * 1024 * 1024, .upgrade = upgrade_handler, .open = open_handler, .message = message_handler, .drain = drain_handler, .ping = ping_handler, .pong = pong_handler, .close = close_handler});
|
||||
|
||||
uws_app_listen(SSL, app, 9001, listen_handler, NULL);
|
||||
|
||||
uws_app_run(SSL, app);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,260 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 Ciro Spaciari
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
// clang-format off
|
||||
#ifndef LIBUWS_CAPI_HEADER
|
||||
#define LIBUWS_CAPI_HEADER
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "libusockets.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
# define DLL_EXPORT __declspec( dllexport )
|
||||
#else
|
||||
# define DLL_EXPORT
|
||||
#endif
|
||||
|
||||
DLL_EXPORT typedef enum
|
||||
{
|
||||
/* These are not actual compression options */
|
||||
_COMPRESSOR_MASK = 0x00FF,
|
||||
_DECOMPRESSOR_MASK = 0x0F00,
|
||||
/* Disabled, shared, shared are "special" values */
|
||||
DISABLED = 0,
|
||||
SHARED_COMPRESSOR = 1,
|
||||
SHARED_DECOMPRESSOR = 1 << 8,
|
||||
/* Highest 4 bits describe decompressor */
|
||||
DEDICATED_DECOMPRESSOR_32KB = 15 << 8,
|
||||
DEDICATED_DECOMPRESSOR_16KB = 14 << 8,
|
||||
DEDICATED_DECOMPRESSOR_8KB = 13 << 8,
|
||||
DEDICATED_DECOMPRESSOR_4KB = 12 << 8,
|
||||
DEDICATED_DECOMPRESSOR_2KB = 11 << 8,
|
||||
DEDICATED_DECOMPRESSOR_1KB = 10 << 8,
|
||||
DEDICATED_DECOMPRESSOR_512B = 9 << 8,
|
||||
/* Same as 32kb */
|
||||
DEDICATED_DECOMPRESSOR = 15 << 8,
|
||||
|
||||
/* Lowest 8 bit describe compressor */
|
||||
DEDICATED_COMPRESSOR_3KB = 9 << 4 | 1,
|
||||
DEDICATED_COMPRESSOR_4KB = 9 << 4 | 2,
|
||||
DEDICATED_COMPRESSOR_8KB = 10 << 4 | 3,
|
||||
DEDICATED_COMPRESSOR_16KB = 11 << 4 | 4,
|
||||
DEDICATED_COMPRESSOR_32KB = 12 << 4 | 5,
|
||||
DEDICATED_COMPRESSOR_64KB = 13 << 4 | 6,
|
||||
DEDICATED_COMPRESSOR_128KB = 14 << 4 | 7,
|
||||
DEDICATED_COMPRESSOR_256KB = 15 << 4 | 8,
|
||||
/* Same as 256kb */
|
||||
DEDICATED_COMPRESSOR = 15 << 4 | 8
|
||||
} uws_compress_options_t;
|
||||
|
||||
DLL_EXPORT typedef enum
|
||||
{
|
||||
CONTINUATION = 0,
|
||||
TEXT = 1,
|
||||
BINARY = 2,
|
||||
CLOSE = 8,
|
||||
PING = 9,
|
||||
PONG = 10
|
||||
} uws_opcode_t;
|
||||
|
||||
DLL_EXPORT typedef enum
|
||||
{
|
||||
BACKPRESSURE,
|
||||
SUCCESS,
|
||||
DROPPED
|
||||
} uws_sendstatus_t;
|
||||
|
||||
DLL_EXPORT typedef struct
|
||||
{
|
||||
|
||||
int port;
|
||||
const char *host;
|
||||
int options;
|
||||
} uws_app_listen_config_t;
|
||||
|
||||
DLL_EXPORT typedef struct {
|
||||
bool ok;
|
||||
bool has_responded;
|
||||
} uws_try_end_result_t;
|
||||
|
||||
DLL_EXPORT struct uws_app_s;
|
||||
DLL_EXPORT struct uws_req_s;
|
||||
DLL_EXPORT struct uws_res_s;
|
||||
DLL_EXPORT struct uws_websocket_s;
|
||||
DLL_EXPORT struct uws_header_iterator_s;
|
||||
DLL_EXPORT typedef struct uws_app_s uws_app_t;
|
||||
DLL_EXPORT typedef struct uws_req_s uws_req_t;
|
||||
DLL_EXPORT typedef struct uws_res_s uws_res_t;
|
||||
DLL_EXPORT typedef struct uws_socket_context_s uws_socket_context_t;
|
||||
DLL_EXPORT typedef struct uws_websocket_s uws_websocket_t;
|
||||
|
||||
DLL_EXPORT typedef void (*uws_websocket_handler)(uws_websocket_t *ws, void* user_data);
|
||||
DLL_EXPORT typedef void (*uws_websocket_message_handler)(uws_websocket_t *ws, const char *message, size_t length, uws_opcode_t opcode, void* user_data);
|
||||
DLL_EXPORT typedef void (*uws_websocket_ping_pong_handler)(uws_websocket_t *ws, const char *message, size_t length, void* user_data);
|
||||
DLL_EXPORT typedef void (*uws_websocket_close_handler)(uws_websocket_t *ws, int code, const char *message, size_t length, void* user_data);
|
||||
DLL_EXPORT typedef void (*uws_websocket_upgrade_handler)(uws_res_t *response, uws_req_t *request, uws_socket_context_t *context, void* user_data);
|
||||
DLL_EXPORT typedef void (*uws_websocket_subscription_handler)(uws_websocket_t *ws, const char *topic_name, size_t topic_name_length, int new_number_of_subscriber, int old_number_of_subscriber, void* user_data);
|
||||
|
||||
DLL_EXPORT typedef struct
|
||||
{
|
||||
uws_compress_options_t compression;
|
||||
/* Maximum message size we can receive */
|
||||
unsigned int maxPayloadLength;
|
||||
/* 2 minutes timeout is good */
|
||||
unsigned short idleTimeout;
|
||||
/* 64kb backpressure is probably good */
|
||||
unsigned int maxBackpressure;
|
||||
bool closeOnBackpressureLimit;
|
||||
/* This one depends on kernel timeouts and is a bad default */
|
||||
bool resetIdleTimeoutOnSend;
|
||||
/* A good default, esp. for newcomers */
|
||||
bool sendPingsAutomatically;
|
||||
/* Maximum socket lifetime in seconds before forced closure (defaults to disabled) */
|
||||
unsigned short maxLifetime;
|
||||
uws_websocket_upgrade_handler upgrade;
|
||||
uws_websocket_handler open;
|
||||
uws_websocket_message_handler message;
|
||||
uws_websocket_handler drain;
|
||||
uws_websocket_ping_pong_handler ping;
|
||||
uws_websocket_ping_pong_handler pong;
|
||||
uws_websocket_close_handler close;
|
||||
uws_websocket_subscription_handler subscription;
|
||||
} uws_socket_behavior_t;
|
||||
|
||||
DLL_EXPORT typedef void (*uws_listen_handler)(struct us_listen_socket_t *listen_socket, uws_app_listen_config_t config, void *user_data);
|
||||
DLL_EXPORT typedef void (*uws_listen_domain_handler)(struct us_listen_socket_t *listen_socket, const char* domain, size_t domain_length, int options, void *user_data);
|
||||
DLL_EXPORT typedef void (*uws_method_handler)(uws_res_t *response, uws_req_t *request, void *user_data);
|
||||
DLL_EXPORT typedef void (*uws_filter_handler)(uws_res_t *response, int, void *user_data);
|
||||
DLL_EXPORT typedef void (*uws_missing_server_handler)(const char *hostname, size_t hostname_length, void *user_data);
|
||||
DLL_EXPORT typedef void (*uws_get_headers_server_handler)(const char *header_name, size_t header_name_size, const char *header_value, size_t header_value_size, void *user_data);
|
||||
//Basic HTTP
|
||||
DLL_EXPORT uws_app_t *uws_create_app(int ssl, struct us_bun_socket_context_options_t options);
|
||||
DLL_EXPORT void uws_app_destroy(int ssl, uws_app_t *app);
|
||||
DLL_EXPORT void uws_app_get(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data);
|
||||
DLL_EXPORT void uws_app_post(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data);
|
||||
DLL_EXPORT void uws_app_options(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data);
|
||||
DLL_EXPORT void uws_app_delete(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data);
|
||||
DLL_EXPORT void uws_app_patch(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data);
|
||||
DLL_EXPORT void uws_app_put(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data);
|
||||
DLL_EXPORT void uws_app_head(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data);
|
||||
DLL_EXPORT void uws_app_connect(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data);
|
||||
DLL_EXPORT void uws_app_trace(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data);
|
||||
DLL_EXPORT void uws_app_any(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data);
|
||||
|
||||
DLL_EXPORT void uws_app_run(int ssl, uws_app_t *);
|
||||
|
||||
DLL_EXPORT void uws_app_listen(int ssl, uws_app_t *app, int port, uws_listen_handler handler, void *user_data);
|
||||
DLL_EXPORT void uws_app_listen_with_config(int ssl, uws_app_t *app, uws_app_listen_config_t config, uws_listen_handler handler, void *user_data);
|
||||
DLL_EXPORT void uws_app_listen_domain(int ssl, uws_app_t *app, const char *domain, size_t domain_length, uws_listen_domain_handler handler, void *user_data);
|
||||
DLL_EXPORT void uws_app_listen_domain_with_options(int ssl, uws_app_t *app, const char *domain,size_t domain_length, int options, uws_listen_domain_handler handler, void *user_data);
|
||||
DLL_EXPORT void uws_app_domain(int ssl, uws_app_t *app, const char* server_name, size_t server_name_length);
|
||||
|
||||
DLL_EXPORT bool uws_constructor_failed(int ssl, uws_app_t *app);
|
||||
DLL_EXPORT unsigned int uws_num_subscribers(int ssl, uws_app_t *app, const char *topic, size_t topic_length);
|
||||
DLL_EXPORT bool uws_publish(int ssl, uws_app_t *app, const char *topic, size_t topic_length, const char *message, size_t message_length, uws_opcode_t opcode, bool compress);
|
||||
DLL_EXPORT void *uws_get_native_handle(int ssl, uws_app_t *app);
|
||||
DLL_EXPORT void uws_remove_server_name(int ssl, uws_app_t *app, const char *hostname_pattern, size_t hostname_pattern_length);
|
||||
DLL_EXPORT void uws_add_server_name(int ssl, uws_app_t *app, const char *hostname_pattern, size_t hostname_pattern_length);
|
||||
DLL_EXPORT void uws_add_server_name_with_options(int ssl, uws_app_t *app, const char *hostname_pattern, size_t hostname_pattern_length, struct us_bun_socket_context_options_t options);
|
||||
DLL_EXPORT void uws_missing_server_name(int ssl, uws_app_t *app, uws_missing_server_handler handler, void *user_data);
|
||||
DLL_EXPORT void uws_filter(int ssl, uws_app_t *app, uws_filter_handler handler, void *user_data);
|
||||
|
||||
//WebSocket
|
||||
DLL_EXPORT void uws_ws(int ssl, uws_app_t *app, const char *pattern, uws_socket_behavior_t behavior, void* user_data);
|
||||
DLL_EXPORT void *uws_ws_get_user_data(int ssl, uws_websocket_t *ws);
|
||||
DLL_EXPORT void uws_ws_close(int ssl, uws_websocket_t *ws);
|
||||
DLL_EXPORT uws_sendstatus_t uws_ws_send(int ssl, uws_websocket_t *ws, const char *message, size_t length, uws_opcode_t opcode);
|
||||
DLL_EXPORT uws_sendstatus_t uws_ws_send_with_options(int ssl, uws_websocket_t *ws, const char *message, size_t length, uws_opcode_t opcode, bool compress, bool fin);
|
||||
DLL_EXPORT uws_sendstatus_t uws_ws_send_fragment(int ssl, uws_websocket_t *ws, const char *message, size_t length, bool compress);
|
||||
DLL_EXPORT uws_sendstatus_t uws_ws_send_first_fragment(int ssl, uws_websocket_t *ws, const char *message, size_t length, bool compress);
|
||||
DLL_EXPORT uws_sendstatus_t uws_ws_send_first_fragment_with_opcode(int ssl, uws_websocket_t *ws, const char *message, size_t length, uws_opcode_t opcode, bool compress);
|
||||
DLL_EXPORT uws_sendstatus_t uws_ws_send_last_fragment(int ssl, uws_websocket_t *ws, const char *message, size_t length, bool compress);
|
||||
DLL_EXPORT void uws_ws_end(int ssl, uws_websocket_t *ws, int code, const char *message, size_t length);
|
||||
DLL_EXPORT void uws_ws_cork(int ssl, uws_websocket_t *ws, void (*handler)(void *user_data), void *user_data);
|
||||
|
||||
DLL_EXPORT bool uws_ws_subscribe(int ssl, uws_websocket_t *ws, const char *topic, size_t length);
|
||||
DLL_EXPORT bool uws_ws_unsubscribe(int ssl, uws_websocket_t *ws, const char *topic, size_t length);
|
||||
DLL_EXPORT bool uws_ws_is_subscribed(int ssl, uws_websocket_t *ws, const char *topic, size_t length);
|
||||
DLL_EXPORT void uws_ws_iterate_topics(int ssl, uws_websocket_t *ws, void (*callback)(const char *topic, size_t length, void *user_data), void *user_data);
|
||||
DLL_EXPORT bool uws_ws_publish(int ssl, uws_websocket_t *ws, const char *topic, size_t topic_length, const char *message, size_t message_length);
|
||||
DLL_EXPORT bool uws_ws_publish_with_options(int ssl, uws_websocket_t *ws, const char *topic, size_t topic_length, const char *message, size_t message_length, uws_opcode_t opcode, bool compress);
|
||||
DLL_EXPORT unsigned int uws_ws_get_buffered_amount(int ssl, uws_websocket_t *ws);
|
||||
DLL_EXPORT size_t uws_ws_get_remote_address(int ssl, uws_websocket_t *ws, const char **dest);
|
||||
DLL_EXPORT size_t uws_ws_get_remote_address_as_text(int ssl, uws_websocket_t *ws, const char **dest);
|
||||
DLL_EXPORT void uws_res_get_remote_address_info(uws_res_t *res, const char **dest, size_t *length, unsigned int *port);
|
||||
|
||||
//Response
|
||||
DLL_EXPORT void uws_res_end(int ssl, uws_res_t *res, const char *data, size_t length, bool close_connection);
|
||||
DLL_EXPORT uws_try_end_result_t uws_res_try_end(int ssl, uws_res_t *res, const char *data, size_t length, uint64_t total_size, bool close_connection);
|
||||
DLL_EXPORT void uws_res_cork(int ssl, uws_res_t *res, void(*callback)(uws_res_t *res, void* user_data) ,void* user_data);
|
||||
DLL_EXPORT void uws_res_pause(int ssl, uws_res_t *res);
|
||||
DLL_EXPORT void uws_res_resume(int ssl, uws_res_t *res);
|
||||
DLL_EXPORT void uws_res_write_continue(int ssl, uws_res_t *res);
|
||||
DLL_EXPORT void uws_res_write_status(int ssl, uws_res_t *res, const char *status, size_t length);
|
||||
DLL_EXPORT void uws_res_write_header(int ssl, uws_res_t *res, const char *key, size_t key_length, const char *value, size_t value_length);
|
||||
|
||||
DLL_EXPORT void uws_res_write_header_int(int ssl, uws_res_t *res, const char *key, size_t key_length, uint64_t value);
|
||||
DLL_EXPORT void uws_res_end_without_body(int ssl, uws_res_t *res, bool close_connection);
|
||||
DLL_EXPORT bool uws_res_write(int ssl, uws_res_t *res, const char *data, size_t length);
|
||||
DLL_EXPORT uint64_t uws_res_get_write_offset(int ssl, uws_res_t *res);
|
||||
DLL_EXPORT void uws_res_override_write_offset(int ssl, uws_res_t *res, uint64_t offset);
|
||||
DLL_EXPORT bool uws_res_has_responded(int ssl, uws_res_t *res);
|
||||
DLL_EXPORT void uws_res_on_writable(int ssl, uws_res_t *res, bool (*handler)(uws_res_t *res, uint64_t, void *optional_data), void *user_data);
|
||||
DLL_EXPORT void uws_res_on_aborted(int ssl, uws_res_t *res, void (*handler)(uws_res_t *res, void *optional_data), void *optional_data);
|
||||
DLL_EXPORT void uws_res_on_data(int ssl, uws_res_t *res, void (*handler)(uws_res_t *res, const char *chunk, size_t chunk_length, bool is_end, void *optional_data), void *optional_data);
|
||||
DLL_EXPORT void uws_res_upgrade(int ssl, uws_res_t *res, void *data, const char *sec_web_socket_key, size_t sec_web_socket_key_length, const char *sec_web_socket_protocol, size_t sec_web_socket_protocol_length, const char *sec_web_socket_extensions, size_t sec_web_socket_extensions_length, uws_socket_context_t *ws);
|
||||
DLL_EXPORT size_t uws_res_get_remote_address(int ssl, uws_res_t *res, const char **dest);
|
||||
DLL_EXPORT size_t uws_res_get_remote_address_as_text(int ssl, uws_res_t *res, const char **dest);
|
||||
#ifdef UWS_WITH_PROXY
|
||||
DLL_EXPORT size_t uws_res_get_proxied_remote_address(int ssl, uws_res_t *res, const char **dest);
|
||||
DLL_EXPORT size_t uws_res_get_proxied_remote_address_as_text(int ssl, uws_res_t *res, const char **dest);
|
||||
#endif
|
||||
DLL_EXPORT void *uws_res_get_native_handle(int ssl, uws_res_t *res);
|
||||
|
||||
//Request
|
||||
DLL_EXPORT bool uws_req_is_ancient(uws_req_t *res);
|
||||
DLL_EXPORT bool uws_req_get_yield(uws_req_t *res);
|
||||
DLL_EXPORT void uws_req_set_yield(uws_req_t *res, bool yield);
|
||||
DLL_EXPORT size_t uws_req_get_url(uws_req_t *res, const char **dest);
|
||||
DLL_EXPORT size_t uws_req_get_full_url(uws_req_t *res, const char **dest);
|
||||
DLL_EXPORT size_t uws_req_get_method(uws_req_t *res, const char **dest);
|
||||
DLL_EXPORT size_t uws_req_get_case_sensitive_method(uws_req_t *res, const char **dest);
|
||||
|
||||
DLL_EXPORT size_t uws_req_get_header(uws_req_t *res, const char *lower_case_header, size_t lower_case_header_length, const char **dest);
|
||||
DLL_EXPORT void uws_req_for_each_header(uws_req_t *res, uws_get_headers_server_handler handler, void *user_data);
|
||||
DLL_EXPORT size_t uws_req_get_query(uws_req_t *res, const char *key, size_t key_length, const char **dest);
|
||||
DLL_EXPORT size_t uws_req_get_parameter(uws_req_t *res, unsigned short index, const char **dest);
|
||||
|
||||
DLL_EXPORT struct us_loop_t *uws_get_loop();
|
||||
DLL_EXPORT struct us_loop_t *uws_get_loop_with_native(void* existing_native_loop);
|
||||
DLL_EXPORT void uws_loop_defer(struct us_loop_t *loop, void( cb(void *user_data) ), void *user_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -124,7 +124,7 @@ private:
|
||||
|
||||
/* Signal broken HTTP request only if we have a pending request */
|
||||
if (httpResponseData->onAborted) {
|
||||
httpResponseData->onAborted();
|
||||
httpResponseData->onAborted((HttpResponse<SSL> *)s, httpResponseData->userData);
|
||||
}
|
||||
|
||||
/* Destruct socket ext */
|
||||
@@ -258,7 +258,7 @@ private:
|
||||
}
|
||||
|
||||
/* We might respond in the handler, so do not change timeout after this */
|
||||
httpResponseData->inStream(data, fin);
|
||||
httpResponseData->inStream(static_cast<HttpResponse<SSL>*>(user), data.data(), data.length(), fin, httpResponseData->userData);
|
||||
|
||||
/* Was the socket closed? */
|
||||
if (us_socket_is_closed(SSL, (struct us_socket_t *) user)) {
|
||||
@@ -366,7 +366,7 @@ private:
|
||||
|
||||
/* We expect the developer to return whether or not write was successful (true).
|
||||
* If write was never called, the developer should still return true so that we may drain. */
|
||||
bool success = httpResponseData->callOnWritable(httpResponseData->offset);
|
||||
bool success = httpResponseData->callOnWritable((HttpResponse<SSL> *)asyncSocket, httpResponseData->offset);
|
||||
|
||||
/* The developer indicated that their onWritable failed. */
|
||||
if (!success) {
|
||||
|
||||
@@ -558,10 +558,11 @@ public:
|
||||
}
|
||||
|
||||
/* Attach handler for writable HTTP response */
|
||||
HttpResponse *onWritable(MoveOnlyFunction<bool(uint64_t)> &&handler) {
|
||||
HttpResponse *onWritable(void* userData, HttpResponseData<SSL>::OnWritableCallback handler) {
|
||||
HttpResponseData<SSL> *httpResponseData = getHttpResponseData();
|
||||
|
||||
httpResponseData->onWritable = std::move(handler);
|
||||
httpResponseData->userData = userData;
|
||||
httpResponseData->onWritable = handler;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -574,17 +575,31 @@ public:
|
||||
}
|
||||
|
||||
/* Attach handler for aborted HTTP request */
|
||||
HttpResponse *onAborted(MoveOnlyFunction<void()> &&handler) {
|
||||
HttpResponse *onAborted(void* userData, HttpResponseData<SSL>::OnAbortedCallback handler) {
|
||||
HttpResponseData<SSL> *httpResponseData = getHttpResponseData();
|
||||
|
||||
httpResponseData->onAborted = std::move(handler);
|
||||
|
||||
httpResponseData->userData = userData;
|
||||
httpResponseData->onAborted = handler;
|
||||
return this;
|
||||
}
|
||||
HttpResponse* clearOnWritableAndAborted() {
|
||||
HttpResponseData<SSL> *httpResponseData = getHttpResponseData();
|
||||
|
||||
httpResponseData->onWritable = nullptr;
|
||||
httpResponseData->onAborted = nullptr;
|
||||
return this;
|
||||
}
|
||||
HttpResponse* clearOnAborted() {
|
||||
HttpResponseData<SSL> *httpResponseData = getHttpResponseData();
|
||||
|
||||
httpResponseData->onAborted = nullptr;
|
||||
return this;
|
||||
}
|
||||
/* Attach a read handler for data sent. Will be called with FIN set true if last segment. */
|
||||
void onData(MoveOnlyFunction<void(std::string_view, bool)> &&handler) {
|
||||
void onData(void* userData, HttpResponseData<SSL>::OnDataCallback handler) {
|
||||
HttpResponseData<SSL> *data = getHttpResponseData();
|
||||
data->inStream = std::move(handler);
|
||||
data->userData = userData;
|
||||
data->inStream = handler;
|
||||
|
||||
/* Always reset this counter here */
|
||||
data->received_bytes_per_timeout = 0;
|
||||
|
||||
@@ -33,6 +33,10 @@ struct HttpResponseData : AsyncSocketData<SSL>, HttpParser {
|
||||
template <bool> friend struct HttpResponse;
|
||||
template <bool> friend struct HttpContext;
|
||||
public:
|
||||
using OnWritableCallback = bool (*)(uWS::HttpResponse<SSL>*, uint64_t, void*);
|
||||
using OnAbortedCallback = void (*)(uWS::HttpResponse<SSL>*, void*);
|
||||
using OnDataCallback = void (*)(uWS::HttpResponse<SSL>* response, const char* chunk, size_t chunk_length, bool, void*);
|
||||
|
||||
/* When we are done with a response we mark it like so */
|
||||
void markDone() {
|
||||
onAborted = nullptr;
|
||||
@@ -46,15 +50,15 @@ struct HttpResponseData : AsyncSocketData<SSL>, HttpParser {
|
||||
}
|
||||
|
||||
/* Caller of onWritable. It is possible onWritable calls markDone so we need to borrow it. */
|
||||
bool callOnWritable(uint64_t offset) {
|
||||
bool callOnWritable( uWS::HttpResponse<SSL>* response, uint64_t offset) {
|
||||
/* Borrow real onWritable */
|
||||
MoveOnlyFunction<bool(uint64_t)> borrowedOnWritable = std::move(onWritable);
|
||||
auto* borrowedOnWritable = std::move(onWritable);
|
||||
|
||||
/* Set onWritable to placeholder */
|
||||
onWritable = [](uint64_t) {return true;};
|
||||
onWritable = [](uWS::HttpResponse<SSL>*, uint64_t, void*) {return true;};
|
||||
|
||||
/* Run borrowed onWritable */
|
||||
bool ret = borrowedOnWritable(offset);
|
||||
bool ret = borrowedOnWritable(response, offset, userData);
|
||||
|
||||
/* If we still have onWritable (the placeholder) then move back the real one */
|
||||
if (onWritable) {
|
||||
@@ -74,10 +78,13 @@ struct HttpResponseData : AsyncSocketData<SSL>, HttpParser {
|
||||
HTTP_CONNECTION_CLOSE = 16 // used
|
||||
};
|
||||
|
||||
/* Shared context pointer */
|
||||
void* userData = nullptr;
|
||||
|
||||
/* Per socket event handlers */
|
||||
MoveOnlyFunction<bool(uint64_t)> onWritable;
|
||||
MoveOnlyFunction<void()> onAborted;
|
||||
MoveOnlyFunction<void(std::string_view, bool)> inStream; // onData
|
||||
OnWritableCallback onWritable = nullptr;
|
||||
OnAbortedCallback onAborted = nullptr;
|
||||
OnDataCallback inStream = nullptr;
|
||||
/* Outgoing offset */
|
||||
uint64_t offset = 0;
|
||||
|
||||
|
||||
@@ -95,13 +95,14 @@ private:
|
||||
// This is both a performance thing, and also to prevent freeing some things which are not meant to be freed
|
||||
// such as uv_tty_t
|
||||
if(loop && cleanMe && !bun_is_exiting()) {
|
||||
cleanMe = false;
|
||||
loop->free();
|
||||
}
|
||||
}
|
||||
Loop *loop = nullptr;
|
||||
bool cleanMe = false;
|
||||
};
|
||||
|
||||
|
||||
static LoopCleaner &getLazyLoop() {
|
||||
static thread_local LoopCleaner lazyLoop;
|
||||
return lazyLoop;
|
||||
@@ -126,6 +127,12 @@ public:
|
||||
return getLazyLoop().loop;
|
||||
}
|
||||
|
||||
static void clearLoopAtThreadExit() {
|
||||
if (getLazyLoop().cleanMe) {
|
||||
getLazyLoop().loop->free();
|
||||
}
|
||||
}
|
||||
|
||||
/* Freeing the default loop should be done once */
|
||||
void free() {
|
||||
LoopData *loopData = (LoopData *) us_loop_ext((us_loop_t *) this);
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#ifndef UWS_PERMESSAGEDEFLATE_H
|
||||
#define UWS_PERMESSAGEDEFLATE_H
|
||||
|
||||
#define UWS_USE_LIBDEFLATE 1
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
@@ -134,6 +136,9 @@ struct ZlibContext {
|
||||
|
||||
struct DeflationStream {
|
||||
z_stream deflationStream = {};
|
||||
#ifdef UWS_USE_LIBDEFLATE
|
||||
unsigned char reset_buffer[4096 + 1];
|
||||
#endif
|
||||
|
||||
DeflationStream(CompressOptions compressOptions) {
|
||||
|
||||
@@ -154,13 +159,11 @@ struct DeflationStream {
|
||||
/* Run a fast path in case of shared_compressor */
|
||||
if (reset) {
|
||||
size_t written = 0;
|
||||
static unsigned char buf[1024 + 1];
|
||||
|
||||
written = libdeflate_deflate_compress(zlibContext->compressor, raw.data(), raw.length(), buf, 1024);
|
||||
written = libdeflate_deflate_compress(zlibContext->compressor, raw.data(), raw.length(), reset_buffer, 4096);
|
||||
|
||||
if (written) {
|
||||
memcpy(&buf[written], "\x00", 1);
|
||||
return std::string_view((char *) buf, written + 1);
|
||||
memcpy(&reset_buffer[written], "\x00", 1);
|
||||
return std::string_view((char *) reset_buffer, written + 1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -214,6 +217,9 @@ struct DeflationStream {
|
||||
|
||||
struct InflationStream {
|
||||
z_stream inflationStream = {};
|
||||
#ifdef UWS_USE_LIBDEFLATE
|
||||
char buf[4096];
|
||||
#endif
|
||||
|
||||
InflationStream(CompressOptions compressOptions) {
|
||||
/* Inflation windowBits are the top 8 bits of the 16 bit compressOptions */
|
||||
@@ -230,13 +236,12 @@ struct InflationStream {
|
||||
#ifdef UWS_USE_LIBDEFLATE
|
||||
/* Try fast path first */
|
||||
size_t written = 0;
|
||||
static char buf[1024];
|
||||
|
||||
/* We have to pad 9 bytes and restore those bytes when done since 9 is more than 6 of next WebSocket message */
|
||||
char tmp[9];
|
||||
memcpy(tmp, (char *) compressed.data() + compressed.length(), 9);
|
||||
memcpy((char *) compressed.data() + compressed.length(), "\x00\x00\xff\xff\x01\x00\x00\xff\xff", 9);
|
||||
libdeflate_result res = libdeflate_deflate_decompress(zlibContext->decompressor, compressed.data(), compressed.length() + 9, buf, 1024, &written);
|
||||
libdeflate_result res = libdeflate_deflate_decompress(zlibContext->decompressor, compressed.data(), compressed.length() + 9, buf, 4096, &written);
|
||||
memcpy((char *) compressed.data() + compressed.length(), tmp, 9);
|
||||
|
||||
if (res == 0) {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// clang-format off
|
||||
#ifndef UWS_WEBSOCKETCONTEXT_H
|
||||
#define UWS_WEBSOCKETCONTEXT_H
|
||||
|
||||
@@ -270,7 +270,7 @@ private:
|
||||
webSocketData->subscriber = nullptr;
|
||||
|
||||
if (webSocketContextData->closeHandler) {
|
||||
webSocketContextData->closeHandler((WebSocket<SSL, isServer, USERDATA> *) s, 1006, {(char *) reason, (size_t) code});
|
||||
webSocketContextData->closeHandler((WebSocket<SSL, isServer, USERDATA> *) s, 1006, reason != NULL && code > 0 ? std::string_view{(char *) reason, (size_t) code} : std::string_view());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <string_view>
|
||||
|
||||
// bun-specific
|
||||
#include "simdutf.h"
|
||||
#include "wtf/SIMDUTF.h"
|
||||
|
||||
namespace uWS {
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@ param(
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
. (Join-Path $PSScriptRoot "env.ps1")
|
||||
|
||||
if ($env:CI) {
|
||||
. (Join-Path $PSScriptRoot "env.ps1")
|
||||
if ($env:CI -eq "true") {
|
||||
& (Join-Path $PSScriptRoot "update-submodules.ps1")
|
||||
}
|
||||
|
||||
@@ -79,6 +79,10 @@ Build-Dependency `
|
||||
-Script "lshpack" `
|
||||
-Outputs @("lshpack.lib")
|
||||
|
||||
Build-Dependency `
|
||||
-Script "libdeflate" `
|
||||
-Outputs @("deflate.lib")
|
||||
|
||||
if (!($Script:DidAnything)) {
|
||||
Write-Host "(run with -Force to rebuild all)"
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ set -eo pipefail
|
||||
source "$(dirname -- "${BASH_SOURCE[0]}")/env.sh"
|
||||
|
||||
if [[ "$CI" ]]; then
|
||||
$(dirname -- "${BASH_SOURCE[0]}")/update-submodules.sh
|
||||
$(dirname -- "${BASH_SOURCE[0]}")/update-submodules.sh
|
||||
fi
|
||||
|
||||
FORCE=
|
||||
@@ -36,9 +36,11 @@ fi
|
||||
dep() {
|
||||
local submodule="$1"
|
||||
local script="$2"
|
||||
CACHE_KEY=
|
||||
if [ "$CACHE" == "1" ]; then
|
||||
CACHE_KEY="$submodule/$(echo "$SUBMODULES" | grep "$submodule" | git hash-object --stdin)"
|
||||
local hash="$(echo "$SUBMODULES" | grep "$submodule" | awk '{print $1}')"
|
||||
local os="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
||||
local arch="$(uname -m)"
|
||||
CACHE_KEY="$submodule/$hash-$os-$arch-$CPU_TARGET"
|
||||
fi
|
||||
if [ -z "$FORCE" ]; then
|
||||
HAS_ALL_DEPS=1
|
||||
@@ -92,6 +94,7 @@ dep mimalloc mimalloc libmimalloc.a libmimalloc.o
|
||||
dep tinycc tinycc libtcc.a
|
||||
dep zlib zlib libz.a
|
||||
dep zstd zstd libzstd.a
|
||||
dep libdeflate libdeflate libdeflate.a
|
||||
dep ls-hpack lshpack liblshpack.a
|
||||
|
||||
if [ "$BUILT_ANY" -eq 0 ]; then
|
||||
|
||||
@@ -3,6 +3,7 @@ $ErrorActionPreference = 'Stop' # Setting strict mode, similar to 'set -euo pip
|
||||
|
||||
Push-Location (Join-Path $BUN_DEPS_DIR 'boringssl')
|
||||
try {
|
||||
Remove-Item -ErrorAction SilentlyContinue -Recurse -Force build
|
||||
Set-Location (mkdir -Force build)
|
||||
|
||||
Run cmake @CMAKE_FLAGS ..
|
||||
|
||||
@@ -6,7 +6,7 @@ cd $BUN_DEPS_DIR/boringssl
|
||||
mkdir -p build
|
||||
cd build
|
||||
|
||||
cmake "${CMAKE_FLAGS[@]}" -DCMAKE_EXE_LINKER_FLAGS="-fuse-ld=lld" -GNinja ..
|
||||
cmake "${CMAKE_FLAGS[@]}" -GNinja ..
|
||||
ninja libcrypto.a libssl.a libdecrepit.a
|
||||
|
||||
cp **/libcrypto.a $BUN_DEPS_OUT_DIR/libcrypto.a
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
param (
|
||||
[switch] $Baseline = $False,
|
||||
[switch] $Fast = $False
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop' # Setting strict mode, similar to 'set -euo pipefail' in bash
|
||||
|
||||
$Tag = If ($Baseline) { "-Baseline" } Else { "" }
|
||||
$UseBaselineBuild = If ($Baseline) { "ON" } Else { "OFF" }
|
||||
$UseLto = If ($Fast) { "OFF" } Else { "ON" }
|
||||
. (Join-Path $PSScriptRoot "env.ps1")
|
||||
if ($env:CI -eq "true") {
|
||||
$env:FORCE_UPDATE_SUBMODULES = "1"
|
||||
& (Join-Path $PSScriptRoot "update-submodules.ps1")
|
||||
& (Join-Path $PSScriptRoot "build-libuv.ps1") -CloneOnly $True
|
||||
}
|
||||
|
||||
# $CANARY_REVISION = if (Test-Path build/.canary_revision) { Get-Content build/.canary_revision } else { "0" }
|
||||
$CANARY_REVISION = 0
|
||||
.\scripts\env.ps1 $Tag
|
||||
.\scripts\update-submodules.ps1
|
||||
.\scripts\build-libuv.ps1 -CloneOnly $True
|
||||
cd build
|
||||
|
||||
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release `
|
||||
cmake .. @CMAKE_FLAGS `
|
||||
-G Ninja `
|
||||
-DCMAKE_BUILD_TYPE=Release `
|
||||
-DNO_CODEGEN=0 `
|
||||
-DNO_CONFIGURE_DEPENDS=1 `
|
||||
"-DUSE_BASELINE_BUILD=${UseBaselineBuild}" `
|
||||
"-DUSE_LTO=${UseLto}" `
|
||||
"-DCANARY=${CANARY_REVISION}" `
|
||||
-DBUN_CPP_ONLY=1 $Flags
|
||||
-DBUN_CPP_ONLY=1
|
||||
if ($LASTEXITCODE -ne 0) { throw "CMake configuration failed" }
|
||||
|
||||
.\compile-cpp-only.ps1 -v
|
||||
if ($LASTEXITCODE -ne 0) { throw "C++ compilation failed" }
|
||||
.\compile-cpp-only.ps1 -v -j $env:CPUS
|
||||
if ($LASTEXITCODE -ne 0) { throw "C++ compilation failed" }
|
||||
|
||||
# HACK: For some reason, the buildkite agent is hanging when uploading bun-cpp-objects.a
|
||||
# Best guess is that there is an issue when uploading files larger than 500 MB
|
||||
#
|
||||
# For now, use FileSplitter to split the file into smaller chunks:
|
||||
# https://www.powershellgallery.com/packages/FileSplitter/1.3
|
||||
if ($env:BUILDKITE) {
|
||||
Split-File -Path (Resolve-Path "bun-cpp-objects.a") -PartSizeBytes "50MB" -Verbose
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user