mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
fix(grpc/http2) fix tonic Rust support (#20738)
Co-authored-by: cirospaciari <6379399+cirospaciari@users.noreply.github.com> Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
This commit is contained in:
@@ -700,13 +700,13 @@ pub const H2FrameParser = struct {
|
||||
// local Window limits the download of data
|
||||
|
||||
// current window size for the connection
|
||||
windowSize: u64 = 65535,
|
||||
windowSize: u64 = DEFAULT_WINDOW_SIZE,
|
||||
// used window size for the connection
|
||||
usedWindowSize: u64 = 0,
|
||||
|
||||
// remote Window limits the upload of data
|
||||
// remote window size for the connection
|
||||
remoteWindowSize: u64 = 0,
|
||||
remoteWindowSize: u64 = DEFAULT_WINDOW_SIZE,
|
||||
// remote used window size for the connection
|
||||
remoteUsedWindowSize: u64 = 0,
|
||||
|
||||
@@ -993,13 +993,13 @@ pub const H2FrameParser = struct {
|
||||
const able_to_send = frame_slice[0..max_size];
|
||||
client.queuedDataSize -= able_to_send.len;
|
||||
written.* += able_to_send.len;
|
||||
this.remoteUsedWindowSize += able_to_send.len;
|
||||
client.remoteUsedWindowSize += able_to_send.len;
|
||||
|
||||
log("dataFrame partial flushed {} {} {} {} {} {} {}", .{ able_to_send.len, frame.end_stream, client.queuedDataSize, this.remoteUsedWindowSize, client.remoteUsedWindowSize, this.remoteWindowSize, client.remoteWindowSize });
|
||||
|
||||
const padding = this.getPadding(able_to_send.len, MAX_PAYLOAD_SIZE_WITHOUT_FRAME - 1);
|
||||
const padding = this.getPadding(able_to_send.len, max_size);
|
||||
const payload_size = able_to_send.len + (if (padding != 0) padding + 1 else 0);
|
||||
|
||||
this.remoteUsedWindowSize += payload_size;
|
||||
client.remoteUsedWindowSize += payload_size;
|
||||
|
||||
var flags: u8 = 0; // we ignore end_stream for now because we know we have more data to send
|
||||
if (padding != 0) {
|
||||
flags |= @intFromEnum(DataFrameFlags.PADDED);
|
||||
@@ -1024,12 +1024,11 @@ pub const H2FrameParser = struct {
|
||||
// flush with some payload
|
||||
client.queuedDataSize -= frame_slice.len;
|
||||
written.* += frame_slice.len;
|
||||
this.remoteUsedWindowSize += frame_slice.len;
|
||||
client.remoteUsedWindowSize += frame_slice.len;
|
||||
log("dataFrame flushed {} {}", .{ frame_slice.len, frame.end_stream });
|
||||
|
||||
const padding = this.getPadding(frame_slice.len, MAX_PAYLOAD_SIZE_WITHOUT_FRAME - 1);
|
||||
const padding = this.getPadding(frame_slice.len, max_size);
|
||||
const payload_size = frame_slice.len + (if (padding != 0) padding + 1 else 0);
|
||||
this.remoteUsedWindowSize += payload_size;
|
||||
client.remoteUsedWindowSize += payload_size;
|
||||
var flags: u8 = if (frame.end_stream and !this.waitForTrailers) @intFromEnum(DataFrameFlags.END_STREAM) else 0;
|
||||
if (padding != 0) {
|
||||
flags |= @intFromEnum(DataFrameFlags.PADDED);
|
||||
@@ -2394,7 +2393,6 @@ pub const H2FrameParser = struct {
|
||||
log("remoteSettings.initialWindowSize: {} {} {}", .{ remoteSettings.initialWindowSize, this.remoteUsedWindowSize, this.remoteWindowSize });
|
||||
|
||||
if (remoteSettings.initialWindowSize >= this.remoteWindowSize) {
|
||||
this.remoteWindowSize = remoteSettings.initialWindowSize;
|
||||
var it = this.streams.valueIterator();
|
||||
while (it.next()) |stream| {
|
||||
if (remoteSettings.initialWindowSize >= stream.remoteWindowSize) {
|
||||
@@ -2426,7 +2424,6 @@ pub const H2FrameParser = struct {
|
||||
this.remoteSettings = remoteSettings;
|
||||
log("remoteSettings.initialWindowSize: {} {} {}", .{ remoteSettings.initialWindowSize, this.remoteUsedWindowSize, this.remoteWindowSize });
|
||||
if (remoteSettings.initialWindowSize >= this.remoteWindowSize) {
|
||||
this.remoteWindowSize = remoteSettings.initialWindowSize;
|
||||
var it = this.streams.valueIterator();
|
||||
while (it.next()) |stream| {
|
||||
if (remoteSettings.initialWindowSize >= stream.remoteWindowSize) {
|
||||
@@ -3262,11 +3259,7 @@ pub const H2FrameParser = struct {
|
||||
max_size = MAX_PAYLOAD_SIZE_WITHOUT_FRAME;
|
||||
}
|
||||
const size = @min(payload.len - offset, max_size);
|
||||
defer if (!enqueued) {
|
||||
log("remoteUsedWindowSize += {} {} {} {}", .{ size, stream.remoteUsedWindowSize, this.remoteUsedWindowSize, this.isServer });
|
||||
stream.remoteUsedWindowSize += size;
|
||||
this.remoteUsedWindowSize += size;
|
||||
};
|
||||
|
||||
const slice = payload[offset..(size + offset)];
|
||||
offset += size;
|
||||
const end_stream = offset >= payload.len and can_close;
|
||||
@@ -3277,8 +3270,10 @@ pub const H2FrameParser = struct {
|
||||
// the callback will only be called after the last frame is sended
|
||||
stream.queueFrame(this, slice, if (offset >= payload.len) callback else .js_undefined, offset >= payload.len and close);
|
||||
} else {
|
||||
const padding = stream.getPadding(size, max_size - 1);
|
||||
const padding = stream.getPadding(size, max_size);
|
||||
const payload_size = size + (if (padding != 0) padding + 1 else 0);
|
||||
stream.remoteUsedWindowSize += payload_size;
|
||||
this.remoteUsedWindowSize += payload_size;
|
||||
var flags: u8 = if (end_stream) @intFromEnum(DataFrameFlags.END_STREAM) else 0;
|
||||
if (padding != 0) {
|
||||
flags |= @intFromEnum(DataFrameFlags.PADDED);
|
||||
@@ -4428,8 +4423,6 @@ pub const H2FrameParser = struct {
|
||||
this.strong_ctx.set(globalObject, context_obj);
|
||||
|
||||
this.hpack = lshpack.HPACK.init(this.localSettings.headerTableSize);
|
||||
this.windowSize = this.localSettings.initialWindowSize;
|
||||
log("windowSize: {d} isServer: {}", .{ this.windowSize, is_server });
|
||||
if (is_server) {
|
||||
_ = this.setSettings(this.localSettings);
|
||||
} else {
|
||||
|
||||
@@ -84,6 +84,7 @@
|
||||
"typeorm": "0.3.20",
|
||||
"typescript": "5.0.2",
|
||||
"undici": "5.20.0",
|
||||
"unzipper": "^0.12.3",
|
||||
"v8-heapsnapshot": "1.3.1",
|
||||
"verdaccio": "6.0.0",
|
||||
"vitest": "0.32.2",
|
||||
@@ -952,6 +953,8 @@
|
||||
|
||||
"bl": ["bl@5.1.0", "", { "dependencies": { "buffer": "^6.0.3", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ=="],
|
||||
|
||||
"bluebird": ["bluebird@3.7.2", "", {}, "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="],
|
||||
|
||||
"blueimp-md5": ["blueimp-md5@2.19.0", "", {}, "sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w=="],
|
||||
|
||||
"bmp-ts": ["bmp-ts@1.0.9", "", {}, "sha512-cTEHk2jLrPyi+12M3dhpEbnnPOsaZuq7C45ylbbQIiWgDFZq4UVYPEY5mlqjvsj/6gJv9qX5sa+ebDzLXT28Vw=="],
|
||||
@@ -1188,6 +1191,8 @@
|
||||
|
||||
"duckdb": ["duckdb@1.3.1", "", { "dependencies": { "@mapbox/node-pre-gyp": "^2.0.0", "node-addon-api": "^7.0.0", "node-gyp": "^9.3.0" } }, "sha512-wSCxu6zSkHkGHtLrI5MmHYUOpbi08s2eIY/QCg2f1YsSyohjA3MRnUMdDb88oqgLa7/h+/wHuIe1RXRu4k04Sw=="],
|
||||
|
||||
"duplexer2": ["duplexer2@0.1.4", "", { "dependencies": { "readable-stream": "^2.0.2" } }, "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA=="],
|
||||
|
||||
"duplexify": ["duplexify@4.1.3", "", { "dependencies": { "end-of-stream": "^1.4.1", "inherits": "^2.0.3", "readable-stream": "^3.1.1", "stream-shift": "^1.0.2" } }, "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA=="],
|
||||
|
||||
"eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
|
||||
@@ -1886,6 +1891,8 @@
|
||||
|
||||
"node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.0.7", "", { "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-test": "build-test.js", "node-gyp-build-optional-packages-optional": "optional.js" } }, "sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w=="],
|
||||
|
||||
"node-int64": ["node-int64@0.4.0", "", {}, "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw=="],
|
||||
|
||||
"node-mock-http": ["node-mock-http@1.0.0", "", {}, "sha512-0uGYQ1WQL1M5kKvGRXWQ3uZCHtLTO8hln3oBjIusM75WoesZ909uQJs/Hb946i2SS+Gsrhkaa6iAO17jRIv6DQ=="],
|
||||
|
||||
"node-releases": ["node-releases@2.0.14", "", {}, "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw=="],
|
||||
@@ -2518,6 +2525,8 @@
|
||||
|
||||
"unstorage": ["unstorage@1.15.0", "", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^4.0.3", "destr": "^2.0.3", "h3": "^1.15.0", "lru-cache": "^10.4.3", "node-fetch-native": "^1.6.6", "ofetch": "^1.4.1", "ufo": "^1.5.4" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6.0.3", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/kv": "^1.0.1", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-m40eHdGY/gA6xAPqo8eaxqXgBuzQTlAKfmB1iF7oCKXE1HfwHwzDJBywK+qQGn52dta+bPlZluPF7++yR3p/bg=="],
|
||||
|
||||
"unzipper": ["unzipper@0.12.3", "", { "dependencies": { "bluebird": "~3.7.2", "duplexer2": "~0.1.4", "fs-extra": "^11.2.0", "graceful-fs": "^4.2.2", "node-int64": "^0.4.0" } }, "sha512-PZ8hTS+AqcGxsaQntl3IRBw65QrBI6lxzqDEL7IAo/XCEqRTKGfOX56Vea5TH9SZczRVxuzk1re04z/YjuYCJA=="],
|
||||
|
||||
"update-browserslist-db": ["update-browserslist-db@1.0.16", "", { "dependencies": { "escalade": "^3.1.2", "picocolors": "^1.0.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ=="],
|
||||
|
||||
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
|
||||
@@ -2928,6 +2937,8 @@
|
||||
|
||||
"duckdb/node-gyp": ["node-gyp@9.4.1", "", { "dependencies": { "env-paths": "^2.2.0", "exponential-backoff": "^3.1.1", "glob": "^7.1.4", "graceful-fs": "^4.2.6", "make-fetch-happen": "^10.0.3", "nopt": "^6.0.0", "npmlog": "^6.0.0", "rimraf": "^3.0.2", "semver": "^7.3.5", "tar": "^6.1.2", "which": "^2.0.2" }, "bin": { "node-gyp": "bin/node-gyp.js" } }, "sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ=="],
|
||||
|
||||
"duplexer2/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
|
||||
|
||||
"duplexify/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
|
||||
|
||||
"ecc-jsbn/jsbn": ["jsbn@0.1.1", "", {}, "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg=="],
|
||||
@@ -3466,6 +3477,12 @@
|
||||
|
||||
"duckdb/node-gyp/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||
|
||||
"duplexer2/readable-stream/isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="],
|
||||
|
||||
"duplexer2/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
|
||||
|
||||
"duplexer2/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
|
||||
|
||||
"engine.io-client/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
|
||||
|
||||
"engine.io/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
|
||||
|
||||
12
test/js/third_party/grpc-js/fixtures/tonic-server/Cargo.toml
vendored
Normal file
12
test/js/third_party/grpc-js/fixtures/tonic-server/Cargo.toml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "server"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
tonic = { version = "0.13.1", features = ["transport", "prost"] }
|
||||
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
|
||||
tokio-stream = "0.1.11"
|
||||
prost = "0.13"
|
||||
[build-dependencies]
|
||||
tonic-build = "0.13.1"
|
||||
3
test/js/third_party/grpc-js/fixtures/tonic-server/build.rs
vendored
Normal file
3
test/js/third_party/grpc-js/fixtures/tonic-server/build.rs
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
tonic_build::compile_protos("proto/helloworld.proto").unwrap();
|
||||
}
|
||||
15
test/js/third_party/grpc-js/fixtures/tonic-server/proto/helloworld.proto
vendored
Normal file
15
test/js/third_party/grpc-js/fixtures/tonic-server/proto/helloworld.proto
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package helloworld;
|
||||
|
||||
service Greeter {
|
||||
rpc SayHello (HelloRequest) returns (HelloReply);
|
||||
}
|
||||
|
||||
message HelloRequest {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
message HelloReply {
|
||||
string message = 1;
|
||||
}
|
||||
40
test/js/third_party/grpc-js/fixtures/tonic-server/src/main.rs
vendored
Normal file
40
test/js/third_party/grpc-js/fixtures/tonic-server/src/main.rs
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
use tonic::{transport::Server, Request, Response, Status};
|
||||
use helloworld::greeter_server::{Greeter, GreeterServer};
|
||||
use helloworld::{HelloRequest, HelloReply};
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
pub mod helloworld {
|
||||
tonic::include_proto!("helloworld");
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MyGreeter {}
|
||||
|
||||
#[tonic::async_trait]
|
||||
impl Greeter for MyGreeter {
|
||||
async fn say_hello(
|
||||
&self,
|
||||
request: Request<HelloRequest>,
|
||||
) -> Result<Response<HelloReply>, Status> {
|
||||
let reply = HelloReply {
|
||||
message: request.into_inner().name,
|
||||
};
|
||||
Ok(Response::new(reply))
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
|
||||
let addr = listener.local_addr().unwrap();
|
||||
|
||||
let greeter = MyGreeter::default();
|
||||
let mut server: Server = Server::builder();
|
||||
println!("Listening on {}", addr);
|
||||
server.add_service(GreeterServer::new(greeter))
|
||||
.serve_with_incoming(tokio_stream::wrappers::TcpListenerStream::new(listener))
|
||||
.await?;
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
126
test/js/third_party/grpc-js/test-tonic.test.ts
vendored
Normal file
126
test/js/third_party/grpc-js/test-tonic.test.ts
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
import grpc from "@grpc/grpc-js";
|
||||
import protoLoader from "@grpc/proto-loader";
|
||||
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
||||
import { rmSync } from "fs";
|
||||
import { chmod, cp, mkdir } from "fs/promises";
|
||||
import { tmpdirSync } from "harness";
|
||||
import path, { join } from "path";
|
||||
import unzipper from "unzipper";
|
||||
|
||||
const protoVersion = "31.0";
|
||||
|
||||
const releases = {
|
||||
"win32_x86_32": `https://github.com/protocolbuffers/protobuf/releases/download/v${protoVersion}/protoc-${protoVersion}-win32.zip`,
|
||||
"win32_x86_64": `https://github.com/protocolbuffers/protobuf/releases/download/v${protoVersion}/protoc-${protoVersion}-win64.zip`,
|
||||
"linux_x86_32": `https://github.com/protocolbuffers/protobuf/releases/download/v${protoVersion}/protoc-${protoVersion}-linux-x86_32.zip`,
|
||||
"linux_x86_64": `https://github.com/protocolbuffers/protobuf/releases/download/v${protoVersion}/protoc-${protoVersion}-linux-x86_64.zip`,
|
||||
"darwin_x86_64": `https://github.com/protocolbuffers/protobuf/releases/download/v${protoVersion}/protoc-${protoVersion}-osx-x86_64.zip`,
|
||||
"darwin_arm64": `https://github.com/protocolbuffers/protobuf/releases/download/v${protoVersion}/protoc-${protoVersion}-osx-aarch_64.zip`,
|
||||
};
|
||||
|
||||
const platform = process.platform;
|
||||
const arch = process.arch === "arm64" ? "arm64" : process.arch === "x64" ? "x86_64" : "x86_32";
|
||||
const release = platform + "_" + arch;
|
||||
const binPath = join("bin", platform === "win32" ? "protoc.exe" : "protoc");
|
||||
|
||||
// Load proto
|
||||
const packageDefinition = protoLoader.loadSync(join(import.meta.dir, "fixtures/tonic-server/proto/helloworld.proto"), {
|
||||
keepCase: true,
|
||||
longs: String,
|
||||
enums: String,
|
||||
defaults: true,
|
||||
oneofs: true,
|
||||
});
|
||||
|
||||
type Server = { address: string; kill: () => Promise<void> };
|
||||
|
||||
const cargoBin = Bun.which("cargo") as string;
|
||||
async function startServer(): Promise<Server> {
|
||||
const tmpDir = tmpdirSync();
|
||||
await cp(join(import.meta.dir, "fixtures/tonic-server"), tmpDir, { recursive: true });
|
||||
const protocZip = await unzipper.Open.buffer(await fetch(releases[release]).then(res => res.bytes()));
|
||||
|
||||
const protocPath = join(tmpDir, "protoc");
|
||||
await mkdir(protocPath, { recursive: true });
|
||||
await protocZip.extract({ path: protocPath });
|
||||
const protocExec = join(protocPath, binPath);
|
||||
await chmod(protocExec, 0o755);
|
||||
|
||||
const server = Bun.spawn([cargoBin, "run", "--quiet", path.join(tmpDir, "server")], {
|
||||
cwd: tmpDir,
|
||||
env: {
|
||||
PROTOC: protocExec,
|
||||
PATH: process.env.PATH,
|
||||
CARGO_HOME: process.env.CARGO_HOME,
|
||||
RUSTUP_HOME: process.env.RUSTUP_HOME,
|
||||
},
|
||||
stdout: "pipe",
|
||||
stdin: "ignore",
|
||||
stderr: "inherit",
|
||||
});
|
||||
|
||||
{
|
||||
const { promise, reject, resolve } = Promise.withResolvers<Server>();
|
||||
const reader = server.stdout.getReader();
|
||||
const decoder = new TextDecoder();
|
||||
async function killServer() {
|
||||
try {
|
||||
server.kill();
|
||||
await server.exited;
|
||||
rmSync(tmpDir, { recursive: true, force: true });
|
||||
} catch {}
|
||||
}
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
const text = decoder.decode(value);
|
||||
if (text.includes("Listening on")) {
|
||||
const [_, address] = text.split("Listening on ");
|
||||
resolve({
|
||||
address: address?.trim(),
|
||||
kill: killServer,
|
||||
});
|
||||
break;
|
||||
} else {
|
||||
await killServer();
|
||||
reject(new Error("Server not started"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return await promise;
|
||||
}
|
||||
}
|
||||
|
||||
describe.skipIf(!cargoBin || !releases[release])("test tonic server", () => {
|
||||
let server: Server;
|
||||
|
||||
beforeAll(async () => {
|
||||
server = await startServer();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
server.kill();
|
||||
});
|
||||
|
||||
test("flow control should work in both directions", async () => {
|
||||
const hello_proto = grpc.loadPackageDefinition(packageDefinition).helloworld;
|
||||
|
||||
// Create client
|
||||
const client = new hello_proto.Greeter(server.address, grpc.credentials.createInsecure());
|
||||
const payload = Buffer.alloc(1024 * 1024, "bun").toString();
|
||||
for (let i = 0; i < 20; i++) {
|
||||
const { promise, reject, resolve } = Promise.withResolvers<string>();
|
||||
// Call SayHello
|
||||
client.SayHello({ name: payload }, (err, response) => {
|
||||
if (err) reject(err);
|
||||
else resolve(response.message);
|
||||
});
|
||||
const result = await promise;
|
||||
expect(result.length).toBe(payload.length);
|
||||
expect(result).toBe(payload);
|
||||
}
|
||||
await client.close();
|
||||
}, 20_000); // debug can take some time
|
||||
});
|
||||
@@ -2051,6 +2051,7 @@ test/js/third_party/grpc-js/test-server-interceptors.test.ts
|
||||
test/js/third_party/grpc-js/test-server.test.ts
|
||||
test/js/third_party/grpc-js/test-status-builder.test.ts
|
||||
test/js/third_party/grpc-js/test-uri-parser.test.ts
|
||||
test/js/third_party/grpc-js/test-tonic.test.ts
|
||||
test/js/third_party/http2-wrapper/http2-wrapper.test.ts
|
||||
test/js/third_party/jsonwebtoken/async_sign.test.js
|
||||
test/js/third_party/jsonwebtoken/buffer.test.js
|
||||
|
||||
@@ -89,6 +89,7 @@
|
||||
"typeorm": "0.3.20",
|
||||
"typescript": "5.0.2",
|
||||
"undici": "5.20.0",
|
||||
"unzipper": "0.12.3",
|
||||
"v8-heapsnapshot": "1.3.1",
|
||||
"verdaccio": "6.0.0",
|
||||
"vitest": "0.32.2",
|
||||
|
||||
Reference in New Issue
Block a user