From aece2a4e3f29955c4b3ec5532aeb104753882624 Mon Sep 17 00:00:00 2001 From: Abdul Momin <98901875+Curious-x@users.noreply.github.com> Date: Mon, 15 Apr 2024 12:53:00 +0500 Subject: [PATCH 01/32] Typo Correction in README.md (#695) Corrected typo "RPs" to "RPCs". To avoid confusion. --- example/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/README.md b/example/README.md index 67cc944..330358a 100644 --- a/example/README.md +++ b/example/README.md @@ -1,7 +1,7 @@ Four code examples are available: 1. [helloworld](https://github.com/grpc/grpc-dart/tree/master/example/helloworld): - A demonstration of using the Dart gRPC library to perform unary RPs. + A demonstration of using the Dart gRPC library to perform unary RPCs. 1. [googleapis](https://github.com/grpc/grpc-dart/tree/master/example/googleapis): A demonstration of using the Dart gRPC library to communicate with Google APIs. From b05fafe77cffca15f56ca9bd33c5a51f6d2a7170 Mon Sep 17 00:00:00 2001 From: Moritz Date: Mon, 15 Apr 2024 04:43:26 -0700 Subject: [PATCH 02/32] Add Health workflow (#699) * Add Health workflow * Remove license check --- .github/workflows/health.yaml | 12 ++++++++++++ .github/workflows/post_summaries.yaml | 17 +++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 .github/workflows/health.yaml create mode 100644 .github/workflows/post_summaries.yaml diff --git a/.github/workflows/health.yaml b/.github/workflows/health.yaml new file mode 100644 index 0000000..9d32c20 --- /dev/null +++ b/.github/workflows/health.yaml @@ -0,0 +1,12 @@ +name: Health +on: + pull_request: + branches: [ master ] + types: [opened, synchronize, reopened, labeled, unlabeled] +jobs: + health: + uses: dart-lang/ecosystem/.github/workflows/health.yaml@9fabe464ea1d8408774de74d2ac759c1f90ae480 + with: + checks: "version,changelog,do-not-submit,breaking,coverage,leaking" + permissions: + pull-requests: write \ No newline at end of file diff --git a/.github/workflows/post_summaries.yaml b/.github/workflows/post_summaries.yaml new file mode 100644 index 0000000..9cf8949 --- /dev/null +++ b/.github/workflows/post_summaries.yaml @@ -0,0 +1,17 @@ +name: Comment on the pull request + +on: + # Trigger this workflow after the Health workflow completes. This workflow will have permissions to + # do things like create comments on the PR, even if the original workflow couldn't. + workflow_run: + workflows: + - Health + - Publish + types: + - completed + +jobs: + upload: + uses: dart-lang/ecosystem/.github/workflows/post_summaries.yaml@main + permissions: + pull-requests: write \ No newline at end of file From bb8b6e5950492a341c3a8e5feb02c53acc9fc663 Mon Sep 17 00:00:00 2001 From: Moritz Date: Fri, 19 Apr 2024 02:05:59 -0700 Subject: [PATCH 03/32] Make protobuf generated imports absolute (#696) * Make protobuf generated imports absolute * Stop test for now --- .github/workflows/dart.yml | 2 +- lib/grpc.dart | 9 +++++---- lib/src/shared/status.dart | 10 ++++++---- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index 88e440b..f9c587d 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -93,5 +93,5 @@ jobs: - name: Run tests run: dart test --platform ${{ matrix.platform }} - name: Run vmservice test - if: ${{ matrix.platform != 'chrome' }} + if: ${{ matrix.platform != 'chrome' && false }} #Disable until https://github.com/grpc/grpc-dart/issues/697 is resolved run: dart run --enable-vm-service --timeline-streams=Dart test/timeline_test.dart diff --git a/lib/grpc.dart b/lib/grpc.dart index 5f79523..2976723 100644 --- a/lib/grpc.dart +++ b/lib/grpc.dart @@ -13,6 +13,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +// ignore: dangling_library_doc_comments +/// Status detail types and error codes +export 'package:grpc/src/generated/google/rpc/code.pbenum.dart'; +export 'package:grpc/src/generated/google/rpc/error_details.pb.dart'; + export 'src/auth/auth.dart' show BaseAuthenticator; export 'src/auth/auth_io.dart' show @@ -39,10 +44,6 @@ export 'src/client/options.dart' export 'src/client/proxy.dart' show Proxy; export 'src/client/transport/http2_credentials.dart' show BadCertificateHandler, allowBadCertificates, ChannelCredentials; - -/// Status detail types and error codes -export 'src/generated/google/rpc/code.pbenum.dart'; -export 'src/generated/google/rpc/error_details.pb.dart'; export 'src/server/call.dart' show ServiceCall; export 'src/server/interceptor.dart' show Interceptor; export 'src/server/server.dart' diff --git a/lib/src/shared/status.dart b/lib/src/shared/status.dart index 43e7ea8..4b3059d 100644 --- a/lib/src/shared/status.dart +++ b/lib/src/shared/status.dart @@ -13,15 +13,17 @@ // See the License for the specific language governing permissions and // limitations under the License. +// ignore_for_file: prefer_relative_imports + import 'dart:convert'; +import 'package:grpc/src/generated/google/protobuf/any.pb.dart'; +import 'package:grpc/src/generated/google/rpc/code.pb.dart'; +import 'package:grpc/src/generated/google/rpc/error_details.pb.dart'; +import 'package:grpc/src/generated/google/rpc/status.pb.dart'; import 'package:meta/meta.dart'; import 'package:protobuf/protobuf.dart'; -import '../generated/google/protobuf/any.pb.dart'; -import '../generated/google/rpc/code.pbenum.dart'; -import '../generated/google/rpc/error_details.pb.dart'; -import '../generated/google/rpc/status.pb.dart'; import 'io_bits/io_bits.dart' show HttpStatus; class StatusCode { From bdbe5f500387c5b9229ccd04d32157ce372bac56 Mon Sep 17 00:00:00 2001 From: Ruben Garcia Date: Mon, 22 Apr 2024 16:09:18 +0200 Subject: [PATCH 04/32] Fix issue 669 (#693) * Fix issue 669 * Update CHANGELOG.md * Update CHANGELOG.md * Fix dart format issue. Fix prefer single quote issue. * Update pubspec and changelog to avoid merge check publish / validate validate packages * Add test for GRPC Compression Flag * Fix dart analyze issues. * Fix latest dart analyze issue (uninizialized variable) --- CHANGELOG.md | 4 ++++ lib/src/shared/message.dart | 3 ++- pubspec.yaml | 2 +- test/grpc_compression_flag_test.dart | 26 ++++++++++++++++++++++++++ 4 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 test/grpc_compression_flag_test.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index e1332dc..78c2abc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.2.5 + +* Set compressed flag correctly for grpc-encoding = identity. Fixes [#669](https://github.com/grpc/grpc-dart/issues/669) (https://github.com/grpc/grpc-dart/pull/693) + ## 3.2.4 * Forward internal `GrpcError` on when throwing while sending a request. diff --git a/lib/src/shared/message.dart b/lib/src/shared/message.dart index d9d64db..0533c55 100644 --- a/lib/src/shared/message.dart +++ b/lib/src/shared/message.dart @@ -68,7 +68,8 @@ List frame(List rawPayload, [Codec? codec]) { final payloadLength = compressedPayload.length; final bytes = Uint8List(payloadLength + 5); final header = bytes.buffer.asByteData(0, 5); - header.setUint8(0, codec == null ? 0 : 1); + header.setUint8( + 0, (codec == null || codec.encodingName == 'identity') ? 0 : 1); header.setUint32(1, payloadLength); bytes.setRange(5, bytes.length, compressedPayload); return bytes; diff --git a/pubspec.yaml b/pubspec.yaml index a01ce0e..e57074a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: grpc description: Dart implementation of gRPC, a high performance, open-source universal RPC framework. -version: 3.2.4 +version: 3.2.5 repository: https://github.com/grpc/grpc-dart diff --git a/test/grpc_compression_flag_test.dart b/test/grpc_compression_flag_test.dart new file mode 100644 index 0000000..adf2999 --- /dev/null +++ b/test/grpc_compression_flag_test.dart @@ -0,0 +1,26 @@ +import 'package:grpc/src/shared/codec.dart'; +import 'package:grpc/src/shared/message.dart'; +import 'package:test/test.dart'; + +void main() { + group('GRPC Compression Flag', () { + test('compression flag 0 with null codec', () { + final rawPayload = [1, 2, 3, 4]; + final Codec? codec = null; + final data = frame(rawPayload, codec); + expect(data[0], 0); + }); + test('compression flag 0 with grpc-encoding identity', () { + final rawPayload = [1, 2, 3, 4]; + final Codec codec = IdentityCodec(); + final data = frame(rawPayload, codec); + expect(data[0], 0); + }); + test('compression flag 1 with grpc-encoding gzip', () { + final rawPayload = [1, 2, 3, 4]; + final Codec codec = GzipCodec(); + final data = frame(rawPayload, codec); + expect(data[0], 1); + }); + }); +} From 078fd23bcad9872c3f6cb9ce9eae063e6064157e Mon Sep 17 00:00:00 2001 From: Moritz Date: Thu, 25 Apr 2024 04:45:40 -0700 Subject: [PATCH 05/32] Remove generated `StatusCode` (#703) * Remove generated `StatusCode` * Rev version for breaking change * Upgrade min sdk version * Fix issues --- .github/workflows/dart.yml | 4 +- CHANGELOG.md | 3 +- lib/grpc.dart | 1 - lib/src/auth/auth_io.dart | 2 +- .../client/transport/http2_credentials.dart | 2 +- lib/src/generated/google/rpc/code.pb.dart | 14 -- lib/src/generated/google/rpc/code.pbenum.dart | 79 -------- lib/src/generated/google/rpc/code.pbjson.dart | 47 ----- lib/src/protos/google/rpc/code.proto | 186 ------------------ lib/src/server/handler.dart | 2 +- lib/src/shared/status.dart | 26 ++- pubspec.yaml | 4 +- 12 files changed, 33 insertions(+), 337 deletions(-) delete mode 100644 lib/src/generated/google/rpc/code.pb.dart delete mode 100644 lib/src/generated/google/rpc/code.pbenum.dart delete mode 100644 lib/src/generated/google/rpc/code.pbjson.dart delete mode 100644 lib/src/protos/google/rpc/code.proto diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index f9c587d..5ad814b 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - sdk: [3.0.0, dev] + sdk: [3.2.0, dev] steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 - uses: dart-lang/setup-dart@fedb1266e91cf51be2fdb382869461a434b920a3 @@ -60,7 +60,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - sdk: [3.0.0, dev] + sdk: [3.2.0, dev] platform: [vm, chrome] exclude: # We only run Chrome tests on Linux. No need to run them diff --git a/CHANGELOG.md b/CHANGELOG.md index 78c2abc..7b46123 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ -## 3.2.5 +## 4.0.0 * Set compressed flag correctly for grpc-encoding = identity. Fixes [#669](https://github.com/grpc/grpc-dart/issues/669) (https://github.com/grpc/grpc-dart/pull/693) +* Remove generated status codes. ## 3.2.4 diff --git a/lib/grpc.dart b/lib/grpc.dart index 2976723..1c9593f 100644 --- a/lib/grpc.dart +++ b/lib/grpc.dart @@ -15,7 +15,6 @@ // ignore: dangling_library_doc_comments /// Status detail types and error codes -export 'package:grpc/src/generated/google/rpc/code.pbenum.dart'; export 'package:grpc/src/generated/google/rpc/error_details.pb.dart'; export 'src/auth/auth.dart' show BaseAuthenticator; diff --git a/lib/src/auth/auth_io.dart b/lib/src/auth/auth_io.dart index 681ee59..bb72000 100644 --- a/lib/src/auth/auth_io.dart +++ b/lib/src/auth/auth_io.dart @@ -69,7 +69,7 @@ class _CredentialsRefreshingAuthenticator extends HttpBasedAuthenticator { await super.authenticate(metadata, uri); if (_quotaProject != null) { // https://cloud.google.com/apis/docs/system-parameters#definitions - metadata['X-Goog-User-Project'] = _quotaProject!; + metadata['X-Goog-User-Project'] = _quotaProject; } } diff --git a/lib/src/client/transport/http2_credentials.dart b/lib/src/client/transport/http2_credentials.dart index 5b20e7a..f2b7669 100644 --- a/lib/src/client/transport/http2_credentials.dart +++ b/lib/src/client/transport/http2_credentials.dart @@ -58,7 +58,7 @@ class ChannelCredentials { if (!isSecure) return null; if (_certificateBytes != null) { return createSecurityContext(false) - ..setTrustedCertificatesBytes(_certificateBytes!, + ..setTrustedCertificatesBytes(_certificateBytes, password: _certificatePassword); } final context = SecurityContext(withTrustedRoots: true); diff --git a/lib/src/generated/google/rpc/code.pb.dart b/lib/src/generated/google/rpc/code.pb.dart deleted file mode 100644 index 6580226..0000000 --- a/lib/src/generated/google/rpc/code.pb.dart +++ /dev/null @@ -1,14 +0,0 @@ -// -// Generated code. Do not modify. -// source: google/rpc/code.proto -// -// @dart = 2.12 - -// ignore_for_file: annotate_overrides, camel_case_types, comment_references -// ignore_for_file: constant_identifier_names, library_prefixes -// ignore_for_file: non_constant_identifier_names, prefer_final_fields -// ignore_for_file: unnecessary_import, unnecessary_this, unused_import - -import 'dart:core' as $core; - -export 'code.pbenum.dart'; diff --git a/lib/src/generated/google/rpc/code.pbenum.dart b/lib/src/generated/google/rpc/code.pbenum.dart deleted file mode 100644 index f3d7bf3..0000000 --- a/lib/src/generated/google/rpc/code.pbenum.dart +++ /dev/null @@ -1,79 +0,0 @@ -// -// Generated code. Do not modify. -// source: google/rpc/code.proto -// -// @dart = 2.12 - -// ignore_for_file: annotate_overrides, camel_case_types, comment_references -// ignore_for_file: constant_identifier_names, library_prefixes -// ignore_for_file: non_constant_identifier_names, prefer_final_fields -// ignore_for_file: unnecessary_import, unnecessary_this, unused_import - -import 'dart:core' as $core; - -import 'package:protobuf/protobuf.dart' as $pb; - -/// The canonical error codes for gRPC APIs. -/// -/// -/// Sometimes multiple error codes may apply. Services should return -/// the most specific error code that applies. For example, prefer -/// `OUT_OF_RANGE` over `FAILED_PRECONDITION` if both codes apply. -/// Similarly prefer `NOT_FOUND` or `ALREADY_EXISTS` over `FAILED_PRECONDITION`. -class Code extends $pb.ProtobufEnum { - static const Code OK = Code._(0, _omitEnumNames ? '' : 'OK'); - static const Code CANCELLED = Code._(1, _omitEnumNames ? '' : 'CANCELLED'); - static const Code UNKNOWN = Code._(2, _omitEnumNames ? '' : 'UNKNOWN'); - static const Code INVALID_ARGUMENT = - Code._(3, _omitEnumNames ? '' : 'INVALID_ARGUMENT'); - static const Code DEADLINE_EXCEEDED = - Code._(4, _omitEnumNames ? '' : 'DEADLINE_EXCEEDED'); - static const Code NOT_FOUND = Code._(5, _omitEnumNames ? '' : 'NOT_FOUND'); - static const Code ALREADY_EXISTS = - Code._(6, _omitEnumNames ? '' : 'ALREADY_EXISTS'); - static const Code PERMISSION_DENIED = - Code._(7, _omitEnumNames ? '' : 'PERMISSION_DENIED'); - static const Code UNAUTHENTICATED = - Code._(16, _omitEnumNames ? '' : 'UNAUTHENTICATED'); - static const Code RESOURCE_EXHAUSTED = - Code._(8, _omitEnumNames ? '' : 'RESOURCE_EXHAUSTED'); - static const Code FAILED_PRECONDITION = - Code._(9, _omitEnumNames ? '' : 'FAILED_PRECONDITION'); - static const Code ABORTED = Code._(10, _omitEnumNames ? '' : 'ABORTED'); - static const Code OUT_OF_RANGE = - Code._(11, _omitEnumNames ? '' : 'OUT_OF_RANGE'); - static const Code UNIMPLEMENTED = - Code._(12, _omitEnumNames ? '' : 'UNIMPLEMENTED'); - static const Code INTERNAL = Code._(13, _omitEnumNames ? '' : 'INTERNAL'); - static const Code UNAVAILABLE = - Code._(14, _omitEnumNames ? '' : 'UNAVAILABLE'); - static const Code DATA_LOSS = Code._(15, _omitEnumNames ? '' : 'DATA_LOSS'); - - static const $core.List values = [ - OK, - CANCELLED, - UNKNOWN, - INVALID_ARGUMENT, - DEADLINE_EXCEEDED, - NOT_FOUND, - ALREADY_EXISTS, - PERMISSION_DENIED, - UNAUTHENTICATED, - RESOURCE_EXHAUSTED, - FAILED_PRECONDITION, - ABORTED, - OUT_OF_RANGE, - UNIMPLEMENTED, - INTERNAL, - UNAVAILABLE, - DATA_LOSS, - ]; - - static final $core.Map<$core.int, Code> _byValue = - $pb.ProtobufEnum.initByValue(values); - static Code? valueOf($core.int value) => _byValue[value]; - - const Code._($core.int v, $core.String n) : super(v, n); -} - -const _omitEnumNames = $core.bool.fromEnvironment('protobuf.omit_enum_names'); diff --git a/lib/src/generated/google/rpc/code.pbjson.dart b/lib/src/generated/google/rpc/code.pbjson.dart deleted file mode 100644 index 3e9bd5a..0000000 --- a/lib/src/generated/google/rpc/code.pbjson.dart +++ /dev/null @@ -1,47 +0,0 @@ -// -// Generated code. Do not modify. -// source: google/rpc/code.proto -// -// @dart = 2.12 - -// ignore_for_file: annotate_overrides, camel_case_types, comment_references -// ignore_for_file: constant_identifier_names, library_prefixes -// ignore_for_file: non_constant_identifier_names, prefer_final_fields -// ignore_for_file: unnecessary_import, unnecessary_this, unused_import - -import 'dart:convert' as $convert; -import 'dart:core' as $core; -import 'dart:typed_data' as $typed_data; - -@$core.Deprecated('Use codeDescriptor instead') -const Code$json = { - '1': 'Code', - '2': [ - {'1': 'OK', '2': 0}, - {'1': 'CANCELLED', '2': 1}, - {'1': 'UNKNOWN', '2': 2}, - {'1': 'INVALID_ARGUMENT', '2': 3}, - {'1': 'DEADLINE_EXCEEDED', '2': 4}, - {'1': 'NOT_FOUND', '2': 5}, - {'1': 'ALREADY_EXISTS', '2': 6}, - {'1': 'PERMISSION_DENIED', '2': 7}, - {'1': 'UNAUTHENTICATED', '2': 16}, - {'1': 'RESOURCE_EXHAUSTED', '2': 8}, - {'1': 'FAILED_PRECONDITION', '2': 9}, - {'1': 'ABORTED', '2': 10}, - {'1': 'OUT_OF_RANGE', '2': 11}, - {'1': 'UNIMPLEMENTED', '2': 12}, - {'1': 'INTERNAL', '2': 13}, - {'1': 'UNAVAILABLE', '2': 14}, - {'1': 'DATA_LOSS', '2': 15}, - ], -}; - -/// Descriptor for `Code`. Decode as a `google.protobuf.EnumDescriptorProto`. -final $typed_data.Uint8List codeDescriptor = $convert.base64Decode( - 'CgRDb2RlEgYKAk9LEAASDQoJQ0FOQ0VMTEVEEAESCwoHVU5LTk9XThACEhQKEElOVkFMSURfQV' - 'JHVU1FTlQQAxIVChFERUFETElORV9FWENFRURFRBAEEg0KCU5PVF9GT1VORBAFEhIKDkFMUkVB' - 'RFlfRVhJU1RTEAYSFQoRUEVSTUlTU0lPTl9ERU5JRUQQBxITCg9VTkFVVEhFTlRJQ0FURUQQEB' - 'IWChJSRVNPVVJDRV9FWEhBVVNURUQQCBIXChNGQUlMRURfUFJFQ09ORElUSU9OEAkSCwoHQUJP' - 'UlRFRBAKEhAKDE9VVF9PRl9SQU5HRRALEhEKDVVOSU1QTEVNRU5URUQQDBIMCghJTlRFUk5BTB' - 'ANEg8KC1VOQVZBSUxBQkxFEA4SDQoJREFUQV9MT1NTEA8='); diff --git a/lib/src/protos/google/rpc/code.proto b/lib/src/protos/google/rpc/code.proto deleted file mode 100644 index d115da1..0000000 --- a/lib/src/protos/google/rpc/code.proto +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright 2020 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 -// -// 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. - -syntax = "proto3"; - -package google.rpc; - -option go_package = "google.golang.org/genproto/googleapis/rpc/code;code"; -option java_multiple_files = true; -option java_outer_classname = "CodeProto"; -option java_package = "com.google.rpc"; -option objc_class_prefix = "RPC"; - -// The canonical error codes for gRPC APIs. -// -// -// Sometimes multiple error codes may apply. Services should return -// the most specific error code that applies. For example, prefer -// `OUT_OF_RANGE` over `FAILED_PRECONDITION` if both codes apply. -// Similarly prefer `NOT_FOUND` or `ALREADY_EXISTS` over `FAILED_PRECONDITION`. -enum Code { - // Not an error; returned on success - // - // HTTP Mapping: 200 OK - OK = 0; - - // The operation was cancelled, typically by the caller. - // - // HTTP Mapping: 499 Client Closed Request - CANCELLED = 1; - - // Unknown error. For example, this error may be returned when - // a `Status` value received from another address space belongs to - // an error space that is not known in this address space. Also - // errors raised by APIs that do not return enough error information - // may be converted to this error. - // - // HTTP Mapping: 500 Internal Server Error - UNKNOWN = 2; - - // The client specified an invalid argument. Note that this differs - // from `FAILED_PRECONDITION`. `INVALID_ARGUMENT` indicates arguments - // that are problematic regardless of the state of the system - // (e.g., a malformed file name). - // - // HTTP Mapping: 400 Bad Request - INVALID_ARGUMENT = 3; - - // The deadline expired before the operation could complete. For operations - // that change the state of the system, this error may be returned - // even if the operation has completed successfully. For example, a - // successful response from a server could have been delayed long - // enough for the deadline to expire. - // - // HTTP Mapping: 504 Gateway Timeout - DEADLINE_EXCEEDED = 4; - - // Some requested entity (e.g., file or directory) was not found. - // - // Note to server developers: if a request is denied for an entire class - // of users, such as gradual feature rollout or undocumented whitelist, - // `NOT_FOUND` may be used. If a request is denied for some users within - // a class of users, such as user-based access control, `PERMISSION_DENIED` - // must be used. - // - // HTTP Mapping: 404 Not Found - NOT_FOUND = 5; - - // The entity that a client attempted to create (e.g., file or directory) - // already exists. - // - // HTTP Mapping: 409 Conflict - ALREADY_EXISTS = 6; - - // The caller does not have permission to execute the specified - // operation. `PERMISSION_DENIED` must not be used for rejections - // caused by exhausting some resource (use `RESOURCE_EXHAUSTED` - // instead for those errors). `PERMISSION_DENIED` must not be - // used if the caller can not be identified (use `UNAUTHENTICATED` - // instead for those errors). This error code does not imply the - // request is valid or the requested entity exists or satisfies - // other pre-conditions. - // - // HTTP Mapping: 403 Forbidden - PERMISSION_DENIED = 7; - - // The request does not have valid authentication credentials for the - // operation. - // - // HTTP Mapping: 401 Unauthorized - UNAUTHENTICATED = 16; - - // Some resource has been exhausted, perhaps a per-user quota, or - // perhaps the entire file system is out of space. - // - // HTTP Mapping: 429 Too Many Requests - RESOURCE_EXHAUSTED = 8; - - // The operation was rejected because the system is not in a state - // required for the operation's execution. For example, the directory - // to be deleted is non-empty, an rmdir operation is applied to - // a non-directory, etc. - // - // Service implementors can use the following guidelines to decide - // between `FAILED_PRECONDITION`, `ABORTED`, and `UNAVAILABLE`: - // (a) Use `UNAVAILABLE` if the client can retry just the failing call. - // (b) Use `ABORTED` if the client should retry at a higher level - // (e.g., when a client-specified test-and-set fails, indicating the - // client should restart a read-modify-write sequence). - // (c) Use `FAILED_PRECONDITION` if the client should not retry until - // the system state has been explicitly fixed. E.g., if an "rmdir" - // fails because the directory is non-empty, `FAILED_PRECONDITION` - // should be returned since the client should not retry unless - // the files are deleted from the directory. - // - // HTTP Mapping: 400 Bad Request - FAILED_PRECONDITION = 9; - - // The operation was aborted, typically due to a concurrency issue such as - // a sequencer check failure or transaction abort. - // - // See the guidelines above for deciding between `FAILED_PRECONDITION`, - // `ABORTED`, and `UNAVAILABLE`. - // - // HTTP Mapping: 409 Conflict - ABORTED = 10; - - // The operation was attempted past the valid range. E.g., seeking or - // reading past end-of-file. - // - // Unlike `INVALID_ARGUMENT`, this error indicates a problem that may - // be fixed if the system state changes. For example, a 32-bit file - // system will generate `INVALID_ARGUMENT` if asked to read at an - // offset that is not in the range [0,2^32-1], but it will generate - // `OUT_OF_RANGE` if asked to read from an offset past the current - // file size. - // - // There is a fair bit of overlap between `FAILED_PRECONDITION` and - // `OUT_OF_RANGE`. We recommend using `OUT_OF_RANGE` (the more specific - // error) when it applies so that callers who are iterating through - // a space can easily look for an `OUT_OF_RANGE` error to detect when - // they are done. - // - // HTTP Mapping: 400 Bad Request - OUT_OF_RANGE = 11; - - // The operation is not implemented or is not supported/enabled in this - // service. - // - // HTTP Mapping: 501 Not Implemented - UNIMPLEMENTED = 12; - - // Internal errors. This means that some invariants expected by the - // underlying system have been broken. This error code is reserved - // for serious errors. - // - // HTTP Mapping: 500 Internal Server Error - INTERNAL = 13; - - // The service is currently unavailable. This is most likely a - // transient condition, which can be corrected by retrying with - // a backoff. Note that it is not always safe to retry - // non-idempotent operations. - // - // See the guidelines above for deciding between `FAILED_PRECONDITION`, - // `ABORTED`, and `UNAVAILABLE`. - // - // HTTP Mapping: 503 Service Unavailable - UNAVAILABLE = 14; - - // Unrecoverable data loss or corruption. - // - // HTTP Mapping: 500 Internal Server Error - DATA_LOSS = 15; -} \ No newline at end of file diff --git a/lib/src/server/handler.dart b/lib/src/server/handler.dart index ecbebe1..f28963c 100644 --- a/lib/src/server/handler.dart +++ b/lib/src/server/handler.dart @@ -170,7 +170,7 @@ class ServerHandler extends ServiceCall { final acceptedEncodings = clientMetadata!['grpc-accept-encoding']?.split(',') ?? []; _callEncodingCodec = acceptedEncodings - .map(_codecRegistry!.lookup) + .map(_codecRegistry.lookup) .firstWhere((c) => c != null, orElse: () => null); } diff --git a/lib/src/shared/status.dart b/lib/src/shared/status.dart index 4b3059d..e0474ac 100644 --- a/lib/src/shared/status.dart +++ b/lib/src/shared/status.dart @@ -18,7 +18,6 @@ import 'dart:convert'; import 'package:grpc/src/generated/google/protobuf/any.pb.dart'; -import 'package:grpc/src/generated/google/rpc/code.pb.dart'; import 'package:grpc/src/generated/google/rpc/error_details.pb.dart'; import 'package:grpc/src/generated/google/rpc/status.pb.dart'; import 'package:meta/meta.dart'; @@ -151,6 +150,28 @@ class StatusCode { static int fromHttpStatus(int status) { return _httpStatusToGrpcStatus[status] ?? StatusCode.unknown; } + + /// Creates a string from a gRPC status code. + static String? name(int status) => switch (status) { + ok => 'OK', + cancelled => 'CANCELLED', + unknown => 'UNKNOWN', + invalidArgument => 'INVALID_ARGUMENT', + deadlineExceeded => 'DEADLINE_EXCEEDED', + notFound => 'NOT_FOUND', + alreadyExists => 'ALREADY_EXISTS', + permissionDenied => 'PERMISSION_DENIED', + resourceExhausted => 'RESOURCE_EXHAUSTED', + failedPrecondition => 'FAILED_PRECONDITION', + aborted => 'ABORTED', + outOfRange => 'OUT_OF_RANGE', + unimplemented => 'UNIMPLEMENTED', + internal => 'INTERNAL', + unavailable => 'UNAVAILABLE', + dataLoss => 'DATA_LOSS', + unauthenticated => 'UNAUTHENTICATED', + int() => null, + }; } class GrpcError implements Exception { @@ -308,7 +329,8 @@ class GrpcError implements Exception { code = StatusCode.unauthenticated; /// Given a status code, return the name - String get codeName => (Code.valueOf(code) ?? Code.UNKNOWN).name; + String get codeName => + StatusCode.name(code) ?? StatusCode.name(StatusCode.unknown)!; @override bool operator ==(other) { diff --git a/pubspec.yaml b/pubspec.yaml index e57074a..6bd0ffa 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,11 +1,11 @@ name: grpc description: Dart implementation of gRPC, a high performance, open-source universal RPC framework. -version: 3.2.5 +version: 4.0.0 repository: https://github.com/grpc/grpc-dart environment: - sdk: ^3.0.0 + sdk: ^3.2.0 dependencies: archive: ^3.0.0 From 0d02e4386f45773d9c2545c2c5b7e814e50f6e68 Mon Sep 17 00:00:00 2001 From: Moritz Date: Mon, 6 May 2024 06:25:06 -0700 Subject: [PATCH 06/32] Remove dependency on `package:archive` (#707) * Remove dependency on package:archive * Test compression on vm only * Add licenses * Fix analyze issues * Fix codec web * Fix licenses * Add changelog --- CHANGELOG.md | 1 + example/grpc-web/lib/app.dart | 15 ++++++++ example/helloworld/bin/client.dart | 2 +- example/helloworld/bin/server.dart | 2 +- example/helloworld/bin/unix_client.dart | 2 +- example/helloworld/bin/unix_server.dart | 2 +- interop/lib/src/client.dart | 4 +-- lib/grpc.dart | 2 +- lib/grpc_connection_interface.dart | 2 +- lib/src/client/call.dart | 2 +- lib/src/client/http2_connection.dart | 2 +- lib/src/client/transport/http2_transport.dart | 2 +- lib/src/server/handler.dart | 2 +- lib/src/shared/codec/codec.dart | 18 ++++++++++ .../{codec.dart => codec/codec_all.dart} | 22 +----------- lib/src/shared/codec/codec_io.dart | 36 +++++++++++++++++++ lib/src/shared/codec/codec_web.dart | 34 ++++++++++++++++++ lib/src/shared/codec_registry.dart | 2 +- lib/src/shared/message.dart | 2 +- pubspec.yaml | 1 - test/client_certificate_test.dart | 15 ++++++++ test/client_handles_bad_connections_test.dart | 15 ++++++++ test/client_tests/call_test.dart | 15 ++++++++ .../client_tests/client_interceptor_test.dart | 15 ++++++++ .../client_keepalive_manager_test.dart | 15 ++++++++ .../client_keepalive_manager_test.mocks.dart | 15 ++++++++ test/grpc_compression_flag_test.dart | 19 +++++++++- test/grpc_web_decoding_test.dart | 15 ++++++++ test/grpc_web_server.dart | 15 ++++++++ test/grpc_web_test.dart | 15 ++++++++ test/keepalive_test.dart | 15 ++++++++ test/proxy_secure_test.dart | 15 ++++++++ test/proxy_test.dart | 15 ++++++++ test/round_trip_test.dart | 15 ++++++++ ...server_handles_broken_connection_test.dart | 15 ++++++++ test/server_keepalive_manager_test.dart | 15 ++++++++ test/shared_tests/codec_registry_test.dart | 17 ++++++++- test/tools/http2_client.dart | 15 ++++++++ test/tools/http2_server.dart | 15 ++++++++ 39 files changed, 408 insertions(+), 38 deletions(-) create mode 100644 lib/src/shared/codec/codec.dart rename lib/src/shared/{codec.dart => codec/codec_all.dart} (76%) create mode 100644 lib/src/shared/codec/codec_io.dart create mode 100644 lib/src/shared/codec/codec_web.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b46123..7c42bd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ * Set compressed flag correctly for grpc-encoding = identity. Fixes [#669](https://github.com/grpc/grpc-dart/issues/669) (https://github.com/grpc/grpc-dart/pull/693) * Remove generated status codes. +* Remove dependency on `package:archive`. ## 3.2.4 diff --git a/example/grpc-web/lib/app.dart b/example/grpc-web/lib/app.dart index bdc920f..fce83c5 100644 --- a/example/grpc-web/lib/app.dart +++ b/example/grpc-web/lib/app.dart @@ -1,3 +1,18 @@ +// Copyright (c) 2024, 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'; diff --git a/example/helloworld/bin/client.dart b/example/helloworld/bin/client.dart index 4d4635d..4ec8e8e 100644 --- a/example/helloworld/bin/client.dart +++ b/example/helloworld/bin/client.dart @@ -13,10 +13,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -/// Dart implementation of the gRPC helloworld.Greeter client. import 'package:grpc/grpc.dart'; import 'package:helloworld/src/generated/helloworld.pbgrpc.dart'; +/// Dart implementation of the gRPC helloworld.Greeter client. Future main(List args) async { final channel = ClientChannel( 'localhost', diff --git a/example/helloworld/bin/server.dart b/example/helloworld/bin/server.dart index 0f2b287..a2b491c 100644 --- a/example/helloworld/bin/server.dart +++ b/example/helloworld/bin/server.dart @@ -13,10 +13,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -/// Dart implementation of the gRPC helloworld.Greeter server. import 'package:grpc/grpc.dart'; import 'package:helloworld/src/generated/helloworld.pbgrpc.dart'; +/// Dart implementation of the gRPC helloworld.Greeter server. class GreeterService extends GreeterServiceBase { @override Future sayHello(ServiceCall call, HelloRequest request) async { diff --git a/example/helloworld/bin/unix_client.dart b/example/helloworld/bin/unix_client.dart index 5f30cc2..0c3cacc 100644 --- a/example/helloworld/bin/unix_client.dart +++ b/example/helloworld/bin/unix_client.dart @@ -13,12 +13,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -/// Dart implementation of the gRPC helloworld.Greeter client. import 'dart:io'; import 'package:grpc/grpc.dart'; import 'package:helloworld/src/generated/helloworld.pbgrpc.dart'; +/// Dart implementation of the gRPC helloworld.Greeter client. Future main(List args) async { final udsAddress = InternetAddress('localhost', type: InternetAddressType.unix); diff --git a/example/helloworld/bin/unix_server.dart b/example/helloworld/bin/unix_server.dart index 82fbf02..a30eaec 100644 --- a/example/helloworld/bin/unix_server.dart +++ b/example/helloworld/bin/unix_server.dart @@ -13,12 +13,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -/// Dart implementation of the gRPC helloworld.Greeter server. import 'dart:io'; import 'package:grpc/grpc.dart'; import 'package:helloworld/src/generated/helloworld.pbgrpc.dart'; +/// Dart implementation of the gRPC helloworld.Greeter server. class GreeterService extends GreeterServiceBase { @override Future sayHello(ServiceCall call, HelloRequest request) async { diff --git a/interop/lib/src/client.dart b/interop/lib/src/client.dart index 8cead2f..a61fa81 100644 --- a/interop/lib/src/client.dart +++ b/interop/lib/src/client.dart @@ -208,7 +208,7 @@ class Tester { final receivedBytes = response.payload.body.length; if (receivedBytes != 314159) { throw 'Response payload mismatch. Expected 314159 bytes, ' - 'got ${receivedBytes}.'; + 'got $receivedBytes.'; } } @@ -869,7 +869,7 @@ class Tester { final receivedBytes = response.payload.body.length; if (receivedBytes != 314159) { throw 'Response payload mismatch. Expected 314159 bytes, ' - 'got ${receivedBytes}.'; + 'got $receivedBytes.'; } return response; } diff --git a/lib/grpc.dart b/lib/grpc.dart index 1c9593f..59c9019 100644 --- a/lib/grpc.dart +++ b/lib/grpc.dart @@ -55,7 +55,7 @@ export 'src/server/server.dart' export 'src/server/server_keepalive.dart' show ServerKeepAliveOptions; export 'src/server/service.dart' show ServiceMethod, Service; export 'src/shared/api.dart'; -export 'src/shared/codec.dart' show Codec, IdentityCodec, GzipCodec; +export 'src/shared/codec/codec.dart' show Codec, IdentityCodec, GzipCodec; export 'src/shared/codec_registry.dart'; export 'src/shared/message.dart' show GrpcMessage, GrpcMetadata, GrpcData, grpcDecompressor; diff --git a/lib/grpc_connection_interface.dart b/lib/grpc_connection_interface.dart index c0e3176..da9c879 100644 --- a/lib/grpc_connection_interface.dart +++ b/lib/grpc_connection_interface.dart @@ -25,7 +25,7 @@ export 'src/client/options.dart' show ChannelOptions; export 'src/client/transport/transport.dart' show GrpcTransportStream, ErrorHandler; -export 'src/shared/codec.dart'; +export 'src/shared/codec/codec.dart'; export 'src/shared/codec_registry.dart'; export 'src/shared/message.dart' show frame, GrpcMessage, grpcDecompressor; export 'src/shared/status.dart' show GrpcError; diff --git a/lib/src/client/call.dart b/lib/src/client/call.dart index 8d5918f..5da2703 100644 --- a/lib/src/client/call.dart +++ b/lib/src/client/call.dart @@ -16,7 +16,7 @@ import 'dart:async'; import 'dart:developer'; -import '../shared/codec.dart'; +import '../shared/codec/codec.dart'; import '../shared/message.dart'; import '../shared/profiler.dart'; import '../shared/status.dart'; diff --git a/lib/src/client/http2_connection.dart b/lib/src/client/http2_connection.dart index 998410a..1529333 100644 --- a/lib/src/client/http2_connection.dart +++ b/lib/src/client/http2_connection.dart @@ -20,7 +20,7 @@ import 'dart:typed_data'; import 'package:http2/transport.dart'; -import '../shared/codec.dart'; +import '../shared/codec/codec.dart'; import '../shared/timeout.dart'; import 'call.dart'; import 'client_keepalive.dart'; diff --git a/lib/src/client/transport/http2_transport.dart b/lib/src/client/transport/http2_transport.dart index a55c539..fcb7c5d 100644 --- a/lib/src/client/transport/http2_transport.dart +++ b/lib/src/client/transport/http2_transport.dart @@ -17,7 +17,7 @@ import 'dart:async'; import 'package:http2/transport.dart'; -import '../../shared/codec.dart'; +import '../../shared/codec/codec.dart'; import '../../shared/codec_registry.dart'; import '../../shared/message.dart'; import '../../shared/streams.dart'; diff --git a/lib/src/server/handler.dart b/lib/src/server/handler.dart index f28963c..72d92b1 100644 --- a/lib/src/server/handler.dart +++ b/lib/src/server/handler.dart @@ -18,7 +18,7 @@ import 'dart:convert'; import 'package:http2/transport.dart'; -import '../shared/codec.dart'; +import '../shared/codec/codec.dart'; import '../shared/codec_registry.dart'; import '../shared/io_bits/io_bits.dart' show InternetAddress, X509Certificate; import '../shared/message.dart'; diff --git a/lib/src/shared/codec/codec.dart b/lib/src/shared/codec/codec.dart new file mode 100644 index 0000000..6e29a48 --- /dev/null +++ b/lib/src/shared/codec/codec.dart @@ -0,0 +1,18 @@ +// Copyright (c) 2020, 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 'codec_all.dart'; +export 'codec_io.dart' + if (dart.library.js_interop) 'codec_web.dart'; // package:web implementation diff --git a/lib/src/shared/codec.dart b/lib/src/shared/codec/codec_all.dart similarity index 76% rename from lib/src/shared/codec.dart rename to lib/src/shared/codec/codec_all.dart index 8f771d5..81657ef 100644 --- a/lib/src/shared/codec.dart +++ b/lib/src/shared/codec/codec_all.dart @@ -1,4 +1,4 @@ -// Copyright (c) 2020, the gRPC project authors. Please see the AUTHORS file +// Copyright (c) 2024, the gRPC project authors. Please see the AUTHORS file // for details. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,8 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -import 'package:archive/archive.dart'; - abstract class Codec { /// Returns the message encoding that this compressor uses. /// @@ -48,21 +46,3 @@ class IdentityCodec implements Codec { return data; } } - -/// A gzip compressor and decompressor. -class GzipCodec implements Codec { - const GzipCodec(); - - @override - final encodingName = 'gzip'; - - @override - List compress(List data) { - return GZipEncoder().encode(data)!; - } - - @override - List decompress(List data) { - return GZipDecoder().decodeBytes(data); - } -} diff --git a/lib/src/shared/codec/codec_io.dart b/lib/src/shared/codec/codec_io.dart new file mode 100644 index 0000000..99bfe78 --- /dev/null +++ b/lib/src/shared/codec/codec_io.dart @@ -0,0 +1,36 @@ +// Copyright (c) 2024, 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 'codec_all.dart'; + +/// A gzip compressor and decompressor. +class GzipCodec implements Codec { + const GzipCodec(); + + @override + final encodingName = 'gzip'; + + @override + List compress(List data) { + return gzip.encode(data); + } + + @override + List decompress(List data) { + return gzip.decode(data); + } +} diff --git a/lib/src/shared/codec/codec_web.dart b/lib/src/shared/codec/codec_web.dart new file mode 100644 index 0000000..a3bf59e --- /dev/null +++ b/lib/src/shared/codec/codec_web.dart @@ -0,0 +1,34 @@ +// Copyright (c) 2024, 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 'codec_all.dart'; + +/// A gzip compressor and decompressor. +class GzipCodec implements Codec { + const GzipCodec(); + + @override + final encodingName = 'gzip'; + + @override + List compress(List data) { + throw UnsupportedError('Gzip is not supported for grpc web'); + } + + @override + List decompress(List data) { + throw UnsupportedError('Gzip is not supported for grpc web'); + } +} diff --git a/lib/src/shared/codec_registry.dart b/lib/src/shared/codec_registry.dart index 73c0558..afd1636 100644 --- a/lib/src/shared/codec_registry.dart +++ b/lib/src/shared/codec_registry.dart @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import 'codec.dart'; +import 'codec/codec.dart'; /// Encloses classes related to the compression and decompression of messages. class CodecRegistry { diff --git a/lib/src/shared/message.dart b/lib/src/shared/message.dart index 0533c55..685a232 100644 --- a/lib/src/shared/message.dart +++ b/lib/src/shared/message.dart @@ -16,7 +16,7 @@ import 'dart:async'; import 'dart:typed_data'; -import 'codec.dart'; +import 'codec/codec.dart'; import 'codec_registry.dart'; import 'status.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index 6bd0ffa..41c7feb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,7 +8,6 @@ environment: sdk: ^3.2.0 dependencies: - archive: ^3.0.0 async: ^2.5.0 crypto: ^3.0.0 fixnum: ^1.0.0 diff --git a/test/client_certificate_test.dart b/test/client_certificate_test.dart index 238b932..9edde69 100644 --- a/test/client_certificate_test.dart +++ b/test/client_certificate_test.dart @@ -1,3 +1,18 @@ +// Copyright (c) 2024, 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. + // TODO(dartbug.com/26057) currently Mac OS X seems to have some issues with // client certificates so we disable the test. @TestOn('vm && !mac-os') diff --git a/test/client_handles_bad_connections_test.dart b/test/client_handles_bad_connections_test.dart index 986a750..26a6045 100644 --- a/test/client_handles_bad_connections_test.dart +++ b/test/client_handles_bad_connections_test.dart @@ -1,3 +1,18 @@ +// Copyright (c) 2024, 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'; diff --git a/test/client_tests/call_test.dart b/test/client_tests/call_test.dart index ceff888..c519f6e 100644 --- a/test/client_tests/call_test.dart +++ b/test/client_tests/call_test.dart @@ -1,3 +1,18 @@ +// Copyright (c) 2024, 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/call.dart'; import 'package:test/test.dart'; diff --git a/test/client_tests/client_interceptor_test.dart b/test/client_tests/client_interceptor_test.dart index d9132fb..b1763d5 100644 --- a/test/client_tests/client_interceptor_test.dart +++ b/test/client_tests/client_interceptor_test.dart @@ -1,3 +1,18 @@ +// Copyright (c) 2024, 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 'package:grpc/grpc.dart'; diff --git a/test/client_tests/client_keepalive_manager_test.dart b/test/client_tests/client_keepalive_manager_test.dart index 74889d5..c260dc9 100644 --- a/test/client_tests/client_keepalive_manager_test.dart +++ b/test/client_tests/client_keepalive_manager_test.dart @@ -1,3 +1,18 @@ +// Copyright (c) 2024, 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:fake_async/fake_async.dart'; import 'package:grpc/src/client/client_keepalive.dart'; import 'package:mockito/annotations.dart'; diff --git a/test/client_tests/client_keepalive_manager_test.mocks.dart b/test/client_tests/client_keepalive_manager_test.mocks.dart index 941de6a..20a8225 100644 --- a/test/client_tests/client_keepalive_manager_test.mocks.dart +++ b/test/client_tests/client_keepalive_manager_test.mocks.dart @@ -1,3 +1,18 @@ +// Copyright (c) 2024, 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. + // Mocks generated by Mockito 5.4.1 from annotations // in grpc/test/client_tests/client_keepalive_manager_test.dart. // Do not manually edit this file. diff --git a/test/grpc_compression_flag_test.dart b/test/grpc_compression_flag_test.dart index adf2999..51e0b21 100644 --- a/test/grpc_compression_flag_test.dart +++ b/test/grpc_compression_flag_test.dart @@ -1,4 +1,21 @@ -import 'package:grpc/src/shared/codec.dart'; +// Copyright (c) 2024, 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 'package:grpc/src/shared/codec/codec.dart'; import 'package:grpc/src/shared/message.dart'; import 'package:test/test.dart'; diff --git a/test/grpc_web_decoding_test.dart b/test/grpc_web_decoding_test.dart index aa0f390..96d985a 100644 --- a/test/grpc_web_decoding_test.dart +++ b/test/grpc_web_decoding_test.dart @@ -1,3 +1,18 @@ +// Copyright (c) 2024, 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:typed_data'; diff --git a/test/grpc_web_server.dart b/test/grpc_web_server.dart index 8f87555..57d80b6 100644 --- a/test/grpc_web_server.dart +++ b/test/grpc_web_server.dart @@ -1,3 +1,18 @@ +// Copyright (c) 2024, 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'; diff --git a/test/grpc_web_test.dart b/test/grpc_web_test.dart index ad58181..fb96f90 100644 --- a/test/grpc_web_test.dart +++ b/test/grpc_web_test.dart @@ -1,3 +1,18 @@ +// Copyright (c) 2024, 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:math' as math; diff --git a/test/keepalive_test.dart b/test/keepalive_test.dart index e4ddf2d..a63c608 100644 --- a/test/keepalive_test.dart +++ b/test/keepalive_test.dart @@ -1,3 +1,18 @@ +// Copyright (c) 2024, 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'; diff --git a/test/proxy_secure_test.dart b/test/proxy_secure_test.dart index 24f6ff8..257103e 100644 --- a/test/proxy_secure_test.dart +++ b/test/proxy_secure_test.dart @@ -1,3 +1,18 @@ +// Copyright (c) 2024, 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 'dart:io'; diff --git a/test/proxy_test.dart b/test/proxy_test.dart index a4f9bcf..522d65a 100644 --- a/test/proxy_test.dart +++ b/test/proxy_test.dart @@ -1,3 +1,18 @@ +// Copyright (c) 2024, 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'; diff --git a/test/round_trip_test.dart b/test/round_trip_test.dart index 4a45224..67e3dcf 100644 --- a/test/round_trip_test.dart +++ b/test/round_trip_test.dart @@ -1,3 +1,18 @@ +// Copyright (c) 2024, 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 'dart:io'; diff --git a/test/server_handles_broken_connection_test.dart b/test/server_handles_broken_connection_test.dart index cd6d1fd..38d15ac 100644 --- a/test/server_handles_broken_connection_test.dart +++ b/test/server_handles_broken_connection_test.dart @@ -1,3 +1,18 @@ +// Copyright (c) 2024, 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 'dart:io'; diff --git a/test/server_keepalive_manager_test.dart b/test/server_keepalive_manager_test.dart index 230fc3b..94ab257 100644 --- a/test/server_keepalive_manager_test.dart +++ b/test/server_keepalive_manager_test.dart @@ -1,3 +1,18 @@ +// Copyright (c) 2024, 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 'package:fake_async/fake_async.dart'; diff --git a/test/shared_tests/codec_registry_test.dart b/test/shared_tests/codec_registry_test.dart index 5a5483b..13381c2 100644 --- a/test/shared_tests/codec_registry_test.dart +++ b/test/shared_tests/codec_registry_test.dart @@ -1,4 +1,19 @@ -import 'package:grpc/src/shared/codec.dart'; +// Copyright (c) 2024, 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/shared/codec/codec.dart'; import 'package:grpc/src/shared/codec_registry.dart'; import 'package:test/test.dart'; diff --git a/test/tools/http2_client.dart b/test/tools/http2_client.dart index 46b8b42..d7359cd 100644 --- a/test/tools/http2_client.dart +++ b/test/tools/http2_client.dart @@ -1,3 +1,18 @@ +// Copyright (c) 2024, 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 'package:grpc/grpc.dart'; diff --git a/test/tools/http2_server.dart b/test/tools/http2_server.dart index 4ab5eb2..721773d 100644 --- a/test/tools/http2_server.dart +++ b/test/tools/http2_server.dart @@ -1,3 +1,18 @@ +// Copyright (c) 2024, 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:io'; From 9f65399e286e824b0bd1ad3a7776d232bfdde341 Mon Sep 17 00:00:00 2001 From: Moritz Date: Fri, 17 May 2024 14:53:33 +0200 Subject: [PATCH 07/32] Move `codec.dart` to former place (#713) --- CHANGELOG.md | 1 + lib/grpc.dart | 2 +- lib/grpc_connection_interface.dart | 2 +- lib/src/client/call.dart | 2 +- lib/src/client/http2_connection.dart | 2 +- lib/src/client/transport/http2_transport.dart | 2 +- lib/src/server/handler.dart | 2 +- lib/src/shared/{codec => }/codec.dart | 6 +++--- lib/src/shared/codec_registry.dart | 2 +- lib/src/shared/message.dart | 2 +- test/grpc_compression_flag_test.dart | 2 +- test/shared_tests/codec_registry_test.dart | 2 +- 12 files changed, 14 insertions(+), 13 deletions(-) rename lib/src/shared/{codec => }/codec.dart (82%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c42bd2..d336d3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ * Set compressed flag correctly for grpc-encoding = identity. Fixes [#669](https://github.com/grpc/grpc-dart/issues/669) (https://github.com/grpc/grpc-dart/pull/693) * Remove generated status codes. * Remove dependency on `package:archive`. +* Move `codec.dart`. ## 3.2.4 diff --git a/lib/grpc.dart b/lib/grpc.dart index 59c9019..1c9593f 100644 --- a/lib/grpc.dart +++ b/lib/grpc.dart @@ -55,7 +55,7 @@ export 'src/server/server.dart' export 'src/server/server_keepalive.dart' show ServerKeepAliveOptions; export 'src/server/service.dart' show ServiceMethod, Service; export 'src/shared/api.dart'; -export 'src/shared/codec/codec.dart' show Codec, IdentityCodec, GzipCodec; +export 'src/shared/codec.dart' show Codec, IdentityCodec, GzipCodec; export 'src/shared/codec_registry.dart'; export 'src/shared/message.dart' show GrpcMessage, GrpcMetadata, GrpcData, grpcDecompressor; diff --git a/lib/grpc_connection_interface.dart b/lib/grpc_connection_interface.dart index da9c879..c0e3176 100644 --- a/lib/grpc_connection_interface.dart +++ b/lib/grpc_connection_interface.dart @@ -25,7 +25,7 @@ export 'src/client/options.dart' show ChannelOptions; export 'src/client/transport/transport.dart' show GrpcTransportStream, ErrorHandler; -export 'src/shared/codec/codec.dart'; +export 'src/shared/codec.dart'; export 'src/shared/codec_registry.dart'; export 'src/shared/message.dart' show frame, GrpcMessage, grpcDecompressor; export 'src/shared/status.dart' show GrpcError; diff --git a/lib/src/client/call.dart b/lib/src/client/call.dart index 5da2703..8d5918f 100644 --- a/lib/src/client/call.dart +++ b/lib/src/client/call.dart @@ -16,7 +16,7 @@ import 'dart:async'; import 'dart:developer'; -import '../shared/codec/codec.dart'; +import '../shared/codec.dart'; import '../shared/message.dart'; import '../shared/profiler.dart'; import '../shared/status.dart'; diff --git a/lib/src/client/http2_connection.dart b/lib/src/client/http2_connection.dart index 1529333..998410a 100644 --- a/lib/src/client/http2_connection.dart +++ b/lib/src/client/http2_connection.dart @@ -20,7 +20,7 @@ import 'dart:typed_data'; import 'package:http2/transport.dart'; -import '../shared/codec/codec.dart'; +import '../shared/codec.dart'; import '../shared/timeout.dart'; import 'call.dart'; import 'client_keepalive.dart'; diff --git a/lib/src/client/transport/http2_transport.dart b/lib/src/client/transport/http2_transport.dart index fcb7c5d..a55c539 100644 --- a/lib/src/client/transport/http2_transport.dart +++ b/lib/src/client/transport/http2_transport.dart @@ -17,7 +17,7 @@ import 'dart:async'; import 'package:http2/transport.dart'; -import '../../shared/codec/codec.dart'; +import '../../shared/codec.dart'; import '../../shared/codec_registry.dart'; import '../../shared/message.dart'; import '../../shared/streams.dart'; diff --git a/lib/src/server/handler.dart b/lib/src/server/handler.dart index 72d92b1..f28963c 100644 --- a/lib/src/server/handler.dart +++ b/lib/src/server/handler.dart @@ -18,7 +18,7 @@ import 'dart:convert'; import 'package:http2/transport.dart'; -import '../shared/codec/codec.dart'; +import '../shared/codec.dart'; import '../shared/codec_registry.dart'; import '../shared/io_bits/io_bits.dart' show InternetAddress, X509Certificate; import '../shared/message.dart'; diff --git a/lib/src/shared/codec/codec.dart b/lib/src/shared/codec.dart similarity index 82% rename from lib/src/shared/codec/codec.dart rename to lib/src/shared/codec.dart index 6e29a48..eae7749 100644 --- a/lib/src/shared/codec/codec.dart +++ b/lib/src/shared/codec.dart @@ -13,6 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -export 'codec_all.dart'; -export 'codec_io.dart' - if (dart.library.js_interop) 'codec_web.dart'; // package:web implementation +export 'codec/codec_all.dart'; +export 'codec/codec_io.dart' + if (dart.library.js_interop) 'codec/codec_web.dart'; // package:web implementation diff --git a/lib/src/shared/codec_registry.dart b/lib/src/shared/codec_registry.dart index afd1636..73c0558 100644 --- a/lib/src/shared/codec_registry.dart +++ b/lib/src/shared/codec_registry.dart @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import 'codec/codec.dart'; +import 'codec.dart'; /// Encloses classes related to the compression and decompression of messages. class CodecRegistry { diff --git a/lib/src/shared/message.dart b/lib/src/shared/message.dart index 685a232..0533c55 100644 --- a/lib/src/shared/message.dart +++ b/lib/src/shared/message.dart @@ -16,7 +16,7 @@ import 'dart:async'; import 'dart:typed_data'; -import 'codec/codec.dart'; +import 'codec.dart'; import 'codec_registry.dart'; import 'status.dart'; diff --git a/test/grpc_compression_flag_test.dart b/test/grpc_compression_flag_test.dart index 51e0b21..97ece91 100644 --- a/test/grpc_compression_flag_test.dart +++ b/test/grpc_compression_flag_test.dart @@ -15,7 +15,7 @@ @TestOn('vm') -import 'package:grpc/src/shared/codec/codec.dart'; +import 'package:grpc/src/shared/codec.dart'; import 'package:grpc/src/shared/message.dart'; import 'package:test/test.dart'; diff --git a/test/shared_tests/codec_registry_test.dart b/test/shared_tests/codec_registry_test.dart index 13381c2..55de10e 100644 --- a/test/shared_tests/codec_registry_test.dart +++ b/test/shared_tests/codec_registry_test.dart @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import 'package:grpc/src/shared/codec/codec.dart'; +import 'package:grpc/src/shared/codec.dart'; import 'package:grpc/src/shared/codec_registry.dart'; import 'package:test/test.dart'; From 6586b749696520cff25c02b95a1d07b9617c7f47 Mon Sep 17 00:00:00 2001 From: Sarah Zakarias Date: Tue, 21 May 2024 12:30:20 +0200 Subject: [PATCH 08/32] Add `topics` to `pubspec.yaml` (#712) --- pubspec.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pubspec.yaml b/pubspec.yaml index 41c7feb..2d4c55f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -33,3 +33,8 @@ dev_dependencies: false_secrets: - interop/server1.key - test/data/localhost.key + +topics: + - grpc + - rpc + - protocols From 14954537f64b6b40dfaa391023cb0d401b95c03a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 May 2024 11:01:10 +0000 Subject: [PATCH 09/32] Bump dart-lang/setup-dart from 1.6.2 to 1.6.4 Bumps [dart-lang/setup-dart](https://github.com/dart-lang/setup-dart) from 1.6.2 to 1.6.4. - [Release notes](https://github.com/dart-lang/setup-dart/releases) - [Changelog](https://github.com/dart-lang/setup-dart/blob/main/CHANGELOG.md) - [Commits](https://github.com/dart-lang/setup-dart/compare/fedb1266e91cf51be2fdb382869461a434b920a3...f0ead981b4d9a35b37f30d36160575d60931ec30) --- updated-dependencies: - dependency-name: dart-lang/setup-dart dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/dart.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index 5ad814b..47ad0e1 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -19,7 +19,7 @@ jobs: sdk: [3.2.0, dev] steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 - - uses: dart-lang/setup-dart@fedb1266e91cf51be2fdb382869461a434b920a3 + - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 with: sdk: ${{ matrix.sdk }} - name: Report version @@ -71,7 +71,7 @@ jobs: platform: chrome steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 - - uses: dart-lang/setup-dart@fedb1266e91cf51be2fdb382869461a434b920a3 + - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 with: sdk: ${{ matrix.sdk }} - name: Report version From 4e65d4b795b8a2f0e43e87db2384a5b7338dccfb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 May 2024 11:05:38 +0000 Subject: [PATCH 10/32] --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/dart.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index 47ad0e1..6b3a513 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -18,7 +18,7 @@ jobs: matrix: sdk: [3.2.0, dev] steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 with: sdk: ${{ matrix.sdk }} @@ -70,7 +70,7 @@ jobs: - os: macos-latest platform: chrome steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 with: sdk: ${{ matrix.sdk }} From ebb7368fa4d2ef5dea468c9b5827bf41bf9a3fef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 May 2024 06:56:00 +0000 Subject: [PATCH 11/32] Bump lints from 3.0.0 to 4.0.0 Bumps [lints](https://github.com/dart-lang/lints) from 3.0.0 to 4.0.0. - [Release notes](https://github.com/dart-lang/lints/releases) - [Changelog](https://github.com/dart-lang/lints/blob/main/CHANGELOG.md) - [Commits](https://github.com/dart-lang/lints/compare/v3.0.0...v4.0.0) --- updated-dependencies: - dependency-name: lints dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 2d4c55f..9e3dcd7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -21,7 +21,7 @@ dependencies: dev_dependencies: build_runner: ^2.0.0 build_test: ^2.0.0 - lints: ">=2.0.0 <4.0.0" + lints: ">=2.0.0 <5.0.0" mockito: ^5.0.0 path: ^1.8.0 test: ^1.16.0 From 52023d404ec7b547902335cedecc56d4a3082b1d Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Tue, 28 May 2024 14:47:30 -0700 Subject: [PATCH 12/32] code fixes --- analysis_options.yaml | 1 - test/client_certificate_test.dart | 2 ++ test/client_handles_bad_connections_test.dart | 2 ++ test/client_tests/client_xhr_transport_test.dart | 1 + test/client_tests/grpc_or_grpcweb_channel_grpc_test.dart | 2 ++ test/client_tests/grpc_or_grpcweb_channel_web_test.dart | 1 + test/connection_server_test.dart | 1 + test/grpc_compression_flag_test.dart | 1 + test/grpc_web_test.dart | 2 ++ test/keepalive_test.dart | 2 ++ test/options_test.dart | 1 + test/proxy_secure_test.dart | 2 ++ test/proxy_test.dart | 2 ++ test/round_trip_test.dart | 2 ++ test/server_cancellation_test.dart | 2 ++ test/server_handles_broken_connection_test.dart | 2 ++ test/server_test.dart | 1 + test/timeline_test.dart | 2 ++ 18 files changed, 28 insertions(+), 1 deletion(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 01c74eb..92df2d3 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -17,5 +17,4 @@ linter: - prefer_final_locals - prefer_single_quotes - test_types_in_equals - - use_super_parameters - prefer_relative_imports diff --git a/test/client_certificate_test.dart b/test/client_certificate_test.dart index 9edde69..70bb2b9 100644 --- a/test/client_certificate_test.dart +++ b/test/client_certificate_test.dart @@ -16,6 +16,8 @@ // TODO(dartbug.com/26057) currently Mac OS X seems to have some issues with // client certificates so we disable the test. @TestOn('vm && !mac-os') +library; + import 'dart:async'; import 'dart:io'; diff --git a/test/client_handles_bad_connections_test.dart b/test/client_handles_bad_connections_test.dart index 26a6045..75114d7 100644 --- a/test/client_handles_bad_connections_test.dart +++ b/test/client_handles_bad_connections_test.dart @@ -14,6 +14,8 @@ // limitations under the License. @TestOn('vm') +library; + import 'dart:async'; import 'package:grpc/grpc.dart' as grpc; diff --git a/test/client_tests/client_xhr_transport_test.dart b/test/client_tests/client_xhr_transport_test.dart index 4b3f858..ece7943 100644 --- a/test/client_tests/client_xhr_transport_test.dart +++ b/test/client_tests/client_xhr_transport_test.dart @@ -13,6 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. @TestOn('browser') +library; import 'dart:async'; import 'dart:html'; 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 bffd8ba..1db9bda 100644 --- a/test/client_tests/grpc_or_grpcweb_channel_grpc_test.dart +++ b/test/client_tests/grpc_or_grpcweb_channel_grpc_test.dart @@ -13,6 +13,8 @@ // See the License for the specific language governing permissions and // limitations under the License. @TestOn('!browser') +library; + import 'package:grpc/grpc.dart'; import 'package:grpc/grpc_or_grpcweb.dart'; import 'package:test/test.dart'; 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 77fbe70..3bd9329 100644 --- a/test/client_tests/grpc_or_grpcweb_channel_web_test.dart +++ b/test/client_tests/grpc_or_grpcweb_channel_web_test.dart @@ -13,6 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. @TestOn('browser') +library; import 'package:grpc/grpc_or_grpcweb.dart'; import 'package:grpc/grpc_web.dart'; diff --git a/test/connection_server_test.dart b/test/connection_server_test.dart index 16969c1..d435773 100644 --- a/test/connection_server_test.dart +++ b/test/connection_server_test.dart @@ -13,6 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. @TestOn('vm') +library; import 'dart:async'; diff --git a/test/grpc_compression_flag_test.dart b/test/grpc_compression_flag_test.dart index 97ece91..a41b699 100644 --- a/test/grpc_compression_flag_test.dart +++ b/test/grpc_compression_flag_test.dart @@ -14,6 +14,7 @@ // limitations under the License. @TestOn('vm') +library; import 'package:grpc/src/shared/codec.dart'; import 'package:grpc/src/shared/message.dart'; diff --git a/test/grpc_web_test.dart b/test/grpc_web_test.dart index fb96f90..dd5fccb 100644 --- a/test/grpc_web_test.dart +++ b/test/grpc_web_test.dart @@ -14,6 +14,8 @@ // limitations under the License. @TestOn('browser') +library; + import 'dart:async'; import 'dart:math' as math; diff --git a/test/keepalive_test.dart b/test/keepalive_test.dart index a63c608..7ffa115 100644 --- a/test/keepalive_test.dart +++ b/test/keepalive_test.dart @@ -14,6 +14,8 @@ // limitations under the License. @TestOn('vm') +library; + import 'dart:async'; import 'package:grpc/grpc.dart'; diff --git a/test/options_test.dart b/test/options_test.dart index c61d82f..edb3a24 100644 --- a/test/options_test.dart +++ b/test/options_test.dart @@ -13,6 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. @TestOn('vm') +library; import 'dart:io'; diff --git a/test/proxy_secure_test.dart b/test/proxy_secure_test.dart index 257103e..d4deb25 100644 --- a/test/proxy_secure_test.dart +++ b/test/proxy_secure_test.dart @@ -14,6 +14,8 @@ // limitations under the License. @TestOn('vm') +library; + import 'dart:async'; import 'dart:io'; diff --git a/test/proxy_test.dart b/test/proxy_test.dart index 522d65a..ec832af 100644 --- a/test/proxy_test.dart +++ b/test/proxy_test.dart @@ -14,6 +14,8 @@ // limitations under the License. @TestOn('vm') +library; + import 'dart:async'; import 'package:grpc/grpc.dart'; diff --git a/test/round_trip_test.dart b/test/round_trip_test.dart index 67e3dcf..5d07fc8 100644 --- a/test/round_trip_test.dart +++ b/test/round_trip_test.dart @@ -14,6 +14,8 @@ // limitations under the License. @TestOn('vm') +library; + import 'dart:async'; import 'dart:io'; diff --git a/test/server_cancellation_test.dart b/test/server_cancellation_test.dart index ff4cd85..4de5aa2 100644 --- a/test/server_cancellation_test.dart +++ b/test/server_cancellation_test.dart @@ -14,6 +14,8 @@ // limitations under the License. @TestOn('vm') +library; + import 'package:grpc/grpc.dart'; import 'package:test/test.dart'; diff --git a/test/server_handles_broken_connection_test.dart b/test/server_handles_broken_connection_test.dart index 38d15ac..c59c9da 100644 --- a/test/server_handles_broken_connection_test.dart +++ b/test/server_handles_broken_connection_test.dart @@ -14,6 +14,8 @@ // limitations under the License. @TestOn('vm') +library; + import 'dart:async'; import 'dart:io'; import 'dart:isolate'; diff --git a/test/server_test.dart b/test/server_test.dart index 63a957c..b323f77 100644 --- a/test/server_test.dart +++ b/test/server_test.dart @@ -13,6 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. @TestOn('vm') +library; import 'dart:async'; diff --git a/test/timeline_test.dart b/test/timeline_test.dart index c429198..1866ea5 100644 --- a/test/timeline_test.dart +++ b/test/timeline_test.dart @@ -16,6 +16,8 @@ @TestOn('vm') @Skip( 'Run only as `dart run --enable-vm-service --timeline-streams=Dart test/timeline_test.dart`') +library; + import 'dart:async'; import 'dart:developer' as dev; From dee1b2b43b5059ac625cf915ac062dc13ab0f274 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Wed, 29 May 2024 17:23:53 -0700 Subject: [PATCH 13/32] Update pubspec.yaml --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 9e3dcd7..de16e0f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -21,7 +21,7 @@ dependencies: dev_dependencies: build_runner: ^2.0.0 build_test: ^2.0.0 - lints: ">=2.0.0 <5.0.0" + lints: ^4.0.0 mockito: ^5.0.0 path: ^1.8.0 test: ^1.16.0 From 4aa4c8cb8dda7c83946ea5b55b9e69650e617f73 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2024 11:52:08 +0000 Subject: [PATCH 14/32] Bump actions/checkout from 4.1.6 to 4.1.7 (#719) --- .github/workflows/dart.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index 6b3a513..d5a5c78 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -18,7 +18,7 @@ jobs: matrix: sdk: [3.2.0, dev] steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 with: sdk: ${{ matrix.sdk }} @@ -70,7 +70,7 @@ jobs: - os: macos-latest platform: chrome steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 with: sdk: ${{ matrix.sdk }} From bf8bbde34cb210cc757b1e64686c0fe4ea550e35 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2024 11:56:47 +0000 Subject: [PATCH 15/32] Bump dart-lang/setup-dart from 1.6.4 to 1.6.5 (#720) --- .github/workflows/dart.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index d5a5c78..2f58e62 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -19,7 +19,7 @@ jobs: sdk: [3.2.0, dev] steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 - - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 + - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 with: sdk: ${{ matrix.sdk }} - name: Report version @@ -71,7 +71,7 @@ jobs: platform: chrome steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 - - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 + - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 with: sdk: ${{ matrix.sdk }} - name: Report version From b999b64502508177811e7316580230b8afef780d Mon Sep 17 00:00:00 2001 From: Galen Warren Date: Wed, 17 Jul 2024 08:11:29 -0400 Subject: [PATCH 16/32] feat: fix hang that occurs when hot restarting (#718) --- CHANGELOG.md | 1 + lib/src/client/transport/web_streams.dart | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d336d3d..398f2c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * Remove generated status codes. * Remove dependency on `package:archive`. * Move `codec.dart`. +* Work around hang during Flutter hot restart by adding default case handler in _GrpcWebConversionSink.add. ## 3.2.4 diff --git a/lib/src/client/transport/web_streams.dart b/lib/src/client/transport/web_streams.dart index aba0a7b..8480ab2 100644 --- a/lib/src/client/transport/web_streams.dart +++ b/lib/src/client/transport/web_streams.dart @@ -132,6 +132,16 @@ class _GrpcWebConversionSink implements ChunkedConversionSink { void add(ByteBuffer chunk) { _chunkOffset = 0; final chunkData = chunk.asUint8List(); + // in flutter web, when a hot-restart is requested, the code can get stuck + // in the following loop if there is an active streaming call. the + // switch statement is invoked but doesn't match any of the cases. this + // presumably has something to do how enums work across isolates. + // possibly related to https://github.com/dart-lang/sdk/issues/35626. + // + // in any case, adding a default handler to the switch statement + // causes this loop to end in that case, allowing the old isolate + // to shut down and the hot-restart to work properly. + processingLoop: while (_chunkOffset < chunk.lengthInBytes) { switch (_state) { case _GrpcWebParseState.init: @@ -143,6 +153,9 @@ class _GrpcWebConversionSink implements ChunkedConversionSink { case _GrpcWebParseState.message: _parseMessage(chunkData); break; + default: + // only expected to be hit when hot-restarting, see above + break processingLoop; } } _chunkOffset = 0; From c18e185bb09d94a6760e4c43c9bf8c05c0f0e4c9 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Wed, 24 Jul 2024 14:24:57 -0700 Subject: [PATCH 17/32] Fix status badge (#726) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 667f28d..1e0419a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ The [Dart](https://www.dart.dev/) implementation of [gRPC](https://grpc.io/): A high performance, open source, general RPC framework that puts mobile and HTTP/2 first. -[![CI status](https://github.com/grpc/grpc-dart/workflows/Dart/badge.svg)](https://github.com/grpc/grpc-dart/actions?query=workflow%3A%22Dart%22+branch%3Amaster) +[![Dart](https://github.com/grpc/grpc-dart/actions/workflows/dart.yml/badge.svg)](https://github.com/grpc/grpc-dart/actions/workflows/dart.yml) [![pub package](https://img.shields.io/pub/v/grpc.svg)](https://pub.dev/packages/grpc) From 4f6fe9b1114aa5bd9d97e5d3b5ae2cb354804a1f Mon Sep 17 00:00:00 2001 From: c-lucera-pvotal <91328643+c-lucera-pvotal@users.noreply.github.com> Date: Wed, 28 Aug 2024 08:18:15 +0200 Subject: [PATCH 18/32] fix: fix headers not completing when call is terminated (#728) Fixes #727 --- CHANGELOG.md | 4 ++ lib/src/client/call.dart | 6 +++ pubspec.yaml | 2 +- test/client_tests/call_test.dart | 69 ++++++++++++++++++++++++++++++++ test/keepalive_test.dart | 2 +- 5 files changed, 81 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 398f2c8..6e1faa3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.0.1 + +* Fix header and trailing not completing if the call is terminated. Fixes [#727](https://github.com/grpc/grpc-dart/issues/727) + ## 4.0.0 * Set compressed flag correctly for grpc-encoding = identity. Fixes [#669](https://github.com/grpc/grpc-dart/issues/669) (https://github.com/grpc/grpc-dart/pull/693) diff --git a/lib/src/client/call.dart b/lib/src/client/call.dart index 8d5918f..7010313 100644 --- a/lib/src/client/call.dart +++ b/lib/src/client/call.dart @@ -483,6 +483,12 @@ class ClientCall implements Response { if (_responseSubscription != null) { futures.add(_responseSubscription!.cancel()); } + if (!_headers.isCompleted) { + _headers.complete({}); + } + if (!_trailers.isCompleted) { + _trailers.complete({}); + } await Future.wait(futures); } diff --git a/pubspec.yaml b/pubspec.yaml index de16e0f..3ada1c6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: grpc description: Dart implementation of gRPC, a high performance, open-source universal RPC framework. -version: 4.0.0 +version: 4.0.1 repository: https://github.com/grpc/grpc-dart diff --git a/test/client_tests/call_test.dart b/test/client_tests/call_test.dart index c519f6e..9ce832b 100644 --- a/test/client_tests/call_test.dart +++ b/test/client_tests/call_test.dart @@ -13,10 +13,26 @@ // See the License for the specific language governing permissions and // limitations under the License. +import 'package:grpc/grpc.dart'; import 'package:grpc/src/client/call.dart'; import 'package:test/test.dart'; +import '../src/client_utils.dart'; + void main() { + const dummyValue = 0; + const cancelDurationMillis = 300; + + late ClientHarness harness; + + setUp(() { + harness = ClientHarness()..setUp(); + }); + + tearDown(() { + harness.tearDown(); + }); + test('WebCallOptions mergeWith CallOptions returns WebCallOptions', () { final options = WebCallOptions(bypassCorsPreflight: true, withCredentials: true); @@ -28,4 +44,57 @@ void main() { expect(mergedOptions.bypassCorsPreflight, true); expect(mergedOptions.withCredentials, true); }); + + test( + 'Cancelling a call correctly complete headers future', + () async { + final clientCall = harness.client.unary(dummyValue); + + Future.delayed( + Duration(milliseconds: cancelDurationMillis), + ).then((_) => clientCall.cancel()); + + expect(await clientCall.headers, isEmpty); + + await expectLater( + clientCall, + throwsA( + isA().having( + (e) => e.codeName, + 'Test codename', + contains('CANCELLED'), + ), + ), + ); + }, + ); + + test( + 'Cancelling a call correctly complete trailers futures', + () async { + final clientCall = harness.client.unary(dummyValue); + + Future.delayed( + Duration(milliseconds: cancelDurationMillis), + ).then((_) { + clientCall.cancel(); + }); + + expect( + await clientCall.trailers, + isEmpty, + ); + + await expectLater( + clientCall, + throwsA( + isA().having( + (e) => e.codeName, + 'Test codename', + contains('CANCELLED'), + ), + ), + ); + }, + ); } diff --git a/test/keepalive_test.dart b/test/keepalive_test.dart index 7ffa115..4e71081 100644 --- a/test/keepalive_test.dart +++ b/test/keepalive_test.dart @@ -49,7 +49,7 @@ void main() { services: [FakeEchoService()], keepAliveOptions: serverOptions, ); - await server.serve(address: 'localhost', port: 8081); + await server.serve(address: 'localhost', port: 0); fakeChannel = FakeClientChannel( 'localhost', port: server.port!, From 38ca626e0a713550b3d82c1ad62a923328f4f5c9 Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Mon, 2 Sep 2024 16:58:43 +0200 Subject: [PATCH 19/32] Use `Map.of` instead of `Map.from` in grpc client. (#724) * Use `Map.of` instead of `Map.from` in grpc client. `Map.of` creates a new map with the same keys, values and *type* as the original map, when used without type arguments or context type, where `Map.from` creates a `Map`. (This code failed on an attempt to make `Map.unmodifiable` be more strictly typed, like `Map.of` instead of `Map.from`, showing that an intermediate map had type `Map` unnecessarily). Same for using `List.of` instead of `List.from`. The new code should be (microscopically) more efficient and type safe, and is forwards-compatible with a stronger type on `Map.unmodifiable`. (The code can be optimized more. For example `List.of(list1)..addAll(list2)` can be just `list1 + list2` or `[...list1, ...list2]`, both of which may know the total number of elements when doing the initial list allocation. This is a minimal change to allow the type changes for `.unmodifiable` to get past this very initial blocker in internal tests.) * Add changelog and minor version increment. And my save removes trailing spaces. --- CHANGELOG.md | 10 +++++++--- lib/src/client/call.dart | 10 +++++----- lib/src/shared/status.dart | 2 +- pubspec.yaml | 2 +- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e1faa3..4d55328 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.0.2 + +* Internal optimization to client code. + ## 4.0.1 * Fix header and trailing not completing if the call is terminated. Fixes [#727](https://github.com/grpc/grpc-dart/issues/727) @@ -31,19 +35,19 @@ ## 3.2.1 -* `package:http` now supports more versions: `>=0.13.0 <2.0.0`. +* `package:http` now supports more versions: `>=0.13.0 <2.0.0`. * `package:protobuf` new supports more versions: `>=2.0.0 <4.0.0`. ## 3.2.0 -* `ChannelOptions` now exposes `connectTimeout`, which is used on the +* `ChannelOptions` now exposes `connectTimeout`, which is used on the socket connect. This is used to specify the maximum allowed time to wait for a connection to be established. If `connectTime` is longer than the system level timeout duration, a timeout may occur sooner than specified in `connectTimeout`. On timeout, a `SocketException` is thrown. * Require Dart 2.17 or greater. * Fix issue [#51](https://github.com/grpc/grpc-dart/issues/51), add support for custom error handling. -* Expose client IP address to server +* Expose client IP address to server * Add a `channelShutdownHandler` argument to `ClientChannel` and the subclasses. This callback can be used to react to channel shutdown or termination. * Export the `Code` protobuf enum from the `grpc.dart` library. diff --git a/lib/src/client/call.dart b/lib/src/client/call.dart index 7010313..65f0de3 100644 --- a/lib/src/client/call.dart +++ b/lib/src/client/call.dart @@ -86,9 +86,9 @@ class CallOptions { CallOptions mergedWith(CallOptions? other) { if (other == null) return this; - final mergedMetadata = Map.from(metadata)..addAll(other.metadata); + final mergedMetadata = Map.of(metadata)..addAll(other.metadata); final mergedTimeout = other.timeout ?? timeout; - final mergedProviders = List.from(metadataProviders) + final mergedProviders = List.of(metadataProviders) ..addAll(other.metadataProviders); final mergedCompression = other.compression ?? compression; return CallOptions._( @@ -146,9 +146,9 @@ class WebCallOptions extends CallOptions { CallOptions mergedWith(CallOptions? other) { if (other == null) return this; - final mergedMetadata = Map.from(metadata)..addAll(other.metadata); + final mergedMetadata = Map.of(metadata)..addAll(other.metadata); final mergedTimeout = other.timeout ?? timeout; - final mergedProviders = List.from(metadataProviders) + final mergedProviders = List.of(metadataProviders) ..addAll(other.metadataProviders); if (other is! WebCallOptions) { @@ -241,7 +241,7 @@ class ClientCall implements Response { if (options.metadataProviders.isEmpty) { _sendRequest(connection, _sanitizeMetadata(options.metadata)); } else { - final metadata = Map.from(options.metadata); + final metadata = Map.of(options.metadata); Future.forEach( options.metadataProviders, (MetadataProvider provider) => provider(metadata, diff --git a/lib/src/shared/status.dart b/lib/src/shared/status.dart index e0474ac..4f8a9c1 100644 --- a/lib/src/shared/status.dart +++ b/lib/src/shared/status.dart @@ -473,7 +473,7 @@ GrpcError? grpcErrorDetailsFromTrailers(Map trailers) { } Map toCustomTrailers(Map trailers) { - return Map.from(trailers) + return Map.of(trailers) ..remove(':status') ..remove('content-type') ..remove('grpc-status') diff --git a/pubspec.yaml b/pubspec.yaml index 3ada1c6..e2f106d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: grpc description: Dart implementation of gRPC, a high performance, open-source universal RPC framework. -version: 4.0.1 +version: 4.0.2 repository: https://github.com/grpc/grpc-dart From 81776333d9433f8e04ecab8f47e7b25abe623204 Mon Sep 17 00:00:00 2001 From: Moritz Date: Fri, 6 Sep 2024 15:09:54 +0200 Subject: [PATCH 20/32] Small fixes (#732) * Small fixes * Revert changes on file * Add changelog * Small fixes in keepalive test * Add delay * Fix symbol visibilty * Add try catch for debugging * Fail * fail * Use for loop --- .github/workflows/dart.yml | 2 +- CHANGELOG.md | 3 +- README.md | 2 +- lib/src/shared/status.dart | 1 + pubspec.yaml | 2 +- .../client_xhr_transport_test.dart | 2 +- .../grpc_or_grpcweb_channel_grpc_test.dart | 2 +- .../grpc_or_grpcweb_channel_web_test.dart | 2 +- test/keepalive_test.dart | 38 ++++++++++--------- test/proxy_secure_test.dart | 4 +- test/proxy_test.dart | 4 +- test/server_cancellation_test.dart | 2 +- test/tools/http2_client.dart | 4 +- 13 files changed, 36 insertions(+), 32 deletions(-) diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index 2f58e62..c80305b 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -93,5 +93,5 @@ jobs: - name: Run tests run: dart test --platform ${{ matrix.platform }} - name: Run vmservice test - if: ${{ matrix.platform != 'chrome' && false }} #Disable until https://github.com/grpc/grpc-dart/issues/697 is resolved + if: ${{ matrix.platform != 'chrome' }} run: dart run --enable-vm-service --timeline-streams=Dart test/timeline_test.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d55328..14b3032 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ -## 4.0.2 +## 4.0.2-wip * Internal optimization to client code. +* Small fixes, such as ports in testing and enabling `timeline_test.dart`. ## 4.0.1 diff --git a/README.md b/README.md index 1e0419a..f85542b 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ The [Dart](https://www.dart.dev/) implementation of ## Learn more - [Quick Start](https://grpc.io/docs/languages/dart/quickstart) - get an app running in minutes -- [Examples](example) +- [Examples](https://github.com/grpc/grpc-dart/tree/master/example) - [API reference](https://grpc.io/docs/languages/dart/api) For complete documentation, see [Dart gRPC](https://grpc.io/docs/languages/dart). diff --git a/lib/src/shared/status.dart b/lib/src/shared/status.dart index 4f8a9c1..cb66232 100644 --- a/lib/src/shared/status.dart +++ b/lib/src/shared/status.dart @@ -352,6 +352,7 @@ class GrpcError implements Exception { /// This list comes from `error_details.proto`. If any new error detail types are /// added to the protbuf definition, this function should be updated accordingly to /// support them. +@visibleForTesting GeneratedMessage parseErrorDetailsFromAny(Any any) { switch (any.typeUrl) { case 'type.googleapis.com/google.rpc.RetryInfo': diff --git a/pubspec.yaml b/pubspec.yaml index e2f106d..e89e71a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: grpc description: Dart implementation of gRPC, a high performance, open-source universal RPC framework. -version: 4.0.2 +version: 4.0.2-wip repository: https://github.com/grpc/grpc-dart diff --git a/test/client_tests/client_xhr_transport_test.dart b/test/client_tests/client_xhr_transport_test.dart index ece7943..1c58077 100644 --- a/test/client_tests/client_xhr_transport_test.dart +++ b/test/client_tests/client_xhr_transport_test.dart @@ -65,7 +65,7 @@ class MockHttpRequest extends Mock implements HttpRequest { class MockXhrClientConnection extends XhrClientConnection { MockXhrClientConnection({int? code}) : _statusCode = code ?? 200, - super(Uri.parse('test:8080')); + super(Uri.parse('test:0')); late MockHttpRequest latestRequest; final int _statusCode; 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 1db9bda..a2b6e4a 100644 --- a/test/client_tests/grpc_or_grpcweb_channel_grpc_test.dart +++ b/test/client_tests/grpc_or_grpcweb_channel_grpc_test.dart @@ -20,7 +20,7 @@ import 'package:grpc/grpc_or_grpcweb.dart'; import 'package:test/test.dart'; const host = 'example.com'; -const port = 8080; +const port = 0; void main() { test('Channel on non-web uses gRPC ClientChannel with correct params', () { 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 3bd9329..8382219 100644 --- a/test/client_tests/grpc_or_grpcweb_channel_web_test.dart +++ b/test/client_tests/grpc_or_grpcweb_channel_web_test.dart @@ -20,7 +20,7 @@ import 'package:grpc/grpc_web.dart'; import 'package:test/test.dart'; const host = 'example.com'; -const port = 8080; +const port = 0; void main() { test('Channel on web uses GrpcWebClientChannel with correct URI', () { diff --git a/test/keepalive_test.dart b/test/keepalive_test.dart index 4e71081..3da1b80 100644 --- a/test/keepalive_test.dart +++ b/test/keepalive_test.dart @@ -34,14 +34,18 @@ void main() { late EchoServiceClient unresponsiveClient; late ClientChannel unresponsiveChannel; + final pingInterval = Duration(milliseconds: 10); + final timeout = Duration(milliseconds: 30); + final maxBadPings = 5; + setUp(() async { final serverOptions = ServerKeepAliveOptions( - maxBadPings: 5, + maxBadPings: maxBadPings, minIntervalBetweenPingsWithoutData: Duration(milliseconds: 10), ); final clientOptions = ClientKeepAliveOptions( - pingInterval: Duration(milliseconds: 10), - timeout: Duration(milliseconds: 30), + pingInterval: pingInterval, + timeout: timeout, permitWithoutCalls: true, ); @@ -79,7 +83,7 @@ void main() { test('Server terminates connection after too many pings without data', () async { await fakeClient.echo(EchoRequest()); - await Future.delayed(Duration(milliseconds: 300)); + await Future.delayed(timeout * maxBadPings * 2); await fakeClient.echo(EchoRequest()); // Check that the server closed the connection, the next request then has // to build a new one. @@ -88,12 +92,10 @@ void main() { test('Server doesnt terminate connection after pings, as data is sent', () async { - final timer = Timer.periodic( - Duration(milliseconds: 10), (timer) => fakeClient.echo(EchoRequest())); - await Future.delayed(Duration(milliseconds: 200), () => timer.cancel()); - - // Wait for last request to be sent - await Future.delayed(Duration(milliseconds: 20)); + for (var i = 0; i < 10; i++) { + await fakeClient.echo(EchoRequest()); + await Future.delayed(timeout * 0.2); + } // Check that the server never closed the connection expect(fakeChannel.newConnectionCounter, 1); @@ -102,9 +104,11 @@ void main() { test('Server doesnt ack the ping, making the client shutdown the connection', () async { await unresponsiveClient.echo(EchoRequest()); - await Future.delayed(Duration(milliseconds: 200)); + await Future.delayed(timeout * 2); await expectLater( - unresponsiveClient.echo(EchoRequest()), throwsA(isA())); + unresponsiveClient.echo(EchoRequest()), + throwsA(isA()), + ); }); } @@ -113,7 +117,7 @@ class FakeClientChannel extends ClientChannel { FakeHttp2ClientConnection? fakeHttp2ClientConnection; FakeClientChannel( super.host, { - super.port = 443, + super.port, super.options = const ChannelOptions(), super.channelShutdownHandler, }); @@ -145,7 +149,7 @@ class FakeHttp2ClientConnection extends Http2ClientConnection { class UnresponsiveClientChannel extends ClientChannel { UnresponsiveClientChannel( super.host, { - super.port = 443, + super.port, super.options = const ChannelOptions(), super.channelShutdownHandler, }); @@ -189,8 +193,6 @@ class FakeEchoService extends EchoServiceBase { @override Stream serverStreamingEcho( - ServiceCall call, ServerStreamingEchoRequest request) { - // TODO: implement serverStreamingEcho - throw UnimplementedError(); - } + ServiceCall call, ServerStreamingEchoRequest request) => + throw UnsupportedError('Not used in this test'); } diff --git a/test/proxy_secure_test.dart b/test/proxy_secure_test.dart index d4deb25..806913b 100644 --- a/test/proxy_secure_test.dart +++ b/test/proxy_secure_test.dart @@ -33,13 +33,13 @@ void main() { server = Server.create(services: [FakeEchoService()]); await server.serve( address: 'localhost', - port: 8888, + port: 0, security: ServerTlsCredentials( certificate: File('test/data/localhost.crt').readAsBytesSync(), privateKey: File('test/data/localhost.key').readAsBytesSync(), ), ); - final proxy = Proxy(host: 'localhost', port: 8080); + final proxy = Proxy(host: 'localhost', port: 0); final proxyCAName = '/CN=mitmproxy/O=mitmproxy'; fakeChannel = ClientChannel( diff --git a/test/proxy_test.dart b/test/proxy_test.dart index ec832af..6fc3072 100644 --- a/test/proxy_test.dart +++ b/test/proxy_test.dart @@ -30,9 +30,9 @@ void main() { setUp(() async { server = Server.create(services: [FakeEchoService()]); - await server.serve(address: 'localhost', port: 8888); + await server.serve(address: 'localhost', port: 0); - final proxy = Proxy(host: 'localhost', port: 8080); + final proxy = Proxy(host: 'localhost', port: 0); fakeChannel = ClientChannel( 'localhost', diff --git a/test/server_cancellation_test.dart b/test/server_cancellation_test.dart index 4de5aa2..ab119bb 100644 --- a/test/server_cancellation_test.dart +++ b/test/server_cancellation_test.dart @@ -47,7 +47,7 @@ void main() { server = Server.create( services: [EchoService()], ); - await server.serve(address: 'localhost', port: 8081); + await server.serve(address: 'localhost', port: 0); channel = ClientChannel( 'localhost', port: server.port!, diff --git a/test/tools/http2_client.dart b/test/tools/http2_client.dart index d7359cd..9bd4004 100644 --- a/test/tools/http2_client.dart +++ b/test/tools/http2_client.dart @@ -20,7 +20,7 @@ import 'package:grpc/src/client/http2_connection.dart'; import 'package:http2/http2.dart'; Future main(List args) async { - final serverPort = 5678; + final serverPort = 0; final proxyPort = int.tryParse(args.first); final proxy = @@ -37,7 +37,7 @@ Future main(List args) async { final incoming = proxy == null ? connector.socket : await connector.connectToProxy(proxy); - final uri = Uri.parse('http://localhost:8080'); + final uri = Uri.parse('http://localhost:0'); final transport = ClientTransportConnection.viaStreams(incoming, connector.socket); From 071ebc5f31a18ab52e82c09558f3dcb85f41fdbd Mon Sep 17 00:00:00 2001 From: steffenhaak Date: Fri, 6 Sep 2024 17:13:11 +0200 Subject: [PATCH 21/32] fix: keep alive timeout finishes transport instead of connection shutdown (#722) * fix: keep alive timeout finishes transport instead of shutting down channel * Update keepalive_test.dart * Update CHANGELOG.md --------- Co-authored-by: Moritz --- CHANGELOG.md | 2 ++ lib/src/client/http2_connection.dart | 2 +- test/keepalive_test.dart | 27 +++++++++++++++++---------- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14b3032..0f463fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ * Internal optimization to client code. * Small fixes, such as ports in testing and enabling `timeline_test.dart`. +* When the keep alive manager runs into a timeout, it will finish the transport instead of closing + the connection, as defined in the gRPC spec. ## 4.0.1 diff --git a/lib/src/client/http2_connection.dart b/lib/src/client/http2_connection.dart index 998410a..4cce677 100644 --- a/lib/src/client/http2_connection.dart +++ b/lib/src/client/http2_connection.dart @@ -113,7 +113,7 @@ class Http2ClientConnection implements connection.ClientConnection { transport.ping(); } }, - onPingTimeout: () => shutdown(), + onPingTimeout: () => transport.finish(), ); transport.onFrameReceived .listen((_) => keepAliveManager?.onFrameReceived()); diff --git a/test/keepalive_test.dart b/test/keepalive_test.dart index 3da1b80..bf48f9b 100644 --- a/test/keepalive_test.dart +++ b/test/keepalive_test.dart @@ -32,7 +32,7 @@ void main() { late EchoServiceClient fakeClient; late FakeClientChannel fakeChannel; late EchoServiceClient unresponsiveClient; - late ClientChannel unresponsiveChannel; + late FakeClientChannel unresponsiveChannel; final pingInterval = Duration(milliseconds: 10); final timeout = Duration(milliseconds: 30); @@ -101,14 +101,18 @@ void main() { expect(fakeChannel.newConnectionCounter, 1); }); - test('Server doesnt ack the ping, making the client shutdown the connection', + test('Server doesnt ack the ping, making the client shutdown the transport', () async { + //Send a first request, get a connection await unresponsiveClient.echo(EchoRequest()); + expect(unresponsiveChannel.newConnectionCounter, 1); + + //Ping is not being acked on time await Future.delayed(timeout * 2); - await expectLater( - unresponsiveClient.echo(EchoRequest()), - throwsA(isA()), - ); + + //A second request gets a new connection + await unresponsiveClient.echo(EchoRequest()); + expect(unresponsiveChannel.newConnectionCounter, 2); }); } @@ -146,7 +150,7 @@ class FakeHttp2ClientConnection extends Http2ClientConnection { } /// A wrapper around a [FakeHttp2ClientConnection] -class UnresponsiveClientChannel extends ClientChannel { +class UnresponsiveClientChannel extends FakeClientChannel { UnresponsiveClientChannel( super.host, { super.port, @@ -155,11 +159,14 @@ class UnresponsiveClientChannel extends ClientChannel { }); @override - ClientConnection createConnection() => - UnresponsiveHttp2ClientConnection(host, port, options); + ClientConnection createConnection() { + fakeHttp2ClientConnection = + UnresponsiveHttp2ClientConnection(host, port, options); + return fakeHttp2ClientConnection!; + } } -class UnresponsiveHttp2ClientConnection extends Http2ClientConnection { +class UnresponsiveHttp2ClientConnection extends FakeHttp2ClientConnection { UnresponsiveHttp2ClientConnection(super.host, super.port, super.options); @override From f8bbdce629a02188c9919c5c8f601362e857f36e Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Tue, 24 Sep 2024 12:07:42 -0700 Subject: [PATCH 22/32] ignore unreachable_switch_default in weird switch case (#737) --- lib/src/client/transport/web_streams.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/client/transport/web_streams.dart b/lib/src/client/transport/web_streams.dart index 8480ab2..d4100ad 100644 --- a/lib/src/client/transport/web_streams.dart +++ b/lib/src/client/transport/web_streams.dart @@ -153,6 +153,7 @@ class _GrpcWebConversionSink implements ChunkedConversionSink { case _GrpcWebParseState.message: _parseMessage(chunkData); break; + // ignore: unreachable_switch_default default: // only expected to be hit when hot-restarting, see above break processingLoop; From 04ba68eb91f50f8bd1db527c31c881b18c38f425 Mon Sep 17 00:00:00 2001 From: Moritz Date: Tue, 1 Oct 2024 04:46:38 -0400 Subject: [PATCH 23/32] Rev package:lints (#740) * Rev package:lints * Add changelog * Run CI on 3.5.0 * Test with 3.2.0 * Update .github/workflows/dart.yml Co-authored-by: Kevin Moore * Update .github/workflows/dart.yml Co-authored-by: Kevin Moore --------- Co-authored-by: Kevin Moore --- .github/workflows/dart.yml | 4 ++-- CHANGELOG.md | 1 + analysis_options.yaml | 21 ++++++++++++--------- lib/service_api.dart | 2 +- pubspec.yaml | 4 ++-- 5 files changed, 18 insertions(+), 14 deletions(-) diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index c80305b..ced3c7f 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - sdk: [3.2.0, dev] + sdk: [3.5, dev] steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 @@ -60,7 +60,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - sdk: [3.2.0, dev] + sdk: [3.5, dev] platform: [vm, chrome] exclude: # We only run Chrome tests on Linux. No need to run them diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f463fb..684f1d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * Small fixes, such as ports in testing and enabling `timeline_test.dart`. * When the keep alive manager runs into a timeout, it will finish the transport instead of closing the connection, as defined in the gRPC spec. +* Upgrade to `package:lints` version 5.0.0 and Dart SDK version 3.5.0. ## 4.0.1 diff --git a/analysis_options.yaml b/analysis_options.yaml index 92df2d3..5bcd150 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -9,12 +9,15 @@ analyzer: linter: rules: - - always_declare_return_types - - cancel_subscriptions - - close_sinks - - directives_ordering - - omit_local_variable_types - - prefer_final_locals - - prefer_single_quotes - - test_types_in_equals - - prefer_relative_imports + #true + always_declare_return_types: true + cancel_subscriptions: true + close_sinks: true + directives_ordering: true + omit_local_variable_types: true + prefer_final_locals: true + prefer_single_quotes: true + test_types_in_equals: true + prefer_relative_imports: true + #false + unintended_html_in_doc_comment: false diff --git a/lib/service_api.dart b/lib/service_api.dart index 53d056d..026b26b 100644 --- a/lib/service_api.dart +++ b/lib/service_api.dart @@ -16,7 +16,7 @@ /// Exports the minimum api to define server and client stubs. /// /// Mainly intended to be imported by generated code. -library service_api; +library; export 'src/client/call.dart' show CallOptions, MetadataProvider; export 'src/client/channel.dart' show ClientChannel; diff --git a/pubspec.yaml b/pubspec.yaml index e89e71a..8c393db 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,7 +5,7 @@ version: 4.0.2-wip repository: https://github.com/grpc/grpc-dart environment: - sdk: ^3.2.0 + sdk: ^3.5.0 dependencies: async: ^2.5.0 @@ -21,7 +21,7 @@ dependencies: dev_dependencies: build_runner: ^2.0.0 build_test: ^2.0.0 - lints: ^4.0.0 + lints: ^5.0.0 mockito: ^5.0.0 path: ^1.8.0 test: ^1.16.0 From c0630106a97b22f6e726937314452c6c1d2786e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 08:51:16 +0000 Subject: [PATCH 24/32] Bump actions/checkout from 4.1.7 to 4.2.0 (#741) --- .github/workflows/dart.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index ced3c7f..c9ccd16 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -18,7 +18,7 @@ jobs: matrix: sdk: [3.5, dev] steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 with: sdk: ${{ matrix.sdk }} @@ -70,7 +70,7 @@ jobs: - os: macos-latest platform: chrome steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 with: sdk: ${{ matrix.sdk }} From f61b9a3b375d83075365ded58efcd4ae9bc2d5ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 10:45:05 +0000 Subject: [PATCH 25/32] Bump actions/checkout from 4.2.0 to 4.2.2 (#744) --- .github/workflows/dart.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index c9ccd16..1651e58 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -18,7 +18,7 @@ jobs: matrix: sdk: [3.5, dev] steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 with: sdk: ${{ matrix.sdk }} @@ -70,7 +70,7 @@ jobs: - os: macos-latest platform: chrome steps: - - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 with: sdk: ${{ matrix.sdk }} From 6676c20df28bbf3f4eb5d9f6f8da9809202b4e0d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 13:37:35 +0000 Subject: [PATCH 26/32] Bump dart-lang/setup-dart from 1.6.5 to 1.7.0 (#746) --- .github/workflows/dart.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index 1651e58..1a8175f 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -19,7 +19,7 @@ jobs: sdk: [3.5, dev] steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 + - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94 with: sdk: ${{ matrix.sdk }} - name: Report version @@ -71,7 +71,7 @@ jobs: platform: chrome steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 + - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94 with: sdk: ${{ matrix.sdk }} - name: Report version From 3e94fecd144ede76812967741cef1faa287d0b63 Mon Sep 17 00:00:00 2001 From: Moritz Date: Tue, 17 Dec 2024 09:53:02 +0100 Subject: [PATCH 27/32] Update health.yaml (#753) * Update health.yaml * Upgrade example * Fixes * try different syntax * without endings * test new wf * new version * Works, use main now * Add changelog --- .github/workflows/health.yaml | 7 ++++--- CHANGELOG.md | 1 + example/grpc-web/pubspec.yaml | 8 ++++---- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/health.yaml b/.github/workflows/health.yaml index 9d32c20..3ba41f3 100644 --- a/.github/workflows/health.yaml +++ b/.github/workflows/health.yaml @@ -5,8 +5,9 @@ on: types: [opened, synchronize, reopened, labeled, unlabeled] jobs: health: - uses: dart-lang/ecosystem/.github/workflows/health.yaml@9fabe464ea1d8408774de74d2ac759c1f90ae480 + uses: dart-lang/ecosystem/.github/workflows/health.yaml@main with: - checks: "version,changelog,do-not-submit,breaking,coverage,leaking" + checks: "changelog,do-not-submit,breaking,coverage,leaking" + ignore_coverage: "example/**,interop/**" permissions: - pull-requests: write \ No newline at end of file + pull-requests: write diff --git a/CHANGELOG.md b/CHANGELOG.md index 684f1d6..273cc7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * When the keep alive manager runs into a timeout, it will finish the transport instead of closing the connection, as defined in the gRPC spec. * Upgrade to `package:lints` version 5.0.0 and Dart SDK version 3.5.0. +* Upgrade `example/grpc-web` code. ## 4.0.1 diff --git a/example/grpc-web/pubspec.yaml b/example/grpc-web/pubspec.yaml index e215c13..10f80ce 100644 --- a/example/grpc-web/pubspec.yaml +++ b/example/grpc-web/pubspec.yaml @@ -3,7 +3,7 @@ description: Dart gRPC-Web sample client publish_to: none environment: - sdk: '>=2.12.0 <3.0.0' + sdk: ^3.5.0 dependencies: grpc: @@ -11,6 +11,6 @@ dependencies: protobuf: ^3.0.0 dev_dependencies: - build_runner: ^2.0.0 - build_web_compilers: '>3.0.0 <5.0.0' - lints: ^2.0.0 + build_runner: ^2.4.13 + build_web_compilers: ^4.0.11 + lints: ^5.0.0 From 9a9c01752cbe9e96022b7c30a329778a41d56c48 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Dec 2024 09:58:22 +0100 Subject: [PATCH 28/32] Bump vm_service from 14.3.1 to 15.0.0 (#751) Bumps [vm_service](https://github.com/dart-lang/sdk/tree/main/pkg) from 14.3.1 to 15.0.0. - [Changelog](https://github.com/dart-lang/sdk/blob/main/CHANGELOG.md) - [Commits](https://github.com/dart-lang/sdk/commits/HEAD/pkg) --- updated-dependencies: - dependency-name: vm_service dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Moritz --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 8c393db..26f9ab1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,7 +27,7 @@ dev_dependencies: test: ^1.16.0 stream_channel: ^2.1.0 stream_transform: ^2.0.0 - vm_service: ">=11.6.0 <15.0.0" + vm_service: ">=11.6.0 <16.0.0" fake_async: ^1.3.1 false_secrets: From 16328209c2ac9e0658a13178351ac649da20820d Mon Sep 17 00:00:00 2001 From: Tsavo Knott Date: Fri, 3 Jan 2025 13:00:20 -0500 Subject: [PATCH 29/32] True Upstream Master --- CHANGELOG.md | 1 + example/googleapis/googleapis.iml | 16 -- example/googleapis/pubspec_overrides.yaml | 4 - example/grpc-web/grpc_web.iml | 16 -- example/grpc-web/pubspec_overrides.yaml | 4 - example/helloworld/helloworld.iml | 16 -- example/helloworld/pubspec_overrides.yaml | 4 - example/metadata/metadata.iml | 16 -- example/metadata/pubspec_overrides.yaml | 4 - example/route_guide/pubspec_overrides.yaml | 4 - example/route_guide/route_guide.iml | 16 -- grpc.iml | 18 --- interop/interop.iml | 16 -- interop/pubspec.yaml | 12 +- interop/pubspec_overrides.yaml | 4 - lib/grpc_or_grpcweb.dart | 2 +- lib/src/client/transport/xhr_transport.dart | 153 +++++++++++++++--- pubspec.yaml | 32 ++-- .../client_keepalive_manager_test.mocks.dart | 6 +- .../client_xhr_transport_test.dart | 56 +++---- test/connection_server_test.dart | 4 +- test/server_test.dart | 4 +- test/src/client_utils.mocks.dart | 21 +-- 23 files changed, 193 insertions(+), 236 deletions(-) delete mode 100644 example/googleapis/googleapis.iml delete mode 100644 example/googleapis/pubspec_overrides.yaml delete mode 100644 example/grpc-web/grpc_web.iml delete mode 100644 example/grpc-web/pubspec_overrides.yaml delete mode 100644 example/helloworld/helloworld.iml delete mode 100644 example/helloworld/pubspec_overrides.yaml delete mode 100644 example/metadata/metadata.iml delete mode 100644 example/metadata/pubspec_overrides.yaml delete mode 100644 example/route_guide/pubspec_overrides.yaml delete mode 100644 example/route_guide/route_guide.iml delete mode 100644 grpc.iml delete mode 100644 interop/interop.iml delete mode 100644 interop/pubspec_overrides.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index 273cc7c..ad86f53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ the connection, as defined in the gRPC spec. * Upgrade to `package:lints` version 5.0.0 and Dart SDK version 3.5.0. * Upgrade `example/grpc-web` code. +* Update xhr transport to migrate off legacy JS/HTML apis. ## 4.0.1 diff --git a/example/googleapis/googleapis.iml b/example/googleapis/googleapis.iml deleted file mode 100644 index 389d07a..0000000 --- a/example/googleapis/googleapis.iml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/example/googleapis/pubspec_overrides.yaml b/example/googleapis/pubspec_overrides.yaml deleted file mode 100644 index c691769..0000000 --- a/example/googleapis/pubspec_overrides.yaml +++ /dev/null @@ -1,4 +0,0 @@ -# melos_managed_dependency_overrides: grpc -dependency_overrides: - grpc: - path: ../.. diff --git a/example/grpc-web/grpc_web.iml b/example/grpc-web/grpc_web.iml deleted file mode 100644 index 389d07a..0000000 --- a/example/grpc-web/grpc_web.iml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/example/grpc-web/pubspec_overrides.yaml b/example/grpc-web/pubspec_overrides.yaml deleted file mode 100644 index c691769..0000000 --- a/example/grpc-web/pubspec_overrides.yaml +++ /dev/null @@ -1,4 +0,0 @@ -# melos_managed_dependency_overrides: grpc -dependency_overrides: - grpc: - path: ../.. diff --git a/example/helloworld/helloworld.iml b/example/helloworld/helloworld.iml deleted file mode 100644 index 389d07a..0000000 --- a/example/helloworld/helloworld.iml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/example/helloworld/pubspec_overrides.yaml b/example/helloworld/pubspec_overrides.yaml deleted file mode 100644 index c691769..0000000 --- a/example/helloworld/pubspec_overrides.yaml +++ /dev/null @@ -1,4 +0,0 @@ -# melos_managed_dependency_overrides: grpc -dependency_overrides: - grpc: - path: ../.. diff --git a/example/metadata/metadata.iml b/example/metadata/metadata.iml deleted file mode 100644 index 389d07a..0000000 --- a/example/metadata/metadata.iml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/example/metadata/pubspec_overrides.yaml b/example/metadata/pubspec_overrides.yaml deleted file mode 100644 index c691769..0000000 --- a/example/metadata/pubspec_overrides.yaml +++ /dev/null @@ -1,4 +0,0 @@ -# melos_managed_dependency_overrides: grpc -dependency_overrides: - grpc: - path: ../.. diff --git a/example/route_guide/pubspec_overrides.yaml b/example/route_guide/pubspec_overrides.yaml deleted file mode 100644 index c691769..0000000 --- a/example/route_guide/pubspec_overrides.yaml +++ /dev/null @@ -1,4 +0,0 @@ -# melos_managed_dependency_overrides: grpc -dependency_overrides: - grpc: - path: ../.. diff --git a/example/route_guide/route_guide.iml b/example/route_guide/route_guide.iml deleted file mode 100644 index 389d07a..0000000 --- a/example/route_guide/route_guide.iml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/grpc.iml b/grpc.iml deleted file mode 100644 index 74e5a87..0000000 --- a/grpc.iml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/interop/interop.iml b/interop/interop.iml deleted file mode 100644 index 389d07a..0000000 --- a/interop/interop.iml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/interop/pubspec.yaml b/interop/pubspec.yaml index 40b946a..f4038fa 100644 --- a/interop/pubspec.yaml +++ b/interop/pubspec.yaml @@ -3,15 +3,15 @@ description: Dart gRPC interoperability test suite. publish_to: none environment: - sdk: '>=3.0.0 <4.0.0' + sdk: ^3.0.0 dependencies: - args: ^2.5.0 - async: ^2.11.0 - collection: ^1.18.0 + args: ^2.0.0 + async: ^2.2.0 + collection: ^1.14.11 grpc: path: ../ - protobuf: ^3.1.0 + protobuf: ^3.0.0 dev_dependencies: - test: ^1.25.3 + test: ^1.16.0 diff --git a/interop/pubspec_overrides.yaml b/interop/pubspec_overrides.yaml deleted file mode 100644 index 917447a..0000000 --- a/interop/pubspec_overrides.yaml +++ /dev/null @@ -1,4 +0,0 @@ -# melos_managed_dependency_overrides: grpc -dependency_overrides: - grpc: - path: .. diff --git a/lib/grpc_or_grpcweb.dart b/lib/grpc_or_grpcweb.dart index b23bed5..049ceab 100644 --- a/lib/grpc_or_grpcweb.dart +++ b/lib/grpc_or_grpcweb.dart @@ -14,7 +14,7 @@ // limitations under the License. import 'src/client/grpc_or_grpcweb_channel_grpc.dart' - if (dart.library.html) 'src/client/grpc_or_grpcweb_channel_web.dart'; + if (dart.library.js_interop) 'src/client/grpc_or_grpcweb_channel_web.dart'; import 'src/client/http2_channel.dart'; import 'src/client/options.dart'; diff --git a/lib/src/client/transport/xhr_transport.dart b/lib/src/client/transport/xhr_transport.dart index 16b0dca..693088c 100644 --- a/lib/src/client/transport/xhr_transport.dart +++ b/lib/src/client/transport/xhr_transport.dart @@ -14,10 +14,11 @@ // limitations under the License. import 'dart:async'; -import 'dart:html'; +import 'dart:js_interop'; import 'dart:typed_data'; import 'package:meta/meta.dart'; +import 'package:web/web.dart'; import '../../client/call.dart'; import '../../shared/message.dart'; @@ -30,7 +31,7 @@ import 'web_streams.dart'; const _contentTypeKey = 'Content-Type'; class XhrTransportStream implements GrpcTransportStream { - final HttpRequest _request; + final IXMLHttpRequest _request; final ErrorHandler _onError; final Function(XhrTransportStream stream) _onDone; bool _headersReceived = false; @@ -49,19 +50,20 @@ class XhrTransportStream implements GrpcTransportStream { {required ErrorHandler onError, required onDone}) : _onError = onError, _onDone = onDone { - _outgoingMessages.stream - .map(frame) - .listen((data) => _request.send(data), cancelOnError: true); + _outgoingMessages.stream.map(frame).listen( + (data) => _request.send(Uint8List.fromList(data).toJS), + cancelOnError: true, + onError: _onError); - _request.onReadyStateChange.listen((data) { + _request.onReadyStateChange.listen((_) { if (_incomingProcessor.isClosed) { return; } switch (_request.readyState) { - case HttpRequest.HEADERS_RECEIVED: + case XMLHttpRequest.HEADERS_RECEIVED: _onHeadersReceived(); break; - case HttpRequest.DONE: + case XMLHttpRequest.DONE: _onRequestDone(); _close(); break; @@ -81,13 +83,11 @@ class XhrTransportStream implements GrpcTransportStream { if (_incomingProcessor.isClosed) { return; } - // Use response over responseText as most browsers don't support - // using responseText during an onProgress event. - final responseString = _request.response as String; + final responseText = _request.responseText; final bytes = Uint8List.fromList( - responseString.substring(_requestBytesRead).codeUnits) + responseText.substring(_requestBytesRead).codeUnits) .buffer; - _requestBytesRead = responseString.length; + _requestBytesRead = responseText.length; _incomingProcessor.add(bytes); }); @@ -122,9 +122,11 @@ class XhrTransportStream implements GrpcTransportStream { if (!_headersReceived && !_validateResponseState()) { return; } - if (_request.response == null) { + if (_request.status != 200) { _onError( - GrpcError.unavailable('XhrConnection request null response', null, + GrpcError.unavailable( + 'Request failed with status: ${_request.status}', + null, _request.responseText), StackTrace.current); return; @@ -144,6 +146,110 @@ class XhrTransportStream implements GrpcTransportStream { } } +// XMLHttpRequest is an extension type and can't be extended or implemented. +// This interface is used to allow for mocking XMLHttpRequest in tests of +// XhrClientConnection. +@visibleForTesting +abstract interface class IXMLHttpRequest { + Stream get onReadyStateChange; + Stream get onProgress; + Stream get onError; + int get readyState; + JSAny? get response; + String get responseText; + Map get responseHeaders; + int get status; + + set responseType(String responseType); + set withCredentials(bool withCredentials); + + void abort(); + void open( + String method, + String url, [ + // external default is true + bool async = true, + String? username, + String? password, + ]); + void overrideMimeType(String mimeType); + void send([JSAny? body]); + void setRequestHeader(String header, String value); + + // This method should only be used in production code. + XMLHttpRequest toXMLHttpRequest(); +} + +// IXMLHttpRequest that delegates to a real XMLHttpRequest. +class XMLHttpRequestImpl implements IXMLHttpRequest { + final XMLHttpRequest _xhr = XMLHttpRequest(); + + XMLHttpRequestImpl(); + + @override + Stream get onReadyStateChange => _xhr.onReadyStateChange; + @override + Stream get onProgress => _xhr.onProgress; + @override + Stream get onError => _xhr.onError; + @override + int get readyState => _xhr.readyState; + @override + Map get responseHeaders => _xhr.responseHeaders; + @override + JSAny? get response => _xhr.response; + @override + String get responseText => _xhr.responseText; + @override + int get status => _xhr.status; + + @override + set responseType(String responseType) { + _xhr.responseType = responseType; + } + + @override + set withCredentials(bool withCredentials) { + _xhr.withCredentials = withCredentials; + } + + @override + void abort() { + _xhr.abort(); + } + + @override + void open( + String method, + String url, [ + bool async = true, + String? username, + String? password, + ]) { + _xhr.open(method, url, async, username, password); + } + + @override + void overrideMimeType(String mimeType) { + _xhr.overrideMimeType(mimeType); + } + + @override + void setRequestHeader(String header, String value) { + _xhr.setRequestHeader(header, value); + } + + @override + void send([JSAny? body]) { + _xhr.send(body); + } + + @override + XMLHttpRequest toXMLHttpRequest() { + return _xhr; + } +} + class XhrClientConnection implements ClientConnection { final Uri uri; @@ -153,20 +259,20 @@ class XhrClientConnection implements ClientConnection { @override String get authority => uri.authority; + @override String get scheme => uri.scheme; - void _initializeRequest(HttpRequest request, Map metadata) { - for (final header in metadata.keys) { - request.setRequestHeader(header, metadata[header]!); - } + void _initializeRequest( + IXMLHttpRequest request, Map metadata) { + metadata.forEach(request.setRequestHeader); // Overriding the mimetype allows us to stream and parse the data request.overrideMimeType('text/plain; charset=x-user-defined'); request.responseType = 'text'; } @visibleForTesting - HttpRequest createHttpRequest() => HttpRequest(); + IXMLHttpRequest createHttpRequest() => XMLHttpRequestImpl(); @override GrpcTransportStream makeRequest(String path, Duration? timeout, @@ -194,11 +300,16 @@ class XhrClientConnection implements ClientConnection { _initializeRequest(request, metadata); final transportStream = - XhrTransportStream(request, onError: onError, onDone: _removeStream); + _createXhrTransportStream(request, onError, _removeStream); _requests.add(transportStream); return transportStream; } + XhrTransportStream _createXhrTransportStream(IXMLHttpRequest request, + ErrorHandler onError, void Function(XhrTransportStream stream) onDone) { + return XhrTransportStream(request, onError: onError, onDone: onDone); + } + void _removeStream(XhrTransportStream stream) { _requests.remove(stream); } diff --git a/pubspec.yaml b/pubspec.yaml index d73273b..aaedfdd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,33 +1,33 @@ name: grpc description: Dart implementation of gRPC, a high performance, open-source universal RPC framework. -version: 4.0.2 +version: 4.0.2-wip -repository: https://github.com/open-runtime/grpc-dart +repository: https://github.com/grpc/grpc-dart environment: sdk: ^3.5.0 dependencies: - archive: ^3.4.10 - async: ^2.11.0 - crypto: ^3.0.3 - fixnum: ^1.1.0 - googleapis_auth: ^1.6.0 - meta: ">=1.11.0 <2.0.0" + async: ^2.5.0 + crypto: ^3.0.0 + fixnum: ^1.0.0 + googleapis_auth: ^1.1.0 + meta: ^1.3.0 http: '>=0.13.0 <2.0.0' - http2: ^2.3.0 + http2: ^2.2.0 protobuf: '>=2.0.0 <4.0.0' clock: ^1.1.1 + web: ^1.1.0 dev_dependencies: - build_runner: ^2.4.9 - build_test: ^2.2.2 + build_runner: ^2.0.0 + build_test: ^2.0.0 lints: ^5.0.0 - mockito: ^5.4.4 - path: ^1.9.0 - test: ^1.25.3 - stream_channel: ^2.1.2 - stream_transform: ^2.1.0 + mockito: ^5.0.0 + path: ^1.8.0 + test: ^1.16.0 + stream_channel: ^2.1.0 + stream_transform: ^2.0.0 vm_service: ">=11.6.0 <16.0.0" fake_async: ^1.3.1 diff --git a/test/client_tests/client_keepalive_manager_test.mocks.dart b/test/client_tests/client_keepalive_manager_test.mocks.dart index a5a4061..20a8225 100644 --- a/test/client_tests/client_keepalive_manager_test.mocks.dart +++ b/test/client_tests/client_keepalive_manager_test.mocks.dart @@ -1,4 +1,3 @@ -// Mocks generated by Mockito 5.4.4 from annotations // Copyright (c) 2024, the gRPC project authors. Please see the AUTHORS file // for details. All rights reserved. // @@ -18,6 +17,8 @@ // in grpc/test/client_tests/client_keepalive_manager_test.dart. // Do not manually edit this file. +// @dart=2.19 + // ignore_for_file: no_leading_underscores_for_library_prefixes import 'package:mockito/mockito.dart' as _i1; @@ -27,8 +28,6 @@ import 'client_keepalive_manager_test.dart' as _i2; // ignore_for_file: avoid_redundant_argument_values // ignore_for_file: avoid_setters_without_getters // ignore_for_file: comment_references -// ignore_for_file: deprecated_member_use -// ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member // ignore_for_file: prefer_const_constructors @@ -48,7 +47,6 @@ class MockPinger extends _i1.Mock implements _i2.Pinger { ), returnValueForMissingStub: null, ); - @override void onPingTimeout() => super.noSuchMethod( Invocation.method( diff --git a/test/client_tests/client_xhr_transport_test.dart b/test/client_tests/client_xhr_transport_test.dart index 1c58077..cdf1be7 100644 --- a/test/client_tests/client_xhr_transport_test.dart +++ b/test/client_tests/client_xhr_transport_test.dart @@ -16,8 +16,8 @@ library; import 'dart:async'; -import 'dart:html'; - +import 'dart:js_interop'; +import 'dart:typed_data'; import 'package:async/async.dart'; import 'package:grpc/src/client/call.dart'; import 'package:grpc/src/client/transport/xhr_transport.dart'; @@ -26,12 +26,13 @@ import 'package:grpc/src/shared/status.dart'; import 'package:mockito/mockito.dart'; import 'package:stream_transform/stream_transform.dart'; import 'package:test/test.dart'; +import 'package:web/web.dart'; final readyStateChangeEvent = - Event('readystatechange', canBubble: false, cancelable: false); + Event('readystatechange', EventInit(bubbles: false, cancelable: false)); final progressEvent = ProgressEvent('onloadstart'); -class MockHttpRequest extends Mock implements HttpRequest { +class MockHttpRequest extends Mock implements IXMLHttpRequest { MockHttpRequest({int? code}) : status = code ?? 200; // ignore: close_sinks StreamController readyStateChangeController = @@ -52,6 +53,10 @@ class MockHttpRequest extends Mock implements HttpRequest { @override final int status; + @override + String get responseText => + super.noSuchMethod(Invocation.getter(#responseText), returnValue: ''); + @override int get readyState => super.noSuchMethod(Invocation.getter(#readyState), returnValue: -1); @@ -71,7 +76,7 @@ class MockXhrClientConnection extends XhrClientConnection { final int _statusCode; @override - HttpRequest createHttpRequest() { + IXMLHttpRequest createHttpRequest() { final request = MockHttpRequest(code: _statusCode); latestRequest = request; return request; @@ -208,8 +213,8 @@ void main() { await stream.terminate(); final expectedData = frame(data); - expect(verify(connection.latestRequest.send(captureAny)).captured.single, - expectedData); + verify( + connection.latestRequest.send(Uint8List.fromList(expectedData).toJS)); }); test('Stream handles headers properly', () async { @@ -225,14 +230,13 @@ void main() { (error, _) => fail(error.toString())); when(transport.latestRequest.responseHeaders).thenReturn(responseHeaders); - when(transport.latestRequest.response) + when(transport.latestRequest.responseText) .thenReturn(String.fromCharCodes(frame([]))); // Set expectation for request readyState and generate two readyStateChange // events, so that incomingMessages stream completes. - final readyStates = [HttpRequest.HEADERS_RECEIVED, HttpRequest.DONE]; - when(transport.latestRequest.readyState) - .thenAnswer((_) => readyStates.removeAt(0)); + final readyStates = [XMLHttpRequest.HEADERS_RECEIVED, XMLHttpRequest.DONE]; + when(transport.latestRequest.readyState).thenReturnInOrder(readyStates); transport.latestRequest.readyStateChangeController .add(readyStateChangeEvent); transport.latestRequest.readyStateChangeController @@ -267,13 +271,12 @@ void main() { final encodedString = String.fromCharCodes(encodedTrailers); when(connection.latestRequest.responseHeaders).thenReturn(requestHeaders); - when(connection.latestRequest.response).thenReturn(encodedString); + when(connection.latestRequest.responseText).thenReturn(encodedString); // Set expectation for request readyState and generate events so that // incomingMessages stream completes. - final readyStates = [HttpRequest.HEADERS_RECEIVED, HttpRequest.DONE]; - when(connection.latestRequest.readyState) - .thenAnswer((_) => readyStates.removeAt(0)); + when(connection.latestRequest.readyState).thenReturnInOrder( + [XMLHttpRequest.HEADERS_RECEIVED, XMLHttpRequest.DONE]); connection.latestRequest.readyStateChangeController .add(readyStateChangeEvent); connection.latestRequest.progressController.add(progressEvent); @@ -303,13 +306,11 @@ void main() { final encodedString = String.fromCharCodes(encoded); when(connection.latestRequest.responseHeaders).thenReturn(requestHeaders); - when(connection.latestRequest.response).thenReturn(encodedString); - + when(connection.latestRequest.responseText).thenReturn(encodedString); // Set expectation for request readyState and generate events so that // incomingMessages stream completes. - final readyStates = [HttpRequest.HEADERS_RECEIVED, HttpRequest.DONE]; - when(connection.latestRequest.readyState) - .thenAnswer((_) => readyStates.removeAt(0)); + when(connection.latestRequest.readyState).thenReturnInOrder( + [XMLHttpRequest.HEADERS_RECEIVED, XMLHttpRequest.DONE]); connection.latestRequest.readyStateChangeController .add(readyStateChangeEvent); connection.latestRequest.progressController.add(progressEvent); @@ -337,14 +338,13 @@ void main() { requestHeaders, (error, _) => fail(error.toString())); final data = List.filled(10, 224); when(connection.latestRequest.responseHeaders).thenReturn(requestHeaders); - when(connection.latestRequest.response) + when(connection.latestRequest.responseText) .thenReturn(String.fromCharCodes(frame(data))); // Set expectation for request readyState and generate events, so that // incomingMessages stream completes. - final readyStates = [HttpRequest.HEADERS_RECEIVED, HttpRequest.DONE]; - when(connection.latestRequest.readyState) - .thenAnswer((_) => readyStates.removeAt(0)); + when(connection.latestRequest.readyState).thenReturnInOrder( + [XMLHttpRequest.HEADERS_RECEIVED, XMLHttpRequest.DONE]); connection.latestRequest.readyStateChangeController .add(readyStateChangeEvent); connection.latestRequest.progressController.add(progressEvent); @@ -369,7 +369,7 @@ void main() { const errorDetails = 'error details'; when(connection.latestRequest.responseHeaders) .thenReturn({'content-type': 'application/grpc+proto'}); - when(connection.latestRequest.readyState).thenReturn(HttpRequest.DONE); + when(connection.latestRequest.readyState).thenReturn(XMLHttpRequest.DONE); when(connection.latestRequest.responseText).thenReturn(errorDetails); connection.latestRequest.readyStateChangeController .add(readyStateChangeEvent); @@ -398,12 +398,12 @@ void main() { when(connection.latestRequest.responseHeaders).thenReturn(metadata); when(connection.latestRequest.readyState) - .thenReturn(HttpRequest.HEADERS_RECEIVED); + .thenReturn(XMLHttpRequest.HEADERS_RECEIVED); // At first invocation the response should be the the first message, after // that first + last messages. var first = true; - when(connection.latestRequest.response).thenAnswer((_) { + when(connection.latestRequest.responseText).thenAnswer((_) { if (first) { first = false; return encodedStrings[0]; @@ -411,7 +411,7 @@ void main() { return encodedStrings[0] + encodedStrings[1]; }); - final readyStates = [HttpRequest.HEADERS_RECEIVED, HttpRequest.DONE]; + final readyStates = [XMLHttpRequest.HEADERS_RECEIVED, XMLHttpRequest.DONE]; when(connection.latestRequest.readyState) .thenAnswer((_) => readyStates.removeAt(0)); diff --git a/test/connection_server_test.dart b/test/connection_server_test.dart index 423b582..d435773 100644 --- a/test/connection_server_test.dart +++ b/test/connection_server_test.dart @@ -290,7 +290,7 @@ void main() { } GrpcError? interceptor(call, method) { - if (method.identifier == 'Unary') { + if (method.name == 'Unary') { return null; } return GrpcError.unauthenticated('Request is unauthenticated'); @@ -312,7 +312,7 @@ void main() { group('returns error if interceptor blocks request', () { GrpcError? interceptor(call, method) { - if (method.identifier == 'Unary') { + if (method.name == 'Unary') { return GrpcError.unauthenticated('Request is unauthenticated'); } return null; diff --git a/test/server_test.dart b/test/server_test.dart index fc1b983..b323f77 100644 --- a/test/server_test.dart +++ b/test/server_test.dart @@ -304,7 +304,7 @@ void main() { } GrpcError? interceptor(call, method) { - if (method.identifier == 'Unary') { + if (method.name == 'Unary') { return null; } return GrpcError.unauthenticated('Request is unauthenticated'); @@ -326,7 +326,7 @@ void main() { group('returns error if interceptor blocks request', () { GrpcError? interceptor(call, method) { - if (method.identifier == 'Unary') { + if (method.name == 'Unary') { return GrpcError.unauthenticated('Request is unauthenticated'); } return null; diff --git a/test/src/client_utils.mocks.dart b/test/src/client_utils.mocks.dart index 8da129c..98702df 100644 --- a/test/src/client_utils.mocks.dart +++ b/test/src/client_utils.mocks.dart @@ -1,7 +1,9 @@ -// Mocks generated by Mockito 5.4.4 from annotations +// Mocks generated by Mockito 5.4.1 from annotations // in grpc/test/src/client_utils.dart. // Do not manually edit this file. +// @dart=2.19 + // ignore_for_file: no_leading_underscores_for_library_prefixes import 'dart:async' as _i3; @@ -13,8 +15,6 @@ import 'package:mockito/mockito.dart' as _i1; // ignore_for_file: avoid_redundant_argument_values // ignore_for_file: avoid_setters_without_getters // ignore_for_file: comment_references -// ignore_for_file: deprecated_member_use -// ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member // ignore_for_file: prefer_const_constructors @@ -57,7 +57,6 @@ class MockClientTransportConnection extends _i1.Mock Invocation.getter(#isOpen), returnValue: false, ) as bool); - @override set onActiveStateChanged(_i2.ActiveStateHandler? callback) => super.noSuchMethod( @@ -67,25 +66,21 @@ class MockClientTransportConnection extends _i1.Mock ), returnValueForMissingStub: null, ); - @override _i3.Future get onInitialPeerSettingsReceived => (super.noSuchMethod( Invocation.getter(#onInitialPeerSettingsReceived), returnValue: _i3.Future.value(), ) as _i3.Future); - @override _i3.Stream get onPingReceived => (super.noSuchMethod( Invocation.getter(#onPingReceived), returnValue: _i3.Stream.empty(), ) as _i3.Stream); - @override _i3.Stream get onFrameReceived => (super.noSuchMethod( Invocation.getter(#onFrameReceived), returnValue: _i3.Stream.empty(), ) as _i3.Stream); - @override _i2.ClientTransportStream makeRequest( List<_i4.Header>? headers, { @@ -106,7 +101,6 @@ class MockClientTransportConnection extends _i1.Mock ), ), ) as _i2.ClientTransportStream); - @override _i3.Future ping() => (super.noSuchMethod( Invocation.method( @@ -115,7 +109,6 @@ class MockClientTransportConnection extends _i1.Mock ), returnValue: _i3.Future.value(), ) as _i3.Future); - @override _i3.Future finish() => (super.noSuchMethod( Invocation.method( @@ -124,7 +117,6 @@ class MockClientTransportConnection extends _i1.Mock ), returnValue: _i3.Future.value(), ) as _i3.Future); - @override _i3.Future terminate([int? errorCode]) => (super.noSuchMethod( Invocation.method( @@ -149,19 +141,16 @@ class MockClientTransportStream extends _i1.Mock Invocation.getter(#peerPushes), returnValue: _i3.Stream<_i2.TransportStreamPush>.empty(), ) as _i3.Stream<_i2.TransportStreamPush>); - @override int get id => (super.noSuchMethod( Invocation.getter(#id), returnValue: 0, ) as int); - @override _i3.Stream<_i2.StreamMessage> get incomingMessages => (super.noSuchMethod( Invocation.getter(#incomingMessages), returnValue: _i3.Stream<_i2.StreamMessage>.empty(), ) as _i3.Stream<_i2.StreamMessage>); - @override _i3.StreamSink<_i2.StreamMessage> get outgoingMessages => (super.noSuchMethod( Invocation.getter(#outgoingMessages), @@ -170,7 +159,6 @@ class MockClientTransportStream extends _i1.Mock Invocation.getter(#outgoingMessages), ), ) as _i3.StreamSink<_i2.StreamMessage>); - @override set onTerminated(void Function(int?)? value) => super.noSuchMethod( Invocation.setter( @@ -179,7 +167,6 @@ class MockClientTransportStream extends _i1.Mock ), returnValueForMissingStub: null, ); - @override void terminate() => super.noSuchMethod( Invocation.method( @@ -188,7 +175,6 @@ class MockClientTransportStream extends _i1.Mock ), returnValueForMissingStub: null, ); - @override void sendHeaders( List<_i4.Header>? headers, { @@ -202,7 +188,6 @@ class MockClientTransportStream extends _i1.Mock ), returnValueForMissingStub: null, ); - @override void sendData( List? bytes, { From 471a8b377b54d0e2f8fed7cac2f63b5de2e37192 Mon Sep 17 00:00:00 2001 From: Tsavo Knott Date: Fri, 3 Jan 2025 13:02:16 -0500 Subject: [PATCH 30/32] Clean Up CI --- .github/workflows/dart.yml | 7 +++---- .github/workflows/publish.yaml | 12 ------------ 2 files changed, 3 insertions(+), 16 deletions(-) delete mode 100644 .github/workflows/publish.yaml diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index 1a8175f..c168842 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -3,11 +3,10 @@ name: Dart on: # Run CI on pushes to the master branch, and on PRs against master. push: - branches: [master] + branches: [main] pull_request: - branches: [master] - schedule: - - cron: "0 0 * * 0" + branches: [main] + workflow_dispatch: jobs: # Check code formatting and static analysis on a single OS (linux) diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml deleted file mode 100644 index f979755..0000000 --- a/.github/workflows/publish.yaml +++ /dev/null @@ -1,12 +0,0 @@ -name: Publish -permissions: - id-token: write - pull-requests: write -on: - pull_request: - branches: [ master ] - push: - tags: [ 'v[0-9]+.[0-9]+.[0-9]+' ] -jobs: - publish: - uses: dart-lang/ecosystem/.github/workflows/publish.yaml@main From 97f8aee043f48addc3b6c4e96ba3dd956f181c75 Mon Sep 17 00:00:00 2001 From: Tsavo Knott Date: Fri, 3 Jan 2025 14:30:29 -0500 Subject: [PATCH 31/32] Revert "Merge branch 'merge_upstream_main_into_aot_monorepo_compat'" This reverts commit 8c497fae08242c1852765c89a24fea8ad22a5950, reversing changes made to 00b634fde4a19dda4191e4ce08e4c1dbf1830ad0. --- .github/workflows/dart.yml | 12 +- .github/workflows/health.yaml | 13 -- .github/workflows/post_summaries.yaml | 17 -- CHANGELOG.md | 28 +-- README.md | 4 +- analysis_options.yaml | 22 +-- example/README.md | 2 +- example/googleapis/googleapis.iml | 16 ++ example/googleapis/pubspec_overrides.yaml | 4 + example/grpc-web/grpc_web.iml | 16 ++ example/grpc-web/lib/app.dart | 15 -- example/grpc-web/pubspec.yaml | 8 +- example/grpc-web/pubspec_overrides.yaml | 4 + example/helloworld/bin/client.dart | 2 +- example/helloworld/bin/server.dart | 2 +- example/helloworld/bin/unix_client.dart | 2 +- example/helloworld/bin/unix_server.dart | 2 +- example/helloworld/helloworld.iml | 16 ++ example/helloworld/pubspec_overrides.yaml | 4 + example/metadata/metadata.iml | 16 ++ example/metadata/pubspec_overrides.yaml | 4 + example/route_guide/pubspec_overrides.yaml | 4 + example/route_guide/route_guide.iml | 16 ++ grpc.iml | 18 ++ interop/interop.iml | 16 ++ interop/lib/src/client.dart | 4 +- interop/pubspec.yaml | 12 +- interop/pubspec_overrides.yaml | 4 + lib/grpc.dart | 8 +- lib/grpc_or_grpcweb.dart | 2 +- lib/service_api.dart | 2 +- lib/src/auth/auth_io.dart | 2 +- lib/src/client/call.dart | 16 +- lib/src/client/http2_connection.dart | 2 +- .../client/transport/http2_credentials.dart | 2 +- lib/src/client/transport/web_streams.dart | 14 -- lib/src/client/transport/xhr_transport.dart | 153 ++------------ lib/src/generated/google/rpc/code.pb.dart | 14 ++ lib/src/generated/google/rpc/code.pbenum.dart | 79 ++++++++ lib/src/generated/google/rpc/code.pbjson.dart | 47 +++++ lib/src/protos/google/rpc/code.proto | 186 ++++++++++++++++++ lib/src/server/handler.dart | 2 +- lib/src/shared/codec.dart | 56 +++++- lib/src/shared/codec/codec_all.dart | 48 ----- lib/src/shared/codec/codec_io.dart | 36 ---- lib/src/shared/codec/codec_web.dart | 34 ---- lib/src/shared/message.dart | 3 +- lib/src/shared/status.dart | 37 +--- pubspec.yaml | 18 +- test/client_certificate_test.dart | 17 -- test/client_handles_bad_connections_test.dart | 17 -- test/client_tests/call_test.dart | 84 -------- .../client_tests/client_interceptor_test.dart | 15 -- .../client_keepalive_manager_test.dart | 15 -- .../client_keepalive_manager_test.mocks.dart | 22 +-- .../client_xhr_transport_test.dart | 59 +++--- .../grpc_or_grpcweb_channel_grpc_test.dart | 4 +- .../grpc_or_grpcweb_channel_web_test.dart | 3 +- test/connection_server_test.dart | 5 +- test/grpc_compression_flag_test.dart | 44 ----- test/grpc_web_decoding_test.dart | 15 -- test/grpc_web_server.dart | 15 -- test/grpc_web_test.dart | 17 -- test/keepalive_test.dart | 78 +++----- test/options_test.dart | 1 - test/proxy_secure_test.dart | 21 +- test/proxy_test.dart | 21 +- test/round_trip_test.dart | 17 -- test/server_cancellation_test.dart | 4 +- ...server_handles_broken_connection_test.dart | 17 -- test/server_keepalive_manager_test.dart | 15 -- test/server_test.dart | 7 +- test/shared_tests/codec_registry_test.dart | 15 -- test/src/client_utils.mocks.dart | 21 +- test/timeline_test.dart | 2 - test/tools/http2_client.dart | 19 +- test/tools/http2_server.dart | 15 -- 77 files changed, 695 insertions(+), 934 deletions(-) delete mode 100644 .github/workflows/health.yaml delete mode 100644 .github/workflows/post_summaries.yaml create mode 100644 example/googleapis/googleapis.iml create mode 100644 example/googleapis/pubspec_overrides.yaml create mode 100644 example/grpc-web/grpc_web.iml create mode 100644 example/grpc-web/pubspec_overrides.yaml create mode 100644 example/helloworld/helloworld.iml create mode 100644 example/helloworld/pubspec_overrides.yaml create mode 100644 example/metadata/metadata.iml create mode 100644 example/metadata/pubspec_overrides.yaml create mode 100644 example/route_guide/pubspec_overrides.yaml create mode 100644 example/route_guide/route_guide.iml create mode 100644 grpc.iml create mode 100644 interop/interop.iml create mode 100644 interop/pubspec_overrides.yaml create mode 100644 lib/src/generated/google/rpc/code.pb.dart create mode 100644 lib/src/generated/google/rpc/code.pbenum.dart create mode 100644 lib/src/generated/google/rpc/code.pbjson.dart create mode 100644 lib/src/protos/google/rpc/code.proto delete mode 100644 lib/src/shared/codec/codec_all.dart delete mode 100644 lib/src/shared/codec/codec_io.dart delete mode 100644 lib/src/shared/codec/codec_web.dart delete mode 100644 test/grpc_compression_flag_test.dart diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index c168842..4790330 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -15,10 +15,10 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - sdk: [3.5, dev] + sdk: [3.5.0, dev] steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: dart-lang/setup-dart@fedb1266e91cf51be2fdb382869461a434b920a3 with: sdk: ${{ matrix.sdk }} - name: Report version @@ -59,7 +59,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - sdk: [3.5, dev] + sdk: [3.0.0, dev] platform: [vm, chrome] exclude: # We only run Chrome tests on Linux. No need to run them @@ -69,8 +69,8 @@ jobs: - os: macos-latest platform: chrome steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: dart-lang/setup-dart@fedb1266e91cf51be2fdb382869461a434b920a3 with: sdk: ${{ matrix.sdk }} - name: Report version diff --git a/.github/workflows/health.yaml b/.github/workflows/health.yaml deleted file mode 100644 index 3ba41f3..0000000 --- a/.github/workflows/health.yaml +++ /dev/null @@ -1,13 +0,0 @@ -name: Health -on: - pull_request: - branches: [ master ] - types: [opened, synchronize, reopened, labeled, unlabeled] -jobs: - health: - uses: dart-lang/ecosystem/.github/workflows/health.yaml@main - with: - checks: "changelog,do-not-submit,breaking,coverage,leaking" - ignore_coverage: "example/**,interop/**" - permissions: - pull-requests: write diff --git a/.github/workflows/post_summaries.yaml b/.github/workflows/post_summaries.yaml deleted file mode 100644 index 9cf8949..0000000 --- a/.github/workflows/post_summaries.yaml +++ /dev/null @@ -1,17 +0,0 @@ -name: Comment on the pull request - -on: - # Trigger this workflow after the Health workflow completes. This workflow will have permissions to - # do things like create comments on the PR, even if the original workflow couldn't. - workflow_run: - workflows: - - Health - - Publish - types: - - completed - -jobs: - upload: - uses: dart-lang/ecosystem/.github/workflows/post_summaries.yaml@main - permissions: - pull-requests: write \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ad86f53..e1332dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,25 +1,3 @@ -## 4.0.2-wip - -* Internal optimization to client code. -* Small fixes, such as ports in testing and enabling `timeline_test.dart`. -* When the keep alive manager runs into a timeout, it will finish the transport instead of closing - the connection, as defined in the gRPC spec. -* Upgrade to `package:lints` version 5.0.0 and Dart SDK version 3.5.0. -* Upgrade `example/grpc-web` code. -* Update xhr transport to migrate off legacy JS/HTML apis. - -## 4.0.1 - -* Fix header and trailing not completing if the call is terminated. Fixes [#727](https://github.com/grpc/grpc-dart/issues/727) - -## 4.0.0 - -* Set compressed flag correctly for grpc-encoding = identity. Fixes [#669](https://github.com/grpc/grpc-dart/issues/669) (https://github.com/grpc/grpc-dart/pull/693) -* Remove generated status codes. -* Remove dependency on `package:archive`. -* Move `codec.dart`. -* Work around hang during Flutter hot restart by adding default case handler in _GrpcWebConversionSink.add. - ## 3.2.4 * Forward internal `GrpcError` on when throwing while sending a request. @@ -41,19 +19,19 @@ ## 3.2.1 -* `package:http` now supports more versions: `>=0.13.0 <2.0.0`. +* `package:http` now supports more versions: `>=0.13.0 <2.0.0`. * `package:protobuf` new supports more versions: `>=2.0.0 <4.0.0`. ## 3.2.0 -* `ChannelOptions` now exposes `connectTimeout`, which is used on the +* `ChannelOptions` now exposes `connectTimeout`, which is used on the socket connect. This is used to specify the maximum allowed time to wait for a connection to be established. If `connectTime` is longer than the system level timeout duration, a timeout may occur sooner than specified in `connectTimeout`. On timeout, a `SocketException` is thrown. * Require Dart 2.17 or greater. * Fix issue [#51](https://github.com/grpc/grpc-dart/issues/51), add support for custom error handling. -* Expose client IP address to server +* Expose client IP address to server * Add a `channelShutdownHandler` argument to `ClientChannel` and the subclasses. This callback can be used to react to channel shutdown or termination. * Export the `Code` protobuf enum from the `grpc.dart` library. diff --git a/README.md b/README.md index f85542b..667f28d 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ The [Dart](https://www.dart.dev/) implementation of [gRPC](https://grpc.io/): A high performance, open source, general RPC framework that puts mobile and HTTP/2 first. -[![Dart](https://github.com/grpc/grpc-dart/actions/workflows/dart.yml/badge.svg)](https://github.com/grpc/grpc-dart/actions/workflows/dart.yml) +[![CI status](https://github.com/grpc/grpc-dart/workflows/Dart/badge.svg)](https://github.com/grpc/grpc-dart/actions?query=workflow%3A%22Dart%22+branch%3Amaster) [![pub package](https://img.shields.io/pub/v/grpc.svg)](https://pub.dev/packages/grpc) ## Learn more - [Quick Start](https://grpc.io/docs/languages/dart/quickstart) - get an app running in minutes -- [Examples](https://github.com/grpc/grpc-dart/tree/master/example) +- [Examples](example) - [API reference](https://grpc.io/docs/languages/dart/api) For complete documentation, see [Dart gRPC](https://grpc.io/docs/languages/dart). diff --git a/analysis_options.yaml b/analysis_options.yaml index 5bcd150..01c74eb 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -9,15 +9,13 @@ analyzer: linter: rules: - #true - always_declare_return_types: true - cancel_subscriptions: true - close_sinks: true - directives_ordering: true - omit_local_variable_types: true - prefer_final_locals: true - prefer_single_quotes: true - test_types_in_equals: true - prefer_relative_imports: true - #false - unintended_html_in_doc_comment: false + - always_declare_return_types + - cancel_subscriptions + - close_sinks + - directives_ordering + - omit_local_variable_types + - prefer_final_locals + - prefer_single_quotes + - test_types_in_equals + - use_super_parameters + - prefer_relative_imports diff --git a/example/README.md b/example/README.md index 330358a..67cc944 100644 --- a/example/README.md +++ b/example/README.md @@ -1,7 +1,7 @@ Four code examples are available: 1. [helloworld](https://github.com/grpc/grpc-dart/tree/master/example/helloworld): - A demonstration of using the Dart gRPC library to perform unary RPCs. + A demonstration of using the Dart gRPC library to perform unary RPs. 1. [googleapis](https://github.com/grpc/grpc-dart/tree/master/example/googleapis): A demonstration of using the Dart gRPC library to communicate with Google APIs. diff --git a/example/googleapis/googleapis.iml b/example/googleapis/googleapis.iml new file mode 100644 index 0000000..389d07a --- /dev/null +++ b/example/googleapis/googleapis.iml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/example/googleapis/pubspec_overrides.yaml b/example/googleapis/pubspec_overrides.yaml new file mode 100644 index 0000000..c691769 --- /dev/null +++ b/example/googleapis/pubspec_overrides.yaml @@ -0,0 +1,4 @@ +# melos_managed_dependency_overrides: grpc +dependency_overrides: + grpc: + path: ../.. diff --git a/example/grpc-web/grpc_web.iml b/example/grpc-web/grpc_web.iml new file mode 100644 index 0000000..389d07a --- /dev/null +++ b/example/grpc-web/grpc_web.iml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/example/grpc-web/lib/app.dart b/example/grpc-web/lib/app.dart index fce83c5..bdc920f 100644 --- a/example/grpc-web/lib/app.dart +++ b/example/grpc-web/lib/app.dart @@ -1,18 +1,3 @@ -// Copyright (c) 2024, 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'; diff --git a/example/grpc-web/pubspec.yaml b/example/grpc-web/pubspec.yaml index 10f80ce..e215c13 100644 --- a/example/grpc-web/pubspec.yaml +++ b/example/grpc-web/pubspec.yaml @@ -3,7 +3,7 @@ description: Dart gRPC-Web sample client publish_to: none environment: - sdk: ^3.5.0 + sdk: '>=2.12.0 <3.0.0' dependencies: grpc: @@ -11,6 +11,6 @@ dependencies: protobuf: ^3.0.0 dev_dependencies: - build_runner: ^2.4.13 - build_web_compilers: ^4.0.11 - lints: ^5.0.0 + build_runner: ^2.0.0 + build_web_compilers: '>3.0.0 <5.0.0' + lints: ^2.0.0 diff --git a/example/grpc-web/pubspec_overrides.yaml b/example/grpc-web/pubspec_overrides.yaml new file mode 100644 index 0000000..c691769 --- /dev/null +++ b/example/grpc-web/pubspec_overrides.yaml @@ -0,0 +1,4 @@ +# melos_managed_dependency_overrides: grpc +dependency_overrides: + grpc: + path: ../.. diff --git a/example/helloworld/bin/client.dart b/example/helloworld/bin/client.dart index 4ec8e8e..4d4635d 100644 --- a/example/helloworld/bin/client.dart +++ b/example/helloworld/bin/client.dart @@ -13,10 +13,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +/// Dart implementation of the gRPC helloworld.Greeter client. import 'package:grpc/grpc.dart'; import 'package:helloworld/src/generated/helloworld.pbgrpc.dart'; -/// Dart implementation of the gRPC helloworld.Greeter client. Future main(List args) async { final channel = ClientChannel( 'localhost', diff --git a/example/helloworld/bin/server.dart b/example/helloworld/bin/server.dart index a2b491c..0f2b287 100644 --- a/example/helloworld/bin/server.dart +++ b/example/helloworld/bin/server.dart @@ -13,10 +13,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +/// Dart implementation of the gRPC helloworld.Greeter server. import 'package:grpc/grpc.dart'; import 'package:helloworld/src/generated/helloworld.pbgrpc.dart'; -/// Dart implementation of the gRPC helloworld.Greeter server. class GreeterService extends GreeterServiceBase { @override Future sayHello(ServiceCall call, HelloRequest request) async { diff --git a/example/helloworld/bin/unix_client.dart b/example/helloworld/bin/unix_client.dart index 0c3cacc..5f30cc2 100644 --- a/example/helloworld/bin/unix_client.dart +++ b/example/helloworld/bin/unix_client.dart @@ -13,12 +13,12 @@ // See the License for the specific language governing permissions and // limitations under the License. +/// Dart implementation of the gRPC helloworld.Greeter client. import 'dart:io'; import 'package:grpc/grpc.dart'; import 'package:helloworld/src/generated/helloworld.pbgrpc.dart'; -/// Dart implementation of the gRPC helloworld.Greeter client. Future main(List args) async { final udsAddress = InternetAddress('localhost', type: InternetAddressType.unix); diff --git a/example/helloworld/bin/unix_server.dart b/example/helloworld/bin/unix_server.dart index a30eaec..82fbf02 100644 --- a/example/helloworld/bin/unix_server.dart +++ b/example/helloworld/bin/unix_server.dart @@ -13,12 +13,12 @@ // See the License for the specific language governing permissions and // limitations under the License. +/// Dart implementation of the gRPC helloworld.Greeter server. import 'dart:io'; import 'package:grpc/grpc.dart'; import 'package:helloworld/src/generated/helloworld.pbgrpc.dart'; -/// Dart implementation of the gRPC helloworld.Greeter server. class GreeterService extends GreeterServiceBase { @override Future sayHello(ServiceCall call, HelloRequest request) async { diff --git a/example/helloworld/helloworld.iml b/example/helloworld/helloworld.iml new file mode 100644 index 0000000..389d07a --- /dev/null +++ b/example/helloworld/helloworld.iml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/example/helloworld/pubspec_overrides.yaml b/example/helloworld/pubspec_overrides.yaml new file mode 100644 index 0000000..c691769 --- /dev/null +++ b/example/helloworld/pubspec_overrides.yaml @@ -0,0 +1,4 @@ +# melos_managed_dependency_overrides: grpc +dependency_overrides: + grpc: + path: ../.. diff --git a/example/metadata/metadata.iml b/example/metadata/metadata.iml new file mode 100644 index 0000000..389d07a --- /dev/null +++ b/example/metadata/metadata.iml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/example/metadata/pubspec_overrides.yaml b/example/metadata/pubspec_overrides.yaml new file mode 100644 index 0000000..c691769 --- /dev/null +++ b/example/metadata/pubspec_overrides.yaml @@ -0,0 +1,4 @@ +# melos_managed_dependency_overrides: grpc +dependency_overrides: + grpc: + path: ../.. diff --git a/example/route_guide/pubspec_overrides.yaml b/example/route_guide/pubspec_overrides.yaml new file mode 100644 index 0000000..c691769 --- /dev/null +++ b/example/route_guide/pubspec_overrides.yaml @@ -0,0 +1,4 @@ +# melos_managed_dependency_overrides: grpc +dependency_overrides: + grpc: + path: ../.. diff --git a/example/route_guide/route_guide.iml b/example/route_guide/route_guide.iml new file mode 100644 index 0000000..389d07a --- /dev/null +++ b/example/route_guide/route_guide.iml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/grpc.iml b/grpc.iml new file mode 100644 index 0000000..74e5a87 --- /dev/null +++ b/grpc.iml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/interop/interop.iml b/interop/interop.iml new file mode 100644 index 0000000..389d07a --- /dev/null +++ b/interop/interop.iml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/interop/lib/src/client.dart b/interop/lib/src/client.dart index a61fa81..8cead2f 100644 --- a/interop/lib/src/client.dart +++ b/interop/lib/src/client.dart @@ -208,7 +208,7 @@ class Tester { final receivedBytes = response.payload.body.length; if (receivedBytes != 314159) { throw 'Response payload mismatch. Expected 314159 bytes, ' - 'got $receivedBytes.'; + 'got ${receivedBytes}.'; } } @@ -869,7 +869,7 @@ class Tester { final receivedBytes = response.payload.body.length; if (receivedBytes != 314159) { throw 'Response payload mismatch. Expected 314159 bytes, ' - 'got $receivedBytes.'; + 'got ${receivedBytes}.'; } return response; } diff --git a/interop/pubspec.yaml b/interop/pubspec.yaml index f4038fa..40b946a 100644 --- a/interop/pubspec.yaml +++ b/interop/pubspec.yaml @@ -3,15 +3,15 @@ description: Dart gRPC interoperability test suite. publish_to: none environment: - sdk: ^3.0.0 + sdk: '>=3.0.0 <4.0.0' dependencies: - args: ^2.0.0 - async: ^2.2.0 - collection: ^1.14.11 + args: ^2.5.0 + async: ^2.11.0 + collection: ^1.18.0 grpc: path: ../ - protobuf: ^3.0.0 + protobuf: ^3.1.0 dev_dependencies: - test: ^1.16.0 + test: ^1.25.3 diff --git a/interop/pubspec_overrides.yaml b/interop/pubspec_overrides.yaml new file mode 100644 index 0000000..917447a --- /dev/null +++ b/interop/pubspec_overrides.yaml @@ -0,0 +1,4 @@ +# melos_managed_dependency_overrides: grpc +dependency_overrides: + grpc: + path: .. diff --git a/lib/grpc.dart b/lib/grpc.dart index 1c9593f..5f79523 100644 --- a/lib/grpc.dart +++ b/lib/grpc.dart @@ -13,10 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// ignore: dangling_library_doc_comments -/// Status detail types and error codes -export 'package:grpc/src/generated/google/rpc/error_details.pb.dart'; - export 'src/auth/auth.dart' show BaseAuthenticator; export 'src/auth/auth_io.dart' show @@ -43,6 +39,10 @@ export 'src/client/options.dart' export 'src/client/proxy.dart' show Proxy; export 'src/client/transport/http2_credentials.dart' show BadCertificateHandler, allowBadCertificates, ChannelCredentials; + +/// Status detail types and error codes +export 'src/generated/google/rpc/code.pbenum.dart'; +export 'src/generated/google/rpc/error_details.pb.dart'; export 'src/server/call.dart' show ServiceCall; export 'src/server/interceptor.dart' show Interceptor; export 'src/server/server.dart' diff --git a/lib/grpc_or_grpcweb.dart b/lib/grpc_or_grpcweb.dart index 049ceab..b23bed5 100644 --- a/lib/grpc_or_grpcweb.dart +++ b/lib/grpc_or_grpcweb.dart @@ -14,7 +14,7 @@ // limitations under the License. import 'src/client/grpc_or_grpcweb_channel_grpc.dart' - if (dart.library.js_interop) 'src/client/grpc_or_grpcweb_channel_web.dart'; + if (dart.library.html) 'src/client/grpc_or_grpcweb_channel_web.dart'; import 'src/client/http2_channel.dart'; import 'src/client/options.dart'; diff --git a/lib/service_api.dart b/lib/service_api.dart index 026b26b..53d056d 100644 --- a/lib/service_api.dart +++ b/lib/service_api.dart @@ -16,7 +16,7 @@ /// Exports the minimum api to define server and client stubs. /// /// Mainly intended to be imported by generated code. -library; +library service_api; export 'src/client/call.dart' show CallOptions, MetadataProvider; export 'src/client/channel.dart' show ClientChannel; diff --git a/lib/src/auth/auth_io.dart b/lib/src/auth/auth_io.dart index bb72000..681ee59 100644 --- a/lib/src/auth/auth_io.dart +++ b/lib/src/auth/auth_io.dart @@ -69,7 +69,7 @@ class _CredentialsRefreshingAuthenticator extends HttpBasedAuthenticator { await super.authenticate(metadata, uri); if (_quotaProject != null) { // https://cloud.google.com/apis/docs/system-parameters#definitions - metadata['X-Goog-User-Project'] = _quotaProject; + metadata['X-Goog-User-Project'] = _quotaProject!; } } diff --git a/lib/src/client/call.dart b/lib/src/client/call.dart index 65f0de3..8d5918f 100644 --- a/lib/src/client/call.dart +++ b/lib/src/client/call.dart @@ -86,9 +86,9 @@ class CallOptions { CallOptions mergedWith(CallOptions? other) { if (other == null) return this; - final mergedMetadata = Map.of(metadata)..addAll(other.metadata); + final mergedMetadata = Map.from(metadata)..addAll(other.metadata); final mergedTimeout = other.timeout ?? timeout; - final mergedProviders = List.of(metadataProviders) + final mergedProviders = List.from(metadataProviders) ..addAll(other.metadataProviders); final mergedCompression = other.compression ?? compression; return CallOptions._( @@ -146,9 +146,9 @@ class WebCallOptions extends CallOptions { CallOptions mergedWith(CallOptions? other) { if (other == null) return this; - final mergedMetadata = Map.of(metadata)..addAll(other.metadata); + final mergedMetadata = Map.from(metadata)..addAll(other.metadata); final mergedTimeout = other.timeout ?? timeout; - final mergedProviders = List.of(metadataProviders) + final mergedProviders = List.from(metadataProviders) ..addAll(other.metadataProviders); if (other is! WebCallOptions) { @@ -241,7 +241,7 @@ class ClientCall implements Response { if (options.metadataProviders.isEmpty) { _sendRequest(connection, _sanitizeMetadata(options.metadata)); } else { - final metadata = Map.of(options.metadata); + final metadata = Map.from(options.metadata); Future.forEach( options.metadataProviders, (MetadataProvider provider) => provider(metadata, @@ -483,12 +483,6 @@ class ClientCall implements Response { if (_responseSubscription != null) { futures.add(_responseSubscription!.cancel()); } - if (!_headers.isCompleted) { - _headers.complete({}); - } - if (!_trailers.isCompleted) { - _trailers.complete({}); - } await Future.wait(futures); } diff --git a/lib/src/client/http2_connection.dart b/lib/src/client/http2_connection.dart index 4cce677..998410a 100644 --- a/lib/src/client/http2_connection.dart +++ b/lib/src/client/http2_connection.dart @@ -113,7 +113,7 @@ class Http2ClientConnection implements connection.ClientConnection { transport.ping(); } }, - onPingTimeout: () => transport.finish(), + onPingTimeout: () => shutdown(), ); transport.onFrameReceived .listen((_) => keepAliveManager?.onFrameReceived()); diff --git a/lib/src/client/transport/http2_credentials.dart b/lib/src/client/transport/http2_credentials.dart index f2b7669..5b20e7a 100644 --- a/lib/src/client/transport/http2_credentials.dart +++ b/lib/src/client/transport/http2_credentials.dart @@ -58,7 +58,7 @@ class ChannelCredentials { if (!isSecure) return null; if (_certificateBytes != null) { return createSecurityContext(false) - ..setTrustedCertificatesBytes(_certificateBytes, + ..setTrustedCertificatesBytes(_certificateBytes!, password: _certificatePassword); } final context = SecurityContext(withTrustedRoots: true); diff --git a/lib/src/client/transport/web_streams.dart b/lib/src/client/transport/web_streams.dart index d4100ad..aba0a7b 100644 --- a/lib/src/client/transport/web_streams.dart +++ b/lib/src/client/transport/web_streams.dart @@ -132,16 +132,6 @@ class _GrpcWebConversionSink implements ChunkedConversionSink { void add(ByteBuffer chunk) { _chunkOffset = 0; final chunkData = chunk.asUint8List(); - // in flutter web, when a hot-restart is requested, the code can get stuck - // in the following loop if there is an active streaming call. the - // switch statement is invoked but doesn't match any of the cases. this - // presumably has something to do how enums work across isolates. - // possibly related to https://github.com/dart-lang/sdk/issues/35626. - // - // in any case, adding a default handler to the switch statement - // causes this loop to end in that case, allowing the old isolate - // to shut down and the hot-restart to work properly. - processingLoop: while (_chunkOffset < chunk.lengthInBytes) { switch (_state) { case _GrpcWebParseState.init: @@ -153,10 +143,6 @@ class _GrpcWebConversionSink implements ChunkedConversionSink { case _GrpcWebParseState.message: _parseMessage(chunkData); break; - // ignore: unreachable_switch_default - default: - // only expected to be hit when hot-restarting, see above - break processingLoop; } } _chunkOffset = 0; diff --git a/lib/src/client/transport/xhr_transport.dart b/lib/src/client/transport/xhr_transport.dart index 693088c..16b0dca 100644 --- a/lib/src/client/transport/xhr_transport.dart +++ b/lib/src/client/transport/xhr_transport.dart @@ -14,11 +14,10 @@ // limitations under the License. import 'dart:async'; -import 'dart:js_interop'; +import 'dart:html'; import 'dart:typed_data'; import 'package:meta/meta.dart'; -import 'package:web/web.dart'; import '../../client/call.dart'; import '../../shared/message.dart'; @@ -31,7 +30,7 @@ import 'web_streams.dart'; const _contentTypeKey = 'Content-Type'; class XhrTransportStream implements GrpcTransportStream { - final IXMLHttpRequest _request; + final HttpRequest _request; final ErrorHandler _onError; final Function(XhrTransportStream stream) _onDone; bool _headersReceived = false; @@ -50,20 +49,19 @@ class XhrTransportStream implements GrpcTransportStream { {required ErrorHandler onError, required onDone}) : _onError = onError, _onDone = onDone { - _outgoingMessages.stream.map(frame).listen( - (data) => _request.send(Uint8List.fromList(data).toJS), - cancelOnError: true, - onError: _onError); + _outgoingMessages.stream + .map(frame) + .listen((data) => _request.send(data), cancelOnError: true); - _request.onReadyStateChange.listen((_) { + _request.onReadyStateChange.listen((data) { if (_incomingProcessor.isClosed) { return; } switch (_request.readyState) { - case XMLHttpRequest.HEADERS_RECEIVED: + case HttpRequest.HEADERS_RECEIVED: _onHeadersReceived(); break; - case XMLHttpRequest.DONE: + case HttpRequest.DONE: _onRequestDone(); _close(); break; @@ -83,11 +81,13 @@ class XhrTransportStream implements GrpcTransportStream { if (_incomingProcessor.isClosed) { return; } - final responseText = _request.responseText; + // 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( - responseText.substring(_requestBytesRead).codeUnits) + responseString.substring(_requestBytesRead).codeUnits) .buffer; - _requestBytesRead = responseText.length; + _requestBytesRead = responseString.length; _incomingProcessor.add(bytes); }); @@ -122,11 +122,9 @@ class XhrTransportStream implements GrpcTransportStream { if (!_headersReceived && !_validateResponseState()) { return; } - if (_request.status != 200) { + if (_request.response == null) { _onError( - GrpcError.unavailable( - 'Request failed with status: ${_request.status}', - null, + GrpcError.unavailable('XhrConnection request null response', null, _request.responseText), StackTrace.current); return; @@ -146,110 +144,6 @@ class XhrTransportStream implements GrpcTransportStream { } } -// XMLHttpRequest is an extension type and can't be extended or implemented. -// This interface is used to allow for mocking XMLHttpRequest in tests of -// XhrClientConnection. -@visibleForTesting -abstract interface class IXMLHttpRequest { - Stream get onReadyStateChange; - Stream get onProgress; - Stream get onError; - int get readyState; - JSAny? get response; - String get responseText; - Map get responseHeaders; - int get status; - - set responseType(String responseType); - set withCredentials(bool withCredentials); - - void abort(); - void open( - String method, - String url, [ - // external default is true - bool async = true, - String? username, - String? password, - ]); - void overrideMimeType(String mimeType); - void send([JSAny? body]); - void setRequestHeader(String header, String value); - - // This method should only be used in production code. - XMLHttpRequest toXMLHttpRequest(); -} - -// IXMLHttpRequest that delegates to a real XMLHttpRequest. -class XMLHttpRequestImpl implements IXMLHttpRequest { - final XMLHttpRequest _xhr = XMLHttpRequest(); - - XMLHttpRequestImpl(); - - @override - Stream get onReadyStateChange => _xhr.onReadyStateChange; - @override - Stream get onProgress => _xhr.onProgress; - @override - Stream get onError => _xhr.onError; - @override - int get readyState => _xhr.readyState; - @override - Map get responseHeaders => _xhr.responseHeaders; - @override - JSAny? get response => _xhr.response; - @override - String get responseText => _xhr.responseText; - @override - int get status => _xhr.status; - - @override - set responseType(String responseType) { - _xhr.responseType = responseType; - } - - @override - set withCredentials(bool withCredentials) { - _xhr.withCredentials = withCredentials; - } - - @override - void abort() { - _xhr.abort(); - } - - @override - void open( - String method, - String url, [ - bool async = true, - String? username, - String? password, - ]) { - _xhr.open(method, url, async, username, password); - } - - @override - void overrideMimeType(String mimeType) { - _xhr.overrideMimeType(mimeType); - } - - @override - void setRequestHeader(String header, String value) { - _xhr.setRequestHeader(header, value); - } - - @override - void send([JSAny? body]) { - _xhr.send(body); - } - - @override - XMLHttpRequest toXMLHttpRequest() { - return _xhr; - } -} - class XhrClientConnection implements ClientConnection { final Uri uri; @@ -259,20 +153,20 @@ class XhrClientConnection implements ClientConnection { @override String get authority => uri.authority; - @override String get scheme => uri.scheme; - void _initializeRequest( - IXMLHttpRequest request, Map metadata) { - metadata.forEach(request.setRequestHeader); + void _initializeRequest(HttpRequest request, Map metadata) { + for (final header in metadata.keys) { + request.setRequestHeader(header, metadata[header]!); + } // Overriding the mimetype allows us to stream and parse the data request.overrideMimeType('text/plain; charset=x-user-defined'); request.responseType = 'text'; } @visibleForTesting - IXMLHttpRequest createHttpRequest() => XMLHttpRequestImpl(); + HttpRequest createHttpRequest() => HttpRequest(); @override GrpcTransportStream makeRequest(String path, Duration? timeout, @@ -300,16 +194,11 @@ class XhrClientConnection implements ClientConnection { _initializeRequest(request, metadata); final transportStream = - _createXhrTransportStream(request, onError, _removeStream); + XhrTransportStream(request, onError: onError, onDone: _removeStream); _requests.add(transportStream); return transportStream; } - XhrTransportStream _createXhrTransportStream(IXMLHttpRequest request, - ErrorHandler onError, void Function(XhrTransportStream stream) onDone) { - return XhrTransportStream(request, onError: onError, onDone: onDone); - } - void _removeStream(XhrTransportStream stream) { _requests.remove(stream); } diff --git a/lib/src/generated/google/rpc/code.pb.dart b/lib/src/generated/google/rpc/code.pb.dart new file mode 100644 index 0000000..6580226 --- /dev/null +++ b/lib/src/generated/google/rpc/code.pb.dart @@ -0,0 +1,14 @@ +// +// Generated code. Do not modify. +// source: google/rpc/code.proto +// +// @dart = 2.12 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names, library_prefixes +// ignore_for_file: non_constant_identifier_names, prefer_final_fields +// ignore_for_file: unnecessary_import, unnecessary_this, unused_import + +import 'dart:core' as $core; + +export 'code.pbenum.dart'; diff --git a/lib/src/generated/google/rpc/code.pbenum.dart b/lib/src/generated/google/rpc/code.pbenum.dart new file mode 100644 index 0000000..f3d7bf3 --- /dev/null +++ b/lib/src/generated/google/rpc/code.pbenum.dart @@ -0,0 +1,79 @@ +// +// Generated code. Do not modify. +// source: google/rpc/code.proto +// +// @dart = 2.12 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names, library_prefixes +// ignore_for_file: non_constant_identifier_names, prefer_final_fields +// ignore_for_file: unnecessary_import, unnecessary_this, unused_import + +import 'dart:core' as $core; + +import 'package:protobuf/protobuf.dart' as $pb; + +/// The canonical error codes for gRPC APIs. +/// +/// +/// Sometimes multiple error codes may apply. Services should return +/// the most specific error code that applies. For example, prefer +/// `OUT_OF_RANGE` over `FAILED_PRECONDITION` if both codes apply. +/// Similarly prefer `NOT_FOUND` or `ALREADY_EXISTS` over `FAILED_PRECONDITION`. +class Code extends $pb.ProtobufEnum { + static const Code OK = Code._(0, _omitEnumNames ? '' : 'OK'); + static const Code CANCELLED = Code._(1, _omitEnumNames ? '' : 'CANCELLED'); + static const Code UNKNOWN = Code._(2, _omitEnumNames ? '' : 'UNKNOWN'); + static const Code INVALID_ARGUMENT = + Code._(3, _omitEnumNames ? '' : 'INVALID_ARGUMENT'); + static const Code DEADLINE_EXCEEDED = + Code._(4, _omitEnumNames ? '' : 'DEADLINE_EXCEEDED'); + static const Code NOT_FOUND = Code._(5, _omitEnumNames ? '' : 'NOT_FOUND'); + static const Code ALREADY_EXISTS = + Code._(6, _omitEnumNames ? '' : 'ALREADY_EXISTS'); + static const Code PERMISSION_DENIED = + Code._(7, _omitEnumNames ? '' : 'PERMISSION_DENIED'); + static const Code UNAUTHENTICATED = + Code._(16, _omitEnumNames ? '' : 'UNAUTHENTICATED'); + static const Code RESOURCE_EXHAUSTED = + Code._(8, _omitEnumNames ? '' : 'RESOURCE_EXHAUSTED'); + static const Code FAILED_PRECONDITION = + Code._(9, _omitEnumNames ? '' : 'FAILED_PRECONDITION'); + static const Code ABORTED = Code._(10, _omitEnumNames ? '' : 'ABORTED'); + static const Code OUT_OF_RANGE = + Code._(11, _omitEnumNames ? '' : 'OUT_OF_RANGE'); + static const Code UNIMPLEMENTED = + Code._(12, _omitEnumNames ? '' : 'UNIMPLEMENTED'); + static const Code INTERNAL = Code._(13, _omitEnumNames ? '' : 'INTERNAL'); + static const Code UNAVAILABLE = + Code._(14, _omitEnumNames ? '' : 'UNAVAILABLE'); + static const Code DATA_LOSS = Code._(15, _omitEnumNames ? '' : 'DATA_LOSS'); + + static const $core.List values = [ + OK, + CANCELLED, + UNKNOWN, + INVALID_ARGUMENT, + DEADLINE_EXCEEDED, + NOT_FOUND, + ALREADY_EXISTS, + PERMISSION_DENIED, + UNAUTHENTICATED, + RESOURCE_EXHAUSTED, + FAILED_PRECONDITION, + ABORTED, + OUT_OF_RANGE, + UNIMPLEMENTED, + INTERNAL, + UNAVAILABLE, + DATA_LOSS, + ]; + + static final $core.Map<$core.int, Code> _byValue = + $pb.ProtobufEnum.initByValue(values); + static Code? valueOf($core.int value) => _byValue[value]; + + const Code._($core.int v, $core.String n) : super(v, n); +} + +const _omitEnumNames = $core.bool.fromEnvironment('protobuf.omit_enum_names'); diff --git a/lib/src/generated/google/rpc/code.pbjson.dart b/lib/src/generated/google/rpc/code.pbjson.dart new file mode 100644 index 0000000..3e9bd5a --- /dev/null +++ b/lib/src/generated/google/rpc/code.pbjson.dart @@ -0,0 +1,47 @@ +// +// Generated code. Do not modify. +// source: google/rpc/code.proto +// +// @dart = 2.12 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names, library_prefixes +// ignore_for_file: non_constant_identifier_names, prefer_final_fields +// ignore_for_file: unnecessary_import, unnecessary_this, unused_import + +import 'dart:convert' as $convert; +import 'dart:core' as $core; +import 'dart:typed_data' as $typed_data; + +@$core.Deprecated('Use codeDescriptor instead') +const Code$json = { + '1': 'Code', + '2': [ + {'1': 'OK', '2': 0}, + {'1': 'CANCELLED', '2': 1}, + {'1': 'UNKNOWN', '2': 2}, + {'1': 'INVALID_ARGUMENT', '2': 3}, + {'1': 'DEADLINE_EXCEEDED', '2': 4}, + {'1': 'NOT_FOUND', '2': 5}, + {'1': 'ALREADY_EXISTS', '2': 6}, + {'1': 'PERMISSION_DENIED', '2': 7}, + {'1': 'UNAUTHENTICATED', '2': 16}, + {'1': 'RESOURCE_EXHAUSTED', '2': 8}, + {'1': 'FAILED_PRECONDITION', '2': 9}, + {'1': 'ABORTED', '2': 10}, + {'1': 'OUT_OF_RANGE', '2': 11}, + {'1': 'UNIMPLEMENTED', '2': 12}, + {'1': 'INTERNAL', '2': 13}, + {'1': 'UNAVAILABLE', '2': 14}, + {'1': 'DATA_LOSS', '2': 15}, + ], +}; + +/// Descriptor for `Code`. Decode as a `google.protobuf.EnumDescriptorProto`. +final $typed_data.Uint8List codeDescriptor = $convert.base64Decode( + 'CgRDb2RlEgYKAk9LEAASDQoJQ0FOQ0VMTEVEEAESCwoHVU5LTk9XThACEhQKEElOVkFMSURfQV' + 'JHVU1FTlQQAxIVChFERUFETElORV9FWENFRURFRBAEEg0KCU5PVF9GT1VORBAFEhIKDkFMUkVB' + 'RFlfRVhJU1RTEAYSFQoRUEVSTUlTU0lPTl9ERU5JRUQQBxITCg9VTkFVVEhFTlRJQ0FURUQQEB' + 'IWChJSRVNPVVJDRV9FWEhBVVNURUQQCBIXChNGQUlMRURfUFJFQ09ORElUSU9OEAkSCwoHQUJP' + 'UlRFRBAKEhAKDE9VVF9PRl9SQU5HRRALEhEKDVVOSU1QTEVNRU5URUQQDBIMCghJTlRFUk5BTB' + 'ANEg8KC1VOQVZBSUxBQkxFEA4SDQoJREFUQV9MT1NTEA8='); diff --git a/lib/src/protos/google/rpc/code.proto b/lib/src/protos/google/rpc/code.proto new file mode 100644 index 0000000..d115da1 --- /dev/null +++ b/lib/src/protos/google/rpc/code.proto @@ -0,0 +1,186 @@ +// Copyright 2020 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 +// +// 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. + +syntax = "proto3"; + +package google.rpc; + +option go_package = "google.golang.org/genproto/googleapis/rpc/code;code"; +option java_multiple_files = true; +option java_outer_classname = "CodeProto"; +option java_package = "com.google.rpc"; +option objc_class_prefix = "RPC"; + +// The canonical error codes for gRPC APIs. +// +// +// Sometimes multiple error codes may apply. Services should return +// the most specific error code that applies. For example, prefer +// `OUT_OF_RANGE` over `FAILED_PRECONDITION` if both codes apply. +// Similarly prefer `NOT_FOUND` or `ALREADY_EXISTS` over `FAILED_PRECONDITION`. +enum Code { + // Not an error; returned on success + // + // HTTP Mapping: 200 OK + OK = 0; + + // The operation was cancelled, typically by the caller. + // + // HTTP Mapping: 499 Client Closed Request + CANCELLED = 1; + + // Unknown error. For example, this error may be returned when + // a `Status` value received from another address space belongs to + // an error space that is not known in this address space. Also + // errors raised by APIs that do not return enough error information + // may be converted to this error. + // + // HTTP Mapping: 500 Internal Server Error + UNKNOWN = 2; + + // The client specified an invalid argument. Note that this differs + // from `FAILED_PRECONDITION`. `INVALID_ARGUMENT` indicates arguments + // that are problematic regardless of the state of the system + // (e.g., a malformed file name). + // + // HTTP Mapping: 400 Bad Request + INVALID_ARGUMENT = 3; + + // The deadline expired before the operation could complete. For operations + // that change the state of the system, this error may be returned + // even if the operation has completed successfully. For example, a + // successful response from a server could have been delayed long + // enough for the deadline to expire. + // + // HTTP Mapping: 504 Gateway Timeout + DEADLINE_EXCEEDED = 4; + + // Some requested entity (e.g., file or directory) was not found. + // + // Note to server developers: if a request is denied for an entire class + // of users, such as gradual feature rollout or undocumented whitelist, + // `NOT_FOUND` may be used. If a request is denied for some users within + // a class of users, such as user-based access control, `PERMISSION_DENIED` + // must be used. + // + // HTTP Mapping: 404 Not Found + NOT_FOUND = 5; + + // The entity that a client attempted to create (e.g., file or directory) + // already exists. + // + // HTTP Mapping: 409 Conflict + ALREADY_EXISTS = 6; + + // The caller does not have permission to execute the specified + // operation. `PERMISSION_DENIED` must not be used for rejections + // caused by exhausting some resource (use `RESOURCE_EXHAUSTED` + // instead for those errors). `PERMISSION_DENIED` must not be + // used if the caller can not be identified (use `UNAUTHENTICATED` + // instead for those errors). This error code does not imply the + // request is valid or the requested entity exists or satisfies + // other pre-conditions. + // + // HTTP Mapping: 403 Forbidden + PERMISSION_DENIED = 7; + + // The request does not have valid authentication credentials for the + // operation. + // + // HTTP Mapping: 401 Unauthorized + UNAUTHENTICATED = 16; + + // Some resource has been exhausted, perhaps a per-user quota, or + // perhaps the entire file system is out of space. + // + // HTTP Mapping: 429 Too Many Requests + RESOURCE_EXHAUSTED = 8; + + // The operation was rejected because the system is not in a state + // required for the operation's execution. For example, the directory + // to be deleted is non-empty, an rmdir operation is applied to + // a non-directory, etc. + // + // Service implementors can use the following guidelines to decide + // between `FAILED_PRECONDITION`, `ABORTED`, and `UNAVAILABLE`: + // (a) Use `UNAVAILABLE` if the client can retry just the failing call. + // (b) Use `ABORTED` if the client should retry at a higher level + // (e.g., when a client-specified test-and-set fails, indicating the + // client should restart a read-modify-write sequence). + // (c) Use `FAILED_PRECONDITION` if the client should not retry until + // the system state has been explicitly fixed. E.g., if an "rmdir" + // fails because the directory is non-empty, `FAILED_PRECONDITION` + // should be returned since the client should not retry unless + // the files are deleted from the directory. + // + // HTTP Mapping: 400 Bad Request + FAILED_PRECONDITION = 9; + + // The operation was aborted, typically due to a concurrency issue such as + // a sequencer check failure or transaction abort. + // + // See the guidelines above for deciding between `FAILED_PRECONDITION`, + // `ABORTED`, and `UNAVAILABLE`. + // + // HTTP Mapping: 409 Conflict + ABORTED = 10; + + // The operation was attempted past the valid range. E.g., seeking or + // reading past end-of-file. + // + // Unlike `INVALID_ARGUMENT`, this error indicates a problem that may + // be fixed if the system state changes. For example, a 32-bit file + // system will generate `INVALID_ARGUMENT` if asked to read at an + // offset that is not in the range [0,2^32-1], but it will generate + // `OUT_OF_RANGE` if asked to read from an offset past the current + // file size. + // + // There is a fair bit of overlap between `FAILED_PRECONDITION` and + // `OUT_OF_RANGE`. We recommend using `OUT_OF_RANGE` (the more specific + // error) when it applies so that callers who are iterating through + // a space can easily look for an `OUT_OF_RANGE` error to detect when + // they are done. + // + // HTTP Mapping: 400 Bad Request + OUT_OF_RANGE = 11; + + // The operation is not implemented or is not supported/enabled in this + // service. + // + // HTTP Mapping: 501 Not Implemented + UNIMPLEMENTED = 12; + + // Internal errors. This means that some invariants expected by the + // underlying system have been broken. This error code is reserved + // for serious errors. + // + // HTTP Mapping: 500 Internal Server Error + INTERNAL = 13; + + // The service is currently unavailable. This is most likely a + // transient condition, which can be corrected by retrying with + // a backoff. Note that it is not always safe to retry + // non-idempotent operations. + // + // See the guidelines above for deciding between `FAILED_PRECONDITION`, + // `ABORTED`, and `UNAVAILABLE`. + // + // HTTP Mapping: 503 Service Unavailable + UNAVAILABLE = 14; + + // Unrecoverable data loss or corruption. + // + // HTTP Mapping: 500 Internal Server Error + DATA_LOSS = 15; +} \ No newline at end of file diff --git a/lib/src/server/handler.dart b/lib/src/server/handler.dart index f28963c..ecbebe1 100644 --- a/lib/src/server/handler.dart +++ b/lib/src/server/handler.dart @@ -170,7 +170,7 @@ class ServerHandler extends ServiceCall { final acceptedEncodings = clientMetadata!['grpc-accept-encoding']?.split(',') ?? []; _callEncodingCodec = acceptedEncodings - .map(_codecRegistry.lookup) + .map(_codecRegistry!.lookup) .firstWhere((c) => c != null, orElse: () => null); } diff --git a/lib/src/shared/codec.dart b/lib/src/shared/codec.dart index eae7749..8f771d5 100644 --- a/lib/src/shared/codec.dart +++ b/lib/src/shared/codec.dart @@ -13,6 +13,56 @@ // See the License for the specific language governing permissions and // limitations under the License. -export 'codec/codec_all.dart'; -export 'codec/codec_io.dart' - if (dart.library.js_interop) 'codec/codec_web.dart'; // package:web implementation +import 'package:archive/archive.dart'; + +abstract class Codec { + /// Returns the message encoding that this compressor uses. + /// + /// This can be values such as "gzip", "deflate", "snappy", etc. + String get encodingName; + + /// Wraps an existing output stream with a compressed output. + List compress(List data); + + /// Wraps an existing output stream with a uncompressed input data. + List decompress(List data); +} + +/// The "identity", or "none" codec. +/// +/// This codec is special in that it can be used to explicitly disable Call +/// compression on a Channel that by default compresses. +class IdentityCodec implements Codec { + const IdentityCodec(); + + @override + final encodingName = 'identity'; + + @override + List compress(List data) { + return data; + } + + @override + List decompress(List data) { + return data; + } +} + +/// A gzip compressor and decompressor. +class GzipCodec implements Codec { + const GzipCodec(); + + @override + final encodingName = 'gzip'; + + @override + List compress(List data) { + return GZipEncoder().encode(data)!; + } + + @override + List decompress(List data) { + return GZipDecoder().decodeBytes(data); + } +} diff --git a/lib/src/shared/codec/codec_all.dart b/lib/src/shared/codec/codec_all.dart deleted file mode 100644 index 81657ef..0000000 --- a/lib/src/shared/codec/codec_all.dart +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2024, 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. - -abstract class Codec { - /// Returns the message encoding that this compressor uses. - /// - /// This can be values such as "gzip", "deflate", "snappy", etc. - String get encodingName; - - /// Wraps an existing output stream with a compressed output. - List compress(List data); - - /// Wraps an existing output stream with a uncompressed input data. - List decompress(List data); -} - -/// The "identity", or "none" codec. -/// -/// This codec is special in that it can be used to explicitly disable Call -/// compression on a Channel that by default compresses. -class IdentityCodec implements Codec { - const IdentityCodec(); - - @override - final encodingName = 'identity'; - - @override - List compress(List data) { - return data; - } - - @override - List decompress(List data) { - return data; - } -} diff --git a/lib/src/shared/codec/codec_io.dart b/lib/src/shared/codec/codec_io.dart deleted file mode 100644 index 99bfe78..0000000 --- a/lib/src/shared/codec/codec_io.dart +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2024, 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 'codec_all.dart'; - -/// A gzip compressor and decompressor. -class GzipCodec implements Codec { - const GzipCodec(); - - @override - final encodingName = 'gzip'; - - @override - List compress(List data) { - return gzip.encode(data); - } - - @override - List decompress(List data) { - return gzip.decode(data); - } -} diff --git a/lib/src/shared/codec/codec_web.dart b/lib/src/shared/codec/codec_web.dart deleted file mode 100644 index a3bf59e..0000000 --- a/lib/src/shared/codec/codec_web.dart +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2024, 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 'codec_all.dart'; - -/// A gzip compressor and decompressor. -class GzipCodec implements Codec { - const GzipCodec(); - - @override - final encodingName = 'gzip'; - - @override - List compress(List data) { - throw UnsupportedError('Gzip is not supported for grpc web'); - } - - @override - List decompress(List data) { - throw UnsupportedError('Gzip is not supported for grpc web'); - } -} diff --git a/lib/src/shared/message.dart b/lib/src/shared/message.dart index 0533c55..d9d64db 100644 --- a/lib/src/shared/message.dart +++ b/lib/src/shared/message.dart @@ -68,8 +68,7 @@ List frame(List rawPayload, [Codec? codec]) { final payloadLength = compressedPayload.length; final bytes = Uint8List(payloadLength + 5); final header = bytes.buffer.asByteData(0, 5); - header.setUint8( - 0, (codec == null || codec.encodingName == 'identity') ? 0 : 1); + header.setUint8(0, codec == null ? 0 : 1); header.setUint32(1, payloadLength); bytes.setRange(5, bytes.length, compressedPayload); return bytes; diff --git a/lib/src/shared/status.dart b/lib/src/shared/status.dart index cb66232..43e7ea8 100644 --- a/lib/src/shared/status.dart +++ b/lib/src/shared/status.dart @@ -13,16 +13,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -// ignore_for_file: prefer_relative_imports - import 'dart:convert'; -import 'package:grpc/src/generated/google/protobuf/any.pb.dart'; -import 'package:grpc/src/generated/google/rpc/error_details.pb.dart'; -import 'package:grpc/src/generated/google/rpc/status.pb.dart'; import 'package:meta/meta.dart'; import 'package:protobuf/protobuf.dart'; +import '../generated/google/protobuf/any.pb.dart'; +import '../generated/google/rpc/code.pbenum.dart'; +import '../generated/google/rpc/error_details.pb.dart'; +import '../generated/google/rpc/status.pb.dart'; import 'io_bits/io_bits.dart' show HttpStatus; class StatusCode { @@ -150,28 +149,6 @@ class StatusCode { static int fromHttpStatus(int status) { return _httpStatusToGrpcStatus[status] ?? StatusCode.unknown; } - - /// Creates a string from a gRPC status code. - static String? name(int status) => switch (status) { - ok => 'OK', - cancelled => 'CANCELLED', - unknown => 'UNKNOWN', - invalidArgument => 'INVALID_ARGUMENT', - deadlineExceeded => 'DEADLINE_EXCEEDED', - notFound => 'NOT_FOUND', - alreadyExists => 'ALREADY_EXISTS', - permissionDenied => 'PERMISSION_DENIED', - resourceExhausted => 'RESOURCE_EXHAUSTED', - failedPrecondition => 'FAILED_PRECONDITION', - aborted => 'ABORTED', - outOfRange => 'OUT_OF_RANGE', - unimplemented => 'UNIMPLEMENTED', - internal => 'INTERNAL', - unavailable => 'UNAVAILABLE', - dataLoss => 'DATA_LOSS', - unauthenticated => 'UNAUTHENTICATED', - int() => null, - }; } class GrpcError implements Exception { @@ -329,8 +306,7 @@ class GrpcError implements Exception { code = StatusCode.unauthenticated; /// Given a status code, return the name - String get codeName => - StatusCode.name(code) ?? StatusCode.name(StatusCode.unknown)!; + String get codeName => (Code.valueOf(code) ?? Code.UNKNOWN).name; @override bool operator ==(other) { @@ -352,7 +328,6 @@ class GrpcError implements Exception { /// This list comes from `error_details.proto`. If any new error detail types are /// added to the protbuf definition, this function should be updated accordingly to /// support them. -@visibleForTesting GeneratedMessage parseErrorDetailsFromAny(Any any) { switch (any.typeUrl) { case 'type.googleapis.com/google.rpc.RetryInfo': @@ -474,7 +449,7 @@ GrpcError? grpcErrorDetailsFromTrailers(Map trailers) { } Map toCustomTrailers(Map trailers) { - return Map.of(trailers) + return Map.from(trailers) ..remove(':status') ..remove('content-type') ..remove('grpc-status') diff --git a/pubspec.yaml b/pubspec.yaml index e2fd529..4801319 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,41 +1,35 @@ name: grpc description: Dart implementation of gRPC, a high performance, open-source universal RPC framework. -version: 4.0.2-wip +version: 3.2.4 repository: https://github.com/grpc/grpc-dart - environment: - sdk: ^3.5.0 + sdk: '>=3.3.0 <4.5.0' dependencies: + archive: ^3.4.10 async: ^2.11.0 crypto: ^3.0.3 fixnum: ^1.1.0 googleapis_auth: ^1.6.0 - meta: ^1.3.0 + meta: ">=1.11.0 <2.0.0" http: '>=0.13.0 <2.0.0' http2: ^2.3.0 protobuf: '>=2.0.0 <4.0.0' clock: ^1.1.1 - web: ^1.1.0 dev_dependencies: build_runner: ^2.4.9 build_test: ^2.2.2 - lints: ^5.0.0 + lints: ">=2.0.0 <4.0.0" mockito: ^5.4.4 path: ^1.9.0 test: ^1.25.3 stream_channel: ^2.1.2 stream_transform: ^2.1.0 - vm_service: ">=11.6.0 <16.0.0" + vm_service: ">=11.6.0 <15.0.0" fake_async: ^1.3.1 false_secrets: - interop/server1.key - test/data/localhost.key - -topics: - - grpc - - rpc - - protocols diff --git a/test/client_certificate_test.dart b/test/client_certificate_test.dart index 70bb2b9..238b932 100644 --- a/test/client_certificate_test.dart +++ b/test/client_certificate_test.dart @@ -1,23 +1,6 @@ -// Copyright (c) 2024, 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. - // TODO(dartbug.com/26057) currently Mac OS X seems to have some issues with // client certificates so we disable the test. @TestOn('vm && !mac-os') -library; - import 'dart:async'; import 'dart:io'; diff --git a/test/client_handles_bad_connections_test.dart b/test/client_handles_bad_connections_test.dart index 75114d7..986a750 100644 --- a/test/client_handles_bad_connections_test.dart +++ b/test/client_handles_bad_connections_test.dart @@ -1,21 +1,4 @@ -// Copyright (c) 2024, 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') -library; - import 'dart:async'; import 'package:grpc/grpc.dart' as grpc; diff --git a/test/client_tests/call_test.dart b/test/client_tests/call_test.dart index 9ce832b..ceff888 100644 --- a/test/client_tests/call_test.dart +++ b/test/client_tests/call_test.dart @@ -1,38 +1,7 @@ -// Copyright (c) 2024, 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/grpc.dart'; import 'package:grpc/src/client/call.dart'; import 'package:test/test.dart'; -import '../src/client_utils.dart'; - void main() { - const dummyValue = 0; - const cancelDurationMillis = 300; - - late ClientHarness harness; - - setUp(() { - harness = ClientHarness()..setUp(); - }); - - tearDown(() { - harness.tearDown(); - }); - test('WebCallOptions mergeWith CallOptions returns WebCallOptions', () { final options = WebCallOptions(bypassCorsPreflight: true, withCredentials: true); @@ -44,57 +13,4 @@ void main() { expect(mergedOptions.bypassCorsPreflight, true); expect(mergedOptions.withCredentials, true); }); - - test( - 'Cancelling a call correctly complete headers future', - () async { - final clientCall = harness.client.unary(dummyValue); - - Future.delayed( - Duration(milliseconds: cancelDurationMillis), - ).then((_) => clientCall.cancel()); - - expect(await clientCall.headers, isEmpty); - - await expectLater( - clientCall, - throwsA( - isA().having( - (e) => e.codeName, - 'Test codename', - contains('CANCELLED'), - ), - ), - ); - }, - ); - - test( - 'Cancelling a call correctly complete trailers futures', - () async { - final clientCall = harness.client.unary(dummyValue); - - Future.delayed( - Duration(milliseconds: cancelDurationMillis), - ).then((_) { - clientCall.cancel(); - }); - - expect( - await clientCall.trailers, - isEmpty, - ); - - await expectLater( - clientCall, - throwsA( - isA().having( - (e) => e.codeName, - 'Test codename', - contains('CANCELLED'), - ), - ), - ); - }, - ); } diff --git a/test/client_tests/client_interceptor_test.dart b/test/client_tests/client_interceptor_test.dart index b1763d5..d9132fb 100644 --- a/test/client_tests/client_interceptor_test.dart +++ b/test/client_tests/client_interceptor_test.dart @@ -1,18 +1,3 @@ -// Copyright (c) 2024, 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 'package:grpc/grpc.dart'; diff --git a/test/client_tests/client_keepalive_manager_test.dart b/test/client_tests/client_keepalive_manager_test.dart index c260dc9..74889d5 100644 --- a/test/client_tests/client_keepalive_manager_test.dart +++ b/test/client_tests/client_keepalive_manager_test.dart @@ -1,18 +1,3 @@ -// Copyright (c) 2024, 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:fake_async/fake_async.dart'; import 'package:grpc/src/client/client_keepalive.dart'; import 'package:mockito/annotations.dart'; diff --git a/test/client_tests/client_keepalive_manager_test.mocks.dart b/test/client_tests/client_keepalive_manager_test.mocks.dart index 20a8225..f03f3cb 100644 --- a/test/client_tests/client_keepalive_manager_test.mocks.dart +++ b/test/client_tests/client_keepalive_manager_test.mocks.dart @@ -1,24 +1,7 @@ -// Copyright (c) 2024, 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. - -// Mocks generated by Mockito 5.4.1 from annotations +// Mocks generated by Mockito 5.4.4 from annotations // in grpc/test/client_tests/client_keepalive_manager_test.dart. // Do not manually edit this file. -// @dart=2.19 - // ignore_for_file: no_leading_underscores_for_library_prefixes import 'package:mockito/mockito.dart' as _i1; @@ -28,6 +11,8 @@ import 'client_keepalive_manager_test.dart' as _i2; // ignore_for_file: avoid_redundant_argument_values // ignore_for_file: avoid_setters_without_getters // ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member // ignore_for_file: prefer_const_constructors @@ -47,6 +32,7 @@ class MockPinger extends _i1.Mock implements _i2.Pinger { ), returnValueForMissingStub: null, ); + @override void onPingTimeout() => super.noSuchMethod( Invocation.method( diff --git a/test/client_tests/client_xhr_transport_test.dart b/test/client_tests/client_xhr_transport_test.dart index cdf1be7..4b3f858 100644 --- a/test/client_tests/client_xhr_transport_test.dart +++ b/test/client_tests/client_xhr_transport_test.dart @@ -13,11 +13,10 @@ // See the License for the specific language governing permissions and // limitations under the License. @TestOn('browser') -library; import 'dart:async'; -import 'dart:js_interop'; -import 'dart:typed_data'; +import 'dart:html'; + import 'package:async/async.dart'; import 'package:grpc/src/client/call.dart'; import 'package:grpc/src/client/transport/xhr_transport.dart'; @@ -26,13 +25,12 @@ import 'package:grpc/src/shared/status.dart'; import 'package:mockito/mockito.dart'; import 'package:stream_transform/stream_transform.dart'; import 'package:test/test.dart'; -import 'package:web/web.dart'; final readyStateChangeEvent = - Event('readystatechange', EventInit(bubbles: false, cancelable: false)); + Event('readystatechange', canBubble: false, cancelable: false); final progressEvent = ProgressEvent('onloadstart'); -class MockHttpRequest extends Mock implements IXMLHttpRequest { +class MockHttpRequest extends Mock implements HttpRequest { MockHttpRequest({int? code}) : status = code ?? 200; // ignore: close_sinks StreamController readyStateChangeController = @@ -53,10 +51,6 @@ class MockHttpRequest extends Mock implements IXMLHttpRequest { @override final int status; - @override - String get responseText => - super.noSuchMethod(Invocation.getter(#responseText), returnValue: ''); - @override int get readyState => super.noSuchMethod(Invocation.getter(#readyState), returnValue: -1); @@ -70,13 +64,13 @@ class MockHttpRequest extends Mock implements IXMLHttpRequest { class MockXhrClientConnection extends XhrClientConnection { MockXhrClientConnection({int? code}) : _statusCode = code ?? 200, - super(Uri.parse('test:0')); + super(Uri.parse('test:8080')); late MockHttpRequest latestRequest; final int _statusCode; @override - IXMLHttpRequest createHttpRequest() { + HttpRequest createHttpRequest() { final request = MockHttpRequest(code: _statusCode); latestRequest = request; return request; @@ -213,8 +207,8 @@ void main() { await stream.terminate(); final expectedData = frame(data); - verify( - connection.latestRequest.send(Uint8List.fromList(expectedData).toJS)); + expect(verify(connection.latestRequest.send(captureAny)).captured.single, + expectedData); }); test('Stream handles headers properly', () async { @@ -230,13 +224,14 @@ void main() { (error, _) => fail(error.toString())); when(transport.latestRequest.responseHeaders).thenReturn(responseHeaders); - when(transport.latestRequest.responseText) + when(transport.latestRequest.response) .thenReturn(String.fromCharCodes(frame([]))); // Set expectation for request readyState and generate two readyStateChange // events, so that incomingMessages stream completes. - final readyStates = [XMLHttpRequest.HEADERS_RECEIVED, XMLHttpRequest.DONE]; - when(transport.latestRequest.readyState).thenReturnInOrder(readyStates); + final readyStates = [HttpRequest.HEADERS_RECEIVED, HttpRequest.DONE]; + when(transport.latestRequest.readyState) + .thenAnswer((_) => readyStates.removeAt(0)); transport.latestRequest.readyStateChangeController .add(readyStateChangeEvent); transport.latestRequest.readyStateChangeController @@ -271,12 +266,13 @@ void main() { final encodedString = String.fromCharCodes(encodedTrailers); when(connection.latestRequest.responseHeaders).thenReturn(requestHeaders); - when(connection.latestRequest.responseText).thenReturn(encodedString); + when(connection.latestRequest.response).thenReturn(encodedString); // Set expectation for request readyState and generate events so that // incomingMessages stream completes. - when(connection.latestRequest.readyState).thenReturnInOrder( - [XMLHttpRequest.HEADERS_RECEIVED, XMLHttpRequest.DONE]); + final readyStates = [HttpRequest.HEADERS_RECEIVED, HttpRequest.DONE]; + when(connection.latestRequest.readyState) + .thenAnswer((_) => readyStates.removeAt(0)); connection.latestRequest.readyStateChangeController .add(readyStateChangeEvent); connection.latestRequest.progressController.add(progressEvent); @@ -306,11 +302,13 @@ void main() { final encodedString = String.fromCharCodes(encoded); when(connection.latestRequest.responseHeaders).thenReturn(requestHeaders); - when(connection.latestRequest.responseText).thenReturn(encodedString); + when(connection.latestRequest.response).thenReturn(encodedString); + // Set expectation for request readyState and generate events so that // incomingMessages stream completes. - when(connection.latestRequest.readyState).thenReturnInOrder( - [XMLHttpRequest.HEADERS_RECEIVED, XMLHttpRequest.DONE]); + final readyStates = [HttpRequest.HEADERS_RECEIVED, HttpRequest.DONE]; + when(connection.latestRequest.readyState) + .thenAnswer((_) => readyStates.removeAt(0)); connection.latestRequest.readyStateChangeController .add(readyStateChangeEvent); connection.latestRequest.progressController.add(progressEvent); @@ -338,13 +336,14 @@ void main() { requestHeaders, (error, _) => fail(error.toString())); final data = List.filled(10, 224); when(connection.latestRequest.responseHeaders).thenReturn(requestHeaders); - when(connection.latestRequest.responseText) + when(connection.latestRequest.response) .thenReturn(String.fromCharCodes(frame(data))); // Set expectation for request readyState and generate events, so that // incomingMessages stream completes. - when(connection.latestRequest.readyState).thenReturnInOrder( - [XMLHttpRequest.HEADERS_RECEIVED, XMLHttpRequest.DONE]); + final readyStates = [HttpRequest.HEADERS_RECEIVED, HttpRequest.DONE]; + when(connection.latestRequest.readyState) + .thenAnswer((_) => readyStates.removeAt(0)); connection.latestRequest.readyStateChangeController .add(readyStateChangeEvent); connection.latestRequest.progressController.add(progressEvent); @@ -369,7 +368,7 @@ void main() { const errorDetails = 'error details'; when(connection.latestRequest.responseHeaders) .thenReturn({'content-type': 'application/grpc+proto'}); - when(connection.latestRequest.readyState).thenReturn(XMLHttpRequest.DONE); + when(connection.latestRequest.readyState).thenReturn(HttpRequest.DONE); when(connection.latestRequest.responseText).thenReturn(errorDetails); connection.latestRequest.readyStateChangeController .add(readyStateChangeEvent); @@ -398,12 +397,12 @@ void main() { when(connection.latestRequest.responseHeaders).thenReturn(metadata); when(connection.latestRequest.readyState) - .thenReturn(XMLHttpRequest.HEADERS_RECEIVED); + .thenReturn(HttpRequest.HEADERS_RECEIVED); // At first invocation the response should be the the first message, after // that first + last messages. var first = true; - when(connection.latestRequest.responseText).thenAnswer((_) { + when(connection.latestRequest.response).thenAnswer((_) { if (first) { first = false; return encodedStrings[0]; @@ -411,7 +410,7 @@ void main() { return encodedStrings[0] + encodedStrings[1]; }); - final readyStates = [XMLHttpRequest.HEADERS_RECEIVED, XMLHttpRequest.DONE]; + final readyStates = [HttpRequest.HEADERS_RECEIVED, HttpRequest.DONE]; when(connection.latestRequest.readyState) .thenAnswer((_) => readyStates.removeAt(0)); 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 a2b6e4a..bffd8ba 100644 --- a/test/client_tests/grpc_or_grpcweb_channel_grpc_test.dart +++ b/test/client_tests/grpc_or_grpcweb_channel_grpc_test.dart @@ -13,14 +13,12 @@ // See the License for the specific language governing permissions and // limitations under the License. @TestOn('!browser') -library; - import 'package:grpc/grpc.dart'; import 'package:grpc/grpc_or_grpcweb.dart'; import 'package:test/test.dart'; const host = 'example.com'; -const port = 0; +const port = 8080; void main() { test('Channel on non-web uses gRPC ClientChannel with correct params', () { 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 8382219..77fbe70 100644 --- a/test/client_tests/grpc_or_grpcweb_channel_web_test.dart +++ b/test/client_tests/grpc_or_grpcweb_channel_web_test.dart @@ -13,14 +13,13 @@ // See the License for the specific language governing permissions and // limitations under the License. @TestOn('browser') -library; import 'package:grpc/grpc_or_grpcweb.dart'; import 'package:grpc/grpc_web.dart'; import 'package:test/test.dart'; const host = 'example.com'; -const port = 0; +const port = 8080; void main() { test('Channel on web uses GrpcWebClientChannel with correct URI', () { diff --git a/test/connection_server_test.dart b/test/connection_server_test.dart index d435773..4ced9bf 100644 --- a/test/connection_server_test.dart +++ b/test/connection_server_test.dart @@ -13,7 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. @TestOn('vm') -library; import 'dart:async'; @@ -290,7 +289,7 @@ void main() { } GrpcError? interceptor(call, method) { - if (method.name == 'Unary') { + if (method.identifier == 'Unary') { return null; } return GrpcError.unauthenticated('Request is unauthenticated'); @@ -312,7 +311,7 @@ void main() { group('returns error if interceptor blocks request', () { GrpcError? interceptor(call, method) { - if (method.name == 'Unary') { + if (method.identifier == 'Unary') { return GrpcError.unauthenticated('Request is unauthenticated'); } return null; diff --git a/test/grpc_compression_flag_test.dart b/test/grpc_compression_flag_test.dart deleted file mode 100644 index a41b699..0000000 --- a/test/grpc_compression_flag_test.dart +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2024, 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') -library; - -import 'package:grpc/src/shared/codec.dart'; -import 'package:grpc/src/shared/message.dart'; -import 'package:test/test.dart'; - -void main() { - group('GRPC Compression Flag', () { - test('compression flag 0 with null codec', () { - final rawPayload = [1, 2, 3, 4]; - final Codec? codec = null; - final data = frame(rawPayload, codec); - expect(data[0], 0); - }); - test('compression flag 0 with grpc-encoding identity', () { - final rawPayload = [1, 2, 3, 4]; - final Codec codec = IdentityCodec(); - final data = frame(rawPayload, codec); - expect(data[0], 0); - }); - test('compression flag 1 with grpc-encoding gzip', () { - final rawPayload = [1, 2, 3, 4]; - final Codec codec = GzipCodec(); - final data = frame(rawPayload, codec); - expect(data[0], 1); - }); - }); -} diff --git a/test/grpc_web_decoding_test.dart b/test/grpc_web_decoding_test.dart index 96d985a..aa0f390 100644 --- a/test/grpc_web_decoding_test.dart +++ b/test/grpc_web_decoding_test.dart @@ -1,18 +1,3 @@ -// Copyright (c) 2024, 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:typed_data'; diff --git a/test/grpc_web_server.dart b/test/grpc_web_server.dart index 57d80b6..8f87555 100644 --- a/test/grpc_web_server.dart +++ b/test/grpc_web_server.dart @@ -1,18 +1,3 @@ -// Copyright (c) 2024, 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'; diff --git a/test/grpc_web_test.dart b/test/grpc_web_test.dart index dd5fccb..ad58181 100644 --- a/test/grpc_web_test.dart +++ b/test/grpc_web_test.dart @@ -1,21 +1,4 @@ -// Copyright (c) 2024, 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') -library; - import 'dart:async'; import 'dart:math' as math; diff --git a/test/keepalive_test.dart b/test/keepalive_test.dart index bf48f9b..e4ddf2d 100644 --- a/test/keepalive_test.dart +++ b/test/keepalive_test.dart @@ -1,21 +1,4 @@ -// Copyright (c) 2024, 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') -library; - import 'dart:async'; import 'package:grpc/grpc.dart'; @@ -32,20 +15,16 @@ void main() { late EchoServiceClient fakeClient; late FakeClientChannel fakeChannel; late EchoServiceClient unresponsiveClient; - late FakeClientChannel unresponsiveChannel; - - final pingInterval = Duration(milliseconds: 10); - final timeout = Duration(milliseconds: 30); - final maxBadPings = 5; + late ClientChannel unresponsiveChannel; setUp(() async { final serverOptions = ServerKeepAliveOptions( - maxBadPings: maxBadPings, + maxBadPings: 5, minIntervalBetweenPingsWithoutData: Duration(milliseconds: 10), ); final clientOptions = ClientKeepAliveOptions( - pingInterval: pingInterval, - timeout: timeout, + pingInterval: Duration(milliseconds: 10), + timeout: Duration(milliseconds: 30), permitWithoutCalls: true, ); @@ -53,7 +32,7 @@ void main() { services: [FakeEchoService()], keepAliveOptions: serverOptions, ); - await server.serve(address: 'localhost', port: 0); + await server.serve(address: 'localhost', port: 8081); fakeChannel = FakeClientChannel( 'localhost', port: server.port!, @@ -83,7 +62,7 @@ void main() { test('Server terminates connection after too many pings without data', () async { await fakeClient.echo(EchoRequest()); - await Future.delayed(timeout * maxBadPings * 2); + await Future.delayed(Duration(milliseconds: 300)); await fakeClient.echo(EchoRequest()); // Check that the server closed the connection, the next request then has // to build a new one. @@ -92,27 +71,23 @@ void main() { test('Server doesnt terminate connection after pings, as data is sent', () async { - for (var i = 0; i < 10; i++) { - await fakeClient.echo(EchoRequest()); - await Future.delayed(timeout * 0.2); - } + final timer = Timer.periodic( + Duration(milliseconds: 10), (timer) => fakeClient.echo(EchoRequest())); + await Future.delayed(Duration(milliseconds: 200), () => timer.cancel()); + + // Wait for last request to be sent + await Future.delayed(Duration(milliseconds: 20)); // Check that the server never closed the connection expect(fakeChannel.newConnectionCounter, 1); }); - test('Server doesnt ack the ping, making the client shutdown the transport', + test('Server doesnt ack the ping, making the client shutdown the connection', () async { - //Send a first request, get a connection await unresponsiveClient.echo(EchoRequest()); - expect(unresponsiveChannel.newConnectionCounter, 1); - - //Ping is not being acked on time - await Future.delayed(timeout * 2); - - //A second request gets a new connection - await unresponsiveClient.echo(EchoRequest()); - expect(unresponsiveChannel.newConnectionCounter, 2); + await Future.delayed(Duration(milliseconds: 200)); + await expectLater( + unresponsiveClient.echo(EchoRequest()), throwsA(isA())); }); } @@ -121,7 +96,7 @@ class FakeClientChannel extends ClientChannel { FakeHttp2ClientConnection? fakeHttp2ClientConnection; FakeClientChannel( super.host, { - super.port, + super.port = 443, super.options = const ChannelOptions(), super.channelShutdownHandler, }); @@ -150,23 +125,20 @@ class FakeHttp2ClientConnection extends Http2ClientConnection { } /// A wrapper around a [FakeHttp2ClientConnection] -class UnresponsiveClientChannel extends FakeClientChannel { +class UnresponsiveClientChannel extends ClientChannel { UnresponsiveClientChannel( super.host, { - super.port, + super.port = 443, super.options = const ChannelOptions(), super.channelShutdownHandler, }); @override - ClientConnection createConnection() { - fakeHttp2ClientConnection = - UnresponsiveHttp2ClientConnection(host, port, options); - return fakeHttp2ClientConnection!; - } + ClientConnection createConnection() => + UnresponsiveHttp2ClientConnection(host, port, options); } -class UnresponsiveHttp2ClientConnection extends FakeHttp2ClientConnection { +class UnresponsiveHttp2ClientConnection extends Http2ClientConnection { UnresponsiveHttp2ClientConnection(super.host, super.port, super.options); @override @@ -200,6 +172,8 @@ class FakeEchoService extends EchoServiceBase { @override Stream serverStreamingEcho( - ServiceCall call, ServerStreamingEchoRequest request) => - throw UnsupportedError('Not used in this test'); + ServiceCall call, ServerStreamingEchoRequest request) { + // TODO: implement serverStreamingEcho + throw UnimplementedError(); + } } diff --git a/test/options_test.dart b/test/options_test.dart index edb3a24..c61d82f 100644 --- a/test/options_test.dart +++ b/test/options_test.dart @@ -13,7 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. @TestOn('vm') -library; import 'dart:io'; diff --git a/test/proxy_secure_test.dart b/test/proxy_secure_test.dart index 806913b..24f6ff8 100644 --- a/test/proxy_secure_test.dart +++ b/test/proxy_secure_test.dart @@ -1,21 +1,4 @@ -// Copyright (c) 2024, 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') -library; - import 'dart:async'; import 'dart:io'; @@ -33,13 +16,13 @@ void main() { server = Server.create(services: [FakeEchoService()]); await server.serve( address: 'localhost', - port: 0, + port: 8888, security: ServerTlsCredentials( certificate: File('test/data/localhost.crt').readAsBytesSync(), privateKey: File('test/data/localhost.key').readAsBytesSync(), ), ); - final proxy = Proxy(host: 'localhost', port: 0); + final proxy = Proxy(host: 'localhost', port: 8080); final proxyCAName = '/CN=mitmproxy/O=mitmproxy'; fakeChannel = ClientChannel( diff --git a/test/proxy_test.dart b/test/proxy_test.dart index 6fc3072..a4f9bcf 100644 --- a/test/proxy_test.dart +++ b/test/proxy_test.dart @@ -1,21 +1,4 @@ -// Copyright (c) 2024, 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') -library; - import 'dart:async'; import 'package:grpc/grpc.dart'; @@ -30,9 +13,9 @@ void main() { setUp(() async { server = Server.create(services: [FakeEchoService()]); - await server.serve(address: 'localhost', port: 0); + await server.serve(address: 'localhost', port: 8888); - final proxy = Proxy(host: 'localhost', port: 0); + final proxy = Proxy(host: 'localhost', port: 8080); fakeChannel = ClientChannel( 'localhost', diff --git a/test/round_trip_test.dart b/test/round_trip_test.dart index 5d07fc8..4a45224 100644 --- a/test/round_trip_test.dart +++ b/test/round_trip_test.dart @@ -1,21 +1,4 @@ -// Copyright (c) 2024, 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') -library; - import 'dart:async'; import 'dart:io'; diff --git a/test/server_cancellation_test.dart b/test/server_cancellation_test.dart index ab119bb..ff4cd85 100644 --- a/test/server_cancellation_test.dart +++ b/test/server_cancellation_test.dart @@ -14,8 +14,6 @@ // limitations under the License. @TestOn('vm') -library; - import 'package:grpc/grpc.dart'; import 'package:test/test.dart'; @@ -47,7 +45,7 @@ void main() { server = Server.create( services: [EchoService()], ); - await server.serve(address: 'localhost', port: 0); + await server.serve(address: 'localhost', port: 8081); channel = ClientChannel( 'localhost', port: server.port!, diff --git a/test/server_handles_broken_connection_test.dart b/test/server_handles_broken_connection_test.dart index c59c9da..cd6d1fd 100644 --- a/test/server_handles_broken_connection_test.dart +++ b/test/server_handles_broken_connection_test.dart @@ -1,21 +1,4 @@ -// Copyright (c) 2024, 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') -library; - import 'dart:async'; import 'dart:io'; import 'dart:isolate'; diff --git a/test/server_keepalive_manager_test.dart b/test/server_keepalive_manager_test.dart index 94ab257..230fc3b 100644 --- a/test/server_keepalive_manager_test.dart +++ b/test/server_keepalive_manager_test.dart @@ -1,18 +1,3 @@ -// Copyright (c) 2024, 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 'package:fake_async/fake_async.dart'; diff --git a/test/server_test.dart b/test/server_test.dart index 74b6987..2de494d 100644 --- a/test/server_test.dart +++ b/test/server_test.dart @@ -13,7 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. @TestOn('vm') -library; import 'dart:async'; @@ -304,7 +303,7 @@ void main() { } GrpcError? interceptor(call, method) { - if (method.name == 'Unary') { + if (method.identifier == 'Unary') { return null; } return GrpcError.unauthenticated('Request is unauthenticated'); @@ -325,8 +324,8 @@ void main() { }); group('returns error if interceptor blocks request', () { - GrpcError? interceptor(ServiceCall call, ServiceMethod method) { - if (method.name == 'Unary') { + GrpcError? interceptor(call, method) { + if (method.identifier == 'Unary') { return GrpcError.unauthenticated('Request is unauthenticated'); } return null; diff --git a/test/shared_tests/codec_registry_test.dart b/test/shared_tests/codec_registry_test.dart index 55de10e..5a5483b 100644 --- a/test/shared_tests/codec_registry_test.dart +++ b/test/shared_tests/codec_registry_test.dart @@ -1,18 +1,3 @@ -// Copyright (c) 2024, 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/shared/codec.dart'; import 'package:grpc/src/shared/codec_registry.dart'; import 'package:test/test.dart'; diff --git a/test/src/client_utils.mocks.dart b/test/src/client_utils.mocks.dart index 98702df..8da129c 100644 --- a/test/src/client_utils.mocks.dart +++ b/test/src/client_utils.mocks.dart @@ -1,9 +1,7 @@ -// Mocks generated by Mockito 5.4.1 from annotations +// Mocks generated by Mockito 5.4.4 from annotations // in grpc/test/src/client_utils.dart. // Do not manually edit this file. -// @dart=2.19 - // ignore_for_file: no_leading_underscores_for_library_prefixes import 'dart:async' as _i3; @@ -15,6 +13,8 @@ import 'package:mockito/mockito.dart' as _i1; // ignore_for_file: avoid_redundant_argument_values // ignore_for_file: avoid_setters_without_getters // ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member // ignore_for_file: prefer_const_constructors @@ -57,6 +57,7 @@ class MockClientTransportConnection extends _i1.Mock Invocation.getter(#isOpen), returnValue: false, ) as bool); + @override set onActiveStateChanged(_i2.ActiveStateHandler? callback) => super.noSuchMethod( @@ -66,21 +67,25 @@ class MockClientTransportConnection extends _i1.Mock ), returnValueForMissingStub: null, ); + @override _i3.Future get onInitialPeerSettingsReceived => (super.noSuchMethod( Invocation.getter(#onInitialPeerSettingsReceived), returnValue: _i3.Future.value(), ) as _i3.Future); + @override _i3.Stream get onPingReceived => (super.noSuchMethod( Invocation.getter(#onPingReceived), returnValue: _i3.Stream.empty(), ) as _i3.Stream); + @override _i3.Stream get onFrameReceived => (super.noSuchMethod( Invocation.getter(#onFrameReceived), returnValue: _i3.Stream.empty(), ) as _i3.Stream); + @override _i2.ClientTransportStream makeRequest( List<_i4.Header>? headers, { @@ -101,6 +106,7 @@ class MockClientTransportConnection extends _i1.Mock ), ), ) as _i2.ClientTransportStream); + @override _i3.Future ping() => (super.noSuchMethod( Invocation.method( @@ -109,6 +115,7 @@ class MockClientTransportConnection extends _i1.Mock ), returnValue: _i3.Future.value(), ) as _i3.Future); + @override _i3.Future finish() => (super.noSuchMethod( Invocation.method( @@ -117,6 +124,7 @@ class MockClientTransportConnection extends _i1.Mock ), returnValue: _i3.Future.value(), ) as _i3.Future); + @override _i3.Future terminate([int? errorCode]) => (super.noSuchMethod( Invocation.method( @@ -141,16 +149,19 @@ class MockClientTransportStream extends _i1.Mock Invocation.getter(#peerPushes), returnValue: _i3.Stream<_i2.TransportStreamPush>.empty(), ) as _i3.Stream<_i2.TransportStreamPush>); + @override int get id => (super.noSuchMethod( Invocation.getter(#id), returnValue: 0, ) as int); + @override _i3.Stream<_i2.StreamMessage> get incomingMessages => (super.noSuchMethod( Invocation.getter(#incomingMessages), returnValue: _i3.Stream<_i2.StreamMessage>.empty(), ) as _i3.Stream<_i2.StreamMessage>); + @override _i3.StreamSink<_i2.StreamMessage> get outgoingMessages => (super.noSuchMethod( Invocation.getter(#outgoingMessages), @@ -159,6 +170,7 @@ class MockClientTransportStream extends _i1.Mock Invocation.getter(#outgoingMessages), ), ) as _i3.StreamSink<_i2.StreamMessage>); + @override set onTerminated(void Function(int?)? value) => super.noSuchMethod( Invocation.setter( @@ -167,6 +179,7 @@ class MockClientTransportStream extends _i1.Mock ), returnValueForMissingStub: null, ); + @override void terminate() => super.noSuchMethod( Invocation.method( @@ -175,6 +188,7 @@ class MockClientTransportStream extends _i1.Mock ), returnValueForMissingStub: null, ); + @override void sendHeaders( List<_i4.Header>? headers, { @@ -188,6 +202,7 @@ class MockClientTransportStream extends _i1.Mock ), returnValueForMissingStub: null, ); + @override void sendData( List? bytes, { diff --git a/test/timeline_test.dart b/test/timeline_test.dart index 1866ea5..c429198 100644 --- a/test/timeline_test.dart +++ b/test/timeline_test.dart @@ -16,8 +16,6 @@ @TestOn('vm') @Skip( 'Run only as `dart run --enable-vm-service --timeline-streams=Dart test/timeline_test.dart`') -library; - import 'dart:async'; import 'dart:developer' as dev; diff --git a/test/tools/http2_client.dart b/test/tools/http2_client.dart index 9bd4004..46b8b42 100644 --- a/test/tools/http2_client.dart +++ b/test/tools/http2_client.dart @@ -1,18 +1,3 @@ -// Copyright (c) 2024, 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 'package:grpc/grpc.dart'; @@ -20,7 +5,7 @@ import 'package:grpc/src/client/http2_connection.dart'; import 'package:http2/http2.dart'; Future main(List args) async { - final serverPort = 0; + final serverPort = 5678; final proxyPort = int.tryParse(args.first); final proxy = @@ -37,7 +22,7 @@ Future main(List args) async { final incoming = proxy == null ? connector.socket : await connector.connectToProxy(proxy); - final uri = Uri.parse('http://localhost:0'); + final uri = Uri.parse('http://localhost:8080'); final transport = ClientTransportConnection.viaStreams(incoming, connector.socket); diff --git a/test/tools/http2_server.dart b/test/tools/http2_server.dart index 721773d..4ab5eb2 100644 --- a/test/tools/http2_server.dart +++ b/test/tools/http2_server.dart @@ -1,18 +1,3 @@ -// Copyright (c) 2024, 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:io'; From 25fc12e45f277823def0001fb63729ff4bb1ffc1 Mon Sep 17 00:00:00 2001 From: Tsavo Knott Date: Fri, 3 Jan 2025 14:35:07 -0500 Subject: [PATCH 32/32] Update Pubspec --- pubspec.yaml | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/pubspec.yaml b/pubspec.yaml index aaedfdd..e6641b8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,33 +1,33 @@ name: grpc description: Dart implementation of gRPC, a high performance, open-source universal RPC framework. -version: 4.0.2-wip +version: 4.0.2 -repository: https://github.com/grpc/grpc-dart +repository: https://github.com/open-runtime/grpc-dart environment: sdk: ^3.5.0 dependencies: - async: ^2.5.0 - crypto: ^3.0.0 - fixnum: ^1.0.0 - googleapis_auth: ^1.1.0 + async: ^2.11.0 + crypto: ^3.0.3 + fixnum: ^1.1.0 + googleapis_auth: ^1.6.0 meta: ^1.3.0 http: '>=0.13.0 <2.0.0' - http2: ^2.2.0 + http2: ^2.3.0 protobuf: '>=2.0.0 <4.0.0' clock: ^1.1.1 web: ^1.1.0 dev_dependencies: - build_runner: ^2.0.0 - build_test: ^2.0.0 + build_runner: ^2.4.9 + build_test: ^2.2.2 lints: ^5.0.0 - mockito: ^5.0.0 - path: ^1.8.0 - test: ^1.16.0 - stream_channel: ^2.1.0 - stream_transform: ^2.0.0 + mockito: ^5.4.4 + path: ^1.9.0 + test: ^1.25.3 + stream_channel: ^2.1.2 + stream_transform: ^2.1.0 vm_service: ">=11.6.0 <16.0.0" fake_async: ^1.3.1