Add GrpcOrGrpcWebClientChannel (#457) (#479)

This commit is contained in:
Piotr Morgwai Kotarbinski 2021-06-02 17:25:23 +07:00 committed by GitHub
parent b272632450
commit e88b84a993
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 232 additions and 0 deletions

View File

@ -7,6 +7,8 @@
200 HTTP status and a supported `Content-Type` header to be present, as well
as `grpc-status: 0` header. When handling malformed responses make effort
to translate HTTP statuses into gRPC statuses.
* Add GrpcOrGrpcWebClientChannel which uses gRPC on all platforms except web,
on which it uses gRPC-web.
## 3.0.0

25
lib/grpc_or_grpcweb.dart Normal file
View File

@ -0,0 +1,25 @@
// Copyright (c) 2021, 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.
/// Exports [GrpcOrWebClientChannel] that underneath uses gRPC [ClientChannel]
/// on all platfroms except web, on which it uses [GrpcWebClientChannel].
///
/// Note that gRPC and gRPC-web are 2 different protocols and server must be
/// able to speak both of them (on separate ports) for this to work. Therefore
/// applications using this class must provide both ports and the channel will
/// use the one for the actual protocol being used.
export 'src/client/grpc_or_grpcweb_channel_grpc.dart'
if (dart.library.html) 'src/client/grpc_or_grpcweb_channel_web.dart';

View File

@ -0,0 +1,45 @@
// Copyright (c) 2021, 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 'http2_channel.dart';
import 'options.dart';
import 'transport/http2_credentials.dart';
class GrpcOrGrpcWebClientChannel extends ClientChannel {
GrpcOrGrpcWebClientChannel({
required String host,
required int grpcPort,
required int grpcWebPort,
required bool secure,
}) : super(
host,
port: grpcPort,
options: ChannelOptions(
credentials: secure
? ChannelCredentials.secure()
: ChannelCredentials.insecure(),
),
) {
if (grpcWebPort == grpcPort) {
throw ArgumentError('grpcPort and grpcWebPort cannot be the same');
}
}
GrpcOrGrpcWebClientChannel.grpc(
Object host, {
int port = 443,
ChannelOptions options = const ChannelOptions(),
}) : super(host, port: port, options: options);
}

View File

@ -0,0 +1,45 @@
// Copyright (c) 2021, 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 'options.dart';
import 'web_channel.dart';
class GrpcOrGrpcWebClientChannel extends GrpcWebClientChannel {
GrpcOrGrpcWebClientChannel({
required String host,
required int grpcPort,
required int grpcWebPort,
required bool secure,
}) : super.xhr(Uri(
host: host, port: grpcWebPort, scheme: secure ? 'https' : 'http')) {
if (grpcWebPort == grpcPort) {
throw ArgumentError('grpcPort and grpcWebPort cannot be the same');
}
}
GrpcOrGrpcWebClientChannel.grpc(
Object host, {
int port = 443,
ChannelOptions options = const ChannelOptions(),
}) : super.xhr(
Uri(
host: host.toString(),
port: port,
scheme: options.credentials.isSecure ? 'https' : 'http'),
) {
// Do not silently ignore options as caller may expect them to have effects.
throw UnsupportedError('not supported by gRPC-web');
}
}

View File

@ -0,0 +1,61 @@
// Copyright (c) 2021, 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 'package:grpc/grpc.dart';
import 'package:grpc/grpc_or_grpcweb.dart';
import 'package:test/test.dart';
const host = 'example.com';
const grpcPort = 9090;
const grpcWebPort = 8080;
void main() {
test('Channel on non-web uses gRPC ClientChannel with correct params', () {
final channel = GrpcOrGrpcWebClientChannel(
host: host,
grpcPort: grpcPort,
grpcWebPort: grpcWebPort,
secure: false,
);
expect(channel is ClientChannel, isTrue);
expect(channel.host, equals(host));
expect(channel.port, equals(grpcPort));
expect(channel.options.credentials.isSecure, isFalse);
});
test('Constructor throws throwsArgumentError if ports are the same', () {
expect(
() => GrpcOrGrpcWebClientChannel(
host: host,
grpcPort: grpcPort,
grpcWebPort: grpcPort,
secure: false,
),
throwsArgumentError);
});
test('Constructor grpc on non-web passes params correctly', () {
final options = ChannelOptions(credentials: ChannelCredentials.insecure());
final channel = GrpcOrGrpcWebClientChannel.grpc(
host,
port: grpcPort,
options: options,
);
expect(channel.host, equals(host));
expect(channel.port, equals(grpcPort));
expect(channel.options, same(options));
});
}

View File

@ -0,0 +1,54 @@
// Copyright (c) 2021, 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 'package:grpc/grpc_or_grpcweb.dart';
import 'package:grpc/grpc_web.dart';
import 'package:test/test.dart';
const host = 'example.com';
const grpcPort = 9090;
const grpcWebPort = 8080;
void main() {
test('Channel on web uses GrpcWebClientChannel with correct URI', () {
final channel = GrpcOrGrpcWebClientChannel(
host: host,
grpcPort: grpcPort,
grpcWebPort: grpcWebPort,
secure: true,
);
expect(channel is GrpcWebClientChannel, isTrue);
final webChannel = channel as GrpcWebClientChannel;
expect(webChannel.uri,
equals(Uri(host: host, port: grpcWebPort, scheme: 'https')));
});
test('Constructor throws throwsArgumentError if ports are the same', () {
expect(
() => GrpcOrGrpcWebClientChannel(
host: host,
grpcPort: grpcPort,
grpcWebPort: grpcPort,
secure: false,
),
throwsArgumentError);
});
test('Constructor grpc on web throws UnsupportedError', () {
expect(() => GrpcOrGrpcWebClientChannel.grpc(host, port: grpcPort),
throwsUnsupportedError);
});
}