24 个版本 (2 个稳定版)
1.1.0 | 2023年3月23日 |
---|---|
1.0.0 | 2022年2月10日 |
1.0.0-alpha.1 | 2022年1月24日 |
0.10.1 | 2020年10月6日 |
0.0.4 | 2019年11月5日 |
#106 in WebAssembly
1,990 每月下载量
用于 7 crates
30KB
363 行
waPC
这是 waPC 主机协议的 Rust 实现。这个工具包定义了 WapcHost
结构体和 WebAssemblyEngineProvider
特性,以提供 WebAssembly 模块的动态执行。有关 WebAssembly 引擎实现的详细信息,请参阅下面的提供者工具包。
wapc
wapc
工具包提供了一个符合 RPC 机制(称为 waPC,即 WebAssembly Procedure Calls)的高级 WebAssembly 主机运行时。waPC 设计为一个固定、轻量级的标准,允许 guest/host 边界两边进行包含任意二进制有效负载的方法调用。合同的任何一方都不需要执行显式分配,确保了可能在不同垃圾收集器和内存重定位、压缩等情况中表现不同的 wasm 目标的最大可移植性。
要使用 wapc
,首先您需要一个符合 waPC 规范的 WebAssembly 模块(称为 guest),以便加载和执行。您可以在 GitHub 仓库 中找到许多这样的示例。
接下来,您需要选择一个运行时引擎。waPC 描述了 wasm-RPC 所需的函数调用流程,但它并没有规定如何执行低级 WebAssembly 函数调用。这允许您选择最适合您需求的引擎,无论是基于 JIT 的引擎还是基于解释器的引擎。只需实例化实现 WebAssemblyEngineProvider 特性的任何内容,并将其传递给 WapcHost 构造函数,WapcHost 将简化所有 RPC。
要执行函数调用,确保在创建您的 WapcHost 时提供了合适的主机回调函数(或闭包)。然后调用 call
函数以启动 RPC 流程。
示例
以下是一个 WebAssembly 主机运行时和 guest 模块之间同步、双向过程调用的示例。
use wasmtime_provider::WasmtimeEngineProvider; // Or Wasm3EngineProvider
use wapc::WapcHost;
use std::error::Error;
pub fn main() -> Result<(), Box<dyn Error>> {
// Sample host callback that prints the operation a WASM module requested.
let host_callback = |id: u64, bd: &str, ns: &str, op: &str, payload: &[u8]| {
println!("Guest {} invoked '{}->{}:{}' with a {} byte payload",
id, bd, ns, op, payload.len());
// Return success with zero-byte payload.
Ok(vec![])
};
let file = "../../wasm/crates/wasm-basic/build/wasm_basic.wasm";
let module_bytes = std::fs::read(file)?;
let engine = WasmtimeEngineProvider::new(&module_bytes, None)?;
let host = WapcHost::new(Box::new(engine), Some(Box::new(host_callback)))?;
let res = host.call("ping", b"payload bytes")?;
assert_eq!(res, b"payload bytes");
Ok(())
}
要运行示例,请参阅各个引擎提供者仓库中的示例。
- wasmtime-provider - 利用Bytecode Alliance运行时wasmtime进行WebAssembly的JIT编译和执行。
- wasm3-provider - 使用wasm3的C解释器运行时(带有Rust封装)
注意
waPC是响应式的。主机发起请求,客户端做出响应。在请求过程中,客户端可以回叫主机并与环境(通过WASI)交互。当请求完成后,客户端应被视为已停放,直到下一次请求。
RPC交换流程
以下是对支持waPC交换流程的函数调用的详细概述,该流程始终由消费者调用call
函数触发。调用和处理这些底层函数是引擎提供者的责任,而协调高级控制流程是WapcHost
的工作。
- 主机通过引擎提供者在WebAssembly模块上调用
__guest_call
- 客户端调用
__guest_request
函数来指示主机将请求参数写入线性内存 - 客户端使用步骤2中生成的指针值以及
op_len和
msg_len
参数来检索操作(UTF-8字符串)和有效负载(不透明的字节数组) - 客户端执行工作
- (可选) 客户端调用主机上的
__host_call
,并使用指示binding
、namespace
、operation
和有效负载的指针和长度 - (可选) 客户端可以使用
__host_response
和host_response_len
函数来获取和解释结果 - (可选) 客户端可以使用
__host_error_len
和__host_error
来获取主机错误(如果有的话)(当__host_call
返回0时)- 步骤5-7可以根据客户端需要的不同主机调用重复进行
- 客户端将调用
guest_error
来指示处理过程中是否发生错误 - 客户端将调用
guest_response
来存储不透明的响应有效负载 - 客户端将在
__guest_call
结束时返回0(错误)或1(成功)
必需的主机导出
必须由主机导出(客户端导入)的函数列表
模块 | 函数 | 参数 | 描述 |
---|---|---|---|
wapc | __host_call | br_ptr: i32 bd_len: i32 ns_ptr: i32 ns_len: i32 op_ptr: i32 op_len: i32 ptr: i32 len: i32 -> i32 |
用于发起主机调用的函数 |
wapc | __console_log | ptr: i32, len: i32 | 允许客户端将日志记录到stdout |
wapc | __guest_request | op_ptr: i32 ptr: i32 |
将客户端请求有效负载和操作名称写入指定位置的线性内存 |
wapc | __host_response | ptr: i32 | 指示主机将主机响应有效负载写入指定位置的线性内存 |
wapc | __host_response_len | -> i32 | 获取当前主机响应的长度 |
wapc | __guest_response | ptr: i32 len: i32 |
告知主机当前客户端响应有效负载的大小和位置 |
wapc | __guest_error | ptr: i32 len: i32 |
告知主机当前客户端错误有效负载的大小和位置 |
wapc | __host_error | ptr: i32 | 指示主机将主机错误有效负载写入指定位置 |
wapc | __host_error_len | -> i32 | 查询主机的当前主机错误长度(如果没有则为0) |
必需的客戶导出
必须由客戶导出的函数列表(由主机调用)
函数 | 参数 | 描述 |
---|---|---|
__guest_call | op_len: i32 msg_len: i32 |
由主机调用以启动与客戶模块的RPC交换 |
依赖关系
~0.7–6MB
~30K SLoC