Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 41 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,41 @@ jobs:
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
# 插件沙箱里的 QuickJS 编成这个目标(crates/tw-plugin/build.rs)
targets: wasm32-unknown-unknown
- uses: Swatinem/rust-cache@v2

# 编插件沙箱要一个能出 wasm 的 clang:这里是 Homebrew 的 llvm,由 build.rs
# 自己找到(顺便测了「装了 brew 的 llvm 就能编」这条路)
- name: Toolchain for the plugin sandbox
run: bash scripts/wasm-toolchain.sh

- name: Format
run: cargo fmt --all -- --check
run: |
cargo fmt --all -- --check
# 沙箱里的那个小工程不在工作区里,上面一行管不到它
cargo fmt --manifest-path crates/tw-plugin/guest/Cargo.toml -- --check

- name: clippy
run: cargo clippy --workspace --all-targets -- -D warnings

# 沙箱里的胶水(编成 wasm32 的 no_std 小工程)。build.rs 编它时不带 -D warnings
# —— 那是给外层工作区的 —— 所以它的告警只在这一步当错误
- name: clippy (plugin sandbox guest)
run: |
LLVM="$(brew --prefix llvm)/bin"
CC_wasm32_unknown_unknown="$LLVM/clang" AR_wasm32_unknown_unknown="$LLVM/llvm-ar" \
cargo clippy --manifest-path crates/tw-plugin/guest/Cargo.toml --target wasm32-unknown-unknown --target-dir target/tw-plugin-guest -- -D warnings

# 默认不跑打真实网络的那些(它们标了 #[ignore])—— CI 上的网络
# 抖动会变成一条和代码无关的红,而那种红看几次就没人看了。
- name: Test
run: cargo test --workspace

# 编进这一版的沙箱是哪个 clang 编的、wasm 的哈希
- name: Which compiler built the plugin sandbox
run: bash scripts/wasm-toolchain.sh record target

# 桌面端从 tw-api 导出前端类型(`ts` feature)。**默认关**,上面几步一行都
# 不编它 —— 而它坏掉的表现是桌面端接下一个 tag 时才发现导不出来。导出来
# 的文件再过一遍 tsc:ts-rs 生成的东西本身也可能不是合法的 TypeScript
Expand Down Expand Up @@ -158,17 +180,25 @@ jobs:
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
targets: wasm32-unknown-unknown
- uses: Swatinem/rust-cache@v2
with:
# 理由见下面 windows 那一段
cache-on-failure: true

# 镜像预装的 clang-15,显式指定(见脚本)
- name: Toolchain for the plugin sandbox
run: bash scripts/wasm-toolchain.sh

- name: clippy
run: cargo clippy --workspace --all-targets -- -D warnings

- name: Test
run: cargo test --workspace

- name: Which compiler built the plugin sandbox
run: bash scripts/wasm-toolchain.sh record target

# 真二进制、真 socket、真数据面,和 macOS 那一步是同一个脚本
- name: Smoke (real binary, real socket, real data plane)
run: ./scripts/smoke.sh
Expand All @@ -185,6 +215,7 @@ jobs:
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
targets: wasm32-unknown-unknown
- uses: Swatinem/rust-cache@v2
with:
# **失败也存。**这个 action 默认只在任务成功时保存缓存,而一个
Expand All @@ -196,12 +227,21 @@ jobs:
# target 目录是安全的,它只是省掉那些与失败无关的部分。
cache-on-failure: true

# 镜像预装的 LLVM(C:\Program Files\LLVM),由 build.rs 自己找到
- name: Toolchain for the plugin sandbox
shell: bash
run: bash scripts/wasm-toolchain.sh

- name: clippy
run: cargo clippy --workspace --all-targets -- -D warnings

- name: Test
run: cargo test --workspace

- name: Which compiler built the plugin sandbox
shell: bash
run: bash scripts/wasm-toolchain.sh record target

- name: Build
run: cargo build --release -p twcore

Expand Down
85 changes: 78 additions & 7 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,27 @@ jobs:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
targets: aarch64-apple-darwin
# wasm32:插件沙箱里的 QuickJS(crates/tw-plugin/build.rs)
targets: aarch64-apple-darwin, wasm32-unknown-unknown
- uses: Swatinem/rust-cache@v2

# 编插件沙箱要一个能出 wasm 的 clang:Homebrew 的 llvm
- name: Toolchain for the plugin sandbox
run: bash scripts/wasm-toolchain.sh

# `-p tw-plugin`:网关还没接上插件之前,它不在 twcore 的依赖里,不点名就
# 没人编它 —— 而这条流水线要证明的正是每个目标平台都编得出沙箱
- name: Build
run: cargo build --release -p twcore --target aarch64-apple-darwin
run: cargo build --release -p twcore -p tw-plugin --target aarch64-apple-darwin

# 这个平台的沙箱是哪个 clang 编的、wasm 的哈希:进摘要,也交给 publish
- name: Which compiler built the plugin sandbox
run: bash scripts/wasm-toolchain.sh record target/aarch64-apple-darwin/release guest-build/aarch64-apple-darwin.txt
- uses: actions/upload-artifact@v4
with:
name: guest-build-aarch64-apple-darwin
path: guest-build/
if-no-files-found: error

# **产物自检。**一个编得过但起不来的二进制,从文件列表上看不出
# 任何问题 —— 而它会一路发到用户手里。
Expand Down Expand Up @@ -98,13 +114,31 @@ jobs:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
targets: x86_64-pc-windows-msvc, aarch64-pc-windows-msvc
targets: x86_64-pc-windows-msvc, aarch64-pc-windows-msvc, wasm32-unknown-unknown
- uses: Swatinem/rust-cache@v2

# 镜像预装的 LLVM(C:\Program Files\LLVM);没有就装官方发行版
- name: Toolchain for the plugin sandbox
shell: bash
run: bash scripts/wasm-toolchain.sh

# arm64 的沙箱机器码在 x64 上交叉编:build.rs 里的 Cranelift 直接编给目标平台
- name: Build
run: |
cargo build --release -p twcore --target x86_64-pc-windows-msvc
cargo build --release -p twcore --target aarch64-pc-windows-msvc
cargo build --release -p twcore -p tw-plugin --target x86_64-pc-windows-msvc
cargo build --release -p twcore -p tw-plugin --target aarch64-pc-windows-msvc

- name: Which compiler built the plugin sandbox
shell: bash
run: |
for t in x86_64-pc-windows-msvc aarch64-pc-windows-msvc; do
bash scripts/wasm-toolchain.sh record "target/$t/release" "guest-build/$t.txt"
done
- uses: actions/upload-artifact@v4
with:
name: guest-build-windows
path: guest-build/
if-no-files-found: error

# **产物自检。**一个编得过但起不来的二进制,从文件列表上看不出任何
# 问题 —— 而它会一路发到用户手里。
Expand Down Expand Up @@ -202,13 +236,25 @@ jobs:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
targets: ${{ matrix.target }}, wasm32-unknown-unknown
- uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.target }}

# 两种 runner 都预装 clang-15,两个架构用同一个版本(见脚本)
- name: Toolchain for the plugin sandbox
run: bash scripts/wasm-toolchain.sh

- name: Build
run: cargo build --release -p twcore --target ${{ matrix.target }}
run: cargo build --release -p twcore -p tw-plugin --target ${{ matrix.target }}

- name: Which compiler built the plugin sandbox
run: bash scripts/wasm-toolchain.sh record "target/${{ matrix.target }}/release" "guest-build/${{ matrix.target }}.txt"
- uses: actions/upload-artifact@v4
with:
name: guest-build-${{ matrix.target }}
path: guest-build/
if-no-files-found: error

# **产物自检。**一个编得过但起不来的二进制,从文件列表上看不出任何
# 问题 —— 而它会一路发到用户手里。
Expand Down Expand Up @@ -332,8 +378,33 @@ jobs:
- uses: actions/download-artifact@v4
with:
path: dist
pattern: twcore-*
merge-multiple: true

# 每个平台的插件沙箱是哪个 clang 编的、wasm 的哈希。**只记录,不卡发版**:
# macOS 用 Homebrew 的 llvm、Linux 用 clang-15、Windows 用镜像里的 LLVM,
# 编译器不同,哈希本来就不同;同一个编译器编的(两个 Linux)应当相同
- uses: actions/download-artifact@v4
with:
path: guest-build
pattern: guest-build-*
merge-multiple: true
- name: Which compiler built each plugin sandbox
run: |
set -euo pipefail
{
echo "### Plugin sandbox"
echo
echo "| target | guest.wasm sha256 | clang |"
echo "|---|---|---|"
for f in guest-build/*.txt; do
t=$(basename "$f" .txt)
sha=$(awk '/^guest.wasm sha256 /{print $3}' "$f")
cc=$(sed -n 's/^clang //p' "$f" | head -n 1)
echo "| $t | \`$sha\` | $cc |"
done
} | tee -a "$GITHUB_STEP_SUMMARY"

# 排练也跑这一步:构建 job 交来的正好是清单上的文件,每个都对得上
# 它的校验和
- name: Every file is here, nothing else is, and each matches its checksum
Expand Down
40 changes: 40 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,19 @@ cargo test --workspace
./scripts/smoke.sh
```

Building `tw-plugin` needs an LLVM clang that targets WebAssembly; the README's
"Build and test" says how to install one. If you changed
`crates/tw-plugin/guest`, which is not a workspace member, check it on its own
as well (on macOS with Homebrew's LLVM):

```bash
cargo fmt --manifest-path crates/tw-plugin/guest/Cargo.toml -- --check
CC_wasm32_unknown_unknown="$(brew --prefix llvm)/bin/clang" \
AR_wasm32_unknown_unknown="$(brew --prefix llvm)/bin/llvm-ar" \
cargo clippy --manifest-path crates/tw-plugin/guest/Cargo.toml --target wasm32-unknown-unknown \
--target-dir target/tw-plugin-guest -- -D warnings
```

Warnings are errors, and relaxing that on CI is the same as removing it.
The toolchain is `stable`, so a newer stable than your local one can
surface lints you cannot reproduce — `rustup update stable` before
Expand Down Expand Up @@ -105,6 +118,33 @@ clean the diff is:
connections to the same handshake before HTTP. The control key never
leaves through the control plane and cannot be changed through it.

## The plugin sandbox

Script plugins run in `tw-plugin`: QuickJS-ng, from the pinned `rquickjs-sys`
crate, compiled to `wasm32-unknown-unknown` and run by Wasmtime. Its
`build.rs` does three things on every build, and nothing is committed or
downloaded:

1. **Compile the guest** (`crates/tw-plugin/guest`, outside the workspace,
with its own `Cargo.lock`) with the clang it finds. The module may import
two functions, a log line and the clock; the build fails if it imports
anything else.
2. **Snapshot it.** It runs the bridge script (`src/bridge.js`) once inside the
module and writes the initialized memory back into it, so every sandbox
starts with QuickJS already set up.
3. **Precompile it** with Cranelift for the target being built, cross targets
included. The binary embeds the result and contains only Wasmtime's
runtime, no compiler.

Wasmtime is pinned to one exact version both as a dependency and as a
build-dependency: a precompiled module only loads in the Wasmtime version, and
with the settings (`src/engine.rs`), it was compiled with. Upgrade both
together.

Only `tw-gateway` and `twcore` may depend on `tw-plugin`.
`crates/tw-plugin/tests/boundary.rs` fails when a crate that Lite or
Enterprise builds reaches it, because their builds would suddenly need clang.

## The configuration reference

`docs/config.md` and `docs/config.zh-CN.md` are written by hand, except the
Expand Down
Loading
Loading