From d4504dacf15f71a81aa177c7344f538b1478a460 Mon Sep 17 00:00:00 2001 From: Piotr Morgwai Kotarbinski Date: Tue, 8 Jun 2021 16:14:57 +0700 Subject: [PATCH] GrpcOrGrpcWeb: provide more flexible constructors (#484) (#485) --- lib/grpc_or_grpcweb.dart | 74 ++++++++++++++++--- .../client/grpc_or_grpcweb_channel_grpc.dart | 20 ++--- .../client/grpc_or_grpcweb_channel_web.dart | 21 ++++-- .../grpc_or_grpcweb_channel_grpc_test.dart | 16 ++-- .../grpc_or_grpcweb_channel_web_test.dart | 16 ++-- 5 files changed, 102 insertions(+), 45 deletions(-) diff --git a/lib/grpc_or_grpcweb.dart b/lib/grpc_or_grpcweb.dart index 7470b71b..3ba0b0c3 100644 --- a/lib/grpc_or_grpcweb.dart +++ b/lib/grpc_or_grpcweb.dart @@ -13,17 +13,71 @@ // 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]. +import 'src/client/grpc_or_grpcweb_channel_grpc.dart' + if (dart.library.html) 'src/client/grpc_or_grpcweb_channel_web.dart'; +import 'src/client/http2_channel.dart'; +import 'src/client/options.dart'; + +/// A client channel that underneath uses gRPC [ClientChannel] on all platforms +/// 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 for this to work. -/// As several existing implementations (such as in-process gRPC-web to gRPC -/// proxies or Envoy gRPC-web to gRPC proxy) expose gRPC and gRPC-web on -/// separate ports, the constructor requires 2 ports to be provided and -/// the channel will use the one for the actual protocol being used. -/// If the server supports both protocols on the same port (such as AspNetCore -/// implementation), then the same port value should be provided on both params. +/// Depending on its exact setup, the server may expose gRPC and gRPC-web on the +/// same port (this is the standard setup of AspNetCore implementation for +/// example), on separate ports of the same host (common setup of in-process +/// gRPC-web to gRPC proxies or colocated Envoy gRPC-web to gRPC proxy), or as +/// a completely separate endpoints (for example if Envoy and gRPC server are +/// exposed as different kubernetes services). A corresponding constructor is +/// provided for each case. +class GrpcOrGrpcWebClientChannel extends GrpcOrGrpcWebClientChannelInternal { + GrpcOrGrpcWebClientChannel.toSeparateEndpoints({ + required String grpcHost, + required int grpcPort, + required bool grpcTransportSecure, + required String grpcWebHost, + required int grpcWebPort, + required bool grpcWebTransportSecure, + }) : super( + grpcHost: grpcHost, + grpcPort: grpcPort, + grpcTransportSecure: grpcTransportSecure, + grpcWebHost: grpcWebHost, + grpcWebPort: grpcWebPort, + grpcWebTransportSecure: grpcWebTransportSecure, + ); -export 'src/client/grpc_or_grpcweb_channel_grpc.dart' - if (dart.library.html) 'src/client/grpc_or_grpcweb_channel_web.dart'; + GrpcOrGrpcWebClientChannel.toSeparatePorts({ + required String host, + required int grpcPort, + required bool grpcTransportSecure, + required int grpcWebPort, + required bool grpcWebTransportSecure, + }) : super( + grpcHost: host, + grpcPort: grpcPort, + grpcTransportSecure: grpcTransportSecure, + grpcWebHost: host, + grpcWebPort: grpcWebPort, + grpcWebTransportSecure: grpcWebTransportSecure, + ); + + GrpcOrGrpcWebClientChannel.toSingleEndpoint({ + required String host, + required int port, + required bool transportSecure, + }) : super( + grpcHost: host, + grpcPort: port, + grpcTransportSecure: transportSecure, + grpcWebHost: host, + grpcWebPort: port, + grpcWebTransportSecure: transportSecure, + ); + + GrpcOrGrpcWebClientChannel.grpc( + Object host, { + int port = 443, + ChannelOptions options = const ChannelOptions(), + }) : super.grpc(host, port: port, options: options); +} diff --git a/lib/src/client/grpc_or_grpcweb_channel_grpc.dart b/lib/src/client/grpc_or_grpcweb_channel_grpc.dart index 8240e1b3..ec335e4d 100644 --- a/lib/src/client/grpc_or_grpcweb_channel_grpc.dart +++ b/lib/src/client/grpc_or_grpcweb_channel_grpc.dart @@ -17,25 +17,27 @@ import 'http2_channel.dart'; import 'options.dart'; import 'transport/http2_credentials.dart'; -class GrpcOrGrpcWebClientChannel extends ClientChannel { - GrpcOrGrpcWebClientChannel({ - required String host, +class GrpcOrGrpcWebClientChannelInternal extends ClientChannel { + GrpcOrGrpcWebClientChannelInternal({ + required String grpcHost, required int grpcPort, + required bool grpcTransportSecure, + required String grpcWebHost, required int grpcWebPort, - required bool secure, + required bool grpcWebTransportSecure, }) : super( - host, + grpcHost, port: grpcPort, options: ChannelOptions( - credentials: secure + credentials: grpcTransportSecure ? ChannelCredentials.secure() : ChannelCredentials.insecure(), ), ); - GrpcOrGrpcWebClientChannel.grpc( + GrpcOrGrpcWebClientChannelInternal.grpc( Object host, { - int port = 443, - ChannelOptions options = const ChannelOptions(), + required int port, + required ChannelOptions options, }) : super(host, port: port, options: options); } diff --git a/lib/src/client/grpc_or_grpcweb_channel_web.dart b/lib/src/client/grpc_or_grpcweb_channel_web.dart index bc354f41..858b0ef7 100644 --- a/lib/src/client/grpc_or_grpcweb_channel_web.dart +++ b/lib/src/client/grpc_or_grpcweb_channel_web.dart @@ -16,19 +16,24 @@ import 'options.dart'; import 'web_channel.dart'; -class GrpcOrGrpcWebClientChannel extends GrpcWebClientChannel { - GrpcOrGrpcWebClientChannel({ - required String host, +class GrpcOrGrpcWebClientChannelInternal extends GrpcWebClientChannel { + GrpcOrGrpcWebClientChannelInternal({ + required String grpcHost, required int grpcPort, + required bool grpcTransportSecure, + required String grpcWebHost, required int grpcWebPort, - required bool secure, + required bool grpcWebTransportSecure, }) : super.xhr(Uri( - host: host, port: grpcWebPort, scheme: secure ? 'https' : 'http')); + host: grpcWebHost, + port: grpcWebPort, + scheme: grpcWebTransportSecure ? 'https' : 'http', + )); - GrpcOrGrpcWebClientChannel.grpc( + GrpcOrGrpcWebClientChannelInternal.grpc( Object host, { - int port = 443, - ChannelOptions options = const ChannelOptions(), + required int port, + required ChannelOptions options, }) : super.xhr( Uri( host: host.toString(), diff --git a/test/client_tests/grpc_or_grpcweb_channel_grpc_test.dart b/test/client_tests/grpc_or_grpcweb_channel_grpc_test.dart index a2542d80..afa2698e 100644 --- a/test/client_tests/grpc_or_grpcweb_channel_grpc_test.dart +++ b/test/client_tests/grpc_or_grpcweb_channel_grpc_test.dart @@ -19,20 +19,18 @@ import 'package:grpc/grpc_or_grpcweb.dart'; import 'package:test/test.dart'; const host = 'example.com'; -const grpcPort = 9090; -const grpcWebPort = 8080; +const port = 8080; void main() { test('Channel on non-web uses gRPC ClientChannel with correct params', () { - final channel = GrpcOrGrpcWebClientChannel( + final channel = GrpcOrGrpcWebClientChannel.toSingleEndpoint( host: host, - grpcPort: grpcPort, - grpcWebPort: grpcWebPort, - secure: false, + port: port, + transportSecure: false, ); expect(channel is ClientChannel, isTrue); expect(channel.host, equals(host)); - expect(channel.port, equals(grpcPort)); + expect(channel.port, equals(port)); expect(channel.options.credentials.isSecure, isFalse); }); @@ -40,11 +38,11 @@ void main() { final options = ChannelOptions(credentials: ChannelCredentials.insecure()); final channel = GrpcOrGrpcWebClientChannel.grpc( host, - port: grpcPort, + port: port, options: options, ); expect(channel.host, equals(host)); - expect(channel.port, equals(grpcPort)); + expect(channel.port, equals(port)); expect(channel.options, same(options)); }); } diff --git a/test/client_tests/grpc_or_grpcweb_channel_web_test.dart b/test/client_tests/grpc_or_grpcweb_channel_web_test.dart index e4619503..77fbe70d 100644 --- a/test/client_tests/grpc_or_grpcweb_channel_web_test.dart +++ b/test/client_tests/grpc_or_grpcweb_channel_web_test.dart @@ -19,25 +19,23 @@ import 'package:grpc/grpc_web.dart'; import 'package:test/test.dart'; const host = 'example.com'; -const grpcPort = 9090; -const grpcWebPort = 8080; +const port = 8080; void main() { test('Channel on web uses GrpcWebClientChannel with correct URI', () { - final channel = GrpcOrGrpcWebClientChannel( + final channel = GrpcOrGrpcWebClientChannel.toSingleEndpoint( host: host, - grpcPort: grpcPort, - grpcWebPort: grpcWebPort, - secure: true, + port: port, + transportSecure: true, ); expect(channel is GrpcWebClientChannel, isTrue); final webChannel = channel as GrpcWebClientChannel; - expect(webChannel.uri, - equals(Uri(host: host, port: grpcWebPort, scheme: 'https'))); + expect( + webChannel.uri, equals(Uri(host: host, port: port, scheme: 'https'))); }); test('Constructor grpc on web throws UnsupportedError', () { - expect(() => GrpcOrGrpcWebClientChannel.grpc(host, port: grpcPort), + expect(() => GrpcOrGrpcWebClientChannel.grpc(host, port: port), throwsUnsupportedError); }); }