Skip to content

Commit fca6d6e

Browse files
authored
Merge pull request #2 from abracadabra233/main
feat: 初始实现基于 WebRTC 的跨 NAT 远程 RPC 中间件
2 parents 13d063b + 3be9d4d commit fca6d6e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+9270
-1
lines changed

.github/workflows/ci.yml

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
name: Build and Release
2+
3+
on:
4+
push:
5+
branches: ["main"]
6+
tags: ["v*.*.*"]
7+
pull_request:
8+
branches: ["main"]
9+
10+
env:
11+
CARGO_TERM_COLOR: always
12+
13+
jobs:
14+
# test: #todo 需要在test 中部署本地 mqtt broker
15+
# name: Test
16+
# runs-on: ubuntu-latest
17+
# steps:
18+
# - uses: actions/checkout@v4
19+
# # 安装依赖 (针对 gRPC/Protobuf)
20+
# - name: Install Dependencies
21+
# run: |
22+
# sudo apt-get update
23+
# sudo apt-get install -y protobuf-compiler
24+
# - uses: dtolnay/rust-toolchain@nightly
25+
# - uses: Swatinem/rust-cache@v2
26+
# - run: cargo test --workspace --features="grpc,rest"
27+
28+
build:
29+
name: Build ${{ matrix.target }}
30+
# 根据 matrix 动态选择运行环境:Windows 用 windows-latest,其他的用 ubuntu-latest
31+
runs-on: ${{ matrix.os }}
32+
# needs: test
33+
strategy:
34+
fail-fast: false
35+
matrix:
36+
include:
37+
# Linux x64: 原生编译
38+
- target: x86_64-unknown-linux-gnu
39+
os: ubuntu-latest
40+
use_cross: false
41+
archive_ext: tar.gz
42+
43+
# Linux ARM64: 使用 cross 工具 (Docker) 编译 #todo 麻烦,没法安装protobuf-compiler
44+
# - target: aarch64-unknown-linux-gnu
45+
# os: ubuntu-latest
46+
# use_cross: true
47+
# archive_ext: tar.gz
48+
49+
# Windows: 原生编译 (注意:通常 Windows 推荐用 msvc 而不是 gnu)
50+
- target: x86_64-pc-windows-msvc
51+
os: windows-latest
52+
use_cross: false
53+
archive_ext: zip
54+
55+
steps:
56+
- uses: actions/checkout@v4
57+
58+
# Linux (非 Cross): 安装 cmake 和 protoc
59+
- name: Install Deps (Linux)
60+
if: runner.os == 'Linux' && !matrix.use_cross
61+
run: |
62+
sudo apt-get update
63+
sudo apt-get install -y protobuf-compiler
64+
65+
# Windows: 使用 Chocolatey 安装 protoc
66+
- name: Install Deps (Windows)
67+
if: runner.os == 'Windows'
68+
run: choco install protoc
69+
70+
# 安装 Rust 工具链
71+
- name: Install Rust
72+
uses: dtolnay/rust-toolchain@nightly
73+
with:
74+
targets: ${{ matrix.target }}
75+
76+
# 缓存依赖
77+
- uses: Swatinem/rust-cache@v2
78+
with:
79+
key: ${{ matrix.target }}
80+
81+
# 安装 cross 工具 (仅当 use_cross 为 true 时)
82+
- name: Install Cross
83+
if: matrix.use_cross
84+
run: cargo install cross --git https://github.com/cross-rs/cross
85+
86+
# 构建二进制文件
87+
# 如果是 cross 模式,命令变成 "cross build",否则是 "cargo build"
88+
- name: Build
89+
shell: bash
90+
run: |
91+
CMD="cargo"
92+
if [[ "${{ matrix.use_cross }}" == "true" ]]; then
93+
CMD="cross"
94+
fi
95+
$CMD build --release --target ${{ matrix.target }} --features="grpc,rest"
96+
97+
# 打包 (兼容 Windows/Linux)
98+
- name: Package
99+
shell: bash
100+
run: |
101+
# 定义需要打包的二进制名称
102+
BINS=("proxyd" "portald" "portal_hub_grpc" "portal_hub_rest")
103+
104+
STAGING="remote_rpc_rs-${{ matrix.target }}"
105+
mkdir -p "$STAGING"
106+
107+
RELEASE_DIR="target/${{ matrix.target }}/release"
108+
109+
for bin in "${BINS[@]}"; do
110+
# 检查是否有 .exe 后缀 (Windows)
111+
if [ -f "$RELEASE_DIR/$bin.exe" ]; then
112+
cp "$RELEASE_DIR/$bin.exe" "$STAGING/"
113+
elif [ -f "$RELEASE_DIR/$bin" ]; then
114+
cp "$RELEASE_DIR/$bin" "$STAGING/"
115+
fi
116+
done
117+
118+
# 压缩
119+
if [ "${{ matrix.archive_ext }}" = "zip" ]; then
120+
7z a "$STAGING.zip" "$STAGING"
121+
echo "ASSET=$STAGING.zip" >> $GITHUB_ENV
122+
else
123+
tar -czvf "$STAGING.tar.gz" "$STAGING"
124+
echo "ASSET=$STAGING.tar.gz" >> $GITHUB_ENV
125+
fi
126+
127+
- name: Upload Artifact
128+
uses: actions/upload-artifact@v4
129+
with:
130+
name: build-${{ matrix.target }}
131+
path: ${{ env.ASSET }}
132+
133+
release:
134+
name: Release
135+
needs: build
136+
runs-on: ubuntu-latest
137+
if: startsWith(github.ref, 'refs/tags/')
138+
permissions:
139+
contents: write
140+
steps:
141+
- uses: actions/download-artifact@v4
142+
with:
143+
path: artifacts
144+
merge-multiple: true
145+
146+
- uses: softprops/action-gh-release@v2
147+
with:
148+
files: artifacts/*
149+
generate_release_notes: true

.github/workflows/mdbook.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: Deploy GitHub Pages
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*" # Trigger on version tags like v1.0.0
7+
branches:
8+
- main
9+
pull_request:
10+
11+
jobs:
12+
deploy-book:
13+
runs-on: ubuntu-22.04
14+
permissions:
15+
contents: write
16+
concurrency:
17+
group: ${{ github.workflow }}-${{ github.ref }}
18+
steps:
19+
- uses: actions/checkout@v4
20+
21+
- name: Setup mdBook
22+
uses: peaceiris/actions-mdbook@v2
23+
with:
24+
mdbook-version: "latest"
25+
26+
- name: Install mdbook-variables
27+
run: cargo install mdbook-variables
28+
29+
- run: mdbook build docs
30+
31+
- name: Deploy
32+
uses: peaceiris/actions-gh-pages@v3
33+
if: ${{ github.ref == 'refs/heads/main' }}
34+
with:
35+
github_token: ${{ secrets.GITHUB_TOKEN }}
36+
publish_dir: ./docs/book

.gitignore

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Certificates
2+
*.pem
3+
*.der
4+
*.pb
5+
# Performance analysis
6+
perf.data*
7+
# Valgrind
8+
cachegrind.out
9+
# Plot
10+
/plot
11+
**/.uuid
12+
# Logs
13+
**/logs/
14+
*.log
15+
16+
# ================
17+
# RUST
18+
# ================
19+
# Generated by Cargo will have compiled files and executables
20+
debug/
21+
target/
22+
23+
# These are backup files generated by rustfmt
24+
**/*.rs.bk
25+
26+
# ================
27+
# MSVC
28+
# ================
29+
# MSVC Windows builds of rustc generate these, which store debugging information
30+
*.pdb
31+
32+
# ================
33+
# VSCODE
34+
# ================
35+
**/.vscode/
36+
37+
# ================
38+
# JETBRAINS
39+
# ================
40+
**/.idea/
41+
42+
# ================
43+
# NODEJS
44+
# ================
45+
# Diagnostic reports (https://nodejs.org/api/report.html)
46+
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
47+
48+
# Runtime data
49+
pids
50+
*.pid
51+
*.seed
52+
*.pid.lock
53+
54+
# Dependency directories
55+
**/node_modules/
56+
57+
# dotenv environment variable files
58+
.env
59+
.env.*
60+
61+
mosquitto/data/
62+
mosquitto/log/
63+
64+
__pycache__/
65+
*.pyc
66+
*.pyo

CHANGELOG.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
1. 完善 portal hub 实现,提供 grpc 和 restful 接口
2+
2. 使用 Cargo features 来控制:可选编译 grpc 的可执行文件
3+
3. 通过 builder 工厂模式来实现封装 PortalManager 和 proxyManager 的 event 逻辑,仅返回一个 event_loop 供外部 tokio::select!
4+
4. 有一个来自 webrtc_sctp 的库 error,并不影响使用,日志屏蔽掉。**[DISPUTED: 检查是否有资源泄露]**
5+
5. src/common.rs 统一命令行 -> mqcfg 逻辑;统一初始化代码;增加 peercfg 的命令行参数;可以传入多个 --stun turn
6+
6. docker compose 增加 debug 编译,release 编译时长太久;docker compose 增加测试用例
7+
7. 完善测试用例,每个 `crates/*/tests` 目录
8+
9+
---
10+
11+
1. binder 完善日志;完善关闭逻辑,dc 和 socket 生命周期保持一致,避免资源泄露
12+
2. Portal 异常断开时,proxy 被通知具有滞后性,Portal 立马重连会导致逻辑上 bug: 为 proxy 实现 drop,在 close 时,proxyManager 删除 proxy 增加筛选条件,pc 状态 unactivate 才删除
13+
3. 完善日志,注释,清理,记录操作后 Manager 容器的当前长度
14+
4. 按照 portal PortalManager 的设计重构 proxy proxyManager
15+
5. 【portal】 使用 Unix 和 Tcp 共有的 trait 来统一 accept_loop,精简代码;unix 文件清理;日志完善
16+
6. 【PortalManager】arc portal_event_rx 在 PortalManager 中应该是独占,但他的方法都是 mut ,如果用 self.portal_event_rx 会导致 mut 传递,导致 self 没法 arc。rust Arc 只能提供 &self,不能提供 &mut self。通过引入一个 run 函数解决,在 run 函数中将 portal_event_rx 作为 mut 传入,所有权转移给 run。**[DISPUTED: 后续可通过 builder 工厂模式来实现封装]**。rust 设计哲学:狠狠地明确所有权,哪怕是微小的一个成员字段
17+
7. 【peer】portal 持有 arc signal,删除 PortalEvent 不合理:当其 close 时无法通知 PortalManager 删除它。重新设计:利用 mpsc,PortalManager 持有唯一的 event_rx,其管理的 Portal 持有 arc event_tx ,利用一个 mpsc 让 Manager 统一管理所有的 Portal 的事件,然后通过 tokio select 可统一处理 signal 的 event 和 Portal 的 event。这样 Portal 还不用持有 signal 的 arc;完美,沃日
18+
8. 【portal】保持代码的简洁,不要为了预留重连逻辑使用复杂的(linus 原则)pc: Arc<RwLock<Option<Arc<RTCPeerConnection>>>,abort_handles 没必要加锁,改为 pc: Arc<RTCPeerConnection>,
19+
9. 【peer】portal 持有 arc signal,去掉 PortalEvent
20+
10. 【PortalManager】PortalManager 和 Portal 的职责区分,addr uri 应该放在 Portal 中,事件循环当 Portal drop 时 abort
21+
11. 【PortalManager】PortalManager 的生命周期应该和 signal 一致,signal 退出时,Manager 则不可用 应该退出或者 drop
22+
23+
---
24+
25+
1. 【signal】完善 message config topic,添加[derive(Default)] ,,引入 strum 简化
26+
2. 【signal】thiserror 对比 anyhow ,简化错误处理,仅做错误打印,anyhow 更合适
27+
3. 【signal】start*event_loop 日志完善,增加跳出原因;使用 let * = tx.send(x) 忽略事件发送失败 **[DISPUTED: 如果发送失败咋办!小概率,除非库 bug]**
28+
- 实现顶掉时的通知机制同样复杂
29+
- MQTT 协议不支持拒绝新连接,硬要实现比较复杂,于是**顶掉旧连接**
30+
- rumqttc 有内置的自动重连机制会导致反复 踢掉-重连
31+
4. 同名的 mqtt broker 会踢掉前一个,signal event_loop 增加 break 条件:被踢掉,或者发布 online 失败,或者 subscribe signal topic 失败
32+
5. 删除 signal Drop 方法,因为已经有 遗嘱消息
33+
6. docker build 改为使用 user 权限,不然 vscode 插件无法生效
34+
7. 提高 signal crate 的代码质量:类名重命名,方法重命令,引入 strum 简化 enum str
35+
8. 增加命令行参数,干掉代码中硬编码的配置项
36+
9. 增加交叉编译选项,文档,docker compose
37+
10. 重构 workspace dependencie 还重构所有 crates 下的 Cargo.toml 。只启用必要特性,只写用到的库,Cargo.toml,README.md

0 commit comments

Comments
 (0)