chore(tonic-web): include crate in top-level workspace (#648)
This PR adds the tonic-web crate to tonic's workspace members. Unit and integration tests should now run as part of CI runs.
This commit is contained in:
@@ -5,6 +5,7 @@ members = [
|
|||||||
"tonic-health",
|
"tonic-health",
|
||||||
"tonic-types",
|
"tonic-types",
|
||||||
"tonic-reflection",
|
"tonic-reflection",
|
||||||
|
"tonic-web",
|
||||||
|
|
||||||
# Non-published crates
|
# Non-published crates
|
||||||
"examples",
|
"examples",
|
||||||
@@ -21,5 +22,6 @@ members = [
|
|||||||
"tests/integration_tests",
|
"tests/integration_tests",
|
||||||
"tests/stream_conflict",
|
"tests/stream_conflict",
|
||||||
"tests/root-crate-path",
|
"tests/root-crate-path",
|
||||||
|
"tonic-web/tests/integration"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
node_modules
|
|
||||||
/target
|
|
||||||
binary
|
|
||||||
text
|
|
||||||
run.sh
|
|
||||||
package-lock.json
|
|
||||||
+21
-6
@@ -1,6 +1,21 @@
|
|||||||
[workspace]
|
[package]
|
||||||
members = [
|
name = "tonic-web"
|
||||||
"tonic-web",
|
version = "0.1.0"
|
||||||
"interop",
|
authors = ["Juan Alvarez <[email protected]>"]
|
||||||
"tests/integration"
|
edition = "2018"
|
||||||
]
|
|
||||||
|
[dependencies]
|
||||||
|
tonic = { path = "../tonic", default-features = false, features = ["transport"] }
|
||||||
|
http = "0.2"
|
||||||
|
base64 = "0.13"
|
||||||
|
futures-core = "0.3"
|
||||||
|
bytes = "1.0"
|
||||||
|
hyper = "0.14"
|
||||||
|
http-body = "0.4"
|
||||||
|
tower-service = "0.3"
|
||||||
|
tracing = "0.1"
|
||||||
|
pin-project = "1"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tokio = { version = "1", features = ["macros", "rt"] }
|
||||||
|
tonic = { path = "../tonic", default-features = false, features = ["transport", "tls"] }
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
*
|
|
||||||
!client/*
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "web-interop"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["Juan Alvarez <[email protected]>"]
|
|
||||||
publish = false
|
|
||||||
edition = "2018"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
interop = { path = "../../interop" }
|
|
||||||
tonic = { path = "../../tonic" }
|
|
||||||
tonic-web = { path = "../tonic-web" }
|
|
||||||
tokio = { version = "1.0.1", features = ["rt-multi-thread", "macros"] }
|
|
||||||
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
FROM node:12-stretch
|
|
||||||
|
|
||||||
RUN apt-get install -y unzip
|
|
||||||
|
|
||||||
WORKDIR /tmp
|
|
||||||
|
|
||||||
RUN curl -sSL https://github.com/protocolbuffers/protobuf/releases/download/v3.14.0/\
|
|
||||||
protoc-3.14.0-linux-x86_64.zip -o protoc.zip && \
|
|
||||||
unzip -qq protoc.zip && \
|
|
||||||
cp ./bin/protoc /usr/local/bin/protoc
|
|
||||||
|
|
||||||
RUN curl -sSL https://github.com/grpc/grpc-web/releases/download/1.2.1/\
|
|
||||||
protoc-gen-grpc-web-1.2.1-linux-x86_64 -o /usr/local/bin/protoc-gen-grpc-web && \
|
|
||||||
chmod +x /usr/local/bin/protoc-gen-grpc-web
|
|
||||||
|
|
||||||
WORKDIR /
|
|
||||||
|
|
||||||
COPY ./client ./
|
|
||||||
|
|
||||||
RUN echo "\nloglevel=error\n" >> $HOME/.npmrc && npm install && mkdir -p binary text
|
|
||||||
|
|
||||||
RUN protoc -I=. ./test.proto\
|
|
||||||
--js_out=import_style=commonjs:./text\
|
|
||||||
--grpc-web_out=import_style=commonjs,mode=grpcwebtext:./text
|
|
||||||
|
|
||||||
RUN protoc -I=. ./test.proto\
|
|
||||||
--js_out=import_style=commonjs:./binary\
|
|
||||||
--grpc-web_out=import_style=commonjs,mode=grpcweb:./binary
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
## Running interop tests
|
|
||||||
|
|
||||||
Start the server:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd tonic-web/interop
|
|
||||||
cargo run
|
|
||||||
```
|
|
||||||
|
|
||||||
Build the client docker image:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd tonic-web/interop
|
|
||||||
docker build -t grpcweb-client .
|
|
||||||
```
|
|
||||||
|
|
||||||
Run tests on linux:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker run --network=host --rm grpcweb-client /test.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
Run tests on docker desktop:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker run --rm grpcweb-client /test.sh host.docker.internal
|
|
||||||
```
|
|
||||||
@@ -1,204 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
* Copyright 2018 Google LLC
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Adapted from https://github.com/grpc/grpc-web/tree/master/test/interop
|
|
||||||
|
|
||||||
global.XMLHttpRequest = require("xhr2");
|
|
||||||
|
|
||||||
const parseArgs = require('minimist');
|
|
||||||
const argv = parseArgs(process.argv, {
|
|
||||||
string: ['mode', 'host']
|
|
||||||
});
|
|
||||||
|
|
||||||
const SERVER_HOST = `http://${argv.host || "localhost"}:9999`;
|
|
||||||
|
|
||||||
if (argv.mode === 'binary') {
|
|
||||||
console.log('Testing tonic-web mode (binary)...');
|
|
||||||
} else {
|
|
||||||
console.log('Testing tonic-web mode (text)...');
|
|
||||||
}
|
|
||||||
console.log('Tonic server:', SERVER_HOST);
|
|
||||||
|
|
||||||
const PROTO_PATH = argv.mode === 'binary' ? './binary' : './text';
|
|
||||||
|
|
||||||
const {
|
|
||||||
Empty,
|
|
||||||
SimpleRequest,
|
|
||||||
StreamingOutputCallRequest,
|
|
||||||
EchoStatus,
|
|
||||||
Payload,
|
|
||||||
ResponseParameters
|
|
||||||
} = require(`${PROTO_PATH}/test_pb.js`);
|
|
||||||
|
|
||||||
const {TestServiceClient} = require(`${PROTO_PATH}/test_grpc_web_pb.js`);
|
|
||||||
|
|
||||||
const assert = require('assert');
|
|
||||||
const grpc = {};
|
|
||||||
grpc.web = require('grpc-web');
|
|
||||||
|
|
||||||
function multiDone(done, count) {
|
|
||||||
return function () {
|
|
||||||
count -= 1;
|
|
||||||
if (count <= 0) {
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function doEmptyUnary(done) {
|
|
||||||
const testService = new TestServiceClient(SERVER_HOST, null, null);
|
|
||||||
testService.emptyCall(new Empty(), null, (err, response) => {
|
|
||||||
assert.ifError(err);
|
|
||||||
assert(response instanceof Empty);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function doLargeUnary(done) {
|
|
||||||
const testService = new TestServiceClient(SERVER_HOST, null, null);
|
|
||||||
const req = new SimpleRequest();
|
|
||||||
const size = 314159;
|
|
||||||
|
|
||||||
const payload = new Payload();
|
|
||||||
payload.setBody('0'.repeat(271828));
|
|
||||||
|
|
||||||
req.setPayload(payload);
|
|
||||||
req.setResponseSize(size);
|
|
||||||
|
|
||||||
testService.unaryCall(req, null, (err, response) => {
|
|
||||||
assert.ifError(err);
|
|
||||||
assert.equal(response.getPayload().getBody().length, size);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function doServerStreaming(done) {
|
|
||||||
const testService = new TestServiceClient(SERVER_HOST, null, null);
|
|
||||||
const sizes = [31415, 9, 2653, 58979];
|
|
||||||
|
|
||||||
const responseParams = sizes.map((size, idx) => {
|
|
||||||
const param = new ResponseParameters();
|
|
||||||
param.setSize(size);
|
|
||||||
param.setIntervalUs(idx * 10);
|
|
||||||
return param;
|
|
||||||
});
|
|
||||||
|
|
||||||
const req = new StreamingOutputCallRequest();
|
|
||||||
req.setResponseParametersList(responseParams);
|
|
||||||
|
|
||||||
const stream = testService.streamingOutputCall(req);
|
|
||||||
|
|
||||||
done = multiDone(done, sizes.length);
|
|
||||||
let numCallbacks = 0;
|
|
||||||
stream.on('data', (response) => {
|
|
||||||
assert.equal(response.getPayload().getBody().length, sizes[numCallbacks]);
|
|
||||||
numCallbacks++;
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function doCustomMetadata(done) {
|
|
||||||
const testService = new TestServiceClient(SERVER_HOST, null, null);
|
|
||||||
done = multiDone(done, 3);
|
|
||||||
|
|
||||||
const req = new SimpleRequest();
|
|
||||||
const size = 314159;
|
|
||||||
const ECHO_INITIAL_KEY = 'x-grpc-test-echo-initial';
|
|
||||||
const ECHO_INITIAL_VALUE = 'test_initial_metadata_value';
|
|
||||||
const ECHO_TRAILING_KEY = 'x-grpc-test-echo-trailing-bin';
|
|
||||||
const ECHO_TRAILING_VALUE = 0xababab;
|
|
||||||
|
|
||||||
const payload = new Payload();
|
|
||||||
payload.setBody('0'.repeat(271828));
|
|
||||||
|
|
||||||
req.setPayload(payload);
|
|
||||||
req.setResponseSize(size);
|
|
||||||
|
|
||||||
const call = testService.unaryCall(req, {
|
|
||||||
[ECHO_INITIAL_KEY]: ECHO_INITIAL_VALUE,
|
|
||||||
[ECHO_TRAILING_KEY]: ECHO_TRAILING_VALUE
|
|
||||||
}, (err, response) => {
|
|
||||||
assert.ifError(err);
|
|
||||||
assert.equal(response.getPayload().getBody().length, size);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
call.on('metadata', (metadata) => {
|
|
||||||
assert(ECHO_INITIAL_KEY in metadata);
|
|
||||||
assert.equal(metadata[ECHO_INITIAL_KEY], ECHO_INITIAL_VALUE);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
call.on('status', (status) => {
|
|
||||||
assert('metadata' in status);
|
|
||||||
assert(ECHO_TRAILING_KEY in status.metadata);
|
|
||||||
assert.equal(status.metadata[ECHO_TRAILING_KEY], ECHO_TRAILING_VALUE);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function doStatusCodeAndMessage(done) {
|
|
||||||
const testService = new TestServiceClient(SERVER_HOST, null, null);
|
|
||||||
const req = new SimpleRequest();
|
|
||||||
|
|
||||||
const TEST_STATUS_MESSAGE = 'test status message';
|
|
||||||
const echoStatus = new EchoStatus();
|
|
||||||
echoStatus.setCode(2);
|
|
||||||
echoStatus.setMessage(TEST_STATUS_MESSAGE);
|
|
||||||
|
|
||||||
req.setResponseStatus(echoStatus);
|
|
||||||
|
|
||||||
testService.unaryCall(req, {}, (err, response) => {
|
|
||||||
assert(err);
|
|
||||||
assert('code' in err);
|
|
||||||
assert('message' in err);
|
|
||||||
assert.equal(err.code, 2);
|
|
||||||
assert.equal(err.message, TEST_STATUS_MESSAGE);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function doUnimplementedMethod(done) {
|
|
||||||
const testService = new TestServiceClient(SERVER_HOST, null, null);
|
|
||||||
testService.unimplementedCall(new Empty(), {}, (err, response) => {
|
|
||||||
assert(err);
|
|
||||||
assert('code' in err);
|
|
||||||
assert.equal(err.code, 12);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const testCases = {
|
|
||||||
'empty_unary': {testFunc: doEmptyUnary},
|
|
||||||
'large_unary': {testFunc: doLargeUnary},
|
|
||||||
'server_streaming': {
|
|
||||||
testFunc: doServerStreaming,
|
|
||||||
skipBinaryMode: true
|
|
||||||
},
|
|
||||||
'custom_metadata': {testFunc: doCustomMetadata},
|
|
||||||
'status_code_and_message': {testFunc: doStatusCodeAndMessage},
|
|
||||||
'unimplemented_method': {testFunc: doUnimplementedMethod}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
describe('tonic-web interop tests', function () {
|
|
||||||
Object.keys(testCases).forEach((testCase) => {
|
|
||||||
if (argv.mode === 'binary' && testCases[testCase].skipBinaryMode) return;
|
|
||||||
it('should pass ' + testCase, testCases[testCase].testFunc);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "grpc-web-interop-test",
|
|
||||||
"version": "0.1.0",
|
|
||||||
"description": "gRPC-Web Interop Test Client",
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"private": true,
|
|
||||||
"scripts": {
|
|
||||||
"test": "mocha -b --timeout 500 ./interop_client.js"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"google-protobuf": "~3.14.0",
|
|
||||||
"grpc-web": "~1.2.1"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"minimist": "~1.2.5",
|
|
||||||
"mocha": "~7.1.1",
|
|
||||||
"xhr2": "~0.2.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
|
|
||||||
// Copyright 2015-2016 gRPC authors.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// Adapted from https://github.com/grpc/grpc-web/tree/master/src/proto/grpc/testing
|
|
||||||
|
|
||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package grpc.testing;
|
|
||||||
|
|
||||||
service TestService {
|
|
||||||
rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty);
|
|
||||||
rpc UnaryCall(SimpleRequest) returns (SimpleResponse);
|
|
||||||
rpc StreamingOutputCall(StreamingOutputCallRequest)
|
|
||||||
returns (stream StreamingOutputCallResponse);
|
|
||||||
rpc UnimplementedCall(grpc.testing.Empty) returns (grpc.testing.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
message Empty {}
|
|
||||||
|
|
||||||
message BoolValue {
|
|
||||||
bool value = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Payload {
|
|
||||||
bytes body = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message EchoStatus {
|
|
||||||
int32 code = 1;
|
|
||||||
string message = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message SimpleRequest {
|
|
||||||
int32 response_size = 2;
|
|
||||||
Payload payload = 3;
|
|
||||||
EchoStatus response_status = 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
message SimpleResponse {
|
|
||||||
Payload payload = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message ResponseParameters {
|
|
||||||
int32 size = 1;
|
|
||||||
int32 interval_us = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message StreamingOutputCallRequest {
|
|
||||||
repeated ResponseParameters response_parameters = 2;
|
|
||||||
Payload payload = 3;
|
|
||||||
EchoStatus response_status = 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
message StreamingOutputCallResponse {
|
|
||||||
Payload payload = 1;
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
HOST=${1:-"localhost"}
|
|
||||||
|
|
||||||
npm test -- --host="$HOST"
|
|
||||||
npm test -- --mode=binary --host="$HOST"
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
use interop::server::{EchoHeadersSvc, TestService, TestServiceServer};
|
|
||||||
use tonic::transport::Server;
|
|
||||||
|
|
||||||
#[tokio::main]
|
|
||||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
let addr = ([127, 0, 0, 1], 9999).into();
|
|
||||||
let test_svc = TestServiceServer::new(TestService::default());
|
|
||||||
let with_echo = EchoHeadersSvc::new(test_svc);
|
|
||||||
|
|
||||||
Server::builder()
|
|
||||||
.accept_http1(true)
|
|
||||||
.add_service(tonic_web::enable(with_echo))
|
|
||||||
.serve(addr)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,7 @@ use std::task::{Context, Poll};
|
|||||||
|
|
||||||
use http::{header, HeaderMap, HeaderValue, Method, Request, Response, StatusCode, Version};
|
use http::{header, HeaderMap, HeaderValue, Method, Request, Response, StatusCode, Version};
|
||||||
use hyper::Body;
|
use hyper::Body;
|
||||||
use tonic::body::{BoxBody, empty_body};
|
use tonic::body::{empty_body, BoxBody};
|
||||||
use tonic::transport::NamedService;
|
use tonic::transport::NamedService;
|
||||||
use tower_service::Service;
|
use tower_service::Service;
|
||||||
use tracing::{debug, trace};
|
use tracing::{debug, trace};
|
||||||
@@ -255,7 +255,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self, _: Request<Body>) -> Self::Future {
|
fn call(&mut self, _: Request<Body>) -> Self::Future {
|
||||||
Box::pin(async { Ok(Response::new(BoxBody::empty())) })
|
Box::pin(async { Ok(Response::new(empty_body())) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7,9 +7,9 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tonic = { path = "../../../tonic" }
|
tonic = { path = "../../../tonic" }
|
||||||
tonic-web = { path = "../../tonic-web" }
|
tonic-web = { path = "../../../tonic-web" }
|
||||||
prost = "0.7"
|
prost = "0.7"
|
||||||
tokio = { version = "1.0.1", features = ["macros", "rt", "net"] }
|
tokio = { version = "1", features = ["macros", "rt", "net"] }
|
||||||
base64 = "0.13"
|
base64 = "0.13"
|
||||||
bytes = "1.0"
|
bytes = "1.0"
|
||||||
tokio-stream = { version = "0.1", features = ["net"] }
|
tokio-stream = { version = "0.1", features = ["net"] }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
use tokio_stream::{self as stream, StreamExt, Stream};
|
use tokio_stream::{self as stream, Stream, StreamExt};
|
||||||
use tonic::{Request, Response, Status, Streaming};
|
use tonic::{Request, Response, Status, Streaming};
|
||||||
|
|
||||||
use pb::{test_server::Test, Input, Output};
|
use pb::{test_server::Test, Input, Output};
|
||||||
|
|||||||
@@ -68,7 +68,6 @@ async fn origin_not_allowed() {
|
|||||||
assert_eq!(res.status(), StatusCode::FORBIDDEN);
|
assert_eq!(res.status(), StatusCode::FORBIDDEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async fn spawn(allowed_origin: &str) -> String {
|
async fn spawn(allowed_origin: &str) -> String {
|
||||||
let addr = SocketAddr::from(([127, 0, 0, 1], 0));
|
let addr = SocketAddr::from(([127, 0, 0, 1], 0));
|
||||||
let listener = TcpListener::bind(addr).await.expect("listener");
|
let listener = TcpListener::bind(addr).await.expect("listener");
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "tonic-web"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["Juan Alvarez <[email protected]>"]
|
|
||||||
edition = "2018"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
tonic = { path = "../../tonic", default-features = false, features = ["transport"] }
|
|
||||||
http = "0.2"
|
|
||||||
base64 = "0.13"
|
|
||||||
futures-core = "0.3"
|
|
||||||
bytes = "1.0"
|
|
||||||
hyper = "0.14"
|
|
||||||
http-body = "0.4"
|
|
||||||
tower-service = "0.3"
|
|
||||||
tracing = "0.1"
|
|
||||||
pin-project = "1"
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
tokio = { version = "1.0.1", features = ["macros", "rt"] }
|
|
||||||
tonic = { path = "../../tonic", default-features = false, features = ["transport", "tls"] }
|
|
||||||
Reference in New Issue
Block a user