我正在开发一个全新的 HTTP-gRPC 远程调用方案。
项目目前刚刚起步,不过已经取得了不少进展,在此与大家分享。
1. 全球最小的 Protobuf 数据 JS 编解码器
首先,我已经实现了一个极其轻量级的、用于 proto 数据的 JS 编解码器。
运行 js0-grpc/proto/test/bundle.js,结果如下:
| file | minify | zstd | gz | br |
|---|---|---|---|---|
| demo/test/D.js | 1896 | 1039 | 1031 | 949 |
| demo/test/E.js | 1596 | 869 | 865 | 789 |
| demo/test/echoD.js | 892 | 526 | 523 | 473 |
| demo/test/echoE.js | 700 | 429 | 426 | 405 |
如果对所有数据类型进行解码和编码,在 br 压缩后,尺寸分别仅为 949 和 789 字节。
如果只对部分数据类型进行解码和编码,比如:
message Echo {
string id = 1;
}
在“摇树优化”(tree-shaking)和 br 压缩后,解码器和编码器的尺寸分别仅为 473 和 405 字节,这个体积远小于市面上任何其他的 Protobuf JavaScript 编解码库。
具体用法参见 js0-grpc/blob/main/proto/test/encode.js。
2. 基于 Protobuf 生成 JS 编解码文件
此工具可基于 .proto 文件生成编解码器的 JS 文件。
比如,运行 ./proto2js/test/gen.js,对于:
message Echo {
string id = 1;
}
会生成其解码器 ./proto2js/test/out/test/EchoD.js:
import { $, string } from "@js0.site/proto/D.js"
export default $([
/* 1 id */ string
])
和编码器 ./proto2js/test/out/test/EchoE.js:
import { $, string } from "@js0.site/proto/E.js"
export default $([
/* 1 id */ string
])
3. 基于 Rust 库生成 Protobuf 文件
运行 ./rs2proto/test.sh。
如下的 Rust 代码:
mod rm;
pub use rm::rm as rm_renamed;
pub mod admin;
pub mod auth;
pub fn add(left: u64, right: u64) -> u64 {
left + right
}
pub fn noargs() {}
pub fn args(
bytes1: &[u8],
bytes2: Vec<u8>,
bytes3: impl AsRef<[u8]>,
u64_1: &[u64],
u64_2: Vec<u64>,
option_u64: Option<u64>
) -> aok::Result<u8>{
Ok(0)
}
pub use use_rename_test as renamed;
可以生成如下的 .proto 文件:
// AUTO GEN BY rs2proto
syntax = "proto3";
package js0_test;
import "google/protobuf/empty.proto";
message argsResult {
uint32 data = 1;
}
message argsArgs {
bytes bytes1 = 1;
bytes bytes2 = 2;
bytes bytes3 = 3;
repeated uint64 u64_1 = 4;
repeated uint64 u64_2 = 5;
optional uint64 option_u64 = 6;
}
message addResult {
uint64 data = 1;
}
message addArgs {
uint64 left = 1;
uint64 right = 2;
}
message authLoginResult {
uint64 data = 1;
}
message authLoginArgs {
string username = 1;
string password = 2;
bytes token = 3;
}
message adminUserNewArgs {
uint64 id = 1;
string name = 2;
}
message rmRenamedArgs {
uint64 id = 1;
}
service Api {
rpc rmRenamed(rmRenamedArgs) returns (google.protobuf.Empty);
rpc adminUserNew(adminUserNewArgs) returns (google.protobuf.Empty);
rpc authLogin(authLoginArgs) returns (authLoginResult);
rpc add(addArgs) returns (addResult);
rpc noargs(google.protobuf.Empty) returns (google.protobuf.Empty);
rpc args(argsArgs) returns (argsResult);
}
正在开发
我正在用 Rust + Tokio 实现一个 HTTP-gRPC 请求转换网关,并能自动生成相应的 JS 调用文件,目标是把 Rust 函数无缝映射到前端网页上。
并且,将支持自动合并多个请求为一个请求(例如,首页上请求用户名和请求消息流是两个不同的 RPC 调用,可以通过类似 setTimeout(()=>{mergePendingRpcCall()},10) 的节流函数,自动将多个调用合并为一个 HTTP 请求)。
同时,通过自动合并结构相同的参数和响应,降低生成的 gRPC JS 调用文件的体积。
此外,还将加入 HTTP 对 gRPC 流响应的支持等等。