#rpc #websocket #async #web

涡轮增压

自动生成的异步RPC绑定,通过WebSockets和WASM即时将JS前端连接到Rust后端服务

4个版本 (破坏性更新)

0.4.0 2022年7月23日
0.3.0 2022年3月5日
0.2.0 2022年1月22日
0.1.0 2021年9月10日
0.0.0 2021年1月14日

#1978 in 异步

Download history

每月下载量 93次

MIT OR Apache-2.0 OR CC0-1.0

38KB
681

涡轮增压

github crates.io docs.rs

自动生成的异步RPC绑定,通过WebSocket连接将JS或Rust/WASM前端即时连接到Rust后端。

查看https://github.com/trevyn/turbocharger-template-dioxushttps://github.com/trevyn/turbocharger-template-svelte以获取完整的模板仓库。

使Rust 后端 函数,例如

use turbocharger::prelude::*;

#[backend]
pub async fn get_person(id: i64) -> Person {
 // ... write any async backend code here; ...
 // ... query a remote database, API, etc. ...
 Person { name: "Bob", age: 21 }
}

无需额外模板即可即时提供给前端,作为一个

  • 异步Rust/WASM函数
  • 并且可选地,一个异步JavaScript函数,带有完整的TypeScript类型定义
  • 通过网络调用后端

Rust/WASM

let person = get_person(1).await;

JS

// export function get_person(id: number): Promise<Person>;

let person = await backend.get_person(1);

Rust前端可以处理所有可以用 bincode 序列化的类型。

JS前端可以处理所有由 wasm-bindgen 支持的类型,包括大多数基本类型和具有支持类型字段的自定义 struct,但是尚未支持(这些值将以TypeScript区分联合的形式出现在另一端)enum变体。

工作原理

过程宏自动生成一个前端 wasm-bindgen 模块,该模块使用 bincode 序列化前端函数调用的参数。这些请求通过共享的WebSocket连接发送到后端服务器上提供的 axum 端点,该端点调用您的后端函数并序列化响应。这是通过WebSocket发送回来的,并解析由原始前端函数调用返回的Promise或Future。

可以在单个多路复用连接上同时进行多个异步请求;一切正常工作。

完整示例:一个完整的SQLite后端和前端绑定的示例

查看https://github.com/trevyn/turbocharger-template-dioxushttps://github.com/trevyn/turbocharger-template-svelte以获取完整的模板仓库。

app.rs

use turbocharger::prelude::*;
use turbosql::Turbosql;

#[backend]
#[derive(Turbosql, Default)]
pub struct Person {
 pub rowid: Option<i64>,
 pub name: Option<String>,
}

#[backend(js)]
pub async fn insert_person(p: Person) -> Result<i64, tracked::StringError> {
 Ok(p.insert()?) // returns rowid
}

#[backend(js)]
pub async fn get_person(rowid: i64) -> Result<Person, tracked::StringError> {
 Ok(turbosql::select!(Person "WHERE rowid = ?", rowid)?)
}

server.rs

mod app;

#[tokio::main]
async fn main() {
 #[derive(rust_embed::RustEmbed)]
 #[folder = "build"]
 struct Frontend;

 eprintln!("Serving on http://127.0.0.1:8080");
 let addr = std::net::SocketAddr::from(([0, 0, 0, 0], 8080));
 turbocharger::serve::<Frontend>(&addr).await;
}

wasm.rs

mod app;

index.js

import turbocharger_init, * as backend from "./turbocharger_generated";

(async () => {
 await turbocharger_init();
 let person = Object.assign(new backend.Person(), { name: "Bob" });
 let rowid = await backend.insert_person(person);
 console.log((await backend.get_person(rowid)).toJSON());
})();

用法

使用 https://github.com/trevyn/turbocharger-template-dioxushttps://github.com/trevyn/turbocharger-template-svelte 启动新项目,以获取完整的项目布局和构建脚本。

您的 app.rs 模块包含在 server.rs 中的服务器 bin 目标以及在 wasm.rs 中的 WASM 目标中。宏 #[backend] 输出三个函数

  • 服务器 bin 目标的函数,保持不变;如果您愿意,可以直接从其他服务器代码中调用它。
  • 为服务器 bin 目标提供 RPC 分发粘合剂的内部函数。
  • 为 WASM 目标提供的一个函数,它执行 RPC 调用并返回响应。

请注意,app.rs 被编译为 wasm32-unknown-unknown 和宿主三元组,并且您可以在 app.rs 中使用 #[backend]#[frontend] 注释函数和结构体。

错误处理

#[backend(js)] 函数需要返回错误时,可以返回一个 Result<T, E: Display>,其中 T 是与 wasm-bindgen 兼容的类型,而 E 是实现了 Display 的类型,包括实现了 std::error::Error 的任何类型,包括 Box<dyn std::error::Error>>anyhow::Error。网络边界之外的错误在服务器端通过它们的 to_string() 方法转换为 String 表示,并通过 JS 侧的 Promise 拒绝交付。

返回 Result<T, tracked::StringError> 被推荐,并将产生一个包含错误位置行号的错误。

许可证:MIT 或 Apache-2.0 或 CC0-1.0(公共领域)

依赖关系

~3–22MB
~323K SLoC