#wasm-module #wasm-engine #wasi #sdk #api-bindings

wapc

一个支持插件引擎的 WebAssembly 主机运行时,实现了 waPC 协议

24 个版本 (2 个稳定版)

1.1.0 2023年3月23日
1.0.0 2022年2月10日
1.0.0-alpha.12022年1月24日
0.10.1 2020年10月6日
0.0.4 2019年11月5日

#106 in WebAssembly

Download history 811/week @ 2024-04-01 992/week @ 2024-04-08 631/week @ 2024-04-15 526/week @ 2024-04-22 357/week @ 2024-04-29 631/week @ 2024-05-06 305/week @ 2024-05-13 445/week @ 2024-05-20 289/week @ 2024-05-27 307/week @ 2024-06-03 441/week @ 2024-06-10 803/week @ 2024-06-17 605/week @ 2024-06-24 267/week @ 2024-07-01 501/week @ 2024-07-08 611/week @ 2024-07-15

1,990 每月下载量
用于 7 crates

Apache-2.0

30KB
363

waPC

crates.io license

这是 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(())
}

要运行示例,请参阅各个引擎提供者仓库中的示例。

注意

waPC是响应式的。主机发起请求,客户端做出响应。在请求过程中,客户端可以回叫主机并与环境(通过WASI)交互。当请求完成后,客户端应被视为已停放,直到下一次请求。

RPC交换流程

以下是对支持waPC交换流程的函数调用的详细概述,该流程始终由消费者调用call函数触发。调用和处理这些底层函数是引擎提供者的责任,而协调高级控制流程是WapcHost的工作。

  1. 主机通过引擎提供者在WebAssembly模块上调用__guest_call
  2. 客户端调用__guest_request函数来指示主机将请求参数写入线性内存
  3. 客户端使用步骤2中生成的指针值以及op_lenmsg_len参数来检索操作(UTF-8字符串)和有效负载(不透明的字节数组)
  4. 客户端执行工作
  5. (可选) 客户端调用主机上的__host_call,并使用指示bindingnamespaceoperation和有效负载的指针和长度
  6. (可选) 客户端可以使用__host_responsehost_response_len函数来获取和解释结果
  7. (可选) 客户端可以使用__host_error_len__host_error来获取主机错误(如果有的话)(当__host_call返回0时)
    1. 步骤5-7可以根据客户端需要的不同主机调用重复进行
  8. 客户端将调用guest_error来指示处理过程中是否发生错误
  9. 客户端将调用guest_response来存储不透明的响应有效负载
  10. 客户端将在__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