Support grpc-web

This commit is contained in:
Jeff Ward 2019-03-15 07:51:06 -04:00 committed by Sigurd Meldgaard
parent 76159960e2
commit d58659507c
50 changed files with 2256 additions and 949 deletions

1
.gitignore vendored
View File

@ -2,6 +2,7 @@
.dart_tool/
.packages
.pub/
.vscode/
build/
# Remove the following pattern if you wish to check in your lock file

View File

@ -1,7 +1,11 @@
language: dart
sudo: false
# Run against both the dev and channel.
# necessary to avoid chrome sandboxing issues
sudo: required
addons:
chrome: stable
# Run against both the dev and stable channel.
dart:
- stable
- dev
@ -9,6 +13,7 @@ dart:
# Define test tasks to run.
dart_task:
- test: --platform vm
- test: --platform chrome
# Only run one instance of the formatter and the analyzer, rather than running
# them against each Dart version.

View File

@ -1,3 +1,8 @@
## 1.1.0
* Add initial support for grpc-web.
See `example/grpc-web` for an example of this working.
## 1.0.1
* Add `service_api.dart` that only contains the minimal imports needed by the code generated by

5
build.yaml Normal file
View File

@ -0,0 +1,5 @@
targets:
$default:
sources:
exclude:
- example/**

View File

@ -0,0 +1,62 @@
# Description
The grpc-web example shows how to use the Dart gRPC library with a gRPC-Web capable server.
This is meant to be used with the echo example provided by the grpc-web repository. The definition of the service is given in echo.proto.
# Prerequistes
You will need a clone of the [grpc-web](https://github.com/grpc/grpc-web) repository to run the example server.
You will also need the dart 'webdev' tool, which you can get by running:
```sh
$ pub global activate webdev
```
# Run the sample code
Follow the instructions for starting the grpc-web example server. The simplest version of this involves running the grpc-web server in a docker container with:
```sh
$ docker-compose up echo-server envoy
```
To compile and run the example, assuming you are in the root of the grpc-web
folder, i.e., .../example/grpc-web/, first get the dependencies by running:
```sh
$ pub get
```
Compile and run the website with:
```sh
$ webdev serve web:9000
```
Note that the alternate port (9000) is necessary because the grpc-web server runs the grpc server on port 8080 by default (the save as webdev).
You can then navigate to http://localhost:9000/ to try out the example.
# Regenerate the stubs
If you have made changes to the message or service definition in
`protos/echo.proto` and need to regenerate the corresponding Dart files,
you will need to have protoc version 3.0.0 or higher and the Dart protoc plugin
version 16.0.0 or higher on your PATH.
To install protoc, see the instructions on
[the Protocol Buffers website](https://developers.google.com/protocol-buffers/).
The easiest way to get the Dart protoc plugin is by running
```sh
$ pub global activate protoc_plugin
```
and follow the directions to add `~/.pub-cache/bin` to your PATH, if you haven't
already done so.
You can now regenerate the Dart files by running
```sh
$ protoc --dart_out=grpc:lib/src/generated -Iprotos protos/echo.proto
```

View File

@ -0,0 +1,47 @@
import 'dart:async';
import 'dart:html';
import 'package:grpc_web/src/generated/echo.pbgrpc.dart';
class EchoApp {
final EchoServiceClient _service;
EchoApp(this._service);
Future<void> echo(String message) async {
_addLeftMessage(message);
final response = await _service.echo(new EchoRequest()..message = message);
_addRightMessage(response.message);
}
void repeatEcho(String message, int count) {
_addLeftMessage(message);
final request = ServerStreamingEchoRequest()
..message = message
..messageCount = count
..messageInterval = 500;
_service.serverStreamingEcho(request).listen((response) {
_addRightMessage(response.message);
}, onDone: () => print('Closed connection to server.'));
}
void _addLeftMessage(String message) {
_addMessage(message, "label-primary pull-left");
}
void _addRightMessage(String message) {
_addMessage(message, "label-default pull-right");
}
void _addMessage(String message, String cssClass) {
final classes = cssClass.split(' ');
querySelector('#first').after(DivElement()
..classes.add('row')
..append(Element.tag('h2')
..append(SpanElement()
..classes.add('label')
..classes.addAll(classes)
..text = message)));
}
}

View File

@ -0,0 +1,131 @@
///
// Generated code. Do not modify.
// source: echo.proto
///
// ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
// ignore: UNUSED_SHOWN_NAME
import 'dart:core' show int, bool, double, String, List, Map, override;
import 'package:protobuf/protobuf.dart' as $pb;
class EchoRequest extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('EchoRequest', package: const $pb.PackageName('grpc.gateway.testing'))
..aOS(1, 'message')
..hasRequiredFields = false
;
EchoRequest() : super();
EchoRequest.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
EchoRequest.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
EchoRequest clone() => new EchoRequest()..mergeFromMessage(this);
EchoRequest copyWith(void Function(EchoRequest) updates) => super.copyWith((message) => updates(message as EchoRequest));
$pb.BuilderInfo get info_ => _i;
static EchoRequest create() => new EchoRequest();
EchoRequest createEmptyInstance() => create();
static $pb.PbList<EchoRequest> createRepeated() => new $pb.PbList<EchoRequest>();
static EchoRequest getDefault() => _defaultInstance ??= create()..freeze();
static EchoRequest _defaultInstance;
static void $checkItem(EchoRequest v) {
if (v is! EchoRequest) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
String get message => $_getS(0, '');
set message(String v) { $_setString(0, v); }
bool hasMessage() => $_has(0);
void clearMessage() => clearField(1);
}
class EchoResponse extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('EchoResponse', package: const $pb.PackageName('grpc.gateway.testing'))
..aOS(1, 'message')
..hasRequiredFields = false
;
EchoResponse() : super();
EchoResponse.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
EchoResponse.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
EchoResponse clone() => new EchoResponse()..mergeFromMessage(this);
EchoResponse copyWith(void Function(EchoResponse) updates) => super.copyWith((message) => updates(message as EchoResponse));
$pb.BuilderInfo get info_ => _i;
static EchoResponse create() => new EchoResponse();
EchoResponse createEmptyInstance() => create();
static $pb.PbList<EchoResponse> createRepeated() => new $pb.PbList<EchoResponse>();
static EchoResponse getDefault() => _defaultInstance ??= create()..freeze();
static EchoResponse _defaultInstance;
static void $checkItem(EchoResponse v) {
if (v is! EchoResponse) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
String get message => $_getS(0, '');
set message(String v) { $_setString(0, v); }
bool hasMessage() => $_has(0);
void clearMessage() => clearField(1);
}
class ServerStreamingEchoRequest extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('ServerStreamingEchoRequest', package: const $pb.PackageName('grpc.gateway.testing'))
..aOS(1, 'message')
..a<int>(2, 'messageCount', $pb.PbFieldType.O3)
..a<int>(3, 'messageInterval', $pb.PbFieldType.O3)
..hasRequiredFields = false
;
ServerStreamingEchoRequest() : super();
ServerStreamingEchoRequest.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
ServerStreamingEchoRequest.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
ServerStreamingEchoRequest clone() => new ServerStreamingEchoRequest()..mergeFromMessage(this);
ServerStreamingEchoRequest copyWith(void Function(ServerStreamingEchoRequest) updates) => super.copyWith((message) => updates(message as ServerStreamingEchoRequest));
$pb.BuilderInfo get info_ => _i;
static ServerStreamingEchoRequest create() => new ServerStreamingEchoRequest();
ServerStreamingEchoRequest createEmptyInstance() => create();
static $pb.PbList<ServerStreamingEchoRequest> createRepeated() => new $pb.PbList<ServerStreamingEchoRequest>();
static ServerStreamingEchoRequest getDefault() => _defaultInstance ??= create()..freeze();
static ServerStreamingEchoRequest _defaultInstance;
static void $checkItem(ServerStreamingEchoRequest v) {
if (v is! ServerStreamingEchoRequest) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
String get message => $_getS(0, '');
set message(String v) { $_setString(0, v); }
bool hasMessage() => $_has(0);
void clearMessage() => clearField(1);
int get messageCount => $_get(1, 0);
set messageCount(int v) { $_setSignedInt32(1, v); }
bool hasMessageCount() => $_has(1);
void clearMessageCount() => clearField(2);
int get messageInterval => $_get(2, 0);
set messageInterval(int v) { $_setSignedInt32(2, v); }
bool hasMessageInterval() => $_has(2);
void clearMessageInterval() => clearField(3);
}
class ServerStreamingEchoResponse extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('ServerStreamingEchoResponse', package: const $pb.PackageName('grpc.gateway.testing'))
..aOS(1, 'message')
..hasRequiredFields = false
;
ServerStreamingEchoResponse() : super();
ServerStreamingEchoResponse.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
ServerStreamingEchoResponse.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
ServerStreamingEchoResponse clone() => new ServerStreamingEchoResponse()..mergeFromMessage(this);
ServerStreamingEchoResponse copyWith(void Function(ServerStreamingEchoResponse) updates) => super.copyWith((message) => updates(message as ServerStreamingEchoResponse));
$pb.BuilderInfo get info_ => _i;
static ServerStreamingEchoResponse create() => new ServerStreamingEchoResponse();
ServerStreamingEchoResponse createEmptyInstance() => create();
static $pb.PbList<ServerStreamingEchoResponse> createRepeated() => new $pb.PbList<ServerStreamingEchoResponse>();
static ServerStreamingEchoResponse getDefault() => _defaultInstance ??= create()..freeze();
static ServerStreamingEchoResponse _defaultInstance;
static void $checkItem(ServerStreamingEchoResponse v) {
if (v is! ServerStreamingEchoResponse) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
String get message => $_getS(0, '');
set message(String v) { $_setString(0, v); }
bool hasMessage() => $_has(0);
void clearMessage() => clearField(1);
}

View File

@ -0,0 +1,6 @@
///
// Generated code. Do not modify.
// source: echo.proto
///
// ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import

View File

@ -0,0 +1,79 @@
///
// Generated code. Do not modify.
// source: echo.proto
///
// ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
import 'dart:async' as $async;
import 'package:grpc/service_api.dart' as $grpc;
import 'echo.pb.dart';
export 'echo.pb.dart';
class EchoServiceClient extends $grpc.Client {
static final _$echo = new $grpc.ClientMethod<EchoRequest, EchoResponse>(
'/grpc.gateway.testing.EchoService/Echo',
(EchoRequest value) => value.writeToBuffer(),
(List<int> value) => new EchoResponse.fromBuffer(value));
static final _$serverStreamingEcho = new $grpc.ClientMethod<
ServerStreamingEchoRequest, ServerStreamingEchoResponse>(
'/grpc.gateway.testing.EchoService/ServerStreamingEcho',
(ServerStreamingEchoRequest value) => value.writeToBuffer(),
(List<int> value) => new ServerStreamingEchoResponse.fromBuffer(value));
EchoServiceClient($grpc.ClientChannel channel, {$grpc.CallOptions options})
: super(channel, options: options);
$grpc.ResponseFuture<EchoResponse> echo(EchoRequest request,
{$grpc.CallOptions options}) {
final call = $createCall(_$echo, new $async.Stream.fromIterable([request]),
options: options);
return new $grpc.ResponseFuture(call);
}
$grpc.ResponseStream<ServerStreamingEchoResponse> serverStreamingEcho(
ServerStreamingEchoRequest request,
{$grpc.CallOptions options}) {
final call = $createCall(
_$serverStreamingEcho, new $async.Stream.fromIterable([request]),
options: options);
return new $grpc.ResponseStream(call);
}
}
abstract class EchoServiceBase extends $grpc.Service {
String get $name => 'grpc.gateway.testing.EchoService';
EchoServiceBase() {
$addMethod(new $grpc.ServiceMethod<EchoRequest, EchoResponse>(
'Echo',
echo_Pre,
false,
false,
(List<int> value) => new EchoRequest.fromBuffer(value),
(EchoResponse value) => value.writeToBuffer()));
$addMethod(new $grpc.ServiceMethod<ServerStreamingEchoRequest,
ServerStreamingEchoResponse>(
'ServerStreamingEcho',
serverStreamingEcho_Pre,
false,
true,
(List<int> value) => new ServerStreamingEchoRequest.fromBuffer(value),
(ServerStreamingEchoResponse value) => value.writeToBuffer()));
}
$async.Future<EchoResponse> echo_Pre(
$grpc.ServiceCall call, $async.Future request) async {
return echo(call, await request);
}
$async.Stream<ServerStreamingEchoResponse> serverStreamingEcho_Pre(
$grpc.ServiceCall call, $async.Future request) async* {
yield* serverStreamingEcho(
call, (await request) as ServerStreamingEchoRequest);
}
$async.Future<EchoResponse> echo($grpc.ServiceCall call, EchoRequest request);
$async.Stream<ServerStreamingEchoResponse> serverStreamingEcho(
$grpc.ServiceCall call, ServerStreamingEchoRequest request);
}

View File

@ -0,0 +1,36 @@
///
// Generated code. Do not modify.
// source: echo.proto
///
// ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
const EchoRequest$json = const {
'1': 'EchoRequest',
'2': const [
const {'1': 'message', '3': 1, '4': 1, '5': 9, '10': 'message'},
],
};
const EchoResponse$json = const {
'1': 'EchoResponse',
'2': const [
const {'1': 'message', '3': 1, '4': 1, '5': 9, '10': 'message'},
],
};
const ServerStreamingEchoRequest$json = const {
'1': 'ServerStreamingEchoRequest',
'2': const [
const {'1': 'message', '3': 1, '4': 1, '5': 9, '10': 'message'},
const {'1': 'message_count', '3': 2, '4': 1, '5': 5, '10': 'messageCount'},
const {'1': 'message_interval', '3': 3, '4': 1, '5': 5, '10': 'messageInterval'},
],
};
const ServerStreamingEchoResponse$json = const {
'1': 'ServerStreamingEchoResponse',
'2': const [
const {'1': 'message', '3': 1, '4': 1, '5': 9, '10': 'message'},
],
};

View File

@ -0,0 +1,41 @@
// 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.
syntax = "proto3";
package grpc.gateway.testing;
message EchoRequest {
string message = 1;
}
message EchoResponse {
string message = 1;
}
message ServerStreamingEchoRequest {
string message = 1;
int32 message_count = 2;
int32 message_interval = 3;
}
message ServerStreamingEchoResponse {
string message = 1;
}
service EchoService {
rpc Echo(EchoRequest) returns (EchoResponse);
rpc ServerStreamingEcho(ServerStreamingEchoRequest)
returns (stream ServerStreamingEchoResponse);
}

View File

@ -0,0 +1,15 @@
name: grpc_web
description: Dart gRPC-Web sample client
homepage: https://github.com/dart-lang/grpc-dart
environment:
sdk: '>=2.0.0 <3.0.0'
dependencies:
grpc:
path: ../../
protobuf: ^0.13.4
dev_dependencies:
build_runner: ^0.10.0
build_web_compilers: '^0.4.1'

View File

@ -0,0 +1,42 @@
<!--
Copyright (c) 2018, the gRPC project authors. Please see the AUTHORS file
for details. All rights reserved.
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.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Echo Example</title>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script defer src="main.dart.js"></script>
</head>
<body>
<div class="container">
<div class="row" id="first">
<div class="form-group">
<div class="input-group">
<input type="text" class="form-control" id="msg">
<span class="input-group-btn">
<button class="btn btn-primary" type="button" id="send">Send
</button>
</span>
</div>
<p class="help-block">Example: "Hello", "4 Hello"</p>
</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,48 @@
// Copyright (c) 2018, the gRPC project authors. Please see the AUTHORS file
// for details. All rights reserved.
//
// 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.
import 'dart:html';
import 'package:grpc/grpc_web.dart';
import 'package:grpc_web/app.dart';
import 'package:grpc_web/src/generated/echo.pbgrpc.dart';
void main() {
final channel = new GrpcWebClientChannel.xhr('http://localhost',
port: 8080);
final service = EchoServiceClient(channel);
final app = EchoApp(service);
final button = querySelector('#send') as ButtonElement;
button.onClick.listen((e) async {
final msg = querySelector('#msg') as TextInputElement;
final value = msg.value.trim();
msg.value = '';
if (value.isEmpty) return false;
if (value.indexOf(' ') > 0) {
final countStr = value.substring(0, value.indexOf(' '));
final count = int.tryParse(countStr);
if (count != null) {
app.repeatEcho(value.substring(value.indexOf(' ') + 1), count);
} else {
app.echo(value);
}
} else {
app.echo(value);
}
});
}

View File

@ -20,7 +20,7 @@ class GreeterClient extends Client {
GreeterClient(ClientChannel channel, {CallOptions options})
: super(channel, options: options);
ResponseFuture<HelloReply> sayHello(HelloRequest request,
Future<HelloReply> sayHello(HelloRequest request,
{CallOptions options}) {
final call = $createCall(_$sayHello, new Stream.fromIterable([request]),
options: options);

View File

@ -13,3 +13,4 @@ dependencies:
dev_dependencies:
test: ^1.3.0

View File

@ -114,6 +114,12 @@ class TestService extends TestServiceBase {
final bufferedResponses = await request.map(_responseForRequest).toList();
yield* new Stream.fromIterable(bufferedResponses);
}
@override
Future<Empty> unimplementedCall(ServiceCall call, Empty request) {
// TODO: implement unimplementedCall
return null;
}
}
Future<void> main(List<String> args) async {

View File

@ -19,9 +19,9 @@ import 'dart:typed_data';
import 'package:collection/collection.dart';
import 'package:grpc/grpc.dart';
import 'package:interop/src/generated/empty.pb.dart';
import 'package:interop/src/generated/messages.pb.dart';
import 'package:interop/src/generated/test.pbgrpc.dart';
import 'generated/empty.pb.dart';
import 'generated/messages.pb.dart';
import 'generated/test.pbgrpc.dart';
const _headerEchoKey = 'x-grpc-test-echo-initial';
const _headerEchoData = 'test_initial_metadata_value';
@ -95,7 +95,7 @@ class Tester {
if (_useTestCA) {
trustedRoot = new File('ca.pem').readAsBytesSync();
}
credentials = new ChannelCredentials.secure(
credentials = new Http2ChannelCredentials.secure(
certificates: trustedRoot, authority: serverHostOverride);
} else {
credentials = const ChannelCredentials.insecure();

View File

@ -1,36 +1,32 @@
///
// Generated code. Do not modify.
// source: empty.proto
///
// ignore_for_file: non_constant_identifier_names,library_prefixes
library grpc.testing_empty;
// ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
// ignore: UNUSED_SHOWN_NAME
import 'dart:core' show int, bool, double, String, List, override;
import 'dart:core' show int, bool, double, String, List, Map, override;
import 'package:protobuf/protobuf.dart';
import 'package:protobuf/protobuf.dart' as $pb;
class Empty extends GeneratedMessage {
static final BuilderInfo _i = new BuilderInfo('Empty')
..hasRequiredFields = false;
class Empty extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('Empty', package: const $pb.PackageName('grpc.testing'))
..hasRequiredFields = false
;
Empty() : super();
Empty.fromBuffer(List<int> i, [ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromBuffer(i, r);
Empty.fromJson(String i, [ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromJson(i, r);
Empty.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
Empty.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
Empty clone() => new Empty()..mergeFromMessage(this);
BuilderInfo get info_ => _i;
Empty copyWith(void Function(Empty) updates) => super.copyWith((message) => updates(message as Empty));
$pb.BuilderInfo get info_ => _i;
static Empty create() => new Empty();
static PbList<Empty> createRepeated() => new PbList<Empty>();
static Empty getDefault() {
if (_defaultInstance == null) _defaultInstance = new _ReadonlyEmpty();
return _defaultInstance;
}
Empty createEmptyInstance() => create();
static $pb.PbList<Empty> createRepeated() => new $pb.PbList<Empty>();
static Empty getDefault() => _defaultInstance ??= create()..freeze();
static Empty _defaultInstance;
static void $checkItem(Empty v) {
if (v is! Empty) checkItemFailed(v, 'Empty');
if (v is! Empty) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
}
class _ReadonlyEmpty extends Empty with ReadonlyMessageMixin {}

View File

@ -1,655 +1,441 @@
///
// Generated code. Do not modify.
// source: messages.proto
///
// ignore_for_file: non_constant_identifier_names,library_prefixes
library grpc.testing_messages;
// ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
// ignore: UNUSED_SHOWN_NAME
import 'dart:core' show int, bool, double, String, List, override;
import 'dart:core' show int, bool, double, String, List, Map, override;
import 'package:protobuf/protobuf.dart';
import 'package:protobuf/protobuf.dart' as $pb;
import 'messages.pbenum.dart';
export 'messages.pbenum.dart';
class BoolValue extends GeneratedMessage {
static final BuilderInfo _i = new BuilderInfo('BoolValue')
class BoolValue extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('BoolValue', package: const $pb.PackageName('grpc.testing'))
..aOB(1, 'value')
..hasRequiredFields = false;
..hasRequiredFields = false
;
BoolValue() : super();
BoolValue.fromBuffer(List<int> i,
[ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromBuffer(i, r);
BoolValue.fromJson(String i, [ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromJson(i, r);
BoolValue.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
BoolValue.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
BoolValue clone() => new BoolValue()..mergeFromMessage(this);
BuilderInfo get info_ => _i;
BoolValue copyWith(void Function(BoolValue) updates) => super.copyWith((message) => updates(message as BoolValue));
$pb.BuilderInfo get info_ => _i;
static BoolValue create() => new BoolValue();
static PbList<BoolValue> createRepeated() => new PbList<BoolValue>();
static BoolValue getDefault() {
if (_defaultInstance == null) _defaultInstance = new _ReadonlyBoolValue();
return _defaultInstance;
}
BoolValue createEmptyInstance() => create();
static $pb.PbList<BoolValue> createRepeated() => new $pb.PbList<BoolValue>();
static BoolValue getDefault() => _defaultInstance ??= create()..freeze();
static BoolValue _defaultInstance;
static void $checkItem(BoolValue v) {
if (v is! BoolValue) checkItemFailed(v, 'BoolValue');
if (v is! BoolValue) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
bool get value => $_get(0, false);
set value(bool v) {
$_setBool(0, v);
}
set value(bool v) { $_setBool(0, v); }
bool hasValue() => $_has(0);
void clearValue() => clearField(1);
}
class _ReadonlyBoolValue extends BoolValue with ReadonlyMessageMixin {}
class Payload extends GeneratedMessage {
static final BuilderInfo _i = new BuilderInfo('Payload')
..e<PayloadType>(1, 'type', PbFieldType.OE, PayloadType.COMPRESSABLE,
PayloadType.valueOf, PayloadType.values)
..a<List<int>>(2, 'body', PbFieldType.OY)
..hasRequiredFields = false;
class Payload extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('Payload', package: const $pb.PackageName('grpc.testing'))
..e<PayloadType>(1, 'type', $pb.PbFieldType.OE, PayloadType.COMPRESSABLE, PayloadType.valueOf, PayloadType.values)
..a<List<int>>(2, 'body', $pb.PbFieldType.OY)
..hasRequiredFields = false
;
Payload() : super();
Payload.fromBuffer(List<int> i,
[ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromBuffer(i, r);
Payload.fromJson(String i, [ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromJson(i, r);
Payload.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
Payload.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
Payload clone() => new Payload()..mergeFromMessage(this);
BuilderInfo get info_ => _i;
Payload copyWith(void Function(Payload) updates) => super.copyWith((message) => updates(message as Payload));
$pb.BuilderInfo get info_ => _i;
static Payload create() => new Payload();
static PbList<Payload> createRepeated() => new PbList<Payload>();
static Payload getDefault() {
if (_defaultInstance == null) _defaultInstance = new _ReadonlyPayload();
return _defaultInstance;
}
Payload createEmptyInstance() => create();
static $pb.PbList<Payload> createRepeated() => new $pb.PbList<Payload>();
static Payload getDefault() => _defaultInstance ??= create()..freeze();
static Payload _defaultInstance;
static void $checkItem(Payload v) {
if (v is! Payload) checkItemFailed(v, 'Payload');
if (v is! Payload) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
PayloadType get type => $_getN(0);
set type(PayloadType v) {
setField(1, v);
}
set type(PayloadType v) { setField(1, v); }
bool hasType() => $_has(0);
void clearType() => clearField(1);
List<int> get body => $_getN(1);
set body(List<int> v) {
$_setBytes(1, v);
}
set body(List<int> v) { $_setBytes(1, v); }
bool hasBody() => $_has(1);
void clearBody() => clearField(2);
}
class _ReadonlyPayload extends Payload with ReadonlyMessageMixin {}
class EchoStatus extends GeneratedMessage {
static final BuilderInfo _i = new BuilderInfo('EchoStatus')
..a<int>(1, 'code', PbFieldType.O3)
class EchoStatus extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('EchoStatus', package: const $pb.PackageName('grpc.testing'))
..a<int>(1, 'code', $pb.PbFieldType.O3)
..aOS(2, 'message')
..hasRequiredFields = false;
..hasRequiredFields = false
;
EchoStatus() : super();
EchoStatus.fromBuffer(List<int> i,
[ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromBuffer(i, r);
EchoStatus.fromJson(String i, [ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromJson(i, r);
EchoStatus.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
EchoStatus.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
EchoStatus clone() => new EchoStatus()..mergeFromMessage(this);
BuilderInfo get info_ => _i;
EchoStatus copyWith(void Function(EchoStatus) updates) => super.copyWith((message) => updates(message as EchoStatus));
$pb.BuilderInfo get info_ => _i;
static EchoStatus create() => new EchoStatus();
static PbList<EchoStatus> createRepeated() => new PbList<EchoStatus>();
static EchoStatus getDefault() {
if (_defaultInstance == null) _defaultInstance = new _ReadonlyEchoStatus();
return _defaultInstance;
}
EchoStatus createEmptyInstance() => create();
static $pb.PbList<EchoStatus> createRepeated() => new $pb.PbList<EchoStatus>();
static EchoStatus getDefault() => _defaultInstance ??= create()..freeze();
static EchoStatus _defaultInstance;
static void $checkItem(EchoStatus v) {
if (v is! EchoStatus) checkItemFailed(v, 'EchoStatus');
if (v is! EchoStatus) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
int get code => $_get(0, 0);
set code(int v) {
$_setUnsignedInt32(0, v);
}
set code(int v) { $_setSignedInt32(0, v); }
bool hasCode() => $_has(0);
void clearCode() => clearField(1);
String get message => $_getS(1, '');
set message(String v) {
$_setString(1, v);
}
set message(String v) { $_setString(1, v); }
bool hasMessage() => $_has(1);
void clearMessage() => clearField(2);
}
class _ReadonlyEchoStatus extends EchoStatus with ReadonlyMessageMixin {}
class SimpleRequest extends GeneratedMessage {
static final BuilderInfo _i = new BuilderInfo('SimpleRequest')
..e<PayloadType>(1, 'responseType', PbFieldType.OE,
PayloadType.COMPRESSABLE, PayloadType.valueOf, PayloadType.values)
..a<int>(2, 'responseSize', PbFieldType.O3)
..a<Payload>(
3, 'payload', PbFieldType.OM, Payload.getDefault, Payload.create)
class SimpleRequest extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('SimpleRequest', package: const $pb.PackageName('grpc.testing'))
..e<PayloadType>(1, 'responseType', $pb.PbFieldType.OE, PayloadType.COMPRESSABLE, PayloadType.valueOf, PayloadType.values)
..a<int>(2, 'responseSize', $pb.PbFieldType.O3)
..a<Payload>(3, 'payload', $pb.PbFieldType.OM, Payload.getDefault, Payload.create)
..aOB(4, 'fillUsername')
..aOB(5, 'fillOauthScope')
..a<BoolValue>(6, 'responseCompressed', PbFieldType.OM,
BoolValue.getDefault, BoolValue.create)
..a<EchoStatus>(7, 'responseStatus', PbFieldType.OM, EchoStatus.getDefault,
EchoStatus.create)
..a<BoolValue>(8, 'expectCompressed', PbFieldType.OM, BoolValue.getDefault,
BoolValue.create)
..hasRequiredFields = false;
..a<BoolValue>(6, 'responseCompressed', $pb.PbFieldType.OM, BoolValue.getDefault, BoolValue.create)
..a<EchoStatus>(7, 'responseStatus', $pb.PbFieldType.OM, EchoStatus.getDefault, EchoStatus.create)
..a<BoolValue>(8, 'expectCompressed', $pb.PbFieldType.OM, BoolValue.getDefault, BoolValue.create)
..hasRequiredFields = false
;
SimpleRequest() : super();
SimpleRequest.fromBuffer(List<int> i,
[ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromBuffer(i, r);
SimpleRequest.fromJson(String i,
[ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromJson(i, r);
SimpleRequest.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
SimpleRequest.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
SimpleRequest clone() => new SimpleRequest()..mergeFromMessage(this);
BuilderInfo get info_ => _i;
SimpleRequest copyWith(void Function(SimpleRequest) updates) => super.copyWith((message) => updates(message as SimpleRequest));
$pb.BuilderInfo get info_ => _i;
static SimpleRequest create() => new SimpleRequest();
static PbList<SimpleRequest> createRepeated() => new PbList<SimpleRequest>();
static SimpleRequest getDefault() {
if (_defaultInstance == null)
_defaultInstance = new _ReadonlySimpleRequest();
return _defaultInstance;
}
SimpleRequest createEmptyInstance() => create();
static $pb.PbList<SimpleRequest> createRepeated() => new $pb.PbList<SimpleRequest>();
static SimpleRequest getDefault() => _defaultInstance ??= create()..freeze();
static SimpleRequest _defaultInstance;
static void $checkItem(SimpleRequest v) {
if (v is! SimpleRequest) checkItemFailed(v, 'SimpleRequest');
if (v is! SimpleRequest) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
PayloadType get responseType => $_getN(0);
set responseType(PayloadType v) {
setField(1, v);
}
set responseType(PayloadType v) { setField(1, v); }
bool hasResponseType() => $_has(0);
void clearResponseType() => clearField(1);
int get responseSize => $_get(1, 0);
set responseSize(int v) {
$_setUnsignedInt32(1, v);
}
set responseSize(int v) { $_setSignedInt32(1, v); }
bool hasResponseSize() => $_has(1);
void clearResponseSize() => clearField(2);
Payload get payload => $_getN(2);
set payload(Payload v) {
setField(3, v);
}
set payload(Payload v) { setField(3, v); }
bool hasPayload() => $_has(2);
void clearPayload() => clearField(3);
bool get fillUsername => $_get(3, false);
set fillUsername(bool v) {
$_setBool(3, v);
}
set fillUsername(bool v) { $_setBool(3, v); }
bool hasFillUsername() => $_has(3);
void clearFillUsername() => clearField(4);
bool get fillOauthScope => $_get(4, false);
set fillOauthScope(bool v) {
$_setBool(4, v);
}
set fillOauthScope(bool v) { $_setBool(4, v); }
bool hasFillOauthScope() => $_has(4);
void clearFillOauthScope() => clearField(5);
BoolValue get responseCompressed => $_getN(5);
set responseCompressed(BoolValue v) {
setField(6, v);
}
set responseCompressed(BoolValue v) { setField(6, v); }
bool hasResponseCompressed() => $_has(5);
void clearResponseCompressed() => clearField(6);
EchoStatus get responseStatus => $_getN(6);
set responseStatus(EchoStatus v) {
setField(7, v);
}
set responseStatus(EchoStatus v) { setField(7, v); }
bool hasResponseStatus() => $_has(6);
void clearResponseStatus() => clearField(7);
BoolValue get expectCompressed => $_getN(7);
set expectCompressed(BoolValue v) {
setField(8, v);
}
set expectCompressed(BoolValue v) { setField(8, v); }
bool hasExpectCompressed() => $_has(7);
void clearExpectCompressed() => clearField(8);
}
class _ReadonlySimpleRequest extends SimpleRequest with ReadonlyMessageMixin {}
class SimpleResponse extends GeneratedMessage {
static final BuilderInfo _i = new BuilderInfo('SimpleResponse')
..a<Payload>(
1, 'payload', PbFieldType.OM, Payload.getDefault, Payload.create)
class SimpleResponse extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('SimpleResponse', package: const $pb.PackageName('grpc.testing'))
..a<Payload>(1, 'payload', $pb.PbFieldType.OM, Payload.getDefault, Payload.create)
..aOS(2, 'username')
..aOS(3, 'oauthScope')
..hasRequiredFields = false;
..hasRequiredFields = false
;
SimpleResponse() : super();
SimpleResponse.fromBuffer(List<int> i,
[ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromBuffer(i, r);
SimpleResponse.fromJson(String i,
[ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromJson(i, r);
SimpleResponse.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
SimpleResponse.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
SimpleResponse clone() => new SimpleResponse()..mergeFromMessage(this);
BuilderInfo get info_ => _i;
SimpleResponse copyWith(void Function(SimpleResponse) updates) => super.copyWith((message) => updates(message as SimpleResponse));
$pb.BuilderInfo get info_ => _i;
static SimpleResponse create() => new SimpleResponse();
static PbList<SimpleResponse> createRepeated() =>
new PbList<SimpleResponse>();
static SimpleResponse getDefault() {
if (_defaultInstance == null)
_defaultInstance = new _ReadonlySimpleResponse();
return _defaultInstance;
}
SimpleResponse createEmptyInstance() => create();
static $pb.PbList<SimpleResponse> createRepeated() => new $pb.PbList<SimpleResponse>();
static SimpleResponse getDefault() => _defaultInstance ??= create()..freeze();
static SimpleResponse _defaultInstance;
static void $checkItem(SimpleResponse v) {
if (v is! SimpleResponse) checkItemFailed(v, 'SimpleResponse');
if (v is! SimpleResponse) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
Payload get payload => $_getN(0);
set payload(Payload v) {
setField(1, v);
}
set payload(Payload v) { setField(1, v); }
bool hasPayload() => $_has(0);
void clearPayload() => clearField(1);
String get username => $_getS(1, '');
set username(String v) {
$_setString(1, v);
}
set username(String v) { $_setString(1, v); }
bool hasUsername() => $_has(1);
void clearUsername() => clearField(2);
String get oauthScope => $_getS(2, '');
set oauthScope(String v) {
$_setString(2, v);
}
set oauthScope(String v) { $_setString(2, v); }
bool hasOauthScope() => $_has(2);
void clearOauthScope() => clearField(3);
}
class _ReadonlySimpleResponse extends SimpleResponse with ReadonlyMessageMixin {
}
class StreamingInputCallRequest extends GeneratedMessage {
static final BuilderInfo _i = new BuilderInfo('StreamingInputCallRequest')
..a<Payload>(
1, 'payload', PbFieldType.OM, Payload.getDefault, Payload.create)
..a<BoolValue>(2, 'expectCompressed', PbFieldType.OM, BoolValue.getDefault,
BoolValue.create)
..hasRequiredFields = false;
class StreamingInputCallRequest extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('StreamingInputCallRequest', package: const $pb.PackageName('grpc.testing'))
..a<Payload>(1, 'payload', $pb.PbFieldType.OM, Payload.getDefault, Payload.create)
..a<BoolValue>(2, 'expectCompressed', $pb.PbFieldType.OM, BoolValue.getDefault, BoolValue.create)
..hasRequiredFields = false
;
StreamingInputCallRequest() : super();
StreamingInputCallRequest.fromBuffer(List<int> i,
[ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromBuffer(i, r);
StreamingInputCallRequest.fromJson(String i,
[ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromJson(i, r);
StreamingInputCallRequest clone() =>
new StreamingInputCallRequest()..mergeFromMessage(this);
BuilderInfo get info_ => _i;
StreamingInputCallRequest.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
StreamingInputCallRequest.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
StreamingInputCallRequest clone() => new StreamingInputCallRequest()..mergeFromMessage(this);
StreamingInputCallRequest copyWith(void Function(StreamingInputCallRequest) updates) => super.copyWith((message) => updates(message as StreamingInputCallRequest));
$pb.BuilderInfo get info_ => _i;
static StreamingInputCallRequest create() => new StreamingInputCallRequest();
static PbList<StreamingInputCallRequest> createRepeated() =>
new PbList<StreamingInputCallRequest>();
static StreamingInputCallRequest getDefault() {
if (_defaultInstance == null)
_defaultInstance = new _ReadonlyStreamingInputCallRequest();
return _defaultInstance;
}
StreamingInputCallRequest createEmptyInstance() => create();
static $pb.PbList<StreamingInputCallRequest> createRepeated() => new $pb.PbList<StreamingInputCallRequest>();
static StreamingInputCallRequest getDefault() => _defaultInstance ??= create()..freeze();
static StreamingInputCallRequest _defaultInstance;
static void $checkItem(StreamingInputCallRequest v) {
if (v is! StreamingInputCallRequest)
checkItemFailed(v, 'StreamingInputCallRequest');
if (v is! StreamingInputCallRequest) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
Payload get payload => $_getN(0);
set payload(Payload v) {
setField(1, v);
}
set payload(Payload v) { setField(1, v); }
bool hasPayload() => $_has(0);
void clearPayload() => clearField(1);
BoolValue get expectCompressed => $_getN(1);
set expectCompressed(BoolValue v) {
setField(2, v);
}
set expectCompressed(BoolValue v) { setField(2, v); }
bool hasExpectCompressed() => $_has(1);
void clearExpectCompressed() => clearField(2);
}
class _ReadonlyStreamingInputCallRequest extends StreamingInputCallRequest
with ReadonlyMessageMixin {}
class StreamingInputCallResponse extends GeneratedMessage {
static final BuilderInfo _i = new BuilderInfo('StreamingInputCallResponse')
..a<int>(1, 'aggregatedPayloadSize', PbFieldType.O3)
..hasRequiredFields = false;
class StreamingInputCallResponse extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('StreamingInputCallResponse', package: const $pb.PackageName('grpc.testing'))
..a<int>(1, 'aggregatedPayloadSize', $pb.PbFieldType.O3)
..hasRequiredFields = false
;
StreamingInputCallResponse() : super();
StreamingInputCallResponse.fromBuffer(List<int> i,
[ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromBuffer(i, r);
StreamingInputCallResponse.fromJson(String i,
[ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromJson(i, r);
StreamingInputCallResponse clone() =>
new StreamingInputCallResponse()..mergeFromMessage(this);
BuilderInfo get info_ => _i;
static StreamingInputCallResponse create() =>
new StreamingInputCallResponse();
static PbList<StreamingInputCallResponse> createRepeated() =>
new PbList<StreamingInputCallResponse>();
static StreamingInputCallResponse getDefault() {
if (_defaultInstance == null)
_defaultInstance = new _ReadonlyStreamingInputCallResponse();
return _defaultInstance;
}
StreamingInputCallResponse.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
StreamingInputCallResponse.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
StreamingInputCallResponse clone() => new StreamingInputCallResponse()..mergeFromMessage(this);
StreamingInputCallResponse copyWith(void Function(StreamingInputCallResponse) updates) => super.copyWith((message) => updates(message as StreamingInputCallResponse));
$pb.BuilderInfo get info_ => _i;
static StreamingInputCallResponse create() => new StreamingInputCallResponse();
StreamingInputCallResponse createEmptyInstance() => create();
static $pb.PbList<StreamingInputCallResponse> createRepeated() => new $pb.PbList<StreamingInputCallResponse>();
static StreamingInputCallResponse getDefault() => _defaultInstance ??= create()..freeze();
static StreamingInputCallResponse _defaultInstance;
static void $checkItem(StreamingInputCallResponse v) {
if (v is! StreamingInputCallResponse)
checkItemFailed(v, 'StreamingInputCallResponse');
if (v is! StreamingInputCallResponse) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
int get aggregatedPayloadSize => $_get(0, 0);
set aggregatedPayloadSize(int v) {
$_setUnsignedInt32(0, v);
}
set aggregatedPayloadSize(int v) { $_setSignedInt32(0, v); }
bool hasAggregatedPayloadSize() => $_has(0);
void clearAggregatedPayloadSize() => clearField(1);
}
class _ReadonlyStreamingInputCallResponse extends StreamingInputCallResponse
with ReadonlyMessageMixin {}
class ResponseParameters extends GeneratedMessage {
static final BuilderInfo _i = new BuilderInfo('ResponseParameters')
..a<int>(1, 'size', PbFieldType.O3)
..a<int>(2, 'intervalUs', PbFieldType.O3)
..a<BoolValue>(
3, 'compressed', PbFieldType.OM, BoolValue.getDefault, BoolValue.create)
..hasRequiredFields = false;
class ResponseParameters extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('ResponseParameters', package: const $pb.PackageName('grpc.testing'))
..a<int>(1, 'size', $pb.PbFieldType.O3)
..a<int>(2, 'intervalUs', $pb.PbFieldType.O3)
..a<BoolValue>(3, 'compressed', $pb.PbFieldType.OM, BoolValue.getDefault, BoolValue.create)
..hasRequiredFields = false
;
ResponseParameters() : super();
ResponseParameters.fromBuffer(List<int> i,
[ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromBuffer(i, r);
ResponseParameters.fromJson(String i,
[ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromJson(i, r);
ResponseParameters clone() =>
new ResponseParameters()..mergeFromMessage(this);
BuilderInfo get info_ => _i;
ResponseParameters.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
ResponseParameters.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
ResponseParameters clone() => new ResponseParameters()..mergeFromMessage(this);
ResponseParameters copyWith(void Function(ResponseParameters) updates) => super.copyWith((message) => updates(message as ResponseParameters));
$pb.BuilderInfo get info_ => _i;
static ResponseParameters create() => new ResponseParameters();
static PbList<ResponseParameters> createRepeated() =>
new PbList<ResponseParameters>();
static ResponseParameters getDefault() {
if (_defaultInstance == null)
_defaultInstance = new _ReadonlyResponseParameters();
return _defaultInstance;
}
ResponseParameters createEmptyInstance() => create();
static $pb.PbList<ResponseParameters> createRepeated() => new $pb.PbList<ResponseParameters>();
static ResponseParameters getDefault() => _defaultInstance ??= create()..freeze();
static ResponseParameters _defaultInstance;
static void $checkItem(ResponseParameters v) {
if (v is! ResponseParameters) checkItemFailed(v, 'ResponseParameters');
if (v is! ResponseParameters) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
int get size => $_get(0, 0);
set size(int v) {
$_setUnsignedInt32(0, v);
}
set size(int v) { $_setSignedInt32(0, v); }
bool hasSize() => $_has(0);
void clearSize() => clearField(1);
int get intervalUs => $_get(1, 0);
set intervalUs(int v) {
$_setUnsignedInt32(1, v);
}
set intervalUs(int v) { $_setSignedInt32(1, v); }
bool hasIntervalUs() => $_has(1);
void clearIntervalUs() => clearField(2);
BoolValue get compressed => $_getN(2);
set compressed(BoolValue v) {
setField(3, v);
}
set compressed(BoolValue v) { setField(3, v); }
bool hasCompressed() => $_has(2);
void clearCompressed() => clearField(3);
}
class _ReadonlyResponseParameters extends ResponseParameters
with ReadonlyMessageMixin {}
class StreamingOutputCallRequest extends GeneratedMessage {
static final BuilderInfo _i = new BuilderInfo('StreamingOutputCallRequest')
..e<PayloadType>(1, 'responseType', PbFieldType.OE,
PayloadType.COMPRESSABLE, PayloadType.valueOf, PayloadType.values)
..pp<ResponseParameters>(2, 'responseParameters', PbFieldType.PM,
ResponseParameters.$checkItem, ResponseParameters.create)
..a<Payload>(
3, 'payload', PbFieldType.OM, Payload.getDefault, Payload.create)
..a<EchoStatus>(7, 'responseStatus', PbFieldType.OM, EchoStatus.getDefault,
EchoStatus.create)
..hasRequiredFields = false;
class StreamingOutputCallRequest extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('StreamingOutputCallRequest', package: const $pb.PackageName('grpc.testing'))
..e<PayloadType>(1, 'responseType', $pb.PbFieldType.OE, PayloadType.COMPRESSABLE, PayloadType.valueOf, PayloadType.values)
..pp<ResponseParameters>(2, 'responseParameters', $pb.PbFieldType.PM, ResponseParameters.$checkItem, ResponseParameters.create)
..a<Payload>(3, 'payload', $pb.PbFieldType.OM, Payload.getDefault, Payload.create)
..a<EchoStatus>(7, 'responseStatus', $pb.PbFieldType.OM, EchoStatus.getDefault, EchoStatus.create)
..hasRequiredFields = false
;
StreamingOutputCallRequest() : super();
StreamingOutputCallRequest.fromBuffer(List<int> i,
[ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromBuffer(i, r);
StreamingOutputCallRequest.fromJson(String i,
[ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromJson(i, r);
StreamingOutputCallRequest clone() =>
new StreamingOutputCallRequest()..mergeFromMessage(this);
BuilderInfo get info_ => _i;
static StreamingOutputCallRequest create() =>
new StreamingOutputCallRequest();
static PbList<StreamingOutputCallRequest> createRepeated() =>
new PbList<StreamingOutputCallRequest>();
static StreamingOutputCallRequest getDefault() {
if (_defaultInstance == null)
_defaultInstance = new _ReadonlyStreamingOutputCallRequest();
return _defaultInstance;
}
StreamingOutputCallRequest.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
StreamingOutputCallRequest.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
StreamingOutputCallRequest clone() => new StreamingOutputCallRequest()..mergeFromMessage(this);
StreamingOutputCallRequest copyWith(void Function(StreamingOutputCallRequest) updates) => super.copyWith((message) => updates(message as StreamingOutputCallRequest));
$pb.BuilderInfo get info_ => _i;
static StreamingOutputCallRequest create() => new StreamingOutputCallRequest();
StreamingOutputCallRequest createEmptyInstance() => create();
static $pb.PbList<StreamingOutputCallRequest> createRepeated() => new $pb.PbList<StreamingOutputCallRequest>();
static StreamingOutputCallRequest getDefault() => _defaultInstance ??= create()..freeze();
static StreamingOutputCallRequest _defaultInstance;
static void $checkItem(StreamingOutputCallRequest v) {
if (v is! StreamingOutputCallRequest)
checkItemFailed(v, 'StreamingOutputCallRequest');
if (v is! StreamingOutputCallRequest) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
PayloadType get responseType => $_getN(0);
set responseType(PayloadType v) {
setField(1, v);
}
set responseType(PayloadType v) { setField(1, v); }
bool hasResponseType() => $_has(0);
void clearResponseType() => clearField(1);
List<ResponseParameters> get responseParameters => $_getList(1);
Payload get payload => $_getN(2);
set payload(Payload v) {
setField(3, v);
}
set payload(Payload v) { setField(3, v); }
bool hasPayload() => $_has(2);
void clearPayload() => clearField(3);
EchoStatus get responseStatus => $_getN(3);
set responseStatus(EchoStatus v) {
setField(7, v);
}
set responseStatus(EchoStatus v) { setField(7, v); }
bool hasResponseStatus() => $_has(3);
void clearResponseStatus() => clearField(7);
}
class _ReadonlyStreamingOutputCallRequest extends StreamingOutputCallRequest
with ReadonlyMessageMixin {}
class StreamingOutputCallResponse extends GeneratedMessage {
static final BuilderInfo _i = new BuilderInfo('StreamingOutputCallResponse')
..a<Payload>(
1, 'payload', PbFieldType.OM, Payload.getDefault, Payload.create)
..hasRequiredFields = false;
class StreamingOutputCallResponse extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('StreamingOutputCallResponse', package: const $pb.PackageName('grpc.testing'))
..a<Payload>(1, 'payload', $pb.PbFieldType.OM, Payload.getDefault, Payload.create)
..hasRequiredFields = false
;
StreamingOutputCallResponse() : super();
StreamingOutputCallResponse.fromBuffer(List<int> i,
[ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromBuffer(i, r);
StreamingOutputCallResponse.fromJson(String i,
[ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromJson(i, r);
StreamingOutputCallResponse clone() =>
new StreamingOutputCallResponse()..mergeFromMessage(this);
BuilderInfo get info_ => _i;
static StreamingOutputCallResponse create() =>
new StreamingOutputCallResponse();
static PbList<StreamingOutputCallResponse> createRepeated() =>
new PbList<StreamingOutputCallResponse>();
static StreamingOutputCallResponse getDefault() {
if (_defaultInstance == null)
_defaultInstance = new _ReadonlyStreamingOutputCallResponse();
return _defaultInstance;
}
StreamingOutputCallResponse.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
StreamingOutputCallResponse.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
StreamingOutputCallResponse clone() => new StreamingOutputCallResponse()..mergeFromMessage(this);
StreamingOutputCallResponse copyWith(void Function(StreamingOutputCallResponse) updates) => super.copyWith((message) => updates(message as StreamingOutputCallResponse));
$pb.BuilderInfo get info_ => _i;
static StreamingOutputCallResponse create() => new StreamingOutputCallResponse();
StreamingOutputCallResponse createEmptyInstance() => create();
static $pb.PbList<StreamingOutputCallResponse> createRepeated() => new $pb.PbList<StreamingOutputCallResponse>();
static StreamingOutputCallResponse getDefault() => _defaultInstance ??= create()..freeze();
static StreamingOutputCallResponse _defaultInstance;
static void $checkItem(StreamingOutputCallResponse v) {
if (v is! StreamingOutputCallResponse)
checkItemFailed(v, 'StreamingOutputCallResponse');
if (v is! StreamingOutputCallResponse) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
Payload get payload => $_getN(0);
set payload(Payload v) {
setField(1, v);
}
set payload(Payload v) { setField(1, v); }
bool hasPayload() => $_has(0);
void clearPayload() => clearField(1);
}
class _ReadonlyStreamingOutputCallResponse extends StreamingOutputCallResponse
with ReadonlyMessageMixin {}
class ReconnectParams extends GeneratedMessage {
static final BuilderInfo _i = new BuilderInfo('ReconnectParams')
..a<int>(1, 'maxReconnectBackoffMs', PbFieldType.O3)
..hasRequiredFields = false;
class ReconnectParams extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('ReconnectParams', package: const $pb.PackageName('grpc.testing'))
..a<int>(1, 'maxReconnectBackoffMs', $pb.PbFieldType.O3)
..hasRequiredFields = false
;
ReconnectParams() : super();
ReconnectParams.fromBuffer(List<int> i,
[ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromBuffer(i, r);
ReconnectParams.fromJson(String i,
[ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromJson(i, r);
ReconnectParams.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
ReconnectParams.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
ReconnectParams clone() => new ReconnectParams()..mergeFromMessage(this);
BuilderInfo get info_ => _i;
ReconnectParams copyWith(void Function(ReconnectParams) updates) => super.copyWith((message) => updates(message as ReconnectParams));
$pb.BuilderInfo get info_ => _i;
static ReconnectParams create() => new ReconnectParams();
static PbList<ReconnectParams> createRepeated() =>
new PbList<ReconnectParams>();
static ReconnectParams getDefault() {
if (_defaultInstance == null)
_defaultInstance = new _ReadonlyReconnectParams();
return _defaultInstance;
}
ReconnectParams createEmptyInstance() => create();
static $pb.PbList<ReconnectParams> createRepeated() => new $pb.PbList<ReconnectParams>();
static ReconnectParams getDefault() => _defaultInstance ??= create()..freeze();
static ReconnectParams _defaultInstance;
static void $checkItem(ReconnectParams v) {
if (v is! ReconnectParams) checkItemFailed(v, 'ReconnectParams');
if (v is! ReconnectParams) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
int get maxReconnectBackoffMs => $_get(0, 0);
set maxReconnectBackoffMs(int v) {
$_setUnsignedInt32(0, v);
}
set maxReconnectBackoffMs(int v) { $_setSignedInt32(0, v); }
bool hasMaxReconnectBackoffMs() => $_has(0);
void clearMaxReconnectBackoffMs() => clearField(1);
}
class _ReadonlyReconnectParams extends ReconnectParams
with ReadonlyMessageMixin {}
class ReconnectInfo extends GeneratedMessage {
static final BuilderInfo _i = new BuilderInfo('ReconnectInfo')
class ReconnectInfo extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('ReconnectInfo', package: const $pb.PackageName('grpc.testing'))
..aOB(1, 'passed')
..p<int>(2, 'backoffMs', PbFieldType.P3)
..hasRequiredFields = false;
..p<int>(2, 'backoffMs', $pb.PbFieldType.P3)
..hasRequiredFields = false
;
ReconnectInfo() : super();
ReconnectInfo.fromBuffer(List<int> i,
[ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromBuffer(i, r);
ReconnectInfo.fromJson(String i,
[ExtensionRegistry r = ExtensionRegistry.EMPTY])
: super.fromJson(i, r);
ReconnectInfo.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
ReconnectInfo.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
ReconnectInfo clone() => new ReconnectInfo()..mergeFromMessage(this);
BuilderInfo get info_ => _i;
ReconnectInfo copyWith(void Function(ReconnectInfo) updates) => super.copyWith((message) => updates(message as ReconnectInfo));
$pb.BuilderInfo get info_ => _i;
static ReconnectInfo create() => new ReconnectInfo();
static PbList<ReconnectInfo> createRepeated() => new PbList<ReconnectInfo>();
static ReconnectInfo getDefault() {
if (_defaultInstance == null)
_defaultInstance = new _ReadonlyReconnectInfo();
return _defaultInstance;
}
ReconnectInfo createEmptyInstance() => create();
static $pb.PbList<ReconnectInfo> createRepeated() => new $pb.PbList<ReconnectInfo>();
static ReconnectInfo getDefault() => _defaultInstance ??= create()..freeze();
static ReconnectInfo _defaultInstance;
static void $checkItem(ReconnectInfo v) {
if (v is! ReconnectInfo) checkItemFailed(v, 'ReconnectInfo');
if (v is! ReconnectInfo) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
bool get passed => $_get(0, false);
set passed(bool v) {
$_setBool(0, v);
}
set passed(bool v) { $_setBool(0, v); }
bool hasPassed() => $_has(0);
void clearPassed() => clearField(1);
List<int> get backoffMs => $_getList(1);
}
class _ReadonlyReconnectInfo extends ReconnectInfo with ReadonlyMessageMixin {}

View File

@ -1,26 +1,26 @@
///
// Generated code. Do not modify.
// source: messages.proto
///
// ignore_for_file: non_constant_identifier_names,library_prefixes
library grpc.testing_messages_pbenum;
// ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
// ignore_for_file: UNDEFINED_SHOWN_NAME,UNUSED_SHOWN_NAME
import 'dart:core' show int, dynamic, String, List, Map;
import 'package:protobuf/protobuf.dart';
import 'package:protobuf/protobuf.dart' as $pb;
class PayloadType extends ProtobufEnum {
static const PayloadType COMPRESSABLE =
const PayloadType._(0, 'COMPRESSABLE');
class PayloadType extends $pb.ProtobufEnum {
static const PayloadType COMPRESSABLE = const PayloadType._(0, 'COMPRESSABLE');
static const List<PayloadType> values = const <PayloadType>[
static const List<PayloadType> values = const <PayloadType> [
COMPRESSABLE,
];
static final Map<int, dynamic> _byValue = ProtobufEnum.initByValue(values);
static PayloadType valueOf(int value) => _byValue[value] as PayloadType;
static final Map<int, PayloadType> _byValue = $pb.ProtobufEnum.initByValue(values);
static PayloadType valueOf(int value) => _byValue[value];
static void $checkItem(PayloadType v) {
if (v is! PayloadType) checkItemFailed(v, 'PayloadType');
if (v is! PayloadType) $pb.checkItemFailed(v, 'PayloadType');
}
const PayloadType._(int v, String n) : super(v, n);
}

View File

@ -1,8 +1,9 @@
///
// Generated code. Do not modify.
// source: test.proto
///
// ignore_for_file: non_constant_identifier_names,library_prefixes
library grpc.testing_test;
// ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
// ignore: UNUSED_SHOWN_NAME
import 'dart:core' show int, bool, double, String, List, override;
import 'dart:core' show int, bool, double, String, List, Map, override;

View File

@ -1,307 +1,343 @@
///
// Generated code. Do not modify.
// source: test.proto
///
// ignore_for_file: non_constant_identifier_names,library_prefixes
library grpc.testing_test_pbgrpc;
// ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
import 'dart:async';
import 'dart:async' as $async;
import 'package:grpc/grpc.dart';
import 'empty.pb.dart';
import 'messages.pb.dart';
import 'package:grpc/service_api.dart' as $grpc;
import 'empty.pb.dart' as $0;
import 'messages.pb.dart' as $1;
export 'test.pb.dart';
class TestServiceClient extends Client {
static final _$emptyCall = new ClientMethod<Empty, Empty>(
class TestServiceClient extends $grpc.Client {
static final _$emptyCall = new $grpc.ClientMethod<$0.Empty, $0.Empty>(
'/grpc.testing.TestService/EmptyCall',
(Empty value) => value.writeToBuffer(),
(List<int> value) => new Empty.fromBuffer(value));
static final _$unaryCall = new ClientMethod<SimpleRequest, SimpleResponse>(
'/grpc.testing.TestService/UnaryCall',
(SimpleRequest value) => value.writeToBuffer(),
(List<int> value) => new SimpleResponse.fromBuffer(value));
($0.Empty value) => value.writeToBuffer(),
(List<int> value) => new $0.Empty.fromBuffer(value));
static final _$unaryCall =
new $grpc.ClientMethod<$1.SimpleRequest, $1.SimpleResponse>(
'/grpc.testing.TestService/UnaryCall',
($1.SimpleRequest value) => value.writeToBuffer(),
(List<int> value) => new $1.SimpleResponse.fromBuffer(value));
static final _$cacheableUnaryCall =
new ClientMethod<SimpleRequest, SimpleResponse>(
new $grpc.ClientMethod<$1.SimpleRequest, $1.SimpleResponse>(
'/grpc.testing.TestService/CacheableUnaryCall',
(SimpleRequest value) => value.writeToBuffer(),
(List<int> value) => new SimpleResponse.fromBuffer(value));
static final _$streamingOutputCall =
new ClientMethod<StreamingOutputCallRequest, StreamingOutputCallResponse>(
'/grpc.testing.TestService/StreamingOutputCall',
(StreamingOutputCallRequest value) => value.writeToBuffer(),
(List<int> value) =>
new StreamingOutputCallResponse.fromBuffer(value));
static final _$streamingInputCall =
new ClientMethod<StreamingInputCallRequest, StreamingInputCallResponse>(
'/grpc.testing.TestService/StreamingInputCall',
(StreamingInputCallRequest value) => value.writeToBuffer(),
(List<int> value) =>
new StreamingInputCallResponse.fromBuffer(value));
static final _$fullDuplexCall =
new ClientMethod<StreamingOutputCallRequest, StreamingOutputCallResponse>(
'/grpc.testing.TestService/FullDuplexCall',
(StreamingOutputCallRequest value) => value.writeToBuffer(),
(List<int> value) =>
new StreamingOutputCallResponse.fromBuffer(value));
static final _$halfDuplexCall =
new ClientMethod<StreamingOutputCallRequest, StreamingOutputCallResponse>(
'/grpc.testing.TestService/HalfDuplexCall',
(StreamingOutputCallRequest value) => value.writeToBuffer(),
(List<int> value) =>
new StreamingOutputCallResponse.fromBuffer(value));
static final _$unimplementedCall = new ClientMethod<Empty, Empty>(
($1.SimpleRequest value) => value.writeToBuffer(),
(List<int> value) => new $1.SimpleResponse.fromBuffer(value));
static final _$streamingOutputCall = new $grpc.ClientMethod<
$1.StreamingOutputCallRequest, $1.StreamingOutputCallResponse>(
'/grpc.testing.TestService/StreamingOutputCall',
($1.StreamingOutputCallRequest value) => value.writeToBuffer(),
(List<int> value) =>
new $1.StreamingOutputCallResponse.fromBuffer(value));
static final _$streamingInputCall = new $grpc.ClientMethod<
$1.StreamingInputCallRequest, $1.StreamingInputCallResponse>(
'/grpc.testing.TestService/StreamingInputCall',
($1.StreamingInputCallRequest value) => value.writeToBuffer(),
(List<int> value) => new $1.StreamingInputCallResponse.fromBuffer(value));
static final _$fullDuplexCall = new $grpc.ClientMethod<
$1.StreamingOutputCallRequest, $1.StreamingOutputCallResponse>(
'/grpc.testing.TestService/FullDuplexCall',
($1.StreamingOutputCallRequest value) => value.writeToBuffer(),
(List<int> value) =>
new $1.StreamingOutputCallResponse.fromBuffer(value));
static final _$halfDuplexCall = new $grpc.ClientMethod<
$1.StreamingOutputCallRequest, $1.StreamingOutputCallResponse>(
'/grpc.testing.TestService/HalfDuplexCall',
($1.StreamingOutputCallRequest value) => value.writeToBuffer(),
(List<int> value) =>
new $1.StreamingOutputCallResponse.fromBuffer(value));
static final _$unimplementedCall = new $grpc.ClientMethod<$0.Empty, $0.Empty>(
'/grpc.testing.TestService/UnimplementedCall',
(Empty value) => value.writeToBuffer(),
(List<int> value) => new Empty.fromBuffer(value));
($0.Empty value) => value.writeToBuffer(),
(List<int> value) => new $0.Empty.fromBuffer(value));
TestServiceClient(ClientChannel channel, {CallOptions options})
TestServiceClient($grpc.ClientChannel channel, {$grpc.CallOptions options})
: super(channel, options: options);
ResponseFuture<Empty> emptyCall(Empty request, {CallOptions options}) {
final call = $createCall(_$emptyCall, new Stream.fromIterable([request]),
options: options);
return new ResponseFuture(call);
}
ResponseFuture<SimpleResponse> unaryCall(SimpleRequest request,
{CallOptions options}) {
final call = $createCall(_$unaryCall, new Stream.fromIterable([request]),
options: options);
return new ResponseFuture(call);
}
ResponseFuture<SimpleResponse> cacheableUnaryCall(SimpleRequest request,
{CallOptions options}) {
$grpc.ResponseFuture<$0.Empty> emptyCall($0.Empty request,
{$grpc.CallOptions options}) {
final call = $createCall(
_$cacheableUnaryCall, new Stream.fromIterable([request]),
_$emptyCall, new $async.Stream.fromIterable([request]),
options: options);
return new ResponseFuture(call);
return new $grpc.ResponseFuture(call);
}
ResponseStream<StreamingOutputCallResponse> streamingOutputCall(
StreamingOutputCallRequest request,
{CallOptions options}) {
$grpc.ResponseFuture<$1.SimpleResponse> unaryCall($1.SimpleRequest request,
{$grpc.CallOptions options}) {
final call = $createCall(
_$streamingOutputCall, new Stream.fromIterable([request]),
_$unaryCall, new $async.Stream.fromIterable([request]),
options: options);
return new ResponseStream(call);
return new $grpc.ResponseFuture(call);
}
ResponseFuture<StreamingInputCallResponse> streamingInputCall(
Stream<StreamingInputCallRequest> request,
{CallOptions options}) {
$grpc.ResponseFuture<$1.SimpleResponse> cacheableUnaryCall(
$1.SimpleRequest request,
{$grpc.CallOptions options}) {
final call = $createCall(
_$cacheableUnaryCall, new $async.Stream.fromIterable([request]),
options: options);
return new $grpc.ResponseFuture(call);
}
$grpc.ResponseStream<$1.StreamingOutputCallResponse> streamingOutputCall(
$1.StreamingOutputCallRequest request,
{$grpc.CallOptions options}) {
final call = $createCall(
_$streamingOutputCall, new $async.Stream.fromIterable([request]),
options: options);
return new $grpc.ResponseStream(call);
}
$grpc.ResponseFuture<$1.StreamingInputCallResponse> streamingInputCall(
$async.Stream<$1.StreamingInputCallRequest> request,
{$grpc.CallOptions options}) {
final call = $createCall(_$streamingInputCall, request, options: options);
return new ResponseFuture(call);
return new $grpc.ResponseFuture(call);
}
ResponseStream<StreamingOutputCallResponse> fullDuplexCall(
Stream<StreamingOutputCallRequest> request,
{CallOptions options}) {
$grpc.ResponseStream<$1.StreamingOutputCallResponse> fullDuplexCall(
$async.Stream<$1.StreamingOutputCallRequest> request,
{$grpc.CallOptions options}) {
final call = $createCall(_$fullDuplexCall, request, options: options);
return new ResponseStream(call);
return new $grpc.ResponseStream(call);
}
ResponseStream<StreamingOutputCallResponse> halfDuplexCall(
Stream<StreamingOutputCallRequest> request,
{CallOptions options}) {
$grpc.ResponseStream<$1.StreamingOutputCallResponse> halfDuplexCall(
$async.Stream<$1.StreamingOutputCallRequest> request,
{$grpc.CallOptions options}) {
final call = $createCall(_$halfDuplexCall, request, options: options);
return new ResponseStream(call);
return new $grpc.ResponseStream(call);
}
ResponseFuture<Empty> unimplementedCall(Empty request,
{CallOptions options}) {
$grpc.ResponseFuture<$0.Empty> unimplementedCall($0.Empty request,
{$grpc.CallOptions options}) {
final call = $createCall(
_$unimplementedCall, new Stream.fromIterable([request]),
_$unimplementedCall, new $async.Stream.fromIterable([request]),
options: options);
return new ResponseFuture(call);
return new $grpc.ResponseFuture(call);
}
}
abstract class TestServiceBase extends Service {
abstract class TestServiceBase extends $grpc.Service {
String get $name => 'grpc.testing.TestService';
TestServiceBase() {
$addMethod(new ServiceMethod<Empty, Empty>(
$addMethod(new $grpc.ServiceMethod<$0.Empty, $0.Empty>(
'EmptyCall',
emptyCall_Pre,
false,
false,
(List<int> value) => new Empty.fromBuffer(value),
(Empty value) => value.writeToBuffer()));
$addMethod(new ServiceMethod<SimpleRequest, SimpleResponse>(
(List<int> value) => new $0.Empty.fromBuffer(value),
($0.Empty value) => value.writeToBuffer()));
$addMethod(new $grpc.ServiceMethod<$1.SimpleRequest, $1.SimpleResponse>(
'UnaryCall',
unaryCall_Pre,
false,
false,
(List<int> value) => new SimpleRequest.fromBuffer(value),
(SimpleResponse value) => value.writeToBuffer()));
$addMethod(new ServiceMethod<SimpleRequest, SimpleResponse>(
(List<int> value) => new $1.SimpleRequest.fromBuffer(value),
($1.SimpleResponse value) => value.writeToBuffer()));
$addMethod(new $grpc.ServiceMethod<$1.SimpleRequest, $1.SimpleResponse>(
'CacheableUnaryCall',
cacheableUnaryCall_Pre,
false,
false,
(List<int> value) => new SimpleRequest.fromBuffer(value),
(SimpleResponse value) => value.writeToBuffer()));
$addMethod(new ServiceMethod<StreamingOutputCallRequest,
StreamingOutputCallResponse>(
(List<int> value) => new $1.SimpleRequest.fromBuffer(value),
($1.SimpleResponse value) => value.writeToBuffer()));
$addMethod(new $grpc.ServiceMethod<$1.StreamingOutputCallRequest,
$1.StreamingOutputCallResponse>(
'StreamingOutputCall',
streamingOutputCall_Pre,
false,
true,
(List<int> value) => new StreamingOutputCallRequest.fromBuffer(value),
(StreamingOutputCallResponse value) => value.writeToBuffer()));
$addMethod(new ServiceMethod<StreamingInputCallRequest,
StreamingInputCallResponse>(
(List<int> value) =>
new $1.StreamingOutputCallRequest.fromBuffer(value),
($1.StreamingOutputCallResponse value) => value.writeToBuffer()));
$addMethod(new $grpc.ServiceMethod<$1.StreamingInputCallRequest,
$1.StreamingInputCallResponse>(
'StreamingInputCall',
streamingInputCall,
true,
false,
(List<int> value) => new StreamingInputCallRequest.fromBuffer(value),
(StreamingInputCallResponse value) => value.writeToBuffer()));
$addMethod(new ServiceMethod<StreamingOutputCallRequest,
StreamingOutputCallResponse>(
(List<int> value) => new $1.StreamingInputCallRequest.fromBuffer(value),
($1.StreamingInputCallResponse value) => value.writeToBuffer()));
$addMethod(new $grpc.ServiceMethod<$1.StreamingOutputCallRequest,
$1.StreamingOutputCallResponse>(
'FullDuplexCall',
fullDuplexCall,
true,
true,
(List<int> value) => new StreamingOutputCallRequest.fromBuffer(value),
(StreamingOutputCallResponse value) => value.writeToBuffer()));
$addMethod(new ServiceMethod<StreamingOutputCallRequest,
StreamingOutputCallResponse>(
(List<int> value) =>
new $1.StreamingOutputCallRequest.fromBuffer(value),
($1.StreamingOutputCallResponse value) => value.writeToBuffer()));
$addMethod(new $grpc.ServiceMethod<$1.StreamingOutputCallRequest,
$1.StreamingOutputCallResponse>(
'HalfDuplexCall',
halfDuplexCall,
true,
true,
(List<int> value) => new StreamingOutputCallRequest.fromBuffer(value),
(StreamingOutputCallResponse value) => value.writeToBuffer()));
}
Future<Empty> emptyCall_Pre(ServiceCall call, Future request) async {
return emptyCall(call, await request);
}
Future<SimpleResponse> unaryCall_Pre(ServiceCall call, Future request) async {
return unaryCall(call, await request);
}
Future<SimpleResponse> cacheableUnaryCall_Pre(
ServiceCall call, Future request) async {
return cacheableUnaryCall(call, await request);
}
Stream<StreamingOutputCallResponse> streamingOutputCall_Pre(
ServiceCall call, Future request) async* {
yield* streamingOutputCall(
call, (await request) as StreamingOutputCallRequest);
}
Future<Empty> emptyCall(ServiceCall call, Empty request);
Future<SimpleResponse> unaryCall(ServiceCall call, SimpleRequest request);
Future<SimpleResponse> cacheableUnaryCall(
ServiceCall call, SimpleRequest request);
Stream<StreamingOutputCallResponse> streamingOutputCall(
ServiceCall call, StreamingOutputCallRequest request);
Future<StreamingInputCallResponse> streamingInputCall(
ServiceCall call, Stream<StreamingInputCallRequest> request);
Stream<StreamingOutputCallResponse> fullDuplexCall(
ServiceCall call, Stream<StreamingOutputCallRequest> request);
Stream<StreamingOutputCallResponse> halfDuplexCall(
ServiceCall call, Stream<StreamingOutputCallRequest> request);
}
class UnimplementedServiceClient extends Client {
static final _$unimplementedCall = new ClientMethod<Empty, Empty>(
'/grpc.testing.UnimplementedService/UnimplementedCall',
(Empty value) => value.writeToBuffer(),
(List<int> value) => new Empty.fromBuffer(value));
UnimplementedServiceClient(ClientChannel channel, {CallOptions options})
: super(channel, options: options);
ResponseFuture<Empty> unimplementedCall(Empty request,
{CallOptions options}) {
final call = $createCall(
_$unimplementedCall, new Stream.fromIterable([request]),
options: options);
return new ResponseFuture(call);
}
}
abstract class UnimplementedServiceBase extends Service {
String get $name => 'grpc.testing.UnimplementedService';
UnimplementedServiceBase() {
$addMethod(new ServiceMethod<Empty, Empty>(
(List<int> value) =>
new $1.StreamingOutputCallRequest.fromBuffer(value),
($1.StreamingOutputCallResponse value) => value.writeToBuffer()));
$addMethod(new $grpc.ServiceMethod<$0.Empty, $0.Empty>(
'UnimplementedCall',
unimplementedCall_Pre,
false,
false,
(List<int> value) => new Empty.fromBuffer(value),
(Empty value) => value.writeToBuffer()));
(List<int> value) => new $0.Empty.fromBuffer(value),
($0.Empty value) => value.writeToBuffer()));
}
Future<Empty> unimplementedCall_Pre(ServiceCall call, Future request) async {
$async.Future<$0.Empty> emptyCall_Pre(
$grpc.ServiceCall call, $async.Future request) async {
return emptyCall(call, await request);
}
$async.Future<$1.SimpleResponse> unaryCall_Pre(
$grpc.ServiceCall call, $async.Future request) async {
return unaryCall(call, await request);
}
$async.Future<$1.SimpleResponse> cacheableUnaryCall_Pre(
$grpc.ServiceCall call, $async.Future request) async {
return cacheableUnaryCall(call, await request);
}
$async.Stream<$1.StreamingOutputCallResponse> streamingOutputCall_Pre(
$grpc.ServiceCall call, $async.Future request) async* {
yield* streamingOutputCall(
call, (await request) as $1.StreamingOutputCallRequest);
}
$async.Future<$0.Empty> unimplementedCall_Pre(
$grpc.ServiceCall call, $async.Future request) async {
return unimplementedCall(call, await request);
}
Future<Empty> unimplementedCall(ServiceCall call, Empty request);
$async.Future<$0.Empty> emptyCall($grpc.ServiceCall call, $0.Empty request);
$async.Future<$1.SimpleResponse> unaryCall(
$grpc.ServiceCall call, $1.SimpleRequest request);
$async.Future<$1.SimpleResponse> cacheableUnaryCall(
$grpc.ServiceCall call, $1.SimpleRequest request);
$async.Stream<$1.StreamingOutputCallResponse> streamingOutputCall(
$grpc.ServiceCall call, $1.StreamingOutputCallRequest request);
$async.Future<$1.StreamingInputCallResponse> streamingInputCall(
$grpc.ServiceCall call,
$async.Stream<$1.StreamingInputCallRequest> request);
$async.Stream<$1.StreamingOutputCallResponse> fullDuplexCall(
$grpc.ServiceCall call,
$async.Stream<$1.StreamingOutputCallRequest> request);
$async.Stream<$1.StreamingOutputCallResponse> halfDuplexCall(
$grpc.ServiceCall call,
$async.Stream<$1.StreamingOutputCallRequest> request);
$async.Future<$0.Empty> unimplementedCall(
$grpc.ServiceCall call, $0.Empty request);
}
class ReconnectServiceClient extends Client {
static final _$start = new ClientMethod<ReconnectParams, Empty>(
'/grpc.testing.ReconnectService/Start',
(ReconnectParams value) => value.writeToBuffer(),
(List<int> value) => new Empty.fromBuffer(value));
static final _$stop = new ClientMethod<Empty, ReconnectInfo>(
'/grpc.testing.ReconnectService/Stop',
(Empty value) => value.writeToBuffer(),
(List<int> value) => new ReconnectInfo.fromBuffer(value));
class UnimplementedServiceClient extends $grpc.Client {
static final _$unimplementedCall = new $grpc.ClientMethod<$0.Empty, $0.Empty>(
'/grpc.testing.UnimplementedService/UnimplementedCall',
($0.Empty value) => value.writeToBuffer(),
(List<int> value) => new $0.Empty.fromBuffer(value));
ReconnectServiceClient(ClientChannel channel, {CallOptions options})
UnimplementedServiceClient($grpc.ClientChannel channel,
{$grpc.CallOptions options})
: super(channel, options: options);
ResponseFuture<Empty> start(ReconnectParams request, {CallOptions options}) {
final call = $createCall(_$start, new Stream.fromIterable([request]),
$grpc.ResponseFuture<$0.Empty> unimplementedCall($0.Empty request,
{$grpc.CallOptions options}) {
final call = $createCall(
_$unimplementedCall, new $async.Stream.fromIterable([request]),
options: options);
return new ResponseFuture(call);
}
ResponseFuture<ReconnectInfo> stop(Empty request, {CallOptions options}) {
final call = $createCall(_$stop, new Stream.fromIterable([request]),
options: options);
return new ResponseFuture(call);
return new $grpc.ResponseFuture(call);
}
}
abstract class ReconnectServiceBase extends Service {
abstract class UnimplementedServiceBase extends $grpc.Service {
String get $name => 'grpc.testing.UnimplementedService';
UnimplementedServiceBase() {
$addMethod(new $grpc.ServiceMethod<$0.Empty, $0.Empty>(
'UnimplementedCall',
unimplementedCall_Pre,
false,
false,
(List<int> value) => new $0.Empty.fromBuffer(value),
($0.Empty value) => value.writeToBuffer()));
}
$async.Future<$0.Empty> unimplementedCall_Pre(
$grpc.ServiceCall call, $async.Future request) async {
return unimplementedCall(call, await request);
}
$async.Future<$0.Empty> unimplementedCall(
$grpc.ServiceCall call, $0.Empty request);
}
class ReconnectServiceClient extends $grpc.Client {
static final _$start = new $grpc.ClientMethod<$1.ReconnectParams, $0.Empty>(
'/grpc.testing.ReconnectService/Start',
($1.ReconnectParams value) => value.writeToBuffer(),
(List<int> value) => new $0.Empty.fromBuffer(value));
static final _$stop = new $grpc.ClientMethod<$0.Empty, $1.ReconnectInfo>(
'/grpc.testing.ReconnectService/Stop',
($0.Empty value) => value.writeToBuffer(),
(List<int> value) => new $1.ReconnectInfo.fromBuffer(value));
ReconnectServiceClient($grpc.ClientChannel channel,
{$grpc.CallOptions options})
: super(channel, options: options);
$grpc.ResponseFuture<$0.Empty> start($1.ReconnectParams request,
{$grpc.CallOptions options}) {
final call = $createCall(_$start, new $async.Stream.fromIterable([request]),
options: options);
return new $grpc.ResponseFuture(call);
}
$grpc.ResponseFuture<$1.ReconnectInfo> stop($0.Empty request,
{$grpc.CallOptions options}) {
final call = $createCall(_$stop, new $async.Stream.fromIterable([request]),
options: options);
return new $grpc.ResponseFuture(call);
}
}
abstract class ReconnectServiceBase extends $grpc.Service {
String get $name => 'grpc.testing.ReconnectService';
ReconnectServiceBase() {
$addMethod(new ServiceMethod<ReconnectParams, Empty>(
$addMethod(new $grpc.ServiceMethod<$1.ReconnectParams, $0.Empty>(
'Start',
start_Pre,
false,
false,
(List<int> value) => new ReconnectParams.fromBuffer(value),
(Empty value) => value.writeToBuffer()));
$addMethod(new ServiceMethod<Empty, ReconnectInfo>(
(List<int> value) => new $1.ReconnectParams.fromBuffer(value),
($0.Empty value) => value.writeToBuffer()));
$addMethod(new $grpc.ServiceMethod<$0.Empty, $1.ReconnectInfo>(
'Stop',
stop_Pre,
false,
false,
(List<int> value) => new Empty.fromBuffer(value),
(ReconnectInfo value) => value.writeToBuffer()));
(List<int> value) => new $0.Empty.fromBuffer(value),
($1.ReconnectInfo value) => value.writeToBuffer()));
}
Future<Empty> start_Pre(ServiceCall call, Future request) async {
$async.Future<$0.Empty> start_Pre(
$grpc.ServiceCall call, $async.Future request) async {
return start(call, await request);
}
Future<ReconnectInfo> stop_Pre(ServiceCall call, Future request) async {
$async.Future<$1.ReconnectInfo> stop_Pre(
$grpc.ServiceCall call, $async.Future request) async {
return stop(call, await request);
}
Future<Empty> start(ServiceCall call, ReconnectParams request);
Future<ReconnectInfo> stop(ServiceCall call, Empty request);
$async.Future<$0.Empty> start(
$grpc.ServiceCall call, $1.ReconnectParams request);
$async.Future<$1.ReconnectInfo> stop(
$grpc.ServiceCall call, $0.Empty request);
}

View File

@ -16,12 +16,15 @@
export 'src/auth/auth.dart';
export 'src/client/call.dart';
export 'src/client/channel.dart';
export 'src/client/channel.dart' hide ClientChannel;
export 'src/client/client.dart';
export 'src/client/common.dart';
export 'src/client/connection.dart';
export 'src/client/http2_channel.dart' show ClientChannel;
export 'src/client/method.dart';
export 'src/client/options.dart';
export 'src/client/transport/http2_credentials.dart';
export 'src/client/transport/transport.dart';
export 'src/server/call.dart';
export 'src/server/handler.dart';
@ -29,6 +32,7 @@ export 'src/server/interceptor.dart';
export 'src/server/server.dart';
export 'src/server/service.dart';
export 'src/shared/message.dart';
export 'src/shared/security.dart';
export 'src/shared/status.dart';
export 'src/shared/streams.dart';

30
lib/grpc_web.dart Normal file
View File

@ -0,0 +1,30 @@
// Copyright (c) 2019, the gRPC project authors. Please see the AUTHORS file
// for details. All rights reserved.
//
// 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.
export 'src/auth/auth.dart';
export 'src/client/call.dart';
export 'src/client/channel.dart' hide ClientChannel;
export 'src/client/client.dart';
export 'src/client/common.dart';
export 'src/client/connection.dart';
export 'src/client/method.dart';
export 'src/client/options.dart';
export 'src/client/transport/transport.dart';
export 'src/client/web_channel.dart' show GrpcWebClientChannel;
export 'src/shared/status.dart';
export 'src/shared/streams.dart';
export 'src/shared/timeout.dart';

View File

@ -24,5 +24,4 @@ export 'src/client/common.dart' show ResponseFuture, ResponseStream;
export 'src/client/method.dart' show ClientMethod;
export 'src/client/options.dart' show CallOptions;
export 'src/server/call.dart' show ServiceCall;
export 'src/server/server.dart' show Server;
export 'src/server/service.dart' show Service, ServiceMethod;

View File

@ -1,4 +1,4 @@
// Copyright (c) 2017, the gRPC project authors. Please see the AUTHORS file
// Copyright (c) 2018, the gRPC project authors. Please see the AUTHORS file
// for details. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
@ -15,15 +15,14 @@
import 'dart:async';
import 'package:http2/transport.dart';
import '../shared/status.dart';
import '../shared/streams.dart';
import '../shared/message.dart';
import 'common.dart';
import 'connection.dart';
import 'method.dart';
import 'options.dart';
import 'transport/transport.dart';
const _reservedHeaders = const [
'content-type',
@ -45,9 +44,9 @@ class ClientCall<Q, R> implements Response {
Map<String, String> _headerMetadata;
TransportStream _stream;
GrpcTransportStream _stream;
StreamController<R> _responses;
StreamSubscription<StreamMessage> _requestSubscription;
StreamSubscription<List<int>> _requestSubscription;
StreamSubscription<GrpcMessage> _responseSubscription;
bool isCancelled = false;
@ -120,8 +119,6 @@ class ClientCall<Q, R> implements Response {
}
_requestSubscription = _requests
.map(_method.requestSerializer)
.map(GrpcHttpEncoder.frame)
.map<StreamMessage>((bytes) => new DataStreamMessage(bytes))
.handleError(_onRequestError)
.listen(_stream.outgoingMessages.add,
onError: _stream.outgoingMessages.addError,
@ -143,13 +140,10 @@ class ClientCall<Q, R> implements Response {
if (_stream != null &&
_responses.hasListener &&
_responseSubscription == null) {
_responseSubscription = _stream.incomingMessages
.transform(new GrpcHttpDecoder())
.transform(grpcDecompressor())
.listen(_onResponseData,
onError: _onResponseError,
onDone: _onResponseDone,
cancelOnError: true);
_responseSubscription = _stream.incomingMessages.listen(_onResponseData,
onError: _onResponseError,
onDone: _onResponseDone,
cancelOnError: true);
if (_responses.isPaused) {
_responseSubscription.pause();
}

View File

@ -21,23 +21,28 @@ import 'call.dart';
import 'connection.dart';
import 'method.dart';
import 'options.dart';
import 'transport/transport.dart';
typedef ConnectTransport = Future<Transport> Function(
String host, int port, ChannelOptions options);
/// A channel to a virtual RPC endpoint.
///
/// For each RPC, the channel picks a [ClientConnection] to dispatch the call.
/// RPCs on the same channel may be sent to different connections, depending on
/// load balancing settings.
class ClientChannel {
abstract class ClientChannel {
final String host;
final int port;
final ChannelOptions options;
final ConnectTransport connectTransport;
// TODO(jakobr): Multiple connections, load balancing.
ClientConnection _connection;
bool _isShutdown = false;
ClientChannel(this.host,
ClientChannel(this.host, this.connectTransport,
{this.port = 443, this.options = const ChannelOptions()});
/// Shuts down this channel.
@ -64,7 +69,7 @@ class ClientChannel {
/// The connection may be shared between multiple RPCs.
Future<ClientConnection> getConnection() async {
if (_isShutdown) throw new GrpcError.unavailable('Channel shutting down.');
return _connection ??= new ClientConnection(host, port, options);
return _connection ??= new ClientConnection(host, port, options, connectTransport);
}
/// Initiates a new RPC on this connection.

View File

@ -14,17 +14,16 @@
// limitations under the License.
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:http2/transport.dart';
import 'package:grpc/src/client/channel.dart';
import 'package:meta/meta.dart';
import '../shared/timeout.dart';
import '../shared/status.dart';
import 'call.dart';
import 'options.dart';
import 'transport/transport.dart';
enum ConnectionState {
/// Actively trying to connect.
connecting,
@ -46,98 +45,38 @@ enum ConnectionState {
///
/// RPCs made on a connection are always sent to the same endpoint.
class ClientConnection {
static final _methodPost = new Header.ascii(':method', 'POST');
static final _schemeHttp = new Header.ascii(':scheme', 'http');
static final _schemeHttps = new Header.ascii(':scheme', 'https');
static final _contentTypeGrpc =
new Header.ascii('content-type', 'application/grpc');
static final _teTrailers = new Header.ascii('te', 'trailers');
static final _grpcAcceptEncoding =
new Header.ascii('grpc-accept-encoding', 'identity');
static final _userAgent = new Header.ascii('user-agent', 'dart-grpc/0.2.0');
final String host;
final int port;
final ChannelOptions options;
final ConnectTransport connectTransport;
ConnectionState _state = ConnectionState.idle;
void Function(ClientConnection connection) onStateChanged;
final _pendingCalls = <ClientCall>[];
ClientTransportConnection _transport;
Transport _transport;
/// Used for idle and reconnect timeout, depending on [_state].
Timer _timer;
Duration _currentReconnectDelay;
ClientConnection(this.host, this.port, this.options);
ClientConnection(this.host, this.port, this.options, this.connectTransport);
ConnectionState get state => _state;
static List<Header> createCallHeaders(bool useTls, String authority,
String path, Duration timeout, Map<String, String> metadata) {
final headers = [
_methodPost,
useTls ? _schemeHttps : _schemeHttp,
new Header(ascii.encode(':path'), utf8.encode(path)),
new Header(ascii.encode(':authority'), utf8.encode(authority)),
];
if (timeout != null) {
headers.add(new Header.ascii('grpc-timeout', toTimeoutString(timeout)));
}
headers.addAll([
_contentTypeGrpc,
_teTrailers,
_grpcAcceptEncoding,
_userAgent,
]);
metadata?.forEach((key, value) {
headers.add(new Header(ascii.encode(key), utf8.encode(value)));
});
return headers;
}
String get authority => options.credentials.authority ?? host;
@visibleForTesting
Future<ClientTransportConnection> connectTransport() async {
final securityContext = options.credentials.securityContext;
var socket = await Socket.connect(host, port);
if (_state == ConnectionState.shutdown) {
socket.destroy();
throw 'Shutting down';
}
if (securityContext != null) {
socket = await SecureSocket.secure(socket,
host: authority,
context: securityContext,
onBadCertificate: _validateBadCertificate);
if (_state == ConnectionState.shutdown) {
socket.destroy();
throw 'Shutting down';
}
}
socket.done.then(_handleSocketClosed);
return new ClientTransportConnection.viaSocket(socket);
}
bool _validateBadCertificate(X509Certificate certificate) {
final validator = options.credentials.onBadCertificate;
if (validator == null) return false;
return validator(certificate, authority);
}
void _connect() {
if (_state != ConnectionState.idle &&
_state != ConnectionState.transientFailure) {
return;
}
_setState(ConnectionState.connecting);
connectTransport().then((transport) {
connectTransport(host, port, options).then((transport) {
_currentReconnectDelay = null;
_transport = transport;
_transport.onActiveStateChanged = _handleActiveStateChanged;
_transport.onSocketClosed = _handleSocketClosed;
_setState(ConnectionState.ready);
_pendingCalls.forEach(_startCall);
_pendingCalls.clear();
@ -160,11 +99,9 @@ class ClientConnection {
}
}
ClientTransportStream makeRequest(
GrpcTransportStream makeRequest(
String path, Duration timeout, Map<String, String> metadata) {
final headers = createCallHeaders(
options.credentials.isSecure, authority, path, timeout, metadata);
return _transport.makeRequest(headers);
return _transport.makeRequest(path, timeout, metadata);
}
void _startCall(ClientCall call) {
@ -261,7 +198,7 @@ class ClientConnection {
_connect();
}
void _handleSocketClosed(_) {
void _handleSocketClosed() {
_cancelTimer();
_transport = null;

View File

@ -0,0 +1,33 @@
// Copyright (c) 2019, the gRPC project authors. Please see the AUTHORS file
// for details. All rights reserved.
//
// 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.
import 'package:meta/meta.dart';
import 'channel.dart' as channel;
import 'options.dart';
import 'transport/transport.dart';
import 'transport/http2_transport.dart';
@visibleForTesting
Future<Transport> connectTransport(
String host, int port, ChannelOptions options) async {
return Http2Transport(host, port, options)..connect();
}
class ClientChannel extends channel.ClientChannel {
ClientChannel(String host,
{int port = 443, ChannelOptions options = const ChannelOptions()})
: super(host, connectTransport, port: port, options: options);
}

View File

@ -14,18 +14,15 @@
// limitations under the License.
import 'dart:async';
import 'dart:io';
import 'package:meta/meta.dart';
import 'dart:math';
import '../shared/security.dart';
const defaultIdleTimeout = const Duration(minutes: 5);
typedef Duration BackoffStrategy(Duration lastBackoff);
// Backoff algorithm from https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md
const _minConnectTimeout = const Duration(seconds: 20);
const _initialBackoff = const Duration(seconds: 1);
const _maxBackoff = const Duration(seconds: 120);
const _multiplier = 1.6;
@ -39,54 +36,16 @@ Duration defaultBackoffStrategy(Duration lastBackoff) {
return nextBackoff < _maxBackoff ? nextBackoff : _maxBackoff;
}
/// Handler for checking certificates that fail validation. If this handler
/// returns `true`, the bad certificate is allowed, and the TLS handshake can
/// continue. If the handler returns `false`, the TLS handshake fails, and the
/// connection is aborted.
typedef bool BadCertificateHandler(X509Certificate certificate, String host);
/// Bad certificate handler that disables all certificate checks.
/// DO NOT USE IN PRODUCTION!
/// Can be used during development and testing to accept self-signed
/// certificates, etc.
bool allowBadCertificates(X509Certificate certificate, String host) => true;
/// Options controlling TLS security settings on a [ClientChannel].
class ChannelCredentials {
final bool isSecure;
final List<int> _certificateBytes;
final String _certificatePassword;
final String authority;
final BadCertificateHandler onBadCertificate;
const ChannelCredentials._(this.isSecure, this._certificateBytes,
this._certificatePassword, this.authority, this.onBadCertificate);
@visibleForOverriding
const ChannelCredentials(this.isSecure, this.authority);
/// Disable TLS. RPCs are sent in clear text.
const ChannelCredentials.insecure() : this._(false, null, null, null, null);
/// Enable TLS and optionally specify the [certificates] to trust. If
/// [certificates] is not provided, the default trust store is used.
const ChannelCredentials.secure(
{List<int> certificates,
String password,
String authority,
BadCertificateHandler onBadCertificate})
: this._(true, certificates, password, authority, onBadCertificate);
SecurityContext get securityContext {
if (!isSecure) return null;
if (_certificateBytes != null) {
return createSecurityContext(false)
..setTrustedCertificatesBytes(_certificateBytes,
password: _certificatePassword);
}
final context = new SecurityContext(withTrustedRoots: true);
if (SecurityContext.alpnSupported) {
context.setAlpnProtocols(supportedAlpnProtocols, false);
}
return context;
}
const ChannelCredentials.insecure() : this(false, null);
}
/// Options controlling how connections are made on a [ClientChannel].
@ -95,14 +54,11 @@ class ChannelOptions {
final Duration idleTimeout;
final BackoffStrategy backoffStrategy;
const ChannelOptions(
{ChannelCredentials credentials,
Duration idleTimeout,
BackoffStrategy backoffStrategy =
defaultBackoffStrategy}) // Remove when dart-lang/sdk#31066 is fixed.
: this.credentials = credentials ?? const ChannelCredentials.secure(),
this.idleTimeout = idleTimeout ?? defaultIdleTimeout,
this.backoffStrategy = backoffStrategy ?? defaultBackoffStrategy;
const ChannelOptions({
ChannelCredentials credentials,
this.idleTimeout = defaultIdleTimeout,
this.backoffStrategy = defaultBackoffStrategy,
}) : this.credentials = credentials ?? const ChannelCredentials.insecure();
}
/// Provides per-RPC metadata.

View File

@ -0,0 +1,63 @@
// Copyright (c) 2018, the gRPC project authors. Please see the AUTHORS file
// for details. All rights reserved.
//
// 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.
import 'dart:io';
import '../../shared/security.dart';
import '../options.dart';
/// Handler for checking certificates that fail validation. If this handler
/// returns `true`, the bad certificate is allowed, and the TLS handshake can
/// continue. If the handler returns `false`, the TLS handshake fails, and the
/// connection is aborted.
typedef bool BadCertificateHandler(X509Certificate certificate, String host);
/// Bad certificate handler that disables all certificate checks.
/// DO NOT USE IN PRODUCTION!
/// Can be used during development and testing to accept self-signed
/// certificates, etc.
bool allowBadCertificates(X509Certificate certificate, String host) => true;
class Http2ChannelCredentials extends ChannelCredentials {
final List<int> _certificateBytes;
final String _certificatePassword;
final BadCertificateHandler onBadCertificate;
const Http2ChannelCredentials._(bool isSecure, String authority,
this._certificateBytes, this._certificatePassword, this.onBadCertificate)
: super(isSecure, authority);
/// Enable TLS and optionally specify the [certificates] to trust. If
/// [certificates] is not provided, the default trust store is used.
const Http2ChannelCredentials.secure(
{List<int> certificates,
String password,
String authority,
BadCertificateHandler onBadCertificate})
: this._(true, authority, certificates, password, onBadCertificate);
SecurityContext get securityContext {
if (!isSecure) return null;
if (_certificateBytes != null) {
return createSecurityContext(false)
..setTrustedCertificatesBytes(_certificateBytes,
password: _certificatePassword);
}
final context = new SecurityContext(withTrustedRoots: true);
context.setAlpnProtocols(supportedAlpnProtocols, false);
return context;
}
}

View File

@ -0,0 +1,169 @@
// Copyright (c) 2018, the gRPC project authors. Please see the AUTHORS file
// for details. All rights reserved.
//
// 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.
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:http2/transport.dart';
import 'package:meta/meta.dart';
import '../../shared/message.dart';
import '../../shared/streams.dart';
import '../../shared/timeout.dart';
import '../options.dart';
import 'http2_credentials.dart';
import 'transport.dart';
class Http2TransportStream extends GrpcTransportStream {
TransportStream _transportStream;
StreamController<GrpcMessage> _incomingMessages;
StreamController<List<int>> _outgoingMessages;
Stream<GrpcMessage> get incomingMessages => _incomingMessages.stream;
StreamSink<List<int>> get outgoingMessages => _outgoingMessages.sink;
Http2TransportStream(this._transportStream) {
_incomingMessages = new StreamController();
_outgoingMessages = new StreamController();
_transportStream.incomingMessages
.transform(new GrpcHttpDecoder())
.transform(grpcDecompressor())
.pipe(_incomingMessages);
_outgoingMessages.stream
.map(frame)
.map<StreamMessage>((bytes) => new DataStreamMessage(bytes))
.handleError(_onRequestError)
.listen(_transportStream.outgoingMessages.add,
onError: _transportStream.outgoingMessages.addError,
onDone: _transportStream.outgoingMessages.close,
cancelOnError: true);
}
void _onRequestError() {
// TODO: Implement errors on requests
}
@override
Future<void> terminate() async {
await _incomingMessages.close();
await _outgoingMessages.close();
_transportStream.terminate();
}
}
class Http2Transport extends Transport {
static final _methodPost = new Header.ascii(':method', 'POST');
static final _schemeHttp = new Header.ascii(':scheme', 'http');
static final _schemeHttps = new Header.ascii(':scheme', 'https');
static final _contentTypeGrpc =
new Header.ascii('content-type', 'application/grpc');
static final _teTrailers = new Header.ascii('te', 'trailers');
static final _grpcAcceptEncoding =
new Header.ascii('grpc-accept-encoding', 'identity');
static final _userAgent = new Header.ascii('user-agent', 'dart-grpc/0.2.0');
final String host;
final int port;
final ChannelOptions options;
@visibleForTesting
ClientTransportConnection transportConnection;
Http2Transport(this.host, this.port, this.options);
String get authority => options.credentials.authority ?? host;
static List<Header> createCallHeaders(bool useTls, String authority,
String path, Duration timeout, Map<String, String> metadata) {
final headers = [
_methodPost,
useTls ? _schemeHttps : _schemeHttp,
new Header(ascii.encode(':path'), utf8.encode(path)),
new Header(ascii.encode(':authority'), utf8.encode(authority)),
];
if (timeout != null) {
headers.add(new Header.ascii('grpc-timeout', toTimeoutString(timeout)));
}
headers.addAll([
_contentTypeGrpc,
_teTrailers,
_grpcAcceptEncoding,
_userAgent,
]);
metadata?.forEach((key, value) {
headers.add(new Header(ascii.encode(key), utf8.encode(value)));
});
return headers;
}
@override
Future<void> connect() async {
var socket = await Socket.connect(host, port);
final credentials = options.credentials;
if (credentials is Http2ChannelCredentials) {
final securityContext = credentials.securityContext;
if (securityContext != null) {
socket = await SecureSocket.secure(socket,
host: authority,
context: securityContext,
onBadCertificate: _validateBadCertificate);
}
}
socket.done.then(_handleSocketClosed);
transportConnection = ClientTransportConnection.viaSocket(socket);
}
@override
GrpcTransportStream makeRequest(
String path, Duration timeout, Map<String, String> metadata) {
final headers = createCallHeaders(
options.credentials.isSecure, authority, path, timeout, metadata);
final stream = transportConnection.makeRequest(headers);
return new Http2TransportStream(stream);
}
@override
Future<void> finish() async {
await transportConnection.finish();
}
@override
Future<void> terminate() async {
await transportConnection.terminate();
}
bool _validateBadCertificate(X509Certificate certificate) {
final credentials = options.credentials;
if (credentials is Http2ChannelCredentials) {
final validator = credentials.onBadCertificate;
if (validator == null) return false;
return validator(certificate, authority);
}
return false;
}
void _handleSocketClosed(_) {
if (onSocketClosed != null) {
onSocketClosed();
}
}
}

View File

@ -0,0 +1,39 @@
// Copyright (c) 2018, the gRPC project authors. Please see the AUTHORS file
// for details. All rights reserved.
//
// 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.
import 'dart:async';
import '../../shared/message.dart';
typedef void SocketClosedHandler();
typedef void ActiveStateHandler(bool isActive);
abstract class GrpcTransportStream {
Stream<GrpcMessage> get incomingMessages;
StreamSink<List<int>> get outgoingMessages;
Future<void> terminate();
}
abstract class Transport {
ActiveStateHandler onActiveStateChanged;
SocketClosedHandler onSocketClosed;
Future<void> connect();
GrpcTransportStream makeRequest(
String path, Duration timeout, Map<String, String> metadata);
Future<void> finish();
Future<void> terminate();
}

View File

@ -0,0 +1,160 @@
// Copyright (c) 2019, the gRPC project authors. Please see the AUTHORS file
// for details. All rights reserved.
//
// 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.
import 'dart:convert';
import 'dart:math';
import 'dart:typed_data';
import '../../shared/message.dart';
import '../../shared/status.dart';
enum _GrpcWebParseState { Init, Length, Message }
class GrpcWebDecoder extends Converter<ByteBuffer, GrpcMessage> {
@override
GrpcMessage convert(ByteBuffer input) {
final sink = GrpcMessageSink();
startChunkedConversion(sink)
..add(input)
..close();
return sink.message;
}
@override
Sink<ByteBuffer> startChunkedConversion(Sink<GrpcMessage> sink) {
return _GrpcWebConversionSink(sink);
}
}
class _GrpcWebConversionSink extends ChunkedConversionSink<ByteBuffer> {
static const int frameTypeData = 0x00;
static const int frameTypeTrailers = 0x80;
final Sink<GrpcMessage> _out;
final _dataHeader = new Uint8List(4);
_GrpcWebParseState _state = _GrpcWebParseState.Init;
int _chunkOffset;
int _frameType;
int _dataOffset = 0;
Uint8List _data;
_GrpcWebConversionSink(this._out);
int _parseFrameType(List<int> chunkData) {
final frameType = chunkData[_chunkOffset];
_chunkOffset++;
if (frameType != frameTypeData && frameType != frameTypeTrailers) {
throw GrpcError.unimplemented('Invalid frame type: ${frameType}');
}
_state = _GrpcWebParseState.Length;
return frameType;
}
void _parseLength(List<int> chunkData) {
final chunkLength = chunkData.length;
final headerRemaining = _dataHeader.lengthInBytes - _dataOffset;
final chunkRemaining = chunkLength - _chunkOffset;
final toCopy = min(headerRemaining, chunkRemaining);
_dataHeader.setRange(
_dataOffset, _dataOffset + toCopy, chunkData, _chunkOffset);
_dataOffset += toCopy;
_chunkOffset += toCopy;
if (_dataOffset == _dataHeader.lengthInBytes) {
final dataLength = _dataHeader.buffer.asByteData().getUint32(0);
_dataOffset = 0;
_state = _GrpcWebParseState.Message;
if (dataLength == 0) {
// empty message
_finishMessage();
}
_data = new Uint8List(dataLength);
}
}
void _parseMessage(List<int> chunkData) {
final dataRemaining = _data.lengthInBytes - _dataOffset;
if (dataRemaining > 0) {
final chunkRemaining = chunkData.length - _chunkOffset;
final toCopy = min(dataRemaining, chunkRemaining);
_data.setRange(
_dataOffset, _dataOffset + toCopy, chunkData, _chunkOffset);
_dataOffset += toCopy;
_chunkOffset += toCopy;
}
if (_dataOffset == _data.lengthInBytes) {
_finishMessage();
}
}
void _finishMessage() {
switch (_frameType) {
case frameTypeData:
_out.add(new GrpcData(_data, isCompressed: false));
break;
case frameTypeTrailers:
final stringData = String.fromCharCodes(_data);
final headers = _parseHttp1Headers(stringData);
_out.add(new GrpcMetadata(headers));
break;
}
_state = _GrpcWebParseState.Init;
_data = null;
_dataOffset = 0;
}
Map<String, String> _parseHttp1Headers(String stringData) {
final chunks = stringData.trim().split('\r\n');
final headers = <String, String>{};
for (final chunk in chunks) {
final pos = chunk.indexOf(':');
headers[chunk.substring(0, pos).trim()] = chunk.substring(pos + 1).trim();
}
return headers;
}
@override
void add(ByteBuffer chunk) {
_chunkOffset = 0;
final chunkData = chunk.asUint8List();
while (_chunkOffset < chunk.lengthInBytes) {
switch (_state) {
case _GrpcWebParseState.Init:
_frameType = _parseFrameType(chunkData);
break;
case _GrpcWebParseState.Length:
_parseLength(chunkData);
break;
case _GrpcWebParseState.Message:
_parseMessage(chunkData);
break;
}
}
_chunkOffset = 0;
}
@override
void close() {
if (_data != null || _dataOffset != 0) {
throw new GrpcError.unavailable('Closed in non-idle state');
}
_out.close();
}
}

View File

@ -0,0 +1,140 @@
// Copyright (c) 2018, the gRPC project authors. Please see the AUTHORS file
// for details. All rights reserved.
//
// 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.
import 'dart:async';
import 'dart:html';
import 'dart:typed_data';
import 'package:meta/meta.dart';
import '../../shared/message.dart';
import 'transport.dart';
import 'web_streams.dart';
class XhrTransportStream implements GrpcTransportStream {
HttpRequest _request;
int _requestBytesRead = 0;
StreamController<ByteBuffer> _incomingProcessor;
StreamController<GrpcMessage> _incomingMessages;
StreamController<List<int>> _outgoingMessages;
@override
Stream<GrpcMessage> get incomingMessages => _incomingMessages.stream;
@override
StreamSink<List<int>> get outgoingMessages => _outgoingMessages.sink;
XhrTransportStream(this._request) {
_incomingProcessor = StreamController();
_incomingMessages = StreamController();
_outgoingMessages = StreamController();
_incomingProcessor.stream
.transform(GrpcWebDecoder())
.transform(grpcDecompressor())
.listen(_incomingMessages.add,
onError: _incomingMessages.addError,
onDone: _incomingMessages.close);
_outgoingMessages.stream
.map(frame)
.listen((data) => _request.send(data));
_request.onReadyStateChange.listen((data) {
final contentType = _request.getResponseHeader('Content-Type');
if (contentType == null) {
return;
}
if (_request.readyState == HttpRequest.HEADERS_RECEIVED) {
if (contentType.startsWith('application/grpc')) {
if (_request.response == null) {
return;
}
// Force a metadata message with headers
final headers = GrpcMetadata(_request.responseHeaders);
_incomingMessages.add(headers);
}
}
if (_request.readyState == HttpRequest.DONE) {
_incomingProcessor.close();
_outgoingMessages.close();
}
});
_request.onProgress.listen((_) {
// use response over responseText as most browsers don't support
// using responseText during an onProgress event.
final responseString = _request.response as String;
final bytes = Uint8List.fromList(
responseString.substring(_requestBytesRead).codeUnits)
.buffer;
_requestBytesRead = responseString.length;
_incomingProcessor.add(bytes);
});
}
@override
Future<void> terminate() async {
await _incomingProcessor.close();
await _outgoingMessages.close();
_request.abort();
}
}
class XhrTransport extends Transport {
final String host;
final int port;
HttpRequest _request;
XhrTransport(this.host, this.port);
@override
Future<void> connect() async {}
@override
Future<void> finish() async {}
@visibleForTesting
void initializeRequest(HttpRequest request, Map<String, String> metadata) {
for (final header in metadata.keys) {
request.setRequestHeader(header, metadata[header]);
}
request.setRequestHeader('Content-Type', 'application/grpc-web+proto');
request.setRequestHeader('X-User-Agent', 'grpc-web-dart/0.1');
request.setRequestHeader('X-Grpc-Web', '1');
// Overriding the mimetype allows us to stream and parse the data
request.overrideMimeType('text/plain; charset=x-user-defined');
request.responseType = 'text';
}
@override
GrpcTransportStream makeRequest(
String path, Duration timeout, Map<String, String> metadata) {
_request = HttpRequest();
_request.open('POST', '${host}:${port}${path}');
initializeRequest(_request, metadata);
return XhrTransportStream(_request);
}
@override
Future<void> terminate() async {}
}

View File

@ -0,0 +1,32 @@
// Copyright (c) 2019, the gRPC project authors. Please see the AUTHORS file
// for details. All rights reserved.
//
// 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.
import 'package:grpc/src/client/options.dart';
import 'package:grpc/src/client/transport/transport.dart';
import 'package:grpc/src/client/transport/xhr_transport.dart';
import 'package:meta/meta.dart';
import 'channel.dart';
@visibleForTesting
Future<Transport> connectXhrTransport(
String host, int port, ChannelOptions _) async {
return XhrTransport(host, port)..connect();
}
class GrpcWebClientChannel extends ClientChannel {
GrpcWebClientChannel.xhr(String host,
{int port = 443}) : super(host, connectXhrTransport, port: port);
}

View File

@ -18,6 +18,7 @@ import 'dart:convert';
import 'package:http2/transport.dart';
import '../shared/message.dart';
import '../shared/status.dart';
import '../shared/streams.dart';
import '../shared/timeout.dart';
@ -228,7 +229,7 @@ class ServerHandler extends ServiceCall {
if (!_headersSent) {
sendHeaders();
}
_stream.sendData(GrpcHttpEncoder.frame(bytes));
_stream.sendData(frame(bytes));
} catch (error) {
final grpcError =
new GrpcError.internal('Error sending response: $error');

View File

@ -0,0 +1,63 @@
import 'dart:async';
import 'dart:typed_data';
abstract class GrpcMessage {}
class GrpcMetadata extends GrpcMessage {
final Map<String, String> metadata;
GrpcMetadata(this.metadata);
@override
String toString() => 'gRPC Metadata ($metadata)';
}
class GrpcData extends GrpcMessage {
final List<int> data;
final bool isCompressed;
GrpcData(this.data, {this.isCompressed});
@override
String toString() => 'gRPC Data (${data.length} bytes)';
}
class GrpcMessageSink extends Sink<GrpcMessage> {
GrpcMessage message;
@override
void add(GrpcMessage data) {
if (message != null) {
throw 'Too many messages received!';
}
message = data;
}
@override
void close() {
if (message == null) {
throw 'No messages received!';
}
}
}
List<int> frame(List<int> payload) {
final payloadLength = payload.length;
final bytes = new Uint8List(payloadLength + 5);
final header = bytes.buffer.asByteData(0, 5);
header.setUint8(0, 0); // TODO(dart-lang/grpc-dart#6): Handle compression
header.setUint32(1, payloadLength);
bytes.setRange(5, bytes.length, payload);
return bytes;
}
StreamTransformer<GrpcMessage, GrpcMessage> grpcDecompressor() =>
new StreamTransformer<GrpcMessage, GrpcMessage>.fromHandlers(
handleData: (GrpcMessage value, EventSink<GrpcMessage> sink) {
if (value is GrpcData) {
if (value.isCompressed) {
// TODO(dart-lang/grpc-dart#6): Actually handle decompression.
sink.add(new GrpcData(value.data, isCompressed: false));
return;
}
}
sink.add(value);
});

View File

@ -20,40 +20,9 @@ import 'dart:typed_data';
import 'package:http2/transport.dart';
import 'message.dart';
import 'status.dart';
abstract class GrpcMessage {}
class GrpcMetadata extends GrpcMessage {
final Map<String, String> metadata;
GrpcMetadata(this.metadata);
@override
String toString() => 'gRPC Metadata ($metadata)';
}
class GrpcData extends GrpcMessage {
final List<int> data;
final bool isCompressed;
GrpcData(this.data, {this.isCompressed});
@override
String toString() => 'gRPC Data (${data.length} bytes)';
}
StreamTransformer<GrpcMessage, GrpcMessage> grpcDecompressor() =>
new StreamTransformer<GrpcMessage, GrpcMessage>.fromHandlers(
handleData: (GrpcMessage value, EventSink<GrpcMessage> sink) {
if (value is GrpcData) {
if (value.isCompressed) {
// TODO(dart-lang/grpc-dart#6): Actually handle decompression.
sink.add(new GrpcData(value.data, isCompressed: false));
return;
}
}
sink.add(value);
});
class GrpcHttpEncoder extends Converter<GrpcMessage, StreamMessage> {
@override
StreamMessage convert(GrpcMessage input) {
@ -68,22 +37,12 @@ class GrpcHttpEncoder extends Converter<GrpcMessage, StreamMessage> {
}
throw new GrpcError.internal('Unexpected message type');
}
static List<int> frame(List<int> payload) {
final payloadLength = payload.length;
final bytes = new Uint8List(payloadLength + 5);
final header = bytes.buffer.asByteData(0, 5);
header.setUint8(0, 0); // TODO(dart-lang/grpc-dart#6): Handle compression
header.setUint32(1, payloadLength);
bytes.setRange(5, bytes.length, payload);
return bytes;
}
}
class GrpcHttpDecoder extends Converter<StreamMessage, GrpcMessage> {
@override
GrpcMessage convert(StreamMessage input) {
final sink = new _GrpcMessageSink();
final sink = new GrpcMessageSink();
startChunkedConversion(sink)
..add(input)
..close();
@ -183,22 +142,3 @@ class _GrpcMessageConversionSink extends ChunkedConversionSink<StreamMessage> {
_out.close();
}
}
class _GrpcMessageSink extends Sink<GrpcMessage> {
GrpcMessage message;
@override
void add(GrpcMessage data) {
if (message != null) {
throw 'Too many messages received!';
}
message = data;
}
@override
void close() {
if (message == null) {
throw 'No messages received!';
}
}
}

View File

@ -1,6 +1,6 @@
name: grpc
description: Dart implementation of gRPC, a high performance, open-source universal RPC framework.
version: 1.0.1
version: 1.1.0
author: Dart Team <misc@dartlang.org>
homepage: https://github.com/dart-lang/grpc-dart
@ -8,12 +8,14 @@ environment:
sdk: '>=2.0.0 <3.0.0'
dependencies:
async: '>=1.13.3 <3.0.0'
googleapis_auth: ^0.2.5+3
meta: ^1.0.5
http: '>=0.11.3+17 <0.13.0'
http2: '>=0.1.7 <2.0.0'
dev_dependencies:
build_runner: ^0.10.0
build_test: ^0.10.3
build_web_compilers: ^0.4.3
mockito: ^4.0.0
test: ^1.5.0

View File

@ -0,0 +1,162 @@
// Copyright (c) 2017, the gRPC project authors. Please see the AUTHORS file
// for details. All rights reserved.
//
// 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.
@TestOn('vm')
import 'dart:async';
import 'package:grpc/grpc.dart';
import 'package:grpc/src/client/transport/http2_credentials.dart';
import 'package:grpc/src/client/transport/http2_transport.dart';
import 'package:http2/transport.dart';
import 'package:mockito/mockito.dart';
import 'package:test/test.dart';
import '../src/utils.dart';
class MockTransport extends Mock implements ClientTransportConnection {}
class MockStream extends Mock implements ClientTransportStream {}
typedef void VerifyHeadersCallback(List<Header> headers);
class MockHttp2Transport extends Http2Transport {
MockStream mockClientStream;
VerifyHeadersCallback onVerifyHeaders;
StreamController<StreamMessage> fromClient;
StreamController<StreamMessage> toClient;
MockHttp2Transport(String host, int port, ChannelOptions options)
: super(host, port, options);
@override
Future<void> connect() async {
transportConnection = MockTransport();
when(transportConnection.makeRequest(any)).thenAnswer((call) {
if (onVerifyHeaders != null) {
onVerifyHeaders(call.positionalArguments[0]);
}
mockClientStream = new MockStream();
fromClient = StreamController<StreamMessage>();
toClient = StreamController<StreamMessage>();
when(mockClientStream.outgoingMessages)
.thenAnswer((_) => fromClient.sink);
when(mockClientStream.incomingMessages)
.thenAnswer((_) => toClient.stream);
return mockClientStream;
});
}
@override
Future<void> terminate() async {
fromClient.close();
toClient.close();
}
}
void main() {
final MockHttp2Transport transport = new MockHttp2Transport(
'host',
9999,
ChannelOptions(
credentials: new Http2ChannelCredentials.secure(authority: 'test')));
setUp(() {
transport.connect();
});
tearDown(() {
transport.terminate();
});
test('Make request passes proper headers', () async {
final metadata = <String, String>{
"parameter_1": "value_1",
"parameter_2": "value_2"
};
transport.onVerifyHeaders = (headers) {
final headerMap = headersToMap(headers);
validateRequestHeaders(headerMap,
path: 'test_path',
customHeaders: metadata,
timeout: toTimeoutString(Duration(seconds: 10)));
};
transport.makeRequest('test_path', Duration(seconds: 10), metadata);
});
test('Sent data converted to StreamMessages properly', () async {
final metadata = <String, String>{
"parameter_1": "value_1",
"parameter_2": "value_2"
};
final stream =
transport.makeRequest('test_path', Duration(seconds: 10), metadata);
transport.fromClient.stream.listen((message) {
final dataMessage = validateDataMessage(message);
expect(dataMessage.data.length, 10);
});
stream.outgoingMessages.add(List.filled(10, 0));
});
test('StreamMessages deserializes headers properly', () async {
final metadata = <String, String>{
"parameter_1": "value_1",
"parameter_2": "value_2"
};
final stream =
transport.makeRequest('test_path', Duration(seconds: 10), metadata);
stream.incomingMessages.listen((message) {
expect(message, TypeMatcher<GrpcMetadata>());
if (message is GrpcMetadata) {
message.metadata.forEach((key, value) {
expect(value, metadata[key]);
});
}
});
final httpMessage = GrpcHttpEncoder().convert(GrpcMetadata(metadata));
transport.toClient.add(httpMessage);
});
test('StreamMessages deserializes data properly', () async {
final metadata = <String, String>{
"parameter_1": "value_1",
"parameter_2": "value_2"
};
final stream =
transport.makeRequest('test_path', Duration(seconds: 10), metadata);
final data = List<int>.filled(10, 0);
stream.incomingMessages.listen((message) {
expect(message, TypeMatcher<GrpcData>());
if (message is GrpcData) {
expect(message.data, equals(data));
}
});
final httpMessage = GrpcHttpEncoder().convert(GrpcData(data));
transport.toClient.add(httpMessage);
});
}

View File

@ -16,11 +16,11 @@
import 'dart:async';
import 'package:grpc/grpc.dart';
import 'package:http2/transport.dart';
import 'package:grpc/src/shared/message.dart';
import 'package:test/test.dart';
import 'src/client_utils.dart';
import 'src/utils.dart';
import '../src/client_utils.dart';
import '../src/utils.dart';
void main() {
const dummyValue = 0;
@ -39,8 +39,8 @@ void main() {
const requestValue = 17;
const responseValue = 19;
void handleRequest(StreamMessage message) {
final data = validateDataMessage(message);
void handleRequest(List<int> message) {
final data = validateClientDataMessage(message);
expect(mockDecode(data.data), requestValue);
harness
@ -63,8 +63,8 @@ void main() {
var index = 0;
void handleRequest(StreamMessage message) {
final data = validateDataMessage(message);
void handleRequest(List<int> message) {
final data = validateClientDataMessage(message);
expect(mockDecode(data.data), requests[index++]);
}
@ -89,8 +89,8 @@ void main() {
const request = 4;
const responses = const [3, 17, 9];
void handleRequest(StreamMessage message) {
final data = validateDataMessage(message);
void handleRequest(List<int> message) {
final data = validateClientDataMessage(message);
expect(mockDecode(data.data), request);
harness.sendResponseHeader();
@ -112,8 +112,8 @@ void main() {
var index = 0;
void handleRequest(StreamMessage message) {
final data = validateDataMessage(message);
void handleRequest(List<int> message) {
final data = validateClientDataMessage(message);
expect(mockDecode(data.data), requests[index]);
if (index == 0) {
@ -244,10 +244,11 @@ void main() {
const customStatusMessage = 'Custom message';
void handleRequest(_) {
harness.toClient.add(new HeadersStreamMessage([
new Header.ascii('grpc-status', '$customStatusCode'),
new Header.ascii('grpc-message', customStatusMessage)
], endStream: true));
final headers = <String, String>{
'grpc-status': '$customStatusCode',
'grpc-message': customStatusMessage
};
harness.toClient.add(new GrpcMetadata(headers));
harness.toClient.close();
}
@ -312,8 +313,8 @@ void main() {
);
});
Future<void> makeUnaryCall() async {
void handleRequest(StreamMessage message) {
Future<Null> makeUnaryCall() async {
void handleRequest(List<int> message) {
harness
..sendResponseHeader()
..sendResponseValue(1)

View File

@ -0,0 +1,214 @@
// Copyright (c) 2017, the gRPC project authors. Please see the AUTHORS file
// for details. All rights reserved.
//
// 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.
@TestOn('browser')
import 'dart:async';
import 'dart:html';
import 'package:grpc/grpc.dart';
import 'package:grpc/src/client/transport/xhr_transport.dart';
import 'package:grpc/src/shared/message.dart';
import 'package:mockito/mockito.dart';
import 'package:test/test.dart';
class MockHttpRequest extends Mock implements HttpRequest {}
class MockXhrTransport extends XhrTransport {
StreamController<Event> readyStateChangeStream = StreamController<Event>();
StreamController<ProgressEvent> progressStream =
StreamController<ProgressEvent>();
MockHttpRequest mockRequest;
MockXhrTransport(this.mockRequest) : super('test', 8080) {}
@override
GrpcTransportStream makeRequest(
String path, Duration timeout, Map<String, String> metadata) {
when(mockRequest.onReadyStateChange)
.thenAnswer((_) => readyStateChangeStream.stream);
when(mockRequest.onProgress).thenAnswer((_) => progressStream.stream);
initializeRequest(mockRequest, metadata);
return XhrTransportStream(mockRequest);
}
@override
Future<void> terminate() async {
readyStateChangeStream.close();
progressStream.close();
}
}
void main() {
test('Make request sends correct headers', () async {
final metadata = <String, String>{
'parameter_1': 'value_1',
'parameter_2': 'value_2'
};
final mockRequest = MockHttpRequest();
final transport = MockXhrTransport(mockRequest);
transport.makeRequest('path', Duration(seconds: 10), metadata);
verify(mockRequest.setRequestHeader(
'Content-Type', 'application/grpc-web+proto'));
verify(mockRequest.setRequestHeader('X-User-Agent', 'grpc-web-dart/0.1'));
verify(mockRequest.setRequestHeader('X-Grpc-Web', '1'));
verify(mockRequest.overrideMimeType('text/plain; charset=x-user-defined'));
verify(mockRequest.responseType = 'text');
});
test('Sent data converted to stream properly', () async {
final metadata = <String, String>{
'parameter_1': 'value_1',
'parameter_2': 'value_2'
};
final mockRequest = MockHttpRequest();
final transport = MockXhrTransport(mockRequest);
final stream =
transport.makeRequest('path', Duration(seconds: 10), metadata);
final data = List.filled(10, 0);
stream.outgoingMessages.add(data);
await stream.terminate();
final expectedData = frame(data);
expect(verify(mockRequest.send(captureAny)).captured.single, expectedData);
});
test('Stream handles headers properly', () async {
final metadata = <String, String>{
'parameter_1': 'value_1',
'parameter_2': 'value_2'
};
final mockRequest = MockHttpRequest();
final transport = MockXhrTransport(mockRequest);
final stream =
transport.makeRequest('test_path', Duration(seconds: 10), metadata);
stream.incomingMessages.listen((message) {
expect(message, TypeMatcher<GrpcMetadata>());
if (message is GrpcMetadata) {
message.metadata.forEach((key, value) {
expect(value, metadata[key]);
});
}
});
});
test('Stream deserializes data properly', () async {
final metadata = <String, String>{
'parameter_1': 'value_1',
'parameter_2': 'value_2'
};
final mockRequest = MockHttpRequest();
final transport = MockXhrTransport(mockRequest);
final stream =
transport.makeRequest('test_path', Duration(seconds: 10), metadata);
final data = List<int>.filled(10, 224);
final encoded = frame(data);
final encodedString = String.fromCharCodes(encoded);
bool dataVerified = false;
stream.incomingMessages.listen((message) {
if (message is GrpcData) {
dataVerified = true;
expect(message.data, equals(data));
}
});
when(mockRequest.getResponseHeader('Content-Type'))
.thenReturn('application/grpc+proto');
when(mockRequest.responseHeaders).thenReturn(metadata);
when(mockRequest.readyState).thenReturn(HttpRequest.HEADERS_RECEIVED);
when(mockRequest.response).thenReturn(encodedString);
transport.readyStateChangeStream.add(null);
transport.progressStream.add(null);
// Wait for all streams to process
await Future.sync(() {});
await stream.terminate();
expect(dataVerified, true);
});
test('Stream recieves multiple messages', () async {
final metadata = <String, String>{
'parameter_1': 'value_1',
'parameter_2': 'value_2'
};
final mockRequest = MockHttpRequest();
final transport = MockXhrTransport(mockRequest);
final stream =
transport.makeRequest('test_path', Duration(seconds: 10), metadata);
final data = <List<int>>[
List<int>.filled(10, 224),
List<int>.filled(5, 124)
];
final encoded = data.map((d) => frame(d));
final encodedStrings = encoded.map((e) => String.fromCharCodes(e)).toList();
// to start - expected response is the first message
var expectedResponse = encodedStrings[0];
final expectedMessages = <GrpcMessage>[
GrpcMetadata(metadata),
GrpcData(data[0]),
GrpcData(data[1])
];
stream.incomingMessages.listen((message) {
final expectedMessage = expectedMessages.removeAt(0);
expect(message.runtimeType, expectedMessage.runtimeType);
if (message is GrpcMetadata) {
expect(message.metadata, (expectedMessage as GrpcMetadata).metadata);
} else if (message is GrpcData) {
expect(message.data, (expectedMessage as GrpcData).data);
}
});
when(mockRequest.getResponseHeader('Content-Type'))
.thenReturn('application/grpc+proto');
when(mockRequest.responseHeaders).thenReturn(metadata);
when(mockRequest.readyState).thenReturn(HttpRequest.HEADERS_RECEIVED);
when(mockRequest.response).thenAnswer((_) => expectedResponse);
transport.readyStateChangeStream.add(null);
transport.progressStream.add(null);
// Wait for all streams to process
await Future.sync(() {});
// After the first call, expected response should now be both responses together
expectedResponse = encodedStrings[0] + encodedStrings[1];
transport.progressStream.add(null);
// Wait for all streams to process
await Future.sync(() {});
await stream.terminate();
expect(expectedMessages.isEmpty, isTrue);
});
}

View File

@ -12,6 +12,7 @@
// 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.
@TestOn('vm')
import 'dart:io';
@ -27,14 +28,14 @@ void main() {
await new File('test/data/certstore.p12').readAsBytes();
final missingPassword =
new ChannelCredentials.secure(certificates: certificates);
new Http2ChannelCredentials.secure(certificates: certificates);
expect(() => missingPassword.securityContext, throwsA(isTlsException));
final wrongPassword = new ChannelCredentials.secure(
final wrongPassword = new Http2ChannelCredentials.secure(
certificates: certificates, password: 'wrong');
expect(() => wrongPassword.securityContext, throwsA(isTlsException));
final correctPassword = new ChannelCredentials.secure(
final correctPassword = new Http2ChannelCredentials.secure(
certificates: certificates, password: 'correct');
expect(correctPassword.securityContext, isNotNull);
});

View File

@ -12,6 +12,7 @@
// 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.
@TestOn('vm')
import 'dart:async';

View File

@ -15,8 +15,7 @@
import 'dart:async';
import 'package:grpc/src/shared/streams.dart';
import 'package:http2/transport.dart';
import 'package:grpc/src/shared/message.dart';
import 'package:test/test.dart';
import 'package:mockito/mockito.dart';
@ -24,29 +23,41 @@ import 'package:grpc/grpc.dart';
import 'utils.dart';
class MockTransport extends Mock implements ClientTransportConnection {}
typedef void ClientTestMessageHandler(List<int> message);
class MockStream extends Mock implements ClientTransportStream {}
GrpcData validateClientDataMessage(List<int> message) {
final decoded = new GrpcData(message);
expect(decoded, new TypeMatcher<GrpcData>());
return decoded;
}
class MockTransport extends Mock implements Transport {}
class MockStream extends Mock implements GrpcTransportStream {}
class FakeConnection extends ClientConnection {
final ClientTransportConnection transport;
var connectionError;
FakeConnection(String host, this.transport, ChannelOptions options)
: super(host, 443, options);
FakeConnection._(String host, Transport transport, ChannelOptions options,
ConnectTransport connectTransport)
: super(host, 443, options, connectTransport);
@override
Future<ClientTransportConnection> connectTransport() async {
if (connectionError != null) throw connectionError;
return transport;
factory FakeConnection(
String host, Transport transport, ChannelOptions options) {
FakeConnection f;
f = FakeConnection._(host, transport, options, (_, _1, _2) async {
if (f.connectionError != null) throw f.connectionError;
return transport;
});
return f;
}
}
Duration testBackoff(Duration lastBackoff) => const Duration(milliseconds: 1);
class FakeChannelOptions implements ChannelOptions {
ChannelCredentials credentials = const ChannelCredentials.secure();
ChannelCredentials credentials = const Http2ChannelCredentials.secure();
Duration idleTimeout = const Duration(seconds: 1);
BackoffStrategy backoffStrategy = testBackoff;
}
@ -62,8 +73,6 @@ class FakeChannel extends ClientChannel {
Future<ClientConnection> getConnection() async => connection;
}
typedef ServerMessageHandler = void Function(StreamMessage message);
class TestClient extends Client {
static final _$unary =
new ClientMethod<int, int>('/Test/Unary', mockEncode, mockDecode);
@ -110,8 +119,8 @@ class ClientHarness {
FakeChannelOptions channelOptions;
MockStream stream;
StreamController<StreamMessage> fromClient;
StreamController<StreamMessage> toClient;
StreamController<List<int>> fromClient;
StreamController<GrpcMessage> toClient;
TestClient client;
@ -123,8 +132,7 @@ class ClientHarness {
stream = new MockStream();
fromClient = new StreamController();
toClient = new StreamController();
when(transport.makeRequest(any, endStream: anyNamed('endStream')))
.thenReturn(stream);
when(transport.makeRequest(any, any, any)).thenReturn(stream);
when(transport.onActiveStateChanged = captureAny).thenReturn(null);
when(stream.outgoingMessages).thenReturn(fromClient.sink);
when(stream.incomingMessages).thenAnswer((_) => toClient.stream);
@ -136,18 +144,17 @@ class ClientHarness {
toClient.close();
}
void sendResponseHeader({List<Header> headers = const []}) {
toClient.add(new HeadersStreamMessage(headers));
void sendResponseHeader({Map<String, String> headers = const {}}) {
toClient.add(new GrpcMetadata(headers));
}
void sendResponseValue(int value) {
toClient
.add(new DataStreamMessage(GrpcHttpEncoder.frame(mockEncode(value))));
toClient.add(new GrpcData(mockEncode(value)));
}
void sendResponseTrailer(
{List<Header> headers = const [], bool closeStream = true}) {
toClient.add(new HeadersStreamMessage(headers, endStream: true));
{Map<String, String> headers = const {}, bool closeStream = true}) {
toClient.add(new GrpcMetadata(headers));
if (closeStream) toClient.close();
}
@ -164,11 +171,11 @@ class ClientHarness {
String expectedPath,
Duration expectedTimeout,
Map<String, String> expectedCustomHeaders,
List<MessageHandler> serverHandlers = const [],
List<ClientTestMessageHandler> serverHandlers = const [],
Function doneHandler,
bool expectDone = true}) async {
int serverHandlerIndex = 0;
void handleServerMessage(StreamMessage message) {
void handleServerMessage(List<int> message) {
serverHandlers[serverHandlerIndex++](message);
}
@ -182,12 +189,17 @@ class ClientHarness {
expect(result, expectedResult);
}
final List<Header> capturedHeaders =
verify(transport.makeRequest(captureAny)).captured.single;
validateRequestHeaders(capturedHeaders,
path: expectedPath,
timeout: toTimeoutString(expectedTimeout),
customHeaders: expectedCustomHeaders);
final capturedParameters =
verify(transport.makeRequest(captureAny, captureAny, captureAny))
.captured;
if (expectedPath != null) {
expect(capturedParameters[0], expectedPath);
}
expect(capturedParameters[1], expectedTimeout);
final Map<String, String> headers = capturedParameters[2];
headers?.forEach((key, value) {
expect(expectedCustomHeaders[key], value);
});
await clientSubscription.cancel();
}
@ -207,7 +219,7 @@ class ClientHarness {
String expectedPath,
Duration expectedTimeout,
Map<String, String> expectedCustomHeaders,
List<MessageHandler> serverHandlers = const [],
List<ClientTestMessageHandler> serverHandlers = const [],
bool expectDone = true}) async {
return runTest(
clientCall: expectThrows(clientCall, expectedException),

View File

@ -15,11 +15,13 @@
import 'dart:async';
import 'package:grpc/src/shared/message.dart';
import 'package:grpc/src/shared/streams.dart';
import 'package:http2/transport.dart';
import 'package:test/test.dart';
import 'package:grpc/grpc.dart';
import 'package:grpc/src/client/transport/http2_transport.dart';
import 'utils.dart';
@ -170,14 +172,14 @@ class ServerHarness {
{String authority = 'test',
Map<String, String> metadata,
Duration timeout}) {
final headers = ClientConnection.createCallHeaders(
final headers = Http2Transport.createCallHeaders(
true, authority, path, timeout, metadata);
toServer.add(new HeadersStreamMessage(headers));
}
void sendData(int value) {
toServer
.add(new DataStreamMessage(GrpcHttpEncoder.frame(mockEncode(value))));
.add(new DataStreamMessage(frame(mockEncode(value))));
}
void runTest(String path, List<int> requests, List<int> expectedResponses) {

View File

@ -16,6 +16,7 @@
import 'dart:convert';
import 'package:grpc/src/shared/streams.dart';
import 'package:grpc/src/shared/message.dart';
import 'package:http2/transport.dart';
import 'package:test/test.dart';
@ -29,26 +30,25 @@ Map<String, String> headersToMap(List<Header> headers) =>
new Map.fromIterable(headers,
key: (h) => ascii.decode(h.name), value: (h) => ascii.decode(h.value));
void validateRequestHeaders(List<Header> headers,
void validateRequestHeaders(Map<String, String> headers,
{String path,
String authority = 'test',
String timeout,
Map<String, String> customHeaders}) {
final headerMap = headersToMap(headers);
expect(headerMap[':method'], 'POST');
expect(headerMap[':scheme'], 'https');
expect(headers[':method'], 'POST');
expect(headers[':scheme'], 'https');
if (path != null) {
expect(headerMap[':path'], path);
expect(headers[':path'], path);
}
expect(headerMap[':authority'], authority);
expect(headerMap['grpc-timeout'], timeout);
expect(headerMap['content-type'], 'application/grpc');
expect(headerMap['te'], 'trailers');
expect(headerMap['grpc-accept-encoding'], 'identity');
expect(headerMap['user-agent'], startsWith('dart-grpc/'));
expect(headers[':authority'], authority);
expect(headers['grpc-timeout'], timeout);
expect(headers['content-type'], 'application/grpc');
expect(headers['te'], 'trailers');
expect(headers['grpc-accept-encoding'], 'identity');
expect(headers['user-agent'], startsWith('dart-grpc/'));
customHeaders?.forEach((key, value) {
expect(headerMap[key], value);
expect(headers[key], value);
});
}

View File

@ -16,12 +16,10 @@
import 'dart:async';
import 'package:grpc/grpc.dart';
import 'package:http2/transport.dart';
import 'package:test/test.dart';
import 'src/client_utils.dart';
import 'src/server_utils.dart';
import 'src/utils.dart';
void main() {
const dummyValue = 0;
@ -75,8 +73,8 @@ void main() {
});
test('Calls time out if deadline is exceeded', () async {
void handleRequest(StreamMessage message) {
validateDataMessage(message);
void handleRequest(List<int> message) {
validateClientDataMessage(message);
final Future delay = new Future.delayed(new Duration(milliseconds: 2));
expect(delay, completes);
delay.then((_) {
@ -142,5 +140,5 @@ void main() {
timeout: new Duration(microseconds: 1));
await harness.fromServer.done;
});
});
}, testOn: 'vm');
}