Skip to content

feat(wasi): expose protobuf RPC request ABI - #2477

Merged
KKRainbow merged 4 commits into
EasyTier:mainfrom
KKRainbow:codex/rpc-wasm-abi
Aug 7, 2026
Merged

feat(wasi): expose protobuf RPC request ABI#2477
KKRainbow merged 4 commits into
EasyTier:mainfrom
KKRainbow:codex/rpc-wasm-abi

Conversation

@KKRainbow

Copy link
Copy Markdown
Member

Summary

  • add a versioned asynchronous DirectRpcRequest/RpcResponse ABI for WASI core instances
  • reuse the shared RPC dispatcher and bounded operation broker for PeerManageRpc, ConnectorManageRpc, and ConfigRpc
  • move the WASI config-server client onto host socket and management adapters, including forwarded instance-management registration
  • bound UDP port-forward clients and serialize eviction, permit handoff, and client/task publication
  • add regression coverage for RPC forwarding and concurrent UDP admission

Testing

  • cargo fmt --all -- --check
  • cargo clippy --all-targets --features full --all -- -D warnings
  • cargo hack check --package easytier --each-feature --exclude-features macos-ne --verbose
  • cargo test -p easytier-core (634 passed)
  • cargo metadata --format-version 1 --locked --no-deps
  • script/build-wasi-core.sh (wasm32-wasip1 release + wasm-opt 131)

Add an instance-scoped asynchronous RPC session backed by the shared
operation broker. Reuse the existing dispatcher and management handlers.
WASI hosts can call PeerManageRpc and ConnectorManageRpc with the same
protobuf payloads as easytier-cli.

Export ABI version, submit, take, and free functions. Bind selectors to
the WASM instance handle and keep method errors in RpcResponse. Enable
management RPC explicitly in the Go-host WASM build.
Serialize UDP client admission across forwarding rules so only one
eviction can claim and wait for a released semaphore permit. Retry
when cleanup concurrently removes the selected client.

Add a multithreaded regression test for the permit handoff while the
evicted client is still referenced.
Hold the admission guard through client and response-task publication
so a concurrent eviction cannot leave an orphan task holding the slot
permit.

Open the data-plane flow before entering the critical section and extend
the multithreaded regression test across the publication window.
Register PeerManageRpc, ConnectorManageRpc, and ConfigRpc in the WASI
WebClient registry so config-server requests reach host forwarding.

Share descriptor-based forwarding across the supported services and add
a regression test for registration and canonical method names.
Copilot AI lite review requested due to automatic review settings August 6, 2026 14:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

This PR adds a versioned, transport-neutral protobuf RPC ABI for WASI core instances, and moves WASI “web client” management calls onto host socket/management adapters while improving UDP port-forward robustness.

Changes:

  • Introduces DirectRpcRequest / RpcResponse-based RPC submission & response-taking guest exports for WASI.
  • Adds a WASI WebClient runtime backed by host-provided management/socket adapters and forwards instance-management RPC.
  • Bounds UDP port-forward clients and adds regression tests for max UDP payload and concurrent admission/eviction behavior.

Reviewed changes

Copilot reviewed 33 out of 33 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
script/build-wasi-core.sh Enables management-rpc feature in the WASI core build script.
easytier-proto/proto/common.proto Adds transport-neutral DirectRpcRequest and HostManagementRequest messages.
easytier-proto/proto/api_config.proto Extends GetConfigResponse with toml_config.
easytier-core/src/wasi/web_client.rs Adds WASI WebClient runtime that forwards management calls to the host.
easytier-core/src/wasi/schema.rs Adds versioned WASI WebClient create-config schema + validation.
easytier-core/src/wasi/runtime/abi/web_client.rs Exposes WebClient lifecycle ABI exports for WASI.
easytier-core/src/wasi/runtime/abi/rpc.rs Adds WASI instance-scoped async RPC request/response ABI exports.
easytier-core/src/wasi/runtime.rs Wires instance runtime host + hooks in management RPC operation session.
easytier-core/src/wasi/mod.rs Exposes WASI web_client module behind management on WASI.
easytier-core/src/wasi/imports.rs Adds host imports for process-level management calls (feature-gated).
easytier-core/src/wasi/adapter/mod.rs Registers WASI management adapter module behind management.
easytier-core/src/wasi/adapter/management.rs Implements host management I/O via WASI imports.
easytier-core/src/wasi/abi.rs Adds ABI versions and export lists for WebClient + RPC ABI.
easytier-core/src/rpc/service_registry.rs Adds method-name resolution support for direct RPC dispatch.
easytier-core/src/rpc/server.rs Refactors server dispatch via shared dispatcher and fixes accepted compression reporting.
easytier-core/src/rpc/packet.rs Adds accepted_compression_algo() helper and updates compression tests.
easytier-core/src/rpc/operation.rs Implements async local RPC operations backed by the operation broker.
easytier-core/src/rpc/mod.rs Wires new dispatch and operation modules.
easytier-core/src/rpc/dispatch.rs Introduces transport-neutral request dispatch helpers.
easytier-core/src/rpc/client.rs Uses accepted_compression_algo() for compression negotiation.
easytier-core/src/management/mod.rs Adds forwarded RPC module and WASI-bound management RPC registration.
easytier-core/src/management/instance_rpc/mod.rs Refactors instance resolution behind a resolver trait; adds bound-instance validation tests.
easytier-core/src/management/instance_rpc/full.rs Extends ConfigRpc GetConfig to also return TOML.
easytier-core/src/management/full/web_client.rs Splits WebClient backend behind a trait; allows WASI host-backed backend.
easytier-core/src/management/full/mod.rs Re-exports WebClientBackend for WASI builds.
easytier-core/src/management/forwarded_rpc.rs Implements forwarding handlers for bound management RPC services.
easytier-core/src/host/mod.rs Adds host management module behind management.
easytier-core/src/host/management.rs Adds host management client abstraction built on HostSocketRuntime ops.
easytier-core/src/gateway/port_forward.rs Bounds UDP clients with semaphore + serialized eviction/handoff; adds concurrency tests.
easytier-core/src/gateway/dataplane/tests.rs Adds regression test for maximum IPv4 UDP payload carriage.
easytier-core/src/gateway/dataplane/stack.rs Configures smoltcp UDP TX buffers/meta sizes.
easytier-core/src/foundation/mod.rs Enables operation broker for WASI management-rpc builds.
easytier-core/Cargo.toml Increases smoltcp fragmentation/reassembly buffer sizes to support large payloads.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +109 to +142
let response = tokio::select! {
_ = cancellation.cancelled() => None,
result = async {
let descriptor = registry
.resolve_method("", &request.full_method_name)
.ok_or_else(|| {
error::Error::InvalidServiceKey(
request.full_method_name.clone(),
String::new(),
)
})?;
dispatch_payload(
registry.as_ref(),
descriptor,
request.request.into(),
request
.timeout_ms
.map(std::time::Duration::from_millis),
None,
)
.await
} => {
Some(encode_response(
result,
started.elapsed().as_micros() as u64,
max_response_len,
))
}
};
let mut state = state.lock().unwrap_or_else(|error| error.into_inner());
state
.broker
.complete_with(operation_id.0, |_, _| response.unwrap_or_default());
});

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This cancellation path cannot expose an empty response. free() moves a pending broker entry to Discarding before cancelling its token, while discard_all() removes the entry entirely. When the spawned task later calls complete_with, the broker either absorbs that late completion in Discarding or finds the operation missing, so the closure containing unwrap_or_default() is never invoked and no response can be read. The pending-operation cancellation test covers this lifecycle.

Comment on lines 286 to 292
#[tokio::test]
async fn compression_negotiation_falls_back_when_zstd_is_unavailable() {
assert_eq!(accepted_compression_algo(), CompressionAlgoPb::None);

let (content, algorithm) = compress_packet(CompressionAlgoPb::Zstd, b"rpc body")
.await
.unwrap();

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assertion is already compiled only under #[cfg(all(test, not(feature = "zstd")))]. With Zstd enabled the entire test module is excluded, so the assertion cannot fail on a Zstd-capable build.

Comment on lines +24 to +31
dispatch_payload(
registry,
descriptor,
Bytes::from(request.request),
Some(Duration::from_millis(request.timeout_ms as u64)),
tunnel_info,
)
.await

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a behavior-preserving extraction from the existing server implementation on main, which already converts RpcRequest.timeout_ms with as u64; the client has the same existing conversion. The new ABI request introduced here uses optional uint64 timeout_ms and does not enter this path. Rejecting negative legacy RpcRequest values is a valid protocol-hardening follow-up, but changing existing wire behavior is outside this ABI patch.

@KKRainbow
KKRainbow merged commit 1e40350 into EasyTier:main Aug 7, 2026
97 of 115 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants