diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index 7684f65..24c29fa 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -11,12 +11,12 @@ on: jobs: # Check code formating and static analysis on a single OS (linux) - # against Dart stable and dev. + # against Dart dev. analyze: runs-on: ubuntu-latest strategy: matrix: - sdk: [stable, dev] + sdk: [dev] steps: - uses: actions/checkout@v2 - uses: cedx/setup-dart@v2 @@ -43,7 +43,7 @@ jobs: # Run tests on a matrix consisting of three dimensions: # 1. OS: mac, windows, linux - # 2. release channel: stable, dev + # 2. release channel: dev # 3. TODO: Dart execution mode: native, web test: needs: analyze @@ -51,7 +51,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - sdk: [stable, dev] + sdk: [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 2bc117f..a8a5822 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.0.0-nullsafety.0 + +* Migrate library and tests to null safety. + ## 2.9.0 * Added support for compression/decompression, which can be configured through diff --git a/example/googleapis/pubspec.yaml b/example/googleapis/pubspec.yaml index dfd1a7d..363f48e 100644 --- a/example/googleapis/pubspec.yaml +++ b/example/googleapis/pubspec.yaml @@ -9,7 +9,7 @@ dependencies: async: ^2.2.0 grpc: path: ../../ - protobuf: ^1.0.1 + protobuf: ^2.0.0-nullsafety dev_dependencies: test: ^1.6.4 diff --git a/example/grpc-web/pubspec.yaml b/example/grpc-web/pubspec.yaml index a11b237..986f519 100644 --- a/example/grpc-web/pubspec.yaml +++ b/example/grpc-web/pubspec.yaml @@ -8,8 +8,7 @@ environment: dependencies: grpc: path: ../../ - protobuf: ^1.0.1 + protobuf: ^2.0.0-nullsafety dev_dependencies: build_runner: ^1.5.2 - build_web_compilers: ^2.1.1 \ No newline at end of file diff --git a/example/helloworld/pubspec.yaml b/example/helloworld/pubspec.yaml index e205df7..3f81e39 100644 --- a/example/helloworld/pubspec.yaml +++ b/example/helloworld/pubspec.yaml @@ -9,4 +9,4 @@ dependencies: async: ^2.2.0 grpc: path: ../../ - protobuf: ^1.0.1 + protobuf: ^2.0.0-nullsafety diff --git a/example/metadata/pubspec.yaml b/example/metadata/pubspec.yaml index b96ec2e..283feb6 100644 --- a/example/metadata/pubspec.yaml +++ b/example/metadata/pubspec.yaml @@ -9,7 +9,7 @@ dependencies: async: ^2.2.0 grpc: path: ../../ - protobuf: ^1.0.1 + protobuf: ^2.0.0-nullsafety dev_dependencies: test: ^1.6.0 diff --git a/example/route_guide/pubspec.yaml b/example/route_guide/pubspec.yaml index 16fbca8..c7fb64c 100644 --- a/example/route_guide/pubspec.yaml +++ b/example/route_guide/pubspec.yaml @@ -9,4 +9,4 @@ dependencies: async: ^2.2.0 grpc: path: ../../ - protobuf: ^1.0.1 + protobuf: ^2.0.0-nullsafety diff --git a/interop/pubspec.yaml b/interop/pubspec.yaml index 2e78076..e1f17c8 100644 --- a/interop/pubspec.yaml +++ b/interop/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: collection: ^1.14.11 grpc: path: ../ - protobuf: ^1.0.1 + protobuf: ^2.0.0-nullsafety dev_dependencies: test: ^1.6.4 diff --git a/lib/src/auth/auth.dart b/lib/src/auth/auth.dart index 4aa9e57..a5ae12b 100644 --- a/lib/src/auth/auth.dart +++ b/lib/src/auth/auth.dart @@ -20,25 +20,26 @@ import 'package:googleapis_auth/auth.dart' as auth; import 'package:http/http.dart' as http; import '../client/call.dart'; -import '../shared/status.dart'; import 'rsa.dart'; const _tokenExpirationThreshold = Duration(seconds: 30); abstract class BaseAuthenticator { - auth.AccessToken _accessToken; - String _lastUri; + auth.AccessToken? _accessToken; + late String _lastUri; + var _lastUriSet = false; Future authenticate(Map metadata, String uri) async { - if (uri == null) { - throw GrpcError.unauthenticated('Credentials require secure transport.'); - } - if (_accessToken == null || _accessToken.hasExpired || uri != _lastUri) { + if (_accessToken == null || + _accessToken!.hasExpired || + !_lastUriSet || + uri != _lastUri) { await obtainAccessCredentials(uri); _lastUri = uri; + _lastUriSet = true; } - final auth = '${_accessToken.type} ${_accessToken.data}'; + final auth = '${_accessToken!.type} ${_accessToken!.data}'; metadata['authorization'] = auth; if (_tokenExpiresSoon) { @@ -47,7 +48,7 @@ abstract class BaseAuthenticator { } } - bool get _tokenExpiresSoon => _accessToken.expiry + bool get _tokenExpiresSoon => _accessToken!.expiry .subtract(_tokenExpirationThreshold) .isBefore(DateTime.now().toUtc()); @@ -57,7 +58,7 @@ abstract class BaseAuthenticator { } abstract class HttpBasedAuthenticator extends BaseAuthenticator { - Future _call; + Future? _call; Future obtainAccessCredentials(String uri) { if (_call == null) { @@ -68,7 +69,7 @@ abstract class HttpBasedAuthenticator extends BaseAuthenticator { authClient.close(); }); } - return _call; + return _call!; } Future obtainCredentialsWithClient( @@ -77,18 +78,21 @@ abstract class HttpBasedAuthenticator extends BaseAuthenticator { class JwtServiceAccountAuthenticator extends BaseAuthenticator { auth.ServiceAccountCredentials _serviceAccountCredentials; - String _projectId; - String _keyId; + String? _projectId; + String? _keyId; - JwtServiceAccountAuthenticator(String serviceAccountJson) { - final serviceAccount = jsonDecode(serviceAccountJson); - _serviceAccountCredentials = - auth.ServiceAccountCredentials.fromJson(serviceAccount); - _projectId = serviceAccount['project_id']; - _keyId = serviceAccount['private_key_id']; - } + JwtServiceAccountAuthenticator.fromJson( + Map serviceAccountJson) + : _serviceAccountCredentials = + auth.ServiceAccountCredentials.fromJson(serviceAccountJson), + _projectId = serviceAccountJson['project_id'], + _keyId = serviceAccountJson['private_key_id']; - String get projectId => _projectId; + factory JwtServiceAccountAuthenticator(String serviceAccountJsonString) => + JwtServiceAccountAuthenticator.fromJson( + jsonDecode(serviceAccountJsonString)); + + String? get projectId => _projectId; Future obtainAccessCredentials(String uri) async { _accessToken = _jwtTokenFor(_serviceAccountCredentials, _keyId, uri); @@ -97,8 +101,8 @@ class JwtServiceAccountAuthenticator extends BaseAuthenticator { // TODO(jakobr): Expose in googleapis_auth. auth.AccessToken _jwtTokenFor( - auth.ServiceAccountCredentials credentials, String keyId, String uri, - {String user, List scopes}) { + auth.ServiceAccountCredentials credentials, String? keyId, String uri, + {String? user, List? scopes}) { // Subtracting 20 seconds from current timestamp to allow for clock skew among // servers. final timestamp = diff --git a/lib/src/auth/auth_io.dart b/lib/src/auth/auth_io.dart index ee1d26a..4d75ce2 100644 --- a/lib/src/auth/auth_io.dart +++ b/lib/src/auth/auth_io.dart @@ -13,18 +13,22 @@ class ComputeEngineAuthenticator extends HttpBasedAuthenticator { } class ServiceAccountAuthenticator extends HttpBasedAuthenticator { - auth.ServiceAccountCredentials _serviceAccountCredentials; + late auth.ServiceAccountCredentials _serviceAccountCredentials; final List _scopes; - String _projectId; + String? _projectId; - ServiceAccountAuthenticator(String serviceAccountJson, this._scopes) { - final serviceAccount = jsonDecode(serviceAccountJson); - _serviceAccountCredentials = - auth.ServiceAccountCredentials.fromJson(serviceAccount); - _projectId = serviceAccount['project_id']; - } + ServiceAccountAuthenticator.fromJson( + Map serviceAccountJson, this._scopes) + : _serviceAccountCredentials = + auth.ServiceAccountCredentials.fromJson(serviceAccountJson), + _projectId = serviceAccountJson['project_id']; - String get projectId => _projectId; + factory ServiceAccountAuthenticator( + String serviceAccountJsonString, List scopes) => + ServiceAccountAuthenticator.fromJson( + jsonDecode(serviceAccountJsonString), scopes); + + String? get projectId => _projectId; Future obtainCredentialsWithClient( http.Client client, String uri) => @@ -35,7 +39,7 @@ class ServiceAccountAuthenticator extends HttpBasedAuthenticator { class _CredentialsRefreshingAuthenticator extends HttpBasedAuthenticator { final auth.ClientId _clientId; auth.AccessCredentials _accessCredentials; - final String _quotaProject; + final String? _quotaProject; _CredentialsRefreshingAuthenticator( this._clientId, @@ -47,7 +51,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!; } } @@ -83,8 +87,8 @@ class _CredentialsRefreshingAuthenticator extends HttpBasedAuthenticator { Future applicationDefaultCredentialsAuthenticator( List scopes, ) async { - File credFile; - String fileSource; + File? credFile; + String? fileSource; // If env var specifies a file to load credentials from we'll do that. final credsEnv = Platform.environment['GOOGLE_APPLICATION_CREDENTIALS']; if (credsEnv != null && credsEnv.isNotEmpty) { @@ -97,10 +101,10 @@ Future applicationDefaultCredentialsAuthenticator( // Attempt to use file created by `gcloud auth application-default login` File gcloudAdcFile; if (Platform.isWindows) { - gcloudAdcFile = File.fromUri(Uri.directory(Platform.environment['APPDATA']) + gcloudAdcFile = File.fromUri(Uri.directory(Platform.environment['APPDATA']!) .resolve('gcloud/application_default_credentials.json')); } else { - gcloudAdcFile = File.fromUri(Uri.directory(Platform.environment['HOME']) + gcloudAdcFile = File.fromUri(Uri.directory(Platform.environment['HOME']!) .resolve('.config/gcloud/application_default_credentials.json')); } // Only try to load from gcloudAdcFile if it exists. diff --git a/lib/src/auth/rsa.dart b/lib/src/auth/rsa.dart index 87ecb73..87a18e1 100644 --- a/lib/src/auth/rsa.dart +++ b/lib/src/auth/rsa.dart @@ -99,7 +99,7 @@ class ASN1Parser { static const SEQUENCE_TAG = 0x30; static ASN1Object parse(Uint8List bytes) { - invalidFormat(String msg) { + Never invalidFormat(String msg) { throw new ArgumentError("Invalid DER encoding: $msg"); } @@ -185,8 +185,6 @@ class ASN1Parser { invalidFormat( 'Unexpected tag $tag at offset ${offset - 1} (end: $end).'); } - // Unreachable. - return null; } final obj = decodeObject(); diff --git a/lib/src/client/call.dart b/lib/src/client/call.dart index 8ee33b6..75f0aba 100644 --- a/lib/src/client/call.dart +++ b/lib/src/client/call.dart @@ -38,6 +38,7 @@ const _reservedHeaders = [ 'grpc-encoding', 'user-agent', ]; +const _statusDetailsHeader = 'grpc-status-details-bin'; /// Provides per-RPC metadata. /// @@ -55,9 +56,9 @@ typedef FutureOr MetadataProvider( /// Runtime options for an RPC. class CallOptions { final Map metadata; - final Duration timeout; + final Duration? timeout; final List metadataProviders; - final Codec compression; + final Codec? compression; CallOptions._( this.metadata, @@ -73,10 +74,10 @@ class CallOptions { /// invoked in order for every RPC, and can modify the outgoing metadata /// (including metadata provided by previous providers). factory CallOptions({ - Map metadata, - Duration timeout, - List providers, - Codec compression, + Map? metadata, + Duration? timeout, + List? providers, + Codec? compression, }) { return CallOptions._( Map.unmodifiable(metadata ?? {}), @@ -89,7 +90,7 @@ class CallOptions { factory CallOptions.from(Iterable options) => options.fold(CallOptions(), (p, o) => p.mergedWith(o)); - CallOptions mergedWith(CallOptions other) { + CallOptions mergedWith(CallOptions? other) { if (other == null) return this; final mergedMetadata = Map.from(metadata)..addAll(other.metadata); final mergedTimeout = other.timeout ?? timeout; @@ -116,16 +117,16 @@ class WebCallOptions extends CallOptions { /// For this to work correctly, a proxy server must be set up that /// understands the query parameter and can unpack/send the original /// list of headers to the server endpoint. - final bool bypassCorsPreflight; + final bool? bypassCorsPreflight; /// Whether to send credentials along with the XHR. /// /// This may be required for proxying or wherever the server /// needs to otherwise inspect client cookies for that domain. - final bool withCredentials; + final bool? withCredentials; // TODO(mightyvoice): add a list of extra QueryParameter for gRPC. - WebCallOptions._(Map metadata, Duration timeout, + WebCallOptions._(Map metadata, Duration? timeout, List metadataProviders, {this.bypassCorsPreflight, this.withCredentials}) : super._(metadata, timeout, metadataProviders, null); @@ -136,11 +137,11 @@ class WebCallOptions extends CallOptions { /// metadata [providers] of [CallOptions], [bypassCorsPreflight] and /// [withCredentials] for CORS request. factory WebCallOptions( - {Map metadata, - Duration timeout, - List providers, - bool bypassCorsPreflight, - bool withCredentials}) { + {Map? metadata, + Duration? timeout, + List? providers, + bool? bypassCorsPreflight, + bool? withCredentials}) { return WebCallOptions._(Map.unmodifiable(metadata ?? {}), timeout, List.unmodifiable(providers ?? []), bypassCorsPreflight: bypassCorsPreflight ?? false, @@ -148,7 +149,7 @@ class WebCallOptions extends CallOptions { } @override - CallOptions mergedWith(CallOptions other) { + CallOptions mergedWith(CallOptions? other) { if (other == null) return this; final mergedMetadata = Map.from(metadata)..addAll(other.metadata); @@ -163,11 +164,9 @@ class WebCallOptions extends CallOptions { withCredentials: withCredentials); } - final otherOptions = other as WebCallOptions; final mergedBypassCorsPreflight = - otherOptions.bypassCorsPreflight ?? bypassCorsPreflight; - final mergedWithCredentials = - otherOptions.withCredentials ?? withCredentials; + other.bypassCorsPreflight ?? bypassCorsPreflight; + final mergedWithCredentials = other.withCredentials ?? withCredentials; return WebCallOptions._(Map.unmodifiable(mergedMetadata), mergedTimeout, List.unmodifiable(mergedProviders), bypassCorsPreflight: mergedBypassCorsPreflight, @@ -185,28 +184,28 @@ class ClientCall implements Response { final _trailers = Completer>(); bool _hasReceivedResponses = false; - Map _headerMetadata; + late Map _headerMetadata; - GrpcTransportStream _stream; - StreamController _responses; - StreamSubscription> _requestSubscription; - StreamSubscription _responseSubscription; + GrpcTransportStream? _stream; + final _responses = StreamController(); + StreamSubscription>? _requestSubscription; + StreamSubscription? _responseSubscription; bool isCancelled = false; - Timer _timeoutTimer; + Timer? _timeoutTimer; - final TimelineTask _requestTimeline; - TimelineTask _responseTimeline; + final TimelineTask? _requestTimeline; + TimelineTask? _responseTimeline; ClientCall(this._method, this._requests, this.options, [this._requestTimeline]) { _requestTimeline?.start('gRPC Request: ${_method.path}', arguments: { 'method': _method.path, - 'timeout': options?.timeout?.toString(), + 'timeout': options.timeout?.toString(), }); - _responses = StreamController(onListen: _onResponseListen); + _responses.onListen = _onResponseListen; if (options.timeout != null) { - _timeoutTimer = Timer(options.timeout, _onTimedOut); + _timeoutTimer = Timer(options.timeout!, _onTimedOut); } } @@ -251,7 +250,7 @@ class ClientCall implements Response { final metadata = Map.from(options.metadata); Future.forEach( options.metadataProviders, - (provider) => provider(metadata, + (MetadataProvider provider) => provider(metadata, '${connection.scheme}://${connection.authority}${audiencePath(_method)}')) .then((_) => _sendRequest(connection, _sanitizeMetadata(metadata))) .catchError(_onMetadataProviderError); @@ -263,8 +262,9 @@ class ClientCall implements Response { } void _sendRequest(ClientConnection connection, Map metadata) { + late final GrpcTransportStream stream; try { - _stream = connection.makeRequest( + stream = connection.makeRequest( _method.path, options.timeout, metadata, @@ -287,16 +287,17 @@ class ClientCall implements Response { return _method.requestSerializer(data); }) .handleError(_onRequestError) - .listen(_stream.outgoingMessages.add, - onError: _stream.outgoingMessages.addError, - onDone: _stream.outgoingMessages.close, + .listen(stream.outgoingMessages.add, + onError: stream.outgoingMessages.addError, + onDone: stream.outgoingMessages.close, cancelOnError: true); + _stream = stream; // The response stream might have been listened to before _stream was ready, // so try setting up the subscription here as well. _onResponseListen(); } - void _finishTimelineWithError(GrpcError error, TimelineTask timeline) { + void _finishTimelineWithError(GrpcError error, TimelineTask? timeline) { timeline?.finish(arguments: { 'error': error.toString(), }); @@ -315,28 +316,31 @@ class ClientCall implements Response { if (_stream != null && _responses.hasListener && _responseSubscription == null) { - _responseSubscription = _stream.incomingMessages.listen(_onResponseData, + // ignore: cancel_subscriptions + final subscription = _stream!.incomingMessages.listen(_onResponseData, onError: _onResponseError, onDone: _onResponseDone, cancelOnError: true); if (_responses.isPaused) { - _responseSubscription.pause(); + subscription.pause(); } - _responses.onPause = _responseSubscription.pause; - _responses.onResume = _responseSubscription.resume; + _responses.onPause = subscription.pause; + _responses.onResume = subscription.resume; _responses.onCancel = cancel; + + _responseSubscription = subscription; } } /// Emit an error response to the user, and tear down this call. - void _responseError(GrpcError error, [StackTrace stackTrace]) { + void _responseError(GrpcError error, [StackTrace? stackTrace]) { _finishTimelineWithError(error, _responseTimeline); _responses.addError(error, stackTrace); _timeoutTimer?.cancel(); _requestSubscription?.cancel(); - _responseSubscription.cancel(); + _responseSubscription!.cancel(); _responses.close(); - _stream.terminate(); + _stream!.terminate(); } /// If there's an error status then process it as a response error @@ -345,15 +349,17 @@ class ClientCall implements Response { final statusCode = int.parse(status ?? '0'); if (statusCode != 0) { - final message = metadata['grpc-message'] == null - ? null - : Uri.decodeFull(metadata['grpc-message']); + final messageMetadata = metadata['grpc-message']; + final message = + messageMetadata == null ? null : Uri.decodeFull(messageMetadata); + final statusDetails = metadata[_statusDetailsHeader]; _responseError(GrpcError.custom( - statusCode, - message, - decodeStatusDetails(metadata['grpc-status-details-bin']), - )); + statusCode, + message, + statusDetails == null + ? const [] + : decodeStatusDetails(statusDetails))); } } @@ -444,7 +450,7 @@ class ClientCall implements Response { _responseTimeline?.finish(); _timeoutTimer?.cancel(); _responses.close(); - _responseSubscription.cancel(); + _responseSubscription!.cancel(); } /// Error handler for the requests stream. Something went wrong while trying @@ -461,7 +467,7 @@ class ClientCall implements Response { _responses.close(); _requestSubscription?.cancel(); _responseSubscription?.cancel(); - _stream.terminate(); + _stream!.terminate(); } Stream get response => _responses.stream; @@ -492,10 +498,10 @@ class ClientCall implements Response { _stream?.terminate(); final futures = []; if (_requestSubscription != null) { - futures.add(_requestSubscription.cancel()); + futures.add(_requestSubscription!.cancel()); } if (_responseSubscription != null) { - futures.add(_responseSubscription.cancel()); + futures.add(_responseSubscription!.cancel()); } await Future.wait(futures); } diff --git a/lib/src/client/channel.dart b/lib/src/client/channel.dart index ad71d76..9ca3c5a 100644 --- a/lib/src/client/channel.dart +++ b/lib/src/client/channel.dart @@ -44,8 +44,8 @@ abstract class ClientChannel { /// Auxiliary base class implementing much of ClientChannel. abstract class ClientChannelBase implements ClientChannel { // TODO(jakobr): Multiple connections, load balancing. - ClientConnection _connection; - + late ClientConnection _connection; + var _connected = false; bool _isShutdown = false; ClientChannelBase(); @@ -54,13 +54,17 @@ abstract class ClientChannelBase implements ClientChannel { Future shutdown() async { if (_isShutdown) return; _isShutdown = true; - if (_connection != null) await _connection.shutdown(); + if (_connected) { + await _connection.shutdown(); + } } @override Future terminate() async { _isShutdown = true; - if (_connection != null) await _connection.terminate(); + if (_connected) { + await _connection.terminate(); + } } ClientConnection createConnection(); @@ -70,7 +74,11 @@ abstract class ClientChannelBase implements ClientChannel { /// The connection may be shared between multiple RPCs. Future getConnection() async { if (_isShutdown) throw GrpcError.unavailable('Channel shutting down.'); - return _connection ??= createConnection(); + if (!_connected) { + _connection = createConnection(); + _connected = true; + } + return _connection; } @override diff --git a/lib/src/client/client.dart b/lib/src/client/client.dart index 1b843f4..2d52124 100644 --- a/lib/src/client/client.dart +++ b/lib/src/client/client.dart @@ -27,7 +27,7 @@ class Client { /// Interceptors will be applied in direct order before making a request. Client(this._channel, - {CallOptions options, Iterable interceptors}) + {CallOptions? options, Iterable? interceptors}) : _options = options ?? CallOptions(), _interceptors = List.unmodifiable(interceptors ?? Iterable.empty()); @@ -39,12 +39,12 @@ regenerate these stubs using protobuf compiler plugin version 19.2.0 or newer. ''') ClientCall $createCall( ClientMethod method, Stream requests, - {CallOptions options}) { + {CallOptions? options}) { return _channel.createCall(method, requests, _options.mergedWith(options)); } ResponseFuture $createUnaryCall(ClientMethod method, Q request, - {CallOptions options}) { + {CallOptions? options}) { ClientUnaryInvoker invoker = (method, request, options) => ResponseFuture( _channel.createCall(method, Stream.value(request), options)); @@ -60,7 +60,7 @@ regenerate these stubs using protobuf compiler plugin version 19.2.0 or newer. ResponseStream $createStreamingCall( ClientMethod method, Stream requests, - {CallOptions options}) { + {CallOptions? options}) { ClientStreamingInvoker invoker = (method, request, options) => ResponseStream(_channel.createCall(method, requests, options)); diff --git a/lib/src/client/common.dart b/lib/src/client/common.dart index fd7e19a..1140703 100644 --- a/lib/src/client/common.dart +++ b/lib/src/client/common.dart @@ -46,21 +46,21 @@ class ResponseFuture extends DelegatingFuture with _ResponseMixin { final ClientCall _call; - static R _ensureOnlyOneResponse(R previous, R element) { + static R _ensureOnlyOneResponse(R? previous, R element) { if (previous != null) { throw GrpcError.unimplemented('More than one response received'); } return element; } - static R _ensureOneResponse(R value) { + static R _ensureOneResponse(R? value) { if (value == null) throw GrpcError.unimplemented('No responses received'); return value; } ResponseFuture(this._call) : super(_call.response - .fold(null, _ensureOnlyOneResponse) + .fold(null, _ensureOnlyOneResponse) .then(_ensureOneResponse)); } diff --git a/lib/src/client/connection.dart b/lib/src/client/connection.dart index e59cfde..b6f9d8e 100644 --- a/lib/src/client/connection.dart +++ b/lib/src/client/connection.dart @@ -42,9 +42,9 @@ abstract class ClientConnection { void dispatchCall(ClientCall call); /// Start a request for [path] with [metadata]. - GrpcTransportStream makeRequest(String path, Duration timeout, + GrpcTransportStream makeRequest(String path, Duration? timeout, Map metadata, ErrorHandler onRequestFailure, - {CallOptions callOptions}); + {required CallOptions callOptions}); /// Shuts down this connection. /// diff --git a/lib/src/client/http2_connection.dart b/lib/src/client/http2_connection.dart index ce87d6a..fbfc22c 100644 --- a/lib/src/client/http2_connection.dart +++ b/lib/src/client/http2_connection.dart @@ -44,19 +44,19 @@ class Http2ClientConnection implements connection.ClientConnection { connection.ConnectionState _state = ConnectionState.idle; @visibleForTesting - void Function(Http2ClientConnection connection) onStateChanged; + void Function(Http2ClientConnection connection)? onStateChanged; final _pendingCalls = []; final ClientTransportConnector _transportConnector; - ClientTransportConnection _transportConnection; + ClientTransportConnection? _transportConnection; /// Used for idle and reconnect timeout, depending on [_state]. - Timer _timer; + Timer? _timer; /// Used for making sure a single connection is not kept alive too long. final Stopwatch _connectionLifeTimer = Stopwatch(); - Duration _currentReconnectDelay; + Duration? _currentReconnectDelay; Http2ClientConnection(Object host, int port, this.options) : _transportConnector = _SocketTransportConnector(host, port, options); @@ -96,7 +96,7 @@ class Http2ClientConnection implements connection.ClientConnection { return; } _setState(ConnectionState.connecting); - connectTransport().then((transport) async { + connectTransport().then((transport) async { _currentReconnectDelay = null; _transportConnection = transport; _connectionLifeTimer @@ -119,11 +119,11 @@ class Http2ClientConnection implements connection.ClientConnection { /// /// Assumes [_transportConnection] is not `null`. void _refreshConnectionIfUnhealthy() { - final bool isHealthy = _transportConnection.isOpen; + final bool isHealthy = _transportConnection!.isOpen; final bool shouldRefresh = _connectionLifeTimer.elapsed > options.connectionTimeout; if (shouldRefresh) { - _transportConnection.finish(); + _transportConnection!.finish(); } if (!isHealthy || shouldRefresh) { _abandonConnection(); @@ -149,9 +149,9 @@ class Http2ClientConnection implements connection.ClientConnection { } } - GrpcTransportStream makeRequest(String path, Duration timeout, + GrpcTransportStream makeRequest(String path, Duration? timeout, Map metadata, ErrorHandler onRequestFailure, - {CallOptions callOptions}) { + {CallOptions? callOptions}) { final compressionCodec = callOptions?.compression; final headers = createCallHeaders( credentials.isSecure, @@ -165,7 +165,7 @@ class Http2ClientConnection implements connection.ClientConnection { (callOptions?.metadata ?? const {})['grpc-accept-encoding'] ?? options.codecRegistry?.supportedEncodings, ); - final stream = _transportConnection.makeRequest(headers); + final stream = _transportConnection!.makeRequest(headers); return Http2TransportStream( stream, onRequestFailure, @@ -208,9 +208,7 @@ class Http2ClientConnection implements connection.ClientConnection { void _setState(ConnectionState state) { _state = state; - if (onStateChanged != null) { - onStateChanged(this); - } + onStateChanged?.call(this); } void _handleIdleTimeout() { @@ -218,7 +216,7 @@ class Http2ClientConnection implements connection.ClientConnection { _cancelTimer(); _transportConnection ?.finish() - ?.catchError((_) => {}); // TODO(jakobr): Log error. + .catchError((_) {}); // TODO(jakobr): Log error. _transportConnection = null; _setState(ConnectionState.idle); } @@ -233,7 +231,7 @@ class Http2ClientConnection implements connection.ClientConnection { _cancelTimer(); } else { if (options.idleTimeout != null) { - _timer ??= Timer(options.idleTimeout, _handleIdleTimeout); + _timer ??= Timer(options.idleTimeout!, _handleIdleTimeout); } } } @@ -281,18 +279,18 @@ class Http2ClientConnection implements connection.ClientConnection { // We have pending RPCs. Reconnect after backoff delay. _setState(ConnectionState.transientFailure); _currentReconnectDelay = options.backoffStrategy(_currentReconnectDelay); - _timer = Timer(_currentReconnectDelay, _handleReconnect); + _timer = Timer(_currentReconnectDelay!, _handleReconnect); } static List
createCallHeaders( bool useTls, String authority, String path, - Duration timeout, - Map metadata, - Codec compressionCodec, { - String userAgent, - String grpcAcceptEncodings, + Duration? timeout, + Map? metadata, + Codec? compressionCodec, { + String? userAgent, + String? grpcAcceptEncodings, }) { final headers = [ _methodPost, @@ -317,12 +315,14 @@ class Http2ClientConnection implements connection.ClientConnection { } class _SocketTransportConnector implements ClientTransportConnector { + /// Either [InternetAddress] or [String]. final Object _host; final int _port; final ChannelOptions _options; - Socket _socket; + late Socket _socket; // ignore: close_sinks - _SocketTransportConnector(this._host, this._port, this._options); + _SocketTransportConnector(this._host, this._port, this._options) + : assert(_host is InternetAddress || _host is String); @override Future connect() async { @@ -349,19 +349,22 @@ class _SocketTransportConnector implements ClientTransportConnector { } @override - String get authority => - _options.credentials.authority ?? - (_port == 443 ? _host : "$_host:$_port"); + String get authority { + final host = + _host is String ? _host as String : (_host as InternetAddress).host; + return _options.credentials.authority ?? + (_port == 443 ? host : "$host:$_port"); + } @override Future get done { - assert(_socket != null); + ArgumentError.checkNotNull(_socket); return _socket.done; } @override void shutdown() { - assert(_socket != null); + ArgumentError.checkNotNull(_socket); _socket.destroy(); } diff --git a/lib/src/client/interceptor.dart b/lib/src/client/interceptor.dart index 2c4a67a..131105b 100644 --- a/lib/src/client/interceptor.dart +++ b/lib/src/client/interceptor.dart @@ -3,10 +3,10 @@ import 'common.dart'; import 'method.dart'; typedef ClientUnaryInvoker = ResponseFuture Function( - ClientMethod method, Q request, CallOptions options); + ClientMethod method, Q request, CallOptions options); typedef ClientStreamingInvoker = ResponseStream Function( - ClientMethod method, Stream requests, CallOptions options); + ClientMethod method, Stream requests, CallOptions options); /// ClientInterceptors intercepts client calls before they are executed. /// diff --git a/lib/src/client/options.dart b/lib/src/client/options.dart index 2791948..dfe0f5d 100644 --- a/lib/src/client/options.dart +++ b/lib/src/client/options.dart @@ -26,7 +26,7 @@ const defaultIdleTimeout = Duration(minutes: 5); const defaultConnectionTimeOut = Duration(minutes: 50); const defaultUserAgent = 'dart-grpc/2.0.0'; -typedef Duration BackoffStrategy(Duration lastBackoff); +typedef Duration BackoffStrategy(Duration? lastBackoff); // Backoff algorithm from https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md const _initialBackoff = Duration(seconds: 1); @@ -35,7 +35,7 @@ const _multiplier = 1.6; const _jitter = 0.2; final _random = Random(); -Duration defaultBackoffStrategy(Duration lastBackoff) { +Duration defaultBackoffStrategy(Duration? lastBackoff) { if (lastBackoff == null) return _initialBackoff; final jitter = _random.nextDouble() * 2 * _jitter - _jitter; final nextBackoff = lastBackoff * (_multiplier + jitter); @@ -45,8 +45,8 @@ Duration defaultBackoffStrategy(Duration lastBackoff) { /// Options controlling how connections are made on a [ClientChannel]. class ChannelOptions { final ChannelCredentials credentials; - final Duration idleTimeout; - final CodecRegistry codecRegistry; + final Duration? idleTimeout; + final CodecRegistry? codecRegistry; /// The maximum time a single connection will be used for new requests. final Duration connectionTimeout; diff --git a/lib/src/client/query_parameter.dart b/lib/src/client/query_parameter.dart index 1cb91e7..2bf3f21 100644 --- a/lib/src/client/query_parameter.dart +++ b/lib/src/client/query_parameter.dart @@ -29,17 +29,24 @@ class QueryParameter implements Comparable { String get value => values.first; /// Creates an instance by wrapping the single value in a [List]. - QueryParameter(this.key, String value) - : assert(key != null && key.trim().isNotEmpty), - values = [value]; + QueryParameter(this.key, String value) : values = [value] { + ArgumentError.checkNotNull(key); + if (key.trim().isEmpty) { + throw ArgumentError(key); + } + } /// Creates an instance from a [List] of values. /// /// This is not the default constructor since the single-value case is the /// most common. QueryParameter.multi(this.key, List values) - : assert(key != null && key.trim().isNotEmpty), - values = values..sort(); + : values = values..sort() { + ArgumentError.checkNotNull(key); + if (key.trim().isEmpty) { + throw ArgumentError(key); + } + } /// Returns the escaped value of the param as will appear in a URL. @override diff --git a/lib/src/client/transport/http2_credentials.dart b/lib/src/client/transport/http2_credentials.dart index 6f54f96..da0b619 100644 --- a/lib/src/client/transport/http2_credentials.dart +++ b/lib/src/client/transport/http2_credentials.dart @@ -32,32 +32,32 @@ bool allowBadCertificates(X509Certificate certificate, String host) => true; /// Options controlling TLS security settings on a [ClientChannel]. class ChannelCredentials { final bool isSecure; - final String authority; - final List _certificateBytes; - final String _certificatePassword; - final BadCertificateHandler onBadCertificate; + final String? authority; + final List? _certificateBytes; + final String? _certificatePassword; + final BadCertificateHandler? onBadCertificate; const ChannelCredentials._(this.isSecure, this._certificateBytes, this._certificatePassword, this.authority, this.onBadCertificate); /// Disable TLS. RPCs are sent in clear text. - const ChannelCredentials.insecure({String authority}) + const ChannelCredentials.insecure({String? authority}) : this._(false, null, null, authority, null); /// Enable TLS and optionally specify the [certificates] to trust. If /// [certificates] is not provided, the default trust store is used. const ChannelCredentials.secure( - {List certificates, - String password, - String authority, - BadCertificateHandler onBadCertificate}) + {List? certificates, + String? password, + String? authority, + BadCertificateHandler? onBadCertificate}) : this._(true, certificates, password, authority, onBadCertificate); - SecurityContext get securityContext { + SecurityContext? get securityContext { if (!isSecure) return null; if (_certificateBytes != null) { return createSecurityContext(false) - ..setTrustedCertificatesBytes(_certificateBytes, + ..setTrustedCertificatesBytes(_certificateBytes!, password: _certificatePassword); } final context = new SecurityContext(withTrustedRoots: true); diff --git a/lib/src/client/transport/http2_transport.dart b/lib/src/client/transport/http2_transport.dart index 5ecda17..3a34a05 100644 --- a/lib/src/client/transport/http2_transport.dart +++ b/lib/src/client/transport/http2_transport.dart @@ -15,9 +15,10 @@ import 'dart:async'; -import 'package:grpc/grpc.dart'; import 'package:http2/transport.dart'; +import '../../shared/codec.dart'; +import '../../shared/codec_registry.dart'; import '../../shared/message.dart'; import '../../shared/streams.dart'; import 'transport.dart'; @@ -33,8 +34,8 @@ class Http2TransportStream extends GrpcTransportStream { Http2TransportStream( this._transportStream, this._onError, - CodecRegistry codecRegistry, - Codec compression, + CodecRegistry? codecRegistry, + Codec? compression, ) : incomingMessages = _transportStream.incomingMessages .transform(GrpcHttpDecoder()) .transform(grpcDecompressor(codecRegistry: codecRegistry)) { diff --git a/lib/src/client/transport/web_streams.dart b/lib/src/client/transport/web_streams.dart index 46a436a..7fa9c77 100644 --- a/lib/src/client/transport/web_streams.dart +++ b/lib/src/client/transport/web_streams.dart @@ -47,10 +47,10 @@ class _GrpcWebConversionSink extends ChunkedConversionSink { final _dataHeader = Uint8List(4); _GrpcWebParseState _state = _GrpcWebParseState.Init; - int _chunkOffset; - int _frameType; - int _dataOffset = 0; - Uint8List _data; + var _chunkOffset = 0; + int? _frameType; + var _dataOffset = 0; + Uint8List? _data; _GrpcWebConversionSink(this._out); @@ -87,16 +87,16 @@ class _GrpcWebConversionSink extends ChunkedConversionSink { } void _parseMessage(List chunkData) { - final dataRemaining = _data.lengthInBytes - _dataOffset; + final dataRemaining = _data!.lengthInBytes - _dataOffset; if (dataRemaining > 0) { final chunkRemaining = chunkData.length - _chunkOffset; final toCopy = min(dataRemaining, chunkRemaining); - _data.setRange( - _dataOffset, _dataOffset + toCopy, chunkData, _chunkOffset); + _data! + .setRange(_dataOffset, _dataOffset + toCopy, chunkData, _chunkOffset); _dataOffset += toCopy; _chunkOffset += toCopy; } - if (_dataOffset == _data.lengthInBytes) { + if (_dataOffset == _data!.lengthInBytes) { _finishMessage(); } } @@ -104,10 +104,10 @@ class _GrpcWebConversionSink extends ChunkedConversionSink { void _finishMessage() { switch (_frameType) { case frameTypeData: - _out.add(GrpcData(_data, isCompressed: false)); + _out.add(GrpcData(_data!, isCompressed: false)); break; case frameTypeTrailers: - final stringData = String.fromCharCodes(_data); + final stringData = String.fromCharCodes(_data!); final headers = _parseHttp1Headers(stringData); _out.add(GrpcMetadata(headers)); break; @@ -119,7 +119,7 @@ class _GrpcWebConversionSink extends ChunkedConversionSink { Map _parseHttp1Headers(String stringData) { final trimmed = stringData.trim(); - final chunks = trimmed == '' ? [] : trimmed.split('\r\n'); + final chunks = trimmed == '' ? [] : trimmed.split('\r\n'); final headers = {}; for (final chunk in chunks) { final pos = chunk.indexOf(':'); diff --git a/lib/src/client/transport/xhr_transport.dart b/lib/src/client/transport/xhr_transport.dart index 776c85b..c9e522d 100644 --- a/lib/src/client/transport/xhr_transport.dart +++ b/lib/src/client/transport/xhr_transport.dart @@ -51,7 +51,8 @@ class XhrTransportStream implements GrpcTransportStream { @override StreamSink> get outgoingMessages => _outgoingMessages.sink; - XhrTransportStream(this._request, {onError, onDone}) + XhrTransportStream(this._request, + {required ErrorHandler onError, required onDone}) : _onError = onError, _onDone = onDone { _outgoingMessages.stream @@ -170,7 +171,7 @@ class XhrClientConnection extends ClientConnection { void _initializeRequest(HttpRequest request, Map metadata) { for (final header in metadata.keys) { - request.setRequestHeader(header, metadata[header]); + request.setRequestHeader(header, metadata[header]!); } // Overriding the mimetype allows us to stream and parse the data request.overrideMimeType('text/plain; charset=x-user-defined'); @@ -181,9 +182,9 @@ class XhrClientConnection extends ClientConnection { HttpRequest createHttpRequest() => HttpRequest(); @override - GrpcTransportStream makeRequest(String path, Duration timeout, + GrpcTransportStream makeRequest(String path, Duration? timeout, Map metadata, ErrorHandler onError, - {CallOptions callOptions}) { + {CallOptions? callOptions}) { // gRPC-web headers. if (_getContentTypeHeader(metadata) == null) { metadata['Content-Type'] = 'application/grpc-web+proto'; @@ -231,7 +232,7 @@ class XhrClientConnection extends ClientConnection { Future shutdown() async {} } -MapEntry _getContentTypeHeader(Map metadata) { +MapEntry? _getContentTypeHeader(Map metadata) { for (var entry in metadata.entries) { if (entry.key.toLowerCase() == _contentTypeKey.toLowerCase()) { return entry; diff --git a/lib/src/generated/google/protobuf/any.pb.dart b/lib/src/generated/google/protobuf/any.pb.dart index 40b2685..81fcf72 100644 --- a/lib/src/generated/google/protobuf/any.pb.dart +++ b/lib/src/generated/google/protobuf/any.pb.dart @@ -2,7 +2,7 @@ // Generated code. Do not modify. // source: google/protobuf/any.proto // -// @dart = 2.3 +// @dart = 2.12 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields import 'dart:core' as $core; @@ -37,7 +37,19 @@ class Any extends $pb.GeneratedMessage with $mixin.AnyMixin { ..hasRequiredFields = false; Any._() : super(); - factory Any() => create(); + factory Any({ + $core.String? typeUrl, + $core.List<$core.int>? value, + }) { + final _result = create(); + if (typeUrl != null) { + _result.typeUrl = typeUrl; + } + if (value != null) { + _result.value = value; + } + return _result; + } factory Any.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); @@ -51,8 +63,9 @@ class Any extends $pb.GeneratedMessage with $mixin.AnyMixin { @$core.Deprecated('Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') - Any copyWith(void Function(Any) updates) => super.copyWith( - (message) => updates(message as Any)); // ignore: deprecated_member_use + Any copyWith(void Function(Any) updates) => + super.copyWith((message) => updates(message as Any)) + as Any; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static Any create() => Any._(); @@ -61,7 +74,7 @@ class Any extends $pb.GeneratedMessage with $mixin.AnyMixin { @$core.pragma('dart2js:noInline') static Any getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static Any _defaultInstance; + static Any? _defaultInstance; @$pb.TagNumber(1) $core.String get typeUrl => $_getSZ(0); diff --git a/lib/src/generated/google/protobuf/any.pbenum.dart b/lib/src/generated/google/protobuf/any.pbenum.dart index 070fd71..e03f029 100644 --- a/lib/src/generated/google/protobuf/any.pbenum.dart +++ b/lib/src/generated/google/protobuf/any.pbenum.dart @@ -2,5 +2,5 @@ // Generated code. Do not modify. // source: google/protobuf/any.proto // -// @dart = 2.3 +// @dart = 2.12 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields diff --git a/lib/src/generated/google/protobuf/any.pbjson.dart b/lib/src/generated/google/protobuf/any.pbjson.dart index 2653115..696648f 100644 --- a/lib/src/generated/google/protobuf/any.pbjson.dart +++ b/lib/src/generated/google/protobuf/any.pbjson.dart @@ -2,9 +2,11 @@ // Generated code. Do not modify. // source: google/protobuf/any.proto // -// @dart = 2.3 +// @dart = 2.12 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields +import 'dart:core' as $core; + const Any$json = const { '1': 'Any', '2': const [ diff --git a/lib/src/generated/google/protobuf/duration.pb.dart b/lib/src/generated/google/protobuf/duration.pb.dart index c34a2e7..0733876 100644 --- a/lib/src/generated/google/protobuf/duration.pb.dart +++ b/lib/src/generated/google/protobuf/duration.pb.dart @@ -2,7 +2,7 @@ // Generated code. Do not modify. // source: google/protobuf/duration.proto // -// @dart = 2.3 +// @dart = 2.12 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields import 'dart:core' as $core; @@ -38,7 +38,19 @@ class Duration extends $pb.GeneratedMessage with $mixin.DurationMixin { ..hasRequiredFields = false; Duration._() : super(); - factory Duration() => create(); + factory Duration({ + $fixnum.Int64? seconds, + $core.int? nanos, + }) { + final _result = create(); + if (seconds != null) { + _result.seconds = seconds; + } + if (nanos != null) { + _result.nanos = nanos; + } + return _result; + } factory Duration.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); @@ -53,8 +65,8 @@ class Duration extends $pb.GeneratedMessage with $mixin.DurationMixin { 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') Duration copyWith(void Function(Duration) updates) => - super.copyWith((message) => - updates(message as Duration)); // ignore: deprecated_member_use + super.copyWith((message) => updates(message as Duration)) + as Duration; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static Duration create() => Duration._(); @@ -63,7 +75,7 @@ class Duration extends $pb.GeneratedMessage with $mixin.DurationMixin { @$core.pragma('dart2js:noInline') static Duration getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static Duration _defaultInstance; + static Duration? _defaultInstance; @$pb.TagNumber(1) $fixnum.Int64 get seconds => $_getI64(0); diff --git a/lib/src/generated/google/protobuf/duration.pbenum.dart b/lib/src/generated/google/protobuf/duration.pbenum.dart index 52aa690..af4119e 100644 --- a/lib/src/generated/google/protobuf/duration.pbenum.dart +++ b/lib/src/generated/google/protobuf/duration.pbenum.dart @@ -2,5 +2,5 @@ // Generated code. Do not modify. // source: google/protobuf/duration.proto // -// @dart = 2.3 +// @dart = 2.12 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields diff --git a/lib/src/generated/google/protobuf/duration.pbjson.dart b/lib/src/generated/google/protobuf/duration.pbjson.dart index a53dbee..9b45a6b 100644 --- a/lib/src/generated/google/protobuf/duration.pbjson.dart +++ b/lib/src/generated/google/protobuf/duration.pbjson.dart @@ -2,9 +2,11 @@ // Generated code. Do not modify. // source: google/protobuf/duration.proto // -// @dart = 2.3 +// @dart = 2.12 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields +import 'dart:core' as $core; + const Duration$json = const { '1': 'Duration', '2': const [ diff --git a/lib/src/generated/google/rpc/code.pb.dart b/lib/src/generated/google/rpc/code.pb.dart index 2f10a69..7f4e72c 100644 --- a/lib/src/generated/google/rpc/code.pb.dart +++ b/lib/src/generated/google/rpc/code.pb.dart @@ -2,7 +2,7 @@ // Generated code. Do not modify. // source: google/rpc/code.proto // -// @dart = 2.3 +// @dart = 2.12 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields import 'dart:core' as $core; diff --git a/lib/src/generated/google/rpc/code.pbenum.dart b/lib/src/generated/google/rpc/code.pbenum.dart index 0366abb..8103531 100644 --- a/lib/src/generated/google/rpc/code.pbenum.dart +++ b/lib/src/generated/google/rpc/code.pbenum.dart @@ -2,7 +2,7 @@ // Generated code. Do not modify. // source: google/rpc/code.proto // -// @dart = 2.3 +// @dart = 2.12 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields // ignore_for_file: UNDEFINED_SHOWN_NAME @@ -115,7 +115,7 @@ class Code extends $pb.ProtobufEnum { static final $core.Map<$core.int, Code> _byValue = $pb.ProtobufEnum.initByValue(values); - static Code valueOf($core.int value) => _byValue[value]; + static Code? valueOf($core.int value) => _byValue[value]; const Code._($core.int v, $core.String n) : super(v, n); } diff --git a/lib/src/generated/google/rpc/code.pbjson.dart b/lib/src/generated/google/rpc/code.pbjson.dart index 32be8b0..0c46b5f 100644 --- a/lib/src/generated/google/rpc/code.pbjson.dart +++ b/lib/src/generated/google/rpc/code.pbjson.dart @@ -2,9 +2,11 @@ // Generated code. Do not modify. // source: google/rpc/code.proto // -// @dart = 2.3 +// @dart = 2.12 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields +import 'dart:core' as $core; + const Code$json = const { '1': 'Code', '2': const [ diff --git a/lib/src/generated/google/rpc/error_details.pb.dart b/lib/src/generated/google/rpc/error_details.pb.dart index b5fccbf..b6859b6 100644 --- a/lib/src/generated/google/rpc/error_details.pb.dart +++ b/lib/src/generated/google/rpc/error_details.pb.dart @@ -2,7 +2,7 @@ // Generated code. Do not modify. // source: google/rpc/error_details.proto // -// @dart = 2.3 +// @dart = 2.12 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields import 'dart:core' as $core; @@ -30,7 +30,15 @@ class RetryInfo extends $pb.GeneratedMessage { ..hasRequiredFields = false; RetryInfo._() : super(); - factory RetryInfo() => create(); + factory RetryInfo({ + $1.Duration? retryDelay, + }) { + final _result = create(); + if (retryDelay != null) { + _result.retryDelay = retryDelay; + } + return _result; + } factory RetryInfo.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); @@ -45,8 +53,8 @@ class RetryInfo extends $pb.GeneratedMessage { 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') RetryInfo copyWith(void Function(RetryInfo) updates) => - super.copyWith((message) => - updates(message as RetryInfo)); // ignore: deprecated_member_use + super.copyWith((message) => updates(message as RetryInfo)) + as RetryInfo; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static RetryInfo create() => RetryInfo._(); @@ -55,7 +63,7 @@ class RetryInfo extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static RetryInfo getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static RetryInfo _defaultInstance; + static RetryInfo? _defaultInstance; @$pb.TagNumber(1) $1.Duration get retryDelay => $_getN(0); @@ -95,7 +103,19 @@ class DebugInfo extends $pb.GeneratedMessage { ..hasRequiredFields = false; DebugInfo._() : super(); - factory DebugInfo() => create(); + factory DebugInfo({ + $core.Iterable<$core.String>? stackEntries, + $core.String? detail, + }) { + final _result = create(); + if (stackEntries != null) { + _result.stackEntries.addAll(stackEntries); + } + if (detail != null) { + _result.detail = detail; + } + return _result; + } factory DebugInfo.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); @@ -110,8 +130,8 @@ class DebugInfo extends $pb.GeneratedMessage { 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') DebugInfo copyWith(void Function(DebugInfo) updates) => - super.copyWith((message) => - updates(message as DebugInfo)); // ignore: deprecated_member_use + super.copyWith((message) => updates(message as DebugInfo)) + as DebugInfo; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static DebugInfo create() => DebugInfo._(); @@ -120,7 +140,7 @@ class DebugInfo extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static DebugInfo getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static DebugInfo _defaultInstance; + static DebugInfo? _defaultInstance; @$pb.TagNumber(1) $core.List<$core.String> get stackEntries => $_getList(0); @@ -161,7 +181,19 @@ class QuotaFailure_Violation extends $pb.GeneratedMessage { ..hasRequiredFields = false; QuotaFailure_Violation._() : super(); - factory QuotaFailure_Violation() => create(); + factory QuotaFailure_Violation({ + $core.String? subject, + $core.String? description, + }) { + final _result = create(); + if (subject != null) { + _result.subject = subject; + } + if (description != null) { + _result.description = description; + } + return _result; + } factory QuotaFailure_Violation.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); @@ -178,8 +210,8 @@ class QuotaFailure_Violation extends $pb.GeneratedMessage { 'Will be removed in next major version') QuotaFailure_Violation copyWith( void Function(QuotaFailure_Violation) updates) => - super.copyWith((message) => updates( - message as QuotaFailure_Violation)); // ignore: deprecated_member_use + super.copyWith((message) => updates(message as QuotaFailure_Violation)) + as QuotaFailure_Violation; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static QuotaFailure_Violation create() => QuotaFailure_Violation._(); @@ -189,7 +221,7 @@ class QuotaFailure_Violation extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static QuotaFailure_Violation getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static QuotaFailure_Violation _defaultInstance; + static QuotaFailure_Violation? _defaultInstance; @$pb.TagNumber(1) $core.String get subject => $_getSZ(0); @@ -236,7 +268,15 @@ class QuotaFailure extends $pb.GeneratedMessage { ..hasRequiredFields = false; QuotaFailure._() : super(); - factory QuotaFailure() => create(); + factory QuotaFailure({ + $core.Iterable? violations, + }) { + final _result = create(); + if (violations != null) { + _result.violations.addAll(violations); + } + return _result; + } factory QuotaFailure.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); @@ -251,8 +291,8 @@ class QuotaFailure extends $pb.GeneratedMessage { 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') QuotaFailure copyWith(void Function(QuotaFailure) updates) => - super.copyWith((message) => - updates(message as QuotaFailure)); // ignore: deprecated_member_use + super.copyWith((message) => updates(message as QuotaFailure)) + as QuotaFailure; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static QuotaFailure create() => QuotaFailure._(); @@ -262,7 +302,7 @@ class QuotaFailure extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static QuotaFailure getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static QuotaFailure _defaultInstance; + static QuotaFailure? _defaultInstance; @$pb.TagNumber(1) $core.List get violations => $_getList(0); @@ -300,7 +340,23 @@ class ErrorInfo extends $pb.GeneratedMessage { ..hasRequiredFields = false; ErrorInfo._() : super(); - factory ErrorInfo() => create(); + factory ErrorInfo({ + $core.String? reason, + $core.String? domain, + $core.Map<$core.String, $core.String>? metadata, + }) { + final _result = create(); + if (reason != null) { + _result.reason = reason; + } + if (domain != null) { + _result.domain = domain; + } + if (metadata != null) { + _result.metadata.addAll(metadata); + } + return _result; + } factory ErrorInfo.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); @@ -315,8 +371,8 @@ class ErrorInfo extends $pb.GeneratedMessage { 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') ErrorInfo copyWith(void Function(ErrorInfo) updates) => - super.copyWith((message) => - updates(message as ErrorInfo)); // ignore: deprecated_member_use + super.copyWith((message) => updates(message as ErrorInfo)) + as ErrorInfo; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static ErrorInfo create() => ErrorInfo._(); @@ -325,7 +381,7 @@ class ErrorInfo extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static ErrorInfo getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static ErrorInfo _defaultInstance; + static ErrorInfo? _defaultInstance; @$pb.TagNumber(1) $core.String get reason => $_getSZ(0); @@ -383,7 +439,23 @@ class PreconditionFailure_Violation extends $pb.GeneratedMessage { ..hasRequiredFields = false; PreconditionFailure_Violation._() : super(); - factory PreconditionFailure_Violation() => create(); + factory PreconditionFailure_Violation({ + $core.String? type, + $core.String? subject, + $core.String? description, + }) { + final _result = create(); + if (type != null) { + _result.type = type; + } + if (subject != null) { + _result.subject = subject; + } + if (description != null) { + _result.description = description; + } + return _result; + } factory PreconditionFailure_Violation.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); @@ -400,8 +472,9 @@ class PreconditionFailure_Violation extends $pb.GeneratedMessage { 'Will be removed in next major version') PreconditionFailure_Violation copyWith( void Function(PreconditionFailure_Violation) updates) => - super.copyWith((message) => updates(message - as PreconditionFailure_Violation)); // ignore: deprecated_member_use + super.copyWith( + (message) => updates(message as PreconditionFailure_Violation)) + as PreconditionFailure_Violation; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static PreconditionFailure_Violation create() => @@ -412,7 +485,7 @@ class PreconditionFailure_Violation extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static PreconditionFailure_Violation getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static PreconditionFailure_Violation _defaultInstance; + static PreconditionFailure_Violation? _defaultInstance; @$pb.TagNumber(1) $core.String get type => $_getSZ(0); @@ -471,7 +544,15 @@ class PreconditionFailure extends $pb.GeneratedMessage { ..hasRequiredFields = false; PreconditionFailure._() : super(); - factory PreconditionFailure() => create(); + factory PreconditionFailure({ + $core.Iterable? violations, + }) { + final _result = create(); + if (violations != null) { + _result.violations.addAll(violations); + } + return _result; + } factory PreconditionFailure.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); @@ -486,8 +567,8 @@ class PreconditionFailure extends $pb.GeneratedMessage { 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') PreconditionFailure copyWith(void Function(PreconditionFailure) updates) => - super.copyWith((message) => updates( - message as PreconditionFailure)); // ignore: deprecated_member_use + super.copyWith((message) => updates(message as PreconditionFailure)) + as PreconditionFailure; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static PreconditionFailure create() => PreconditionFailure._(); @@ -497,7 +578,7 @@ class PreconditionFailure extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static PreconditionFailure getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static PreconditionFailure _defaultInstance; + static PreconditionFailure? _defaultInstance; @$pb.TagNumber(1) $core.List get violations => $_getList(0); @@ -526,7 +607,19 @@ class BadRequest_FieldViolation extends $pb.GeneratedMessage { ..hasRequiredFields = false; BadRequest_FieldViolation._() : super(); - factory BadRequest_FieldViolation() => create(); + factory BadRequest_FieldViolation({ + $core.String? field_1, + $core.String? description, + }) { + final _result = create(); + if (field_1 != null) { + _result.field_1 = field_1; + } + if (description != null) { + _result.description = description; + } + return _result; + } factory BadRequest_FieldViolation.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); @@ -543,8 +636,8 @@ class BadRequest_FieldViolation extends $pb.GeneratedMessage { 'Will be removed in next major version') BadRequest_FieldViolation copyWith( void Function(BadRequest_FieldViolation) updates) => - super.copyWith((message) => updates(message - as BadRequest_FieldViolation)); // ignore: deprecated_member_use + super.copyWith((message) => updates(message as BadRequest_FieldViolation)) + as BadRequest_FieldViolation; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static BadRequest_FieldViolation create() => BadRequest_FieldViolation._(); @@ -554,7 +647,7 @@ class BadRequest_FieldViolation extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static BadRequest_FieldViolation getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static BadRequest_FieldViolation _defaultInstance; + static BadRequest_FieldViolation? _defaultInstance; @$pb.TagNumber(1) $core.String get field_1 => $_getSZ(0); @@ -601,7 +694,15 @@ class BadRequest extends $pb.GeneratedMessage { ..hasRequiredFields = false; BadRequest._() : super(); - factory BadRequest() => create(); + factory BadRequest({ + $core.Iterable? fieldViolations, + }) { + final _result = create(); + if (fieldViolations != null) { + _result.fieldViolations.addAll(fieldViolations); + } + return _result; + } factory BadRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); @@ -616,8 +717,8 @@ class BadRequest extends $pb.GeneratedMessage { 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') BadRequest copyWith(void Function(BadRequest) updates) => - super.copyWith((message) => - updates(message as BadRequest)); // ignore: deprecated_member_use + super.copyWith((message) => updates(message as BadRequest)) + as BadRequest; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static BadRequest create() => BadRequest._(); @@ -626,7 +727,7 @@ class BadRequest extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static BadRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static BadRequest _defaultInstance; + static BadRequest? _defaultInstance; @$pb.TagNumber(1) $core.List get fieldViolations => $_getList(0); @@ -655,7 +756,19 @@ class RequestInfo extends $pb.GeneratedMessage { ..hasRequiredFields = false; RequestInfo._() : super(); - factory RequestInfo() => create(); + factory RequestInfo({ + $core.String? requestId, + $core.String? servingData, + }) { + final _result = create(); + if (requestId != null) { + _result.requestId = requestId; + } + if (servingData != null) { + _result.servingData = servingData; + } + return _result; + } factory RequestInfo.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); @@ -670,8 +783,8 @@ class RequestInfo extends $pb.GeneratedMessage { 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') RequestInfo copyWith(void Function(RequestInfo) updates) => - super.copyWith((message) => - updates(message as RequestInfo)); // ignore: deprecated_member_use + super.copyWith((message) => updates(message as RequestInfo)) + as RequestInfo; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static RequestInfo create() => RequestInfo._(); @@ -680,7 +793,7 @@ class RequestInfo extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static RequestInfo getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static RequestInfo _defaultInstance; + static RequestInfo? _defaultInstance; @$pb.TagNumber(1) $core.String get requestId => $_getSZ(0); @@ -737,7 +850,27 @@ class ResourceInfo extends $pb.GeneratedMessage { ..hasRequiredFields = false; ResourceInfo._() : super(); - factory ResourceInfo() => create(); + factory ResourceInfo({ + $core.String? resourceType, + $core.String? resourceName, + $core.String? owner, + $core.String? description, + }) { + final _result = create(); + if (resourceType != null) { + _result.resourceType = resourceType; + } + if (resourceName != null) { + _result.resourceName = resourceName; + } + if (owner != null) { + _result.owner = owner; + } + if (description != null) { + _result.description = description; + } + return _result; + } factory ResourceInfo.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); @@ -752,8 +885,8 @@ class ResourceInfo extends $pb.GeneratedMessage { 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') ResourceInfo copyWith(void Function(ResourceInfo) updates) => - super.copyWith((message) => - updates(message as ResourceInfo)); // ignore: deprecated_member_use + super.copyWith((message) => updates(message as ResourceInfo)) + as ResourceInfo; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static ResourceInfo create() => ResourceInfo._(); @@ -763,7 +896,7 @@ class ResourceInfo extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static ResourceInfo getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static ResourceInfo _defaultInstance; + static ResourceInfo? _defaultInstance; @$pb.TagNumber(1) $core.String get resourceType => $_getSZ(0); @@ -837,7 +970,19 @@ class Help_Link extends $pb.GeneratedMessage { ..hasRequiredFields = false; Help_Link._() : super(); - factory Help_Link() => create(); + factory Help_Link({ + $core.String? description, + $core.String? url, + }) { + final _result = create(); + if (description != null) { + _result.description = description; + } + if (url != null) { + _result.url = url; + } + return _result; + } factory Help_Link.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); @@ -852,8 +997,8 @@ class Help_Link extends $pb.GeneratedMessage { 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') Help_Link copyWith(void Function(Help_Link) updates) => - super.copyWith((message) => - updates(message as Help_Link)); // ignore: deprecated_member_use + super.copyWith((message) => updates(message as Help_Link)) + as Help_Link; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static Help_Link create() => Help_Link._(); @@ -862,7 +1007,7 @@ class Help_Link extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static Help_Link getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static Help_Link _defaultInstance; + static Help_Link? _defaultInstance; @$pb.TagNumber(1) $core.String get description => $_getSZ(0); @@ -909,7 +1054,15 @@ class Help extends $pb.GeneratedMessage { ..hasRequiredFields = false; Help._() : super(); - factory Help() => create(); + factory Help({ + $core.Iterable? links, + }) { + final _result = create(); + if (links != null) { + _result.links.addAll(links); + } + return _result; + } factory Help.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); @@ -923,8 +1076,9 @@ class Help extends $pb.GeneratedMessage { @$core.Deprecated('Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') - Help copyWith(void Function(Help) updates) => super.copyWith( - (message) => updates(message as Help)); // ignore: deprecated_member_use + Help copyWith(void Function(Help) updates) => + super.copyWith((message) => updates(message as Help)) + as Help; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static Help create() => Help._(); @@ -933,7 +1087,7 @@ class Help extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static Help getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static Help _defaultInstance; + static Help? _defaultInstance; @$pb.TagNumber(1) $core.List get links => $_getList(0); @@ -962,7 +1116,19 @@ class LocalizedMessage extends $pb.GeneratedMessage { ..hasRequiredFields = false; LocalizedMessage._() : super(); - factory LocalizedMessage() => create(); + factory LocalizedMessage({ + $core.String? locale, + $core.String? message, + }) { + final _result = create(); + if (locale != null) { + _result.locale = locale; + } + if (message != null) { + _result.message = message; + } + return _result; + } factory LocalizedMessage.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); @@ -977,8 +1143,8 @@ class LocalizedMessage extends $pb.GeneratedMessage { 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') LocalizedMessage copyWith(void Function(LocalizedMessage) updates) => - super.copyWith((message) => updates( - message as LocalizedMessage)); // ignore: deprecated_member_use + super.copyWith((message) => updates(message as LocalizedMessage)) + as LocalizedMessage; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static LocalizedMessage create() => LocalizedMessage._(); @@ -988,7 +1154,7 @@ class LocalizedMessage extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static LocalizedMessage getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static LocalizedMessage _defaultInstance; + static LocalizedMessage? _defaultInstance; @$pb.TagNumber(1) $core.String get locale => $_getSZ(0); diff --git a/lib/src/generated/google/rpc/error_details.pbenum.dart b/lib/src/generated/google/rpc/error_details.pbenum.dart index 46ae38b..dc40603 100644 --- a/lib/src/generated/google/rpc/error_details.pbenum.dart +++ b/lib/src/generated/google/rpc/error_details.pbenum.dart @@ -2,5 +2,5 @@ // Generated code. Do not modify. // source: google/rpc/error_details.proto // -// @dart = 2.3 +// @dart = 2.12 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields diff --git a/lib/src/generated/google/rpc/error_details.pbjson.dart b/lib/src/generated/google/rpc/error_details.pbjson.dart index 6e20f55..d1071f9 100644 --- a/lib/src/generated/google/rpc/error_details.pbjson.dart +++ b/lib/src/generated/google/rpc/error_details.pbjson.dart @@ -2,9 +2,11 @@ // Generated code. Do not modify. // source: google/rpc/error_details.proto // -// @dart = 2.3 +// @dart = 2.12 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields +import 'dart:core' as $core; + const RetryInfo$json = const { '1': 'RetryInfo', '2': const [ diff --git a/lib/src/generated/google/rpc/status.pb.dart b/lib/src/generated/google/rpc/status.pb.dart index 452fbcb..86261f3 100644 --- a/lib/src/generated/google/rpc/status.pb.dart +++ b/lib/src/generated/google/rpc/status.pb.dart @@ -2,7 +2,7 @@ // Generated code. Do not modify. // source: google/rpc/status.proto // -// @dart = 2.3 +// @dart = 2.12 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields import 'dart:core' as $core; @@ -40,7 +40,23 @@ class Status extends $pb.GeneratedMessage { ..hasRequiredFields = false; Status._() : super(); - factory Status() => create(); + factory Status({ + $core.int? code, + $core.String? message, + $core.Iterable<$0.Any>? details, + }) { + final _result = create(); + if (code != null) { + _result.code = code; + } + if (message != null) { + _result.message = message; + } + if (details != null) { + _result.details.addAll(details); + } + return _result; + } factory Status.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); @@ -54,8 +70,9 @@ class Status extends $pb.GeneratedMessage { @$core.Deprecated('Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') - Status copyWith(void Function(Status) updates) => super.copyWith( - (message) => updates(message as Status)); // ignore: deprecated_member_use + Status copyWith(void Function(Status) updates) => + super.copyWith((message) => updates(message as Status)) + as Status; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static Status create() => Status._(); @@ -64,7 +81,7 @@ class Status extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static Status getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static Status _defaultInstance; + static Status? _defaultInstance; @$pb.TagNumber(1) $core.int get code => $_getIZ(0); diff --git a/lib/src/generated/google/rpc/status.pbenum.dart b/lib/src/generated/google/rpc/status.pbenum.dart index f116ab4..290e941 100644 --- a/lib/src/generated/google/rpc/status.pbenum.dart +++ b/lib/src/generated/google/rpc/status.pbenum.dart @@ -2,5 +2,5 @@ // Generated code. Do not modify. // source: google/rpc/status.proto // -// @dart = 2.3 +// @dart = 2.12 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields diff --git a/lib/src/generated/google/rpc/status.pbjson.dart b/lib/src/generated/google/rpc/status.pbjson.dart index e489969..a89467d 100644 --- a/lib/src/generated/google/rpc/status.pbjson.dart +++ b/lib/src/generated/google/rpc/status.pbjson.dart @@ -2,9 +2,11 @@ // Generated code. Do not modify. // source: google/rpc/status.proto // -// @dart = 2.3 +// @dart = 2.12 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields +import 'dart:core' as $core; + const Status$json = const { '1': 'Status', '2': const [ diff --git a/lib/src/server/call.dart b/lib/src/server/call.dart index 656dc48..4605bdc 100644 --- a/lib/src/server/call.dart +++ b/lib/src/server/call.dart @@ -19,19 +19,19 @@ /// ability to set custom metadata on the header/trailer sent to the client. abstract class ServiceCall { /// Custom metadata from the client. - Map get clientMetadata; + Map? get clientMetadata; /// Custom metadata to be sent to the client. Will be [null] once the headers /// have been sent, either when [sendHeaders] is called, or when the first /// response message is sent. - Map get headers; + Map? get headers; /// Custom metadata to be sent to the client after all response messages. - Map get trailers; + Map? get trailers; /// Deadline for this call. If the call is still active after this time, then /// the client or server may cancel it. - DateTime get deadline; + DateTime? get deadline; /// Returns [true] if the [deadline] has been exceeded. bool get isTimedOut; @@ -50,5 +50,5 @@ abstract class ServiceCall { /// /// The call will be closed after calling this method, and no further /// responses can be sent. - void sendTrailers({int status, String message}); + void sendTrailers({int? status, String? message}); } diff --git a/lib/src/server/handler.dart b/lib/src/server/handler.dart index 27a6a79..f8f0886 100644 --- a/lib/src/server/handler.dart +++ b/lib/src/server/handler.dart @@ -31,32 +31,33 @@ import 'service.dart'; /// Handles an incoming gRPC call. class ServerHandler_ extends ServiceCall { final ServerTransportStream _stream; - final Service Function(String service) _serviceLookup; + final Service? Function(String service) _serviceLookup; final List _interceptors; - final CodecRegistry _codecRegistry; + final CodecRegistry? _codecRegistry; - StreamSubscription _incomingSubscription; + // ignore: cancel_subscriptions + StreamSubscription? _incomingSubscription; - Service _service; - ServiceMethod _descriptor; + late Service _service; + late ServiceMethod _descriptor; - Map _clientMetadata; - Codec _callEncodingCodec; + Map? _clientMetadata; + Codec? _callEncodingCodec; - StreamController _requests; + StreamController? _requests; bool _hasReceivedRequest = false; - Stream _responses; - StreamSubscription _responseSubscription; + late Stream _responses; + StreamSubscription? _responseSubscription; bool _headersSent = false; - Map _customHeaders = {}; - Map _customTrailers = {}; + Map? _customHeaders = {}; + Map? _customTrailers = {}; - DateTime _deadline; + DateTime? _deadline; bool _isCanceled = false; bool _isTimedOut = false; - Timer _timeoutTimer; + Timer? _timeoutTimer; ServerHandler_( this._serviceLookup, @@ -65,17 +66,17 @@ class ServerHandler_ extends ServiceCall { this._codecRegistry, ); - DateTime get deadline => _deadline; + DateTime? get deadline => _deadline; bool get isCanceled => _isCanceled; bool get isTimedOut => _isTimedOut; - Map get clientMetadata => _clientMetadata; + Map? get clientMetadata => _clientMetadata; - Map get headers => _customHeaders; + Map? get headers => _customHeaders; - Map get trailers => _customTrailers; + Map? get trailers => _customTrailers; void handle() { _stream.onTerminated = (_) => cancel(); @@ -95,23 +96,21 @@ class ServerHandler_ extends ServiceCall { /// We need the catchError() handler here, since otherwise the error would /// be an unhandled exception. void _cancelResponseSubscription() { - _responseSubscription?.cancel()?.catchError((_) {}); + _responseSubscription?.cancel().catchError((_) {}); } // -- Idle state, incoming data -- - void _onDataIdle(GrpcMessage message) async { - if (message is! GrpcMetadata) { + void _onDataIdle(GrpcMessage headerMessage) async { + if (headerMessage is! GrpcMetadata) { _sendError(GrpcError.unimplemented('Expected header frame')); _sinkIncoming(); return; } - _incomingSubscription.pause(); + _incomingSubscription!.pause(); - final headerMessage = message - as GrpcMetadata; // TODO(jakobr): Cast should not be necessary here. _clientMetadata = headerMessage.metadata; - final path = _clientMetadata[':path']; + final path = _clientMetadata![':path']!; final pathSegments = path.split('/'); if (pathSegments.length < 3) { _sendError(GrpcError.unimplemented('Invalid path')); @@ -122,19 +121,21 @@ class ServerHandler_ extends ServiceCall { final methodName = pathSegments[2]; if (_codecRegistry != null) { final acceptedEncodings = - clientMetadata['grpc-accept-encoding']?.split(',') ?? []; + clientMetadata!['grpc-accept-encoding']?.split(',') ?? []; _callEncodingCodec = acceptedEncodings - .map(_codecRegistry.lookup) + .map(_codecRegistry!.lookup) .firstWhere((c) => c != null, orElse: () => null); } - _service = _serviceLookup(serviceName); - _descriptor = _service?.$lookupMethod(methodName); - if (_descriptor == null) { + final service = _serviceLookup(serviceName); + final descriptor = service?.$lookupMethod(methodName); + if (descriptor == null) { _sendError(GrpcError.unimplemented('Path $path not found')); _sinkIncoming(); return; } + _service = service!; + _descriptor = descriptor; final error = await _applyInterceptors(); if (error != null) { @@ -146,7 +147,7 @@ class ServerHandler_ extends ServiceCall { _startStreamingRequest(); } - GrpcError _onMetadata() { + GrpcError? _onMetadata() { try { _service.$onMetadata(this); } on GrpcError catch (error) { @@ -158,7 +159,7 @@ class ServerHandler_ extends ServiceCall { return null; } - Future _applyInterceptors() async { + Future _applyInterceptors() async { try { for (final interceptor in _interceptors) { final error = await interceptor(this, this._descriptor); @@ -174,13 +175,14 @@ class ServerHandler_ extends ServiceCall { } void _startStreamingRequest() { - _requests = _descriptor.createRequestStream(_incomingSubscription); - _incomingSubscription.onData(_onDataActive); + final requests = _descriptor.createRequestStream(_incomingSubscription!); + _requests = requests; + _incomingSubscription!.onData(_onDataActive); final error = _onMetadata(); if (error != null) { - if (!_requests.isClosed) { - _requests + if (!requests.isClosed) { + requests ..addError(error) ..close(); } @@ -190,16 +192,16 @@ class ServerHandler_ extends ServiceCall { return; } - _responses = _descriptor.handle(this, _requests.stream); + _responses = _descriptor.handle(this, requests.stream); _responseSubscription = _responses.listen(_onResponse, onError: _onResponseError, onDone: _onResponseDone, cancelOnError: true); - _incomingSubscription.onData(_onDataActive); - _incomingSubscription.onDone(_onDoneExpected); + _incomingSubscription!.onData(_onDataActive); + _incomingSubscription!.onDone(_onDoneExpected); - final timeout = fromTimeoutString(_clientMetadata['grpc-timeout']); + final timeout = fromTimeoutString(_clientMetadata!['grpc-timeout']); if (timeout != null) { _deadline = DateTime.now().add(timeout); _timeoutTimer = Timer(timeout, _onTimedOut); @@ -212,8 +214,8 @@ class ServerHandler_ extends ServiceCall { _isCanceled = true; final error = GrpcError.deadlineExceeded('Deadline exceeded'); _sendError(error); - if (!_requests.isClosed) { - _requests + if (!_requests!.isClosed) { + _requests! ..addError(error) ..close(); } @@ -225,7 +227,7 @@ class ServerHandler_ extends ServiceCall { if (message is! GrpcData) { final error = GrpcError.unimplemented('Expected request'); _sendError(error); - _requests + _requests! ..addError(error) ..close(); return; @@ -234,14 +236,13 @@ class ServerHandler_ extends ServiceCall { if (_hasReceivedRequest && !_descriptor.streamingRequest) { final error = GrpcError.unimplemented('Too many requests'); _sendError(error); - _requests + _requests! ..addError(error) ..close(); return; } - // TODO(jakobr): Cast should not be necessary here. - final data = message as GrpcData; + final data = message; var request; try { request = _descriptor.deserialize(data.data); @@ -249,12 +250,12 @@ class ServerHandler_ extends ServiceCall { final grpcError = GrpcError.internal('Error deserializing request: $error'); _sendError(grpcError); - _requests + _requests! ..addError(grpcError) ..close(); return; } - _requests.add(request); + _requests!.add(request); _hasReceivedRequest = true; } @@ -269,9 +270,9 @@ class ServerHandler_ extends ServiceCall { _stream.sendData(frame(bytes, _callEncodingCodec)); } catch (error) { final grpcError = GrpcError.internal('Error sending response: $error'); - if (!_requests.isClosed) { + if (!_requests!.isClosed) { // If we can, alert the handler that things are going wrong. - _requests + _requests! ..addError(grpcError) ..close(); } @@ -295,17 +296,17 @@ class ServerHandler_ extends ServiceCall { void sendHeaders() { if (_headersSent) throw GrpcError.internal('Headers already sent'); - _customHeaders..remove(':status')..remove('content-type'); + _customHeaders!..remove(':status')..remove('content-type'); // TODO(jakobr): Should come from package:http2? final outgoingHeadersMap = { ':status': '200', 'content-type': 'application/grpc', if (_callEncodingCodec != null) - 'grpc-encoding': _callEncodingCodec.encodingName, + 'grpc-encoding': _callEncodingCodec!.encodingName, }; - outgoingHeadersMap.addAll(_customHeaders); + outgoingHeadersMap.addAll(_customHeaders!); _customHeaders = null; final outgoingHeaders =
[]; @@ -315,7 +316,7 @@ class ServerHandler_ extends ServiceCall { _headersSent = true; } - void sendTrailers({int status = 0, String message}) { + void sendTrailers({int? status = 0, String? message}) { _timeoutTimer?.cancel(); final outgoingTrailersMap = {}; @@ -324,13 +325,13 @@ class ServerHandler_ extends ServiceCall { outgoingTrailersMap[':status'] = '200'; outgoingTrailersMap['content-type'] = 'application/grpc'; - _customHeaders..remove(':status')..remove('content-type'); - outgoingTrailersMap.addAll(_customHeaders); + _customHeaders!..remove(':status')..remove('content-type'); + outgoingTrailersMap.addAll(_customHeaders!); _customHeaders = null; _headersSent = true; } - _customTrailers..remove(':status')..remove('content-type'); - outgoingTrailersMap.addAll(_customTrailers); + _customTrailers!..remove(':status')..remove('content-type'); + outgoingTrailersMap.addAll(_customTrailers!); _customTrailers = null; outgoingTrailersMap['grpc-status'] = status.toString(); if (message != null) { @@ -354,11 +355,11 @@ class ServerHandler_ extends ServiceCall { // client, so we treat it as such. _timeoutTimer?.cancel(); _isCanceled = true; - if (_requests != null && !_requests.isClosed) { - _requests.addError(GrpcError.cancelled('Cancelled')); + if (_requests != null && !_requests!.isClosed) { + _requests!.addError(GrpcError.cancelled('Cancelled')); } _cancelResponseSubscription(); - _incomingSubscription.cancel(); + _incomingSubscription!.cancel(); _stream.terminate(); } @@ -371,20 +372,20 @@ class ServerHandler_ extends ServiceCall { if (!(_hasReceivedRequest || _descriptor.streamingRequest)) { final error = GrpcError.unimplemented('No request received'); _sendError(error); - _requests.addError(error); + _requests!.addError(error); } _onDone(); } void _onDone() { _requests?.close(); - _incomingSubscription.cancel(); + _incomingSubscription!.cancel(); } /// Sink incoming requests. This is used when an error has already been /// reported, but we still need to consume the request stream from the client. void _sinkIncoming() { - _incomingSubscription + _incomingSubscription! ..onData((_) {}) ..onDone(_onDone); } @@ -405,6 +406,6 @@ class ServerHandler extends ServerHandler_ { Service Function(String service) serviceLookup, stream, [ List interceptors = const [], - CodecRegistry codecRegistry, + CodecRegistry? codecRegistry, ]) : super(serviceLookup, stream, interceptors, codecRegistry); } diff --git a/lib/src/server/interceptor.dart b/lib/src/server/interceptor.dart index 65426a6..ee9286c 100644 --- a/lib/src/server/interceptor.dart +++ b/lib/src/server/interceptor.dart @@ -10,5 +10,5 @@ import 'service.dart'; /// If the interceptor returns a [GrpcError], the error will be returned as a response and [ServiceMethod] wouldn't be called. /// If the interceptor throws [Exception], [GrpcError.internal] with exception.toString() will be returned. /// If the interceptor returns null, the corresponding [ServiceMethod] of [Service] will be called. -typedef Interceptor = FutureOr Function( +typedef Interceptor = FutureOr Function( ServiceCall call, ServiceMethod method); diff --git a/lib/src/server/server.dart b/lib/src/server/server.dart index dd5d95f..a0c0e8c 100644 --- a/lib/src/server/server.dart +++ b/lib/src/server/server.dart @@ -16,10 +16,10 @@ import 'dart:async'; import 'dart:io'; -import 'package:grpc/grpc.dart'; import 'package:http2/transport.dart'; import 'package:meta/meta.dart'; +import '../shared/codec_registry.dart'; import '../shared/security.dart'; import 'handler.dart'; import 'interceptor.dart'; @@ -33,7 +33,7 @@ abstract class ServerCredentials { /// Creates [SecurityContext] from these credentials if possible. /// Otherwise returns [null]. - SecurityContext get securityContext; + SecurityContext? get securityContext; } /// Set of credentials that only allows local TCP connections. @@ -42,14 +42,14 @@ class ServerLocalCredentials extends ServerCredentials { bool validateClient(Socket socket) => socket.remoteAddress.isLoopback; @override - SecurityContext get securityContext => null; + SecurityContext? get securityContext => null; } class ServerTlsCredentials extends ServerCredentials { - final List certificate; - final String certificatePassword; - final List privateKey; - final String privateKeyPassword; + final List? certificate; + final String? certificatePassword; + final List? privateKey; + final String? privateKeyPassword; /// TLS credentials for a [Server]. /// @@ -64,10 +64,10 @@ class ServerTlsCredentials extends ServerCredentials { SecurityContext get securityContext { final context = createSecurityContext(true); if (privateKey != null) { - context.usePrivateKeyBytes(privateKey, password: privateKeyPassword); + context.usePrivateKeyBytes(privateKey!, password: privateKeyPassword); } if (certificate != null) { - context.useCertificateChainBytes(certificate, + context.useCertificateChainBytes(certificate!, password: certificatePassword); } return context; @@ -84,7 +84,7 @@ class ServerTlsCredentials extends ServerCredentials { class ConnectionServer { final Map _services = {}; final List _interceptors; - final CodecRegistry _codecRegistry; + final CodecRegistry? _codecRegistry; final _connections = []; @@ -92,7 +92,7 @@ class ConnectionServer { ConnectionServer( List services, [ List interceptors = const [], - CodecRegistry codecRegistry, + CodecRegistry? codecRegistry, ]) : _codecRegistry = codecRegistry, _interceptors = interceptors { for (final service in services) { @@ -100,11 +100,11 @@ class ConnectionServer { } } - Service lookupService(String service) => _services[service]; + Service? lookupService(String service) => _services[service]; Future serveConnection(ServerTransportConnection connection) async { _connections.add(connection); - ServerHandler_ handler; + ServerHandler_? handler; // TODO(jakobr): Set active state handlers, close connection after idle // timeout. connection.incomingStreams.listen((stream) { @@ -134,39 +134,39 @@ class ConnectionServer { /// /// Listens for incoming RPCs, dispatching them to the right [Service] handler. class Server extends ConnectionServer { - ServerSocket _insecureServer; - SecureServerSocket _secureServer; + ServerSocket? _insecureServer; + SecureServerSocket? _secureServer; /// Create a server for the given [services]. Server( List services, [ List interceptors = const [], - CodecRegistry codecRegistry, + CodecRegistry? codecRegistry, ]) : super(services, interceptors, codecRegistry); /// The port that the server is listening on, or `null` if the server is not /// active. - int get port { - if (_secureServer != null) return _secureServer.port; - if (_insecureServer != null) return _insecureServer.port; + int? get port { + if (_secureServer != null) return _secureServer!.port; + if (_insecureServer != null) return _insecureServer!.port; return null; } - Service lookupService(String service) => _services[service]; + Service? lookupService(String service) => _services[service]; /// Starts the [Server] with the given options. /// [address] can be either a [String] or an [InternetAddress], in the latter /// case it can be a Unix Domain Socket address. Future serve( {dynamic address, - int port, - ServerCredentials security, - ServerSettings http2ServerSettings, + int? port, + ServerCredentials? security, + ServerSettings? http2ServerSettings, int backlog: 0, bool v6Only: false, bool shared: false}) async { // TODO(dart-lang/grpc-dart#9): Handle HTTP/1.1 upgrade to h2c, if allowed. - Stream server; + Stream? server; final securityContext = security?.securityContext; if (securityContext != null) { _secureServer = await SecureServerSocket.bind( @@ -183,7 +183,7 @@ class Server extends ConnectionServer { ); server = _insecureServer; } - server.listen((socket) { + server!.listen((socket) { // Don't wait for io buffers to fill up before sending requests. if (socket.address.type != InternetAddressType.unix) { socket.setOption(SocketOption.tcpNoDelay, true); @@ -213,10 +213,10 @@ class Server extends ConnectionServer { Future shutdown() async { final done = _connections.map((connection) => connection.finish()).toList(); if (_insecureServer != null) { - done.add(_insecureServer.close()); + done.add(_insecureServer!.close()); } if (_secureServer != null) { - done.add(_secureServer.close()); + done.add(_secureServer!.close()); } await Future.wait(done); _insecureServer = null; diff --git a/lib/src/server/service.dart b/lib/src/server/service.dart index 7956903..303efca 100644 --- a/lib/src/server/service.dart +++ b/lib/src/server/service.dart @@ -56,36 +56,39 @@ class ServiceMethod { return handler(call, _toSingleFuture(requests)); } } else { - Future response; - if (streamingRequest) { - response = handler(call, requests); - } else { - response = handler(call, _toSingleFuture(requests)); - } + final response = streamingRequest + ? handler(call, requests) + : handler(call, _toSingleFuture(requests)); return response.asStream(); } } Future _toSingleFuture(Stream stream) { - Q _ensureOnlyOneRequest(Q previous, Q element) { + Q _ensureOnlyOneRequest(Q? previous, Q element) { if (previous != null) { throw GrpcError.unimplemented('More than one request received'); } return element; } - Q _ensureOneRequest(Q value) { + Q _ensureOneRequest(Q? value) { if (value == null) throw GrpcError.unimplemented('No requests received'); return value; } final future = - stream.fold(null, _ensureOnlyOneRequest).then(_ensureOneRequest); + stream.fold(null, _ensureOnlyOneRequest).then(_ensureOneRequest); // Make sure errors on the future aren't unhandled, but return the original // future so the request handler can also get the error. - future.catchError((_) {}); + _awaitAndCatch(future); return future; } + + void _awaitAndCatch(Future f) async { + try { + await f; + } catch (_) {} + } } /// Definition of a gRPC service. @@ -104,5 +107,5 @@ abstract class Service { /// metadata from the client. void $onMetadata(ServiceCall context) {} - ServiceMethod $lookupMethod(String name) => _$methods[name]; + ServiceMethod? $lookupMethod(String name) => _$methods[name]; } diff --git a/lib/src/shared/codec.dart b/lib/src/shared/codec.dart index c9566bf..c6316a9 100644 --- a/lib/src/shared/codec.dart +++ b/lib/src/shared/codec.dart @@ -36,7 +36,7 @@ class IdentityCodec implements Codec { const IdentityCodec(); @override - String get encodingName => "identity"; + final encodingName = 'identity'; @override List compress(List data) { @@ -54,11 +54,11 @@ class GzipCodec implements Codec { const GzipCodec(); @override - String get encodingName => "gzip"; + final encodingName = "gzip"; @override List compress(List data) { - return GZipEncoder().encode(data); + return GZipEncoder().encode(data)!; } @override diff --git a/lib/src/shared/codec_registry.dart b/lib/src/shared/codec_registry.dart index 368348c..73c0558 100644 --- a/lib/src/shared/codec_registry.dart +++ b/lib/src/shared/codec_registry.dart @@ -18,8 +18,7 @@ import 'codec.dart'; /// Encloses classes related to the compression and decompression of messages. class CodecRegistry { CodecRegistry({List codecs = const [IdentityCodec()]}) - : assert(codecs != null), - _codecs = Map.fromIterable(codecs, key: (c) => c.encodingName), + : _codecs = {for (var codec in codecs) codec.encodingName: codec}, _supportedEncodings = codecs.map((c) { if (c.encodingName.contains(',')) { throw ArgumentError.value(c.encodingName, 'codecs', @@ -33,16 +32,14 @@ class CodecRegistry { } } - factory CodecRegistry.empty() { - return CodecRegistry(codecs: []); - } + factory CodecRegistry.empty() => CodecRegistry(codecs: []); /// Key refers to the `encodingName` param from the [Codec]. final Map _codecs; final String _supportedEncodings; - Codec lookup(String codecName) { + Codec? lookup(String codecName) { return _codecs[codecName]; } diff --git a/lib/src/shared/message.dart b/lib/src/shared/message.dart index dcf251b..8b48fb0 100644 --- a/lib/src/shared/message.dart +++ b/lib/src/shared/message.dart @@ -33,32 +33,36 @@ class GrpcMetadata extends GrpcMessage { class GrpcData extends GrpcMessage { final List data; final bool isCompressed; - GrpcData(this.data, {this.isCompressed}) : assert(data != null); + GrpcData(this.data, {required this.isCompressed}) { + ArgumentError.checkNotNull(data); + } @override String toString() => 'gRPC Data (${data.length} bytes)'; } class GrpcMessageSink extends Sink { - GrpcMessage message; + late final GrpcMessage message; + bool _messageReceived = false; @override void add(GrpcMessage data) { - if (message != null) { + if (_messageReceived) { throw StateError('Too many messages received!'); } message = data; + _messageReceived = true; } @override void close() { - if (message == null) { + if (!_messageReceived) { throw StateError('No messages received!'); } } } -List frame(List rawPayload, [Codec codec]) { +List frame(List rawPayload, [Codec? codec]) { final compressedPayload = codec == null ? rawPayload : codec.compress(rawPayload); final payloadLength = compressedPayload.length; @@ -71,9 +75,9 @@ List frame(List rawPayload, [Codec codec]) { } StreamTransformer grpcDecompressor({ - CodecRegistry codecRegistry, + CodecRegistry? codecRegistry, }) { - Codec codec; + Codec? codec; return StreamTransformer.fromHandlers( handleData: (GrpcMessage value, EventSink sink) { if (value is GrpcData && value.isCompressed) { @@ -83,12 +87,12 @@ StreamTransformer grpcDecompressor({ ); return; } - sink.add(GrpcData(codec.decompress(value.data), isCompressed: false)); + sink.add(GrpcData(codec!.decompress(value.data), isCompressed: false)); return; } if (value is GrpcMetadata && value.metadata.containsKey('grpc-encoding')) { - codec = codecRegistry?.lookup(value.metadata['grpc-encoding']); + codec = codecRegistry?.lookup(value.metadata['grpc-encoding']!); } sink.add(value); }); diff --git a/lib/src/shared/profiler.dart b/lib/src/shared/profiler.dart index 1215189..ddd49a0 100644 --- a/lib/src/shared/profiler.dart +++ b/lib/src/shared/profiler.dart @@ -16,12 +16,12 @@ import 'dart:developer'; typedef TimelineTask TimelineTaskFactory( - {String filterKey, TimelineTask parent}); + {String? filterKey, TimelineTask? parent}); TimelineTaskFactory timelineTaskFactory = _defaultTimelineTaskFactory; TimelineTask _defaultTimelineTaskFactory( - {String filterKey, TimelineTask parent}) => + {String? filterKey, TimelineTask? parent}) => TimelineTask(filterKey: filterKey, parent: parent); const String clientTimelineFilterKey = 'grpc/client'; diff --git a/lib/src/shared/status.dart b/lib/src/shared/status.dart index d6d6c66..b624c50 100644 --- a/lib/src/shared/status.dart +++ b/lib/src/shared/status.dart @@ -125,9 +125,9 @@ class StatusCode { class GrpcError implements Exception { final int code; final String codeName; - final String message; - final List details; - final Object rawResponse; + final String? message; + final Object? rawResponse; + final List? details; /// Custom error code. GrpcError.custom(this.code, [this.message, this.details, this.rawResponse]) diff --git a/lib/src/shared/streams.dart b/lib/src/shared/streams.dart index 7a62b77..cfd5869 100644 --- a/lib/src/shared/streams.dart +++ b/lib/src/shared/streams.dart @@ -58,7 +58,7 @@ class _GrpcMessageConversionSink extends ChunkedConversionSink { final Sink _out; final _dataHeader = Uint8List(5); - Uint8List _data; + Uint8List? _data; int _dataOffset = 0; _GrpcMessageConversionSink(this._out); @@ -87,17 +87,17 @@ class _GrpcMessageConversionSink extends ChunkedConversionSink { } if (_data != null) { // Reading data. - final dataRemaining = _data.lengthInBytes - _dataOffset; + final dataRemaining = _data!.lengthInBytes - _dataOffset; if (dataRemaining > 0) { final chunkRemaining = chunkLength - chunkReadOffset; final toCopy = min(dataRemaining, chunkRemaining); - _data.setRange( + _data!.setRange( _dataOffset, _dataOffset + toCopy, chunkData, chunkReadOffset); _dataOffset += toCopy; chunkReadOffset += toCopy; } - if (_dataOffset == _data.lengthInBytes) { - _out.add(GrpcData(_data, + if (_dataOffset == _data!.lengthInBytes) { + _out.add(GrpcData(_data!, isCompressed: _dataHeader.buffer.asByteData().getUint8(0) != 0)); _data = null; _dataOffset = 0; diff --git a/lib/src/shared/timeout.dart b/lib/src/shared/timeout.dart index 1ef839c..c00ee9b 100644 --- a/lib/src/shared/timeout.dart +++ b/lib/src/shared/timeout.dart @@ -17,7 +17,6 @@ // Mostly inspired by grpc-java implementation. // TODO(jakobr): Modify to match grpc/core implementation instead. String toTimeoutString(Duration duration) { - if (duration == null) return null; const cutoff = 100000; final timeout = duration.inMicroseconds; if (timeout < 0) { @@ -38,7 +37,7 @@ String toTimeoutString(Duration duration) { /// Convert [timeout] from grpc-timeout header string format to [Duration]. /// Returns [null] if [timeout] is not correctly formatted. -Duration fromTimeoutString(String timeout) { +Duration? fromTimeoutString(String? timeout) { if (timeout == null) return null; if (timeout.length < 2) return null; final value = int.tryParse(timeout.substring(0, timeout.length - 1)); diff --git a/pubspec.yaml b/pubspec.yaml index bf47634..8048d27 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,28 +1,42 @@ name: grpc description: Dart implementation of gRPC, a high performance, open-source universal RPC framework. -version: 2.9.0 +version: 3.0.0-nullsafety.0 homepage: https://github.com/dart-lang/grpc-dart environment: - sdk: '>=2.8.0 <3.0.0' + sdk: '>=2.12.0-0 <3.0.0' dependencies: - archive: ^2.0.13 + archive: ^3.0.0-nullsafety async: ^2.2.0 - crypto: ^2.1.4 - fixnum: ^0.10.11 + crypto: ^3.0.0-nullsafety + fixnum: ^1.0.0-nullsafety googleapis_auth: ^0.2.7 meta: ^1.1.6 http: ^0.12.0 - http2: ^1.0.0 - protobuf: ^1.0.1 + http2: ^2.0.0-nullsafety + protobuf: ^2.0.0-nullsafety.1 dev_dependencies: - build_runner: ^1.5.2 - build_test: ^0.10.8 - build_web_compilers: ^2.1.1 - mockito: ^4.1.0 - test: ^1.6.4 + build_runner: ^1.11.0 + build_test: ^1.3.4 + mockito: ^5.0.0-nullsafety.5 + test: ^1.16.0-nullsafety.16 stream_channel: ^2.0.0 + stream_transform: ^2.0.0-nullsafety + +dependency_overrides: + http: + git: + url: https://github.com/dart-lang/http.git + ref: 3845753a54624b070828cb3eff7a6c2a4e046cfb + googleapis_auth: + git: + url: https://github.com/dart-lang/googleapis_auth.git + ref: 30c084b7650fbd3e52525a127e0e65fc528e85a8 + shelf: + git: + url: https://github.com/dart-lang/shelf.git + ref: 2102572a6c27b1321823bb3e3723ddb5448e04ae diff --git a/test/client_handles_bad_connections_test.dart b/test/client_handles_bad_connections_test.dart index fb25ea0..805b0ac 100644 --- a/test/client_handles_bad_connections_test.dart +++ b/test/client_handles_bad_connections_test.dart @@ -16,7 +16,7 @@ class TestClient extends grpc.Client { (List value) => value[0]); TestClient(ClientChannel channel) : super(channel); - grpc.ResponseStream stream(int request, {grpc.CallOptions options}) { + grpc.ResponseStream stream(int request, {grpc.CallOptions? options}) { return $createStreamingCall(_$stream, Stream.value(request), options: options); } @@ -56,7 +56,7 @@ main() async { final channel = FixedConnectionClientChannel(Http2ClientConnection( address, - server.port, + server.port!, grpc.ChannelOptions( idleTimeout: Duration(minutes: 1), // Short delay to test that it will time out. @@ -84,7 +84,7 @@ main() async { final channel = FixedConnectionClientChannel(Http2ClientConnection( address, - server.port, + server.port!, grpc.ChannelOptions(credentials: grpc.ChannelCredentials.insecure()))); final states = []; channel.clientConnection.onStateChanged = diff --git a/test/client_tests/client_test.dart b/test/client_tests/client_test.dart index b46feac..ac4f6cc 100644 --- a/test/client_tests/client_test.dart +++ b/test/client_tests/client_test.dart @@ -31,7 +31,7 @@ import '../src/utils.dart'; void main() { const dummyValue = 0; - ClientHarness harness; + late ClientHarness harness; setUp(() { harness = ClientHarness()..setUp(); @@ -399,8 +399,8 @@ void main() { test('Connection errors are reported', () async { final connectionStates = []; - harness.connection.connectionError = 'Connection error'; - harness.connection.onStateChanged = (connection) { + harness.connection!.connectionError = 'Connection error'; + harness.connection!.onStateChanged = (connection) { final state = connection.state; connectionStates.add(state); }; @@ -418,7 +418,7 @@ void main() { test('Connections time out if idle', () async { final done = Completer(); final connectionStates = []; - harness.connection.onStateChanged = (connection) { + harness.connection!.onStateChanged = (connection) { final state = connection.state; connectionStates.add(state); if (state == ConnectionState.idle) done.complete(); @@ -464,7 +464,7 @@ void main() { credentials: ChannelCredentials.insecure(authority: 'myauthority.com')); expect(Http2ClientConnection('localhost', 8080, channelOptions).authority, 'myauthority.com'); - expect(Http2ClientConnection('localhost', null, channelOptions).authority, + expect(Http2ClientConnection('localhost', 443, channelOptions).authority, 'myauthority.com'); }); @@ -485,12 +485,6 @@ void main() { expect(decodedDetails.length, 0); }); - test('decodeStatusDetails should handle a null input', () { - final decodedDetails = decodeStatusDetails(null); - expect(decodedDetails, isA>()); - expect(decodedDetails.length, 0); - }); - test('parseGeneratedMessage should parse out a valid Any type', () { final status = Status.fromBuffer(base64Url.decode( 'CAMSEGFtb3VudCB0b28gc21hbGwafgopdHlwZS5nb29nbGVhcGlzLmNvbS9nb29nbGUucnBjLkJhZFJlcXVlc3QSUQpPCgZhbW91bnQSRVRoZSByZXF1aXJlZCBjdXJyZW5jeSBjb252ZXJzaW9uIHdvdWxkIHJlc3VsdCBpbiBhIHplcm8gdmFsdWUgcGF5bWVudA==')); diff --git a/test/client_tests/client_transport_connector_test.dart b/test/client_tests/client_transport_connector_test.dart index c0dd437..f4340c4 100644 --- a/test/client_tests/client_transport_connector_test.dart +++ b/test/client_tests/client_transport_connector_test.dart @@ -26,7 +26,7 @@ import '../src/utils.dart'; void main() { const dummyValue = 0; - ClientTransportConnectorHarness harness; + late ClientTransportConnectorHarness harness; setUp(() { harness = ClientTransportConnectorHarness()..setUp(); @@ -349,8 +349,8 @@ void main() { test('Connection errors are reported', () async { final connectionStates = []; - harness.connection.connectionError = 'Connection error'; - harness.connection.onStateChanged = (connection) { + harness.connection!.connectionError = 'Connection error'; + harness.connection!.onStateChanged = (connection) { final state = connection.state; connectionStates.add(state); }; @@ -368,7 +368,7 @@ void main() { test('Connections time out if idle', () async { final done = Completer(); final connectionStates = []; - harness.connection.onStateChanged = (connection) { + harness.connection!.onStateChanged = (connection) { final state = connection.state; connectionStates.add(state); if (state == ConnectionState.idle) done.complete(); @@ -414,7 +414,7 @@ void main() { credentials: ChannelCredentials.insecure(authority: 'myauthority.com')); expect(Http2ClientConnection('localhost', 8080, channelOptions).authority, 'myauthority.com'); - expect(Http2ClientConnection('localhost', null, channelOptions).authority, + expect(Http2ClientConnection('localhost', 443, channelOptions).authority, 'myauthority.com'); }); } diff --git a/test/client_tests/client_xhr_transport_test.dart b/test/client_tests/client_xhr_transport_test.dart index ffa5732..76f8553 100644 --- a/test/client_tests/client_xhr_transport_test.dart +++ b/test/client_tests/client_xhr_transport_test.dart @@ -18,16 +18,22 @@ import 'dart:async'; import 'dart:html'; +import 'package:async/async.dart'; import 'package:grpc/src/client/call.dart'; import 'package:grpc/src/client/transport/xhr_transport.dart'; import 'package:grpc/src/shared/message.dart'; import 'package:grpc/src/shared/status.dart'; import 'package:mockito/mockito.dart'; +import 'package:stream_transform/stream_transform.dart'; import 'package:test/test.dart'; +final readyStateChangeEvent = + Event('readystatechange', canBubble: false, cancelable: false); +final progressEvent = ProgressEvent('onloadstart'); + class MockHttpRequest extends Mock implements HttpRequest { - MockHttpRequest({int code}) : status = code ?? 200; + MockHttpRequest({int? code}) : status = code ?? 200; // ignore: close_sinks StreamController readyStateChangeController = StreamController(); @@ -46,14 +52,20 @@ class MockHttpRequest extends Mock implements HttpRequest { @override final int status; + + int get readyState => super.noSuchMethod(Invocation.getter(#readyState), -1); + + @override + Map get responseHeaders => super + .noSuchMethod(Invocation.getter(#responseHeaders), {}); } class MockXhrClientConnection extends XhrClientConnection { - MockXhrClientConnection({int code}) + MockXhrClientConnection({int? code}) : _statusCode = code ?? 200, super(Uri.parse('test:8080')); - MockHttpRequest latestRequest; + late MockHttpRequest latestRequest; final int _statusCode; @override @@ -199,28 +211,40 @@ void main() { }); test('Stream handles headers properly', () async { - final metadata = { + final responseHeaders = { 'parameter_1': 'value_1', 'parameter_2': 'value_2' }; final transport = MockXhrClientConnection(); - final stream = transport.makeRequest('test_path', Duration(seconds: 10), - metadata, (error, _) => fail(error.toString())); + final stream = transport.makeRequest('test_path', Duration(seconds: 10), {}, + (error, _) => fail(error.toString())); - stream.incomingMessages.listen((message) { - expect(message, TypeMatcher()); - if (message is GrpcMetadata) { - message.metadata.forEach((key, value) { - expect(value, metadata[key]); - }); - } - }); + when(transport.latestRequest.responseHeaders).thenReturn(responseHeaders); + when(transport.latestRequest.getResponseHeader('Content-Type')) + .thenReturn('application/grpc+proto'); + 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 = [HttpRequest.HEADERS_RECEIVED, HttpRequest.DONE]; + when(transport.latestRequest.readyState) + .thenAnswer((_) => readyStates.removeAt(0)); + transport.latestRequest.readyStateChangeController + .add(readyStateChangeEvent); + transport.latestRequest.readyStateChangeController + .add(readyStateChangeEvent); + + // Should be only one metadata message with headers. + final message = await stream.incomingMessages.single as GrpcMetadata; + expect(message.metadata, responseHeaders); }); test('Stream handles trailers properly', () async { - final trailers = { + final requestHeaders = {'parameter_1': 'value_1'}; + final responseTrailers = { 'trailer_1': 'value_1', 'trailer_2': 'value_2' }; @@ -228,31 +252,37 @@ void main() { final connection = MockXhrClientConnection(); final stream = connection.makeRequest('test_path', Duration(seconds: 10), - {}, (error, _) => fail(error.toString())); + requestHeaders, (error, _) => fail(error.toString())); - final encodedTrailers = frame(trailers.entries + final encodedTrailers = frame(responseTrailers.entries .map((e) => '${e.key}:${e.value}') .join('\r\n') .codeUnits); encodedTrailers[0] = 0x80; // Mark this frame as trailers. final encodedString = String.fromCharCodes(encodedTrailers); - stream.incomingMessages.listen((message) { - expect(message, TypeMatcher()); - if (message is GrpcMetadata) { - message.metadata.forEach((key, value) { - expect(value, trailers[key]); - }); - } - }); when(connection.latestRequest.getResponseHeader('Content-Type')) .thenReturn('application/grpc+proto'); when(connection.latestRequest.responseHeaders).thenReturn({}); - when(connection.latestRequest.readyState) - .thenReturn(HttpRequest.HEADERS_RECEIVED); when(connection.latestRequest.response).thenReturn(encodedString); - connection.latestRequest.readyStateChangeController.add(null); - connection.latestRequest.progressController.add(null); + + // 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)); + connection.latestRequest.readyStateChangeController + .add(readyStateChangeEvent); + connection.latestRequest.progressController.add(progressEvent); + connection.latestRequest.readyStateChangeController + .add(readyStateChangeEvent); + + // Should be two metadata messages: headers and trailers. + final messages = + await stream.incomingMessages.whereType().toList(); + expect(messages.length, 2); + expect(messages.first.metadata, isEmpty); + expect(messages.last.metadata, responseTrailers); }); test('Stream handles empty trailers properly', () async { @@ -265,24 +295,32 @@ void main() { encoded[0] = 0x80; // Mark this frame as trailers. final encodedString = String.fromCharCodes(encoded); - stream.incomingMessages.listen((message) { - expect(message, TypeMatcher()); - if (message is GrpcMetadata) { - message.metadata.isEmpty; - } - }); when(connection.latestRequest.getResponseHeader('Content-Type')) .thenReturn('application/grpc+proto'); when(connection.latestRequest.responseHeaders).thenReturn({}); - when(connection.latestRequest.readyState) - .thenReturn(HttpRequest.HEADERS_RECEIVED); when(connection.latestRequest.response).thenReturn(encodedString); - connection.latestRequest.readyStateChangeController.add(null); - connection.latestRequest.progressController.add(null); + + // 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)); + connection.latestRequest.readyStateChangeController + .add(readyStateChangeEvent); + connection.latestRequest.progressController.add(progressEvent); + connection.latestRequest.readyStateChangeController + .add(readyStateChangeEvent); + + // Should be two metadata messages: headers and trailers. + final messages = + await stream.incomingMessages.whereType().toList(); + expect(messages.length, 2); + expect(messages.first.metadata, isEmpty); + expect(messages.last.metadata, isEmpty); }); test('Stream deserializes data properly', () async { - final metadata = { + final requestHeaders = { 'parameter_1': 'value_1', 'parameter_2': 'value_2' }; @@ -290,57 +328,50 @@ void main() { final connection = MockXhrClientConnection(); final stream = connection.makeRequest('test_path', Duration(seconds: 10), - metadata, (error, _) => fail(error.toString())); + requestHeaders, (error, _) => fail(error.toString())); final data = List.filled(10, 224); - final encoded = frame(data); - final encodedString = String.fromCharCodes(encoded); - - stream.incomingMessages.listen(expectAsync1((message) { - if (message is GrpcData) { - expect(message.data, equals(data)); - } - }, count: 2)); - when(connection.latestRequest.getResponseHeader('Content-Type')) .thenReturn('application/grpc+proto'); - when(connection.latestRequest.responseHeaders).thenReturn(metadata); + when(connection.latestRequest.responseHeaders).thenReturn({}); + when(connection.latestRequest.response) + .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) - .thenReturn(HttpRequest.HEADERS_RECEIVED); - when(connection.latestRequest.response).thenReturn(encodedString); - connection.latestRequest.readyStateChangeController.add(null); - connection.latestRequest.progressController.add(null); + .thenAnswer((_) => readyStates.removeAt(0)); + connection.latestRequest.readyStateChangeController + .add(readyStateChangeEvent); + connection.latestRequest.progressController.add(progressEvent); + connection.latestRequest.readyStateChangeController + .add(readyStateChangeEvent); + + // Expect a single data message. + final message = await stream.incomingMessages.whereType().single; + expect(message.data, data); }); test('GrpcError with error details in response', () async { - final metadata = { - 'parameter_1': 'value_1', - 'parameter_2': 'value_2' - }; - final connection = MockXhrClientConnection(code: 400); - final errorStream = StreamController(); - connection.makeRequest('test_path', Duration(seconds: 10), metadata, - (e, _) => errorStream.add(e)); - const errorDetails = "error details"; - int count = 0; - - errorStream.stream.listen((error) { - expect( - error, - TypeMatcher() - .having((e) => e.rawResponse, 'rawResponse', errorDetails)); - count++; - if (count == 2) { - errorStream.close(); - } + final errors = []; + // The incoming messages stream never completes when there's an error, so + // using completer. + final errorReceived = Completer(); + connection.makeRequest('test_path', Duration(seconds: 10), {}, (e, _) { + errorReceived.complete(); + errors.add(e); }); - + const errorDetails = "error details"; when(connection.latestRequest.getResponseHeader('Content-Type')) .thenReturn('application/grpc+proto'); - when(connection.latestRequest.responseHeaders).thenReturn(metadata); + when(connection.latestRequest.responseHeaders).thenReturn({}); when(connection.latestRequest.readyState).thenReturn(HttpRequest.DONE); when(connection.latestRequest.responseText).thenReturn(errorDetails); - connection.latestRequest.readyStateChangeController.add(null); + connection.latestRequest.readyStateChangeController + .add(readyStateChangeEvent); + await errorReceived; + expect(errors.single.rawResponse, errorDetails); }); test('Stream recieves multiple messages', () async { @@ -358,40 +389,44 @@ void main() { List.filled(10, 224), List.filled(5, 124) ]; - final encoded = data.map((d) => frame(d)); - final encodedStrings = encoded.map((e) => String.fromCharCodes(e)).toList(); - - final expectedMessages = [ - GrpcMetadata(metadata), - GrpcData(data[0]), - GrpcData(data[1]) - ]; - int i = 0; - stream.incomingMessages.listen(expectAsync1((message) { - final expectedMessage = expectedMessages[i]; - i++; - expect(message.runtimeType, expectedMessage.runtimeType); - if (message is GrpcMetadata) { - expect(message.metadata, (expectedMessage as GrpcMetadata).metadata); - } else if (message is GrpcData) { - expect(message.data, (expectedMessage as GrpcData).data); - } - }, count: expectedMessages.length)); + final encodedStrings = + data.map((d) => String.fromCharCodes(frame(d))).toList(); when(connection.latestRequest.getResponseHeader('Content-Type')) .thenReturn('application/grpc+proto'); when(connection.latestRequest.responseHeaders).thenReturn(metadata); when(connection.latestRequest.readyState) .thenReturn(HttpRequest.HEADERS_RECEIVED); - // At first - expected response is the first message - when(connection.latestRequest.response) - .thenAnswer((_) => encodedStrings[0]); - connection.latestRequest.readyStateChangeController.add(null); - connection.latestRequest.progressController.add(null); - // After the first call, expected response should now be both responses together - when(connection.latestRequest.response) - .thenAnswer((_) => encodedStrings[0] + encodedStrings[1]); - connection.latestRequest.progressController.add(null); + // At first invocation the response should be the the first message, after + // that first + last messages. + var first = true; + when(connection.latestRequest.response).thenAnswer((_) { + if (first) { + first = false; + return encodedStrings[0]; + } + return encodedStrings[0] + encodedStrings[1]; + }); + + final readyStates = [HttpRequest.HEADERS_RECEIVED, HttpRequest.DONE]; + when(connection.latestRequest.readyState) + .thenAnswer((_) => readyStates.removeAt(0)); + + final queue = StreamQueue(stream.incomingMessages); + // Headers. + connection.latestRequest.readyStateChangeController + .add(readyStateChangeEvent); + expect(((await queue.next) as GrpcMetadata).metadata, metadata); + // Data 1. + connection.latestRequest.progressController.add(progressEvent); + expect(((await queue.next) as GrpcData).data, data[0]); + // Data 2. + connection.latestRequest.progressController.add(progressEvent); + expect(((await queue.next) as GrpcData).data, data[1]); + // Done. + connection.latestRequest.readyStateChangeController + .add(readyStateChangeEvent); + expect(await queue.hasNext, isFalse); }); } diff --git a/test/connection_server_test.dart b/test/connection_server_test.dart index 0073bbb..8e0a681 100644 --- a/test/connection_server_test.dart +++ b/test/connection_server_test.dart @@ -25,7 +25,7 @@ import 'src/server_utils.dart'; void main() { const dummyValue = 17; - ConnectionServerHarness harness; + late ConnectionServerHarness harness; setUp(() { harness = ConnectionServerHarness()..setUp(); @@ -257,7 +257,7 @@ void main() { harness ..service.unaryHandler = methodHandler ..fromServer.stream.listen(expectAsync1((_) {}, count: 0), - onError: expectAsync1((error) { + onError: expectAsync1((dynamic error) { expect(error, 'TERMINATED'); }, count: 1), onDone: expectAsync0(() {}, count: 1)) diff --git a/test/grpc_web_test.dart b/test/grpc_web_test.dart index 25a70b3..83c1ae0 100644 --- a/test/grpc_web_test.dart +++ b/test/grpc_web_test.dart @@ -11,7 +11,7 @@ import 'package:grpc/grpc_web.dart'; import 'src/generated/echo.pbgrpc.dart'; void main() { - GrpcWebServer server; + late GrpcWebServer server; setUpAll(() async { server = await GrpcWebServer.start(); diff --git a/test/options_test.dart b/test/options_test.dart index 5b94b3f..c61d82f 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') + import 'dart:io'; import 'package:grpc/src/client/transport/http2_credentials.dart'; diff --git a/test/round_trip_test.dart b/test/round_trip_test.dart index 5c07d96..7902c4f 100644 --- a/test/round_trip_test.dart +++ b/test/round_trip_test.dart @@ -16,7 +16,7 @@ class TestClient extends Client { (int value) => [value], (List value) => value[0]); TestClient(api.ClientChannel channel) : super(channel); - ResponseStream stream(int request, {CallOptions options}) { + ResponseStream stream(int request, {CallOptions? options}) { return $createStreamingCall(_$stream, Stream.value(request), options: options); } @@ -66,7 +66,7 @@ main() async { final channel = FixedConnectionClientChannel(Http2ClientConnection( address, - server.port, + server.port!, ChannelOptions(credentials: ChannelCredentials.insecure()), )); final testClient = TestClient(channel); @@ -83,7 +83,7 @@ main() async { final channel = FixedConnectionClientChannel(Http2ClientConnection( address, - server.port, + server.port!, ChannelOptions( credentials: ChannelCredentials.insecure(), codecRegistry: CodecRegistry(codecs: const [GzipCodec()]), @@ -111,7 +111,7 @@ main() async { final channel = FixedConnectionClientChannel(Http2ClientConnection( address, - server.port, + server.port!, ChannelOptions( credentials: ChannelCredentials.secure( certificates: File('test/data/localhost.crt').readAsBytesSync(), @@ -129,7 +129,7 @@ main() async { final channel = FixedConnectionClientChannel(Http2ClientConnection( 'localhost', - server.port, + server.port!, ChannelOptions(credentials: ChannelCredentials.insecure()), )); final testClient = TestClient(channel); @@ -145,7 +145,7 @@ main() async { final channel = FixedConnectionClientChannel(Http2ClientConnection( 'localhost', - server.port, + server.port!, ChannelOptions(credentials: ChannelCredentials.insecure()), )); final testClient = TestClient(channel); diff --git a/test/server_handles_broken_connection_test.dart b/test/server_handles_broken_connection_test.dart index 2ac1ef2..1eda3e0 100644 --- a/test/server_handles_broken_connection_test.dart +++ b/test/server_handles_broken_connection_test.dart @@ -14,7 +14,7 @@ class TestClient extends grpc.Client { TestClient(grpc.ClientChannel channel) : super(channel); grpc.ResponseStream infiniteStream(int request, - {grpc.CallOptions options}) { + {grpc.CallOptions? options}) { return $createStreamingCall(_$infiniteStream, Stream.value(request), options: options); } @@ -24,12 +24,13 @@ class TestService extends grpc.Service { String get $name => 'test.TestService'; final void Function() finallyCallback; - TestService({this.finallyCallback}) { + TestService({required this.finallyCallback}) { $addMethod(grpc.ServiceMethod('infiniteStream', infiniteStream, false, true, (List value) => value[0], (int value) => [value])); } - Stream infiniteStream(grpc.ServiceCall call, Future request) async* { + Stream infiniteStream( + grpc.ServiceCall call, Future request) async* { int count = await request; try { while (true) { @@ -50,7 +51,8 @@ class ClientData { final InternetAddress address; final int port; final SendPort sendPort; - ClientData({this.address, this.port, this.sendPort}); + ClientData( + {required this.address, required this.port, required this.sendPort}); } void client(clientData) async { @@ -73,7 +75,7 @@ main() async { "the client interrupting the connection does not crash the server", (address) async { // interrrupt the connect of client, the server does not crash. - grpc.Server server; + late grpc.Server server; server = grpc.Server([ TestService( finallyCallback: expectAsync0(() { @@ -86,7 +88,7 @@ main() async { client, ClientData( address: address, - port: server.port, + port: server.port!, sendPort: receivePort.sendPort)); receivePort.listen(expectAsync1((e) { expect(e, isA()); diff --git a/test/server_test.dart b/test/server_test.dart index c9fd0eb..38ab2de 100644 --- a/test/server_test.dart +++ b/test/server_test.dart @@ -25,7 +25,7 @@ import 'src/server_utils.dart'; void main() { const dummyValue = 17; - ServerHarness harness; + late ServerHarness harness; setUp(() { harness = ServerHarness()..setUp(); @@ -271,7 +271,7 @@ void main() { harness ..service.unaryHandler = methodHandler ..fromServer.stream.listen(expectAsync1((_) {}, count: 0), - onError: expectAsync1((error) { + onError: expectAsync1((dynamic error) { expect(error, 'TERMINATED'); }, count: 1), onDone: expectAsync0(() {}, count: 1)) diff --git a/test/src/client_utils.dart b/test/src/client_utils.dart index 6597247..a22bcdc 100644 --- a/test/src/client_utils.dart +++ b/test/src/client_utils.dart @@ -21,15 +21,14 @@ import 'package:grpc/src/client/channel.dart' as base; import 'package:grpc/src/client/http2_connection.dart'; import 'package:grpc/src/shared/message.dart'; import 'package:http2/transport.dart'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:test/test.dart'; +import 'client_utils.mocks.dart'; import 'utils.dart'; -class MockTransport extends Mock implements ClientTransportConnection {} - -class MockStream extends Mock implements ClientTransportStream {} - +@GenerateMocks([ClientTransportConnection, ClientTransportStream]) class FakeConnection extends Http2ClientConnection { final ClientTransportConnection transport; @@ -60,7 +59,7 @@ class FakeClientTransportConnection extends Http2ClientConnection { } } -Duration testBackoff(Duration lastBackoff) => const Duration(milliseconds: 1); +Duration testBackoff(Duration? lastBackoff) => const Duration(milliseconds: 1); class FakeChannelOptions implements ChannelOptions { ChannelCredentials credentials = const ChannelCredentials.secure(); @@ -97,16 +96,16 @@ class FakeClientConnectorChannel extends ClientTransportConnectorChannel { typedef ServerMessageHandler = void Function(StreamMessage message); class TestClient extends Client { - ClientMethod _$unary; - ClientMethod _$clientStreaming; - ClientMethod _$serverStreaming; - ClientMethod _$bidirectional; + late ClientMethod _$unary; + late ClientMethod _$clientStreaming; + late ClientMethod _$serverStreaming; + late ClientMethod _$bidirectional; final int Function(List value) decode; TestClient(base.ClientChannel channel, - {CallOptions options, - Iterable interceptors, + {CallOptions? options, + Iterable? interceptors, this.decode: mockDecode}) : super(channel, options: options, interceptors: interceptors) { _$unary = ClientMethod('/Test/Unary', mockEncode, decode); @@ -118,34 +117,34 @@ class TestClient extends Client { ClientMethod('/Test/Bidirectional', mockEncode, decode); } - ResponseFuture unary(int request, {CallOptions options}) { + ResponseFuture unary(int request, {CallOptions? options}) { return $createUnaryCall(_$unary, request, options: options); } ResponseFuture clientStreaming(Stream request, - {CallOptions options}) { + {CallOptions? options}) { return $createStreamingCall(_$clientStreaming, request, options: options) .single; } - ResponseStream serverStreaming(int request, {CallOptions options}) { + ResponseStream serverStreaming(int request, {CallOptions? options}) { return $createStreamingCall(_$serverStreaming, Stream.value(request), options: options); } ResponseStream bidirectional(Stream request, - {CallOptions options}) { + {CallOptions? options}) { return $createStreamingCall(_$bidirectional, request, options: options); } } class ClientHarness extends _Harness { - FakeConnection connection; + FakeConnection? connection; @override FakeChannel createChannel() { connection = FakeConnection('test', transport, channelOptions); - return FakeChannel('test', connection, channelOptions); + return FakeChannel('test', connection!, channelOptions); } @override @@ -153,14 +152,14 @@ class ClientHarness extends _Harness { } class ClientTransportConnectorHarness extends _Harness { - FakeClientTransportConnection connection; - ClientTransportConnector connector; + FakeClientTransportConnection? connection; + late ClientTransportConnector connector; @override FakeClientConnectorChannel createChannel() { connector = FakeClientTransportConnector(transport); connection = FakeClientTransportConnection(connector, channelOptions); - return FakeClientConnectorChannel(connector, connection, channelOptions); + return FakeClientConnectorChannel(connector, connection!, channelOptions); } @override @@ -187,27 +186,27 @@ class FakeClientTransportConnector extends ClientTransportConnector { } abstract class _Harness { - MockTransport transport; - base.ClientChannel channel; - FakeChannelOptions channelOptions; - MockStream stream; + late MockClientTransportConnection transport; + late base.ClientChannel channel; + late FakeChannelOptions channelOptions; + late MockClientTransportStream stream; - StreamController fromClient; - StreamController toClient; + late StreamController fromClient; + late StreamController toClient; - Iterable interceptors; + Iterable? interceptors; - TestClient client; + late TestClient client; base.ClientChannel createChannel(); String get expectedAuthority; void setUp() { - transport = MockTransport(); + transport = MockClientTransportConnection(); channelOptions = FakeChannelOptions(); channel = createChannel(); - stream = MockStream(); + stream = MockClientTransportStream(); fromClient = StreamController(); toClient = StreamController(); when(transport.makeRequest(any, endStream: anyNamed('endStream'))) @@ -216,6 +215,8 @@ abstract class _Harness { when(transport.isOpen).thenReturn(true); when(stream.outgoingMessages).thenReturn(fromClient.sink); when(stream.incomingMessages).thenAnswer((_) => toClient.stream); + when(stream.terminate()).thenReturn(null); + when(transport.finish()).thenAnswer((_) async {}); client = TestClient(channel, interceptors: interceptors); } @@ -246,13 +247,13 @@ abstract class _Harness { } Future runTest( - {Future clientCall, + {Future? clientCall, dynamic expectedResult, - String expectedPath, - Duration expectedTimeout, - Map expectedCustomHeaders, + String? expectedPath, + Duration? expectedTimeout, + Map? expectedCustomHeaders, List serverHandlers = const [], - Function doneHandler, + void Function()? doneHandler, bool expectDone = true}) async { int serverHandlerIndex = 0; void handleServerMessage(StreamMessage message) { @@ -261,7 +262,7 @@ abstract class _Harness { final clientSubscription = fromClient.stream.listen( expectAsync1(handleServerMessage, count: serverHandlers.length), - onError: expectAsync1((_) {}, count: 0), + onError: expectAsync1((dynamic _) {}, count: 0), onDone: expectAsync0(doneHandler ?? () {}, count: expectDone ? 1 : 0)); final result = await clientCall; @@ -276,13 +277,14 @@ abstract class _Harness { MapEntry(utf8.decode(header.name), utf8.decode(header.value)))), path: expectedPath, authority: expectedAuthority, - timeout: toTimeoutString(expectedTimeout), + timeout: + expectedTimeout == null ? null : toTimeoutString(expectedTimeout), customHeaders: expectedCustomHeaders); await clientSubscription.cancel(); } - Future expectThrows(Future future, dynamic exception) async { + Future expectThrows(Future? future, dynamic exception) async { try { await future; fail('Did not throw'); @@ -293,11 +295,11 @@ abstract class _Harness { } Future runFailureTest( - {Future clientCall, + {Future? clientCall, dynamic expectedException, - String expectedPath, - Duration expectedTimeout, - Map expectedCustomHeaders, + String? expectedPath, + Duration? expectedTimeout, + Map? expectedCustomHeaders, List serverHandlers = const [], bool expectDone = true}) async { return runTest( diff --git a/test/src/client_utils.mocks.dart b/test/src/client_utils.mocks.dart new file mode 100644 index 0000000..927733a --- /dev/null +++ b/test/src/client_utils.mocks.dart @@ -0,0 +1,91 @@ +import 'dart:async' as _i3; + +import 'package:http2/src/hpack/hpack.dart' as _i4; +import 'package:http2/transport.dart' as _i2; +import 'package:mockito/mockito.dart' as _i1; + +// ignore_for_file: comment_references + +// ignore_for_file: unnecessary_parenthesis + +class _FakeClientTransportStream extends _i1.Fake + implements _i2.ClientTransportStream {} + +class _FakeStreamSink extends _i1.Fake implements _i3.StreamSink {} + +/// A class which mocks [ClientTransportConnection]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockClientTransportConnection extends _i1.Mock + implements _i2.ClientTransportConnection { + MockClientTransportConnection() { + _i1.throwOnMissingStub(this); + } + + @override + bool get isOpen => + (super.noSuchMethod(Invocation.getter(#isOpen), false) as bool); + @override + set onActiveStateChanged(_i2.ActiveStateHandler? callback) => + super.noSuchMethod(Invocation.setter(#onActiveStateChanged, callback)); + @override + _i3.Future get onInitialPeerSettingsReceived => (super.noSuchMethod( + Invocation.getter(#onInitialPeerSettingsReceived), Future.value(null)) + as _i3.Future); + @override + _i2.ClientTransportStream makeRequest(List<_i4.Header>? headers, + {bool? endStream = false}) => + (super.noSuchMethod( + Invocation.method(#makeRequest, [headers], {#endStream: endStream}), + _FakeClientTransportStream()) as _i2.ClientTransportStream); + @override + _i3.Future ping() => + (super.noSuchMethod(Invocation.method(#ping, []), Future.value(null)) + as _i3.Future); + @override + _i3.Future finish() => + (super.noSuchMethod(Invocation.method(#finish, []), Future.value(null)) + as _i3.Future); + @override + _i3.Future terminate() => + (super.noSuchMethod(Invocation.method(#terminate, []), Future.value(null)) + as _i3.Future); +} + +/// A class which mocks [ClientTransportStream]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockClientTransportStream extends _i1.Mock + implements _i2.ClientTransportStream { + MockClientTransportStream() { + _i1.throwOnMissingStub(this); + } + + @override + _i3.Stream<_i2.TransportStreamPush> get peerPushes => (super.noSuchMethod( + Invocation.getter(#peerPushes), + Stream<_i2.TransportStreamPush>.empty()) + as _i3.Stream<_i2.TransportStreamPush>); + @override + int get id => (super.noSuchMethod(Invocation.getter(#id), 0) as int); + @override + _i3.Stream<_i2.StreamMessage> get incomingMessages => (super.noSuchMethod( + Invocation.getter(#incomingMessages), + Stream<_i2.StreamMessage>.empty()) as _i3.Stream<_i2.StreamMessage>); + @override + _i3.StreamSink<_i2.StreamMessage> get outgoingMessages => (super.noSuchMethod( + Invocation.getter(#outgoingMessages), + _FakeStreamSink<_i2.StreamMessage>()) + as _i3.StreamSink<_i2.StreamMessage>); + @override + set onTerminated(void Function(int?)? value) => + super.noSuchMethod(Invocation.setter(#onTerminated, value)); + @override + void sendHeaders(List<_i4.Header>? headers, {bool? endStream = false}) => + super.noSuchMethod( + Invocation.method(#sendHeaders, [headers], {#endStream: endStream})); + @override + void sendData(List? bytes, {bool? endStream = false}) => + super.noSuchMethod( + Invocation.method(#sendData, [bytes], {#endStream: endStream})); +} diff --git a/test/src/generated/echo.pb.dart b/test/src/generated/echo.pb.dart index 2131a3b..4f2165d 100644 --- a/test/src/generated/echo.pb.dart +++ b/test/src/generated/echo.pb.dart @@ -2,7 +2,7 @@ // Generated code. Do not modify. // source: echo.proto // -// @dart = 2.3 +// @dart = 2.12 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields import 'dart:core' as $core; @@ -27,7 +27,15 @@ class EchoRequest extends $pb.GeneratedMessage { ..hasRequiredFields = false; EchoRequest._() : super(); - factory EchoRequest() => create(); + factory EchoRequest({ + $core.String? message, + }) { + final _result = create(); + if (message != null) { + _result.message = message; + } + return _result; + } factory EchoRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); @@ -42,8 +50,8 @@ class EchoRequest extends $pb.GeneratedMessage { 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') EchoRequest copyWith(void Function(EchoRequest) updates) => - super.copyWith((message) => - updates(message as EchoRequest)); // ignore: deprecated_member_use + super.copyWith((message) => updates(message as EchoRequest)) + as EchoRequest; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static EchoRequest create() => EchoRequest._(); @@ -52,7 +60,7 @@ class EchoRequest extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static EchoRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static EchoRequest _defaultInstance; + static EchoRequest? _defaultInstance; @$pb.TagNumber(1) $core.String get message => $_getSZ(0); @@ -85,7 +93,15 @@ class EchoResponse extends $pb.GeneratedMessage { ..hasRequiredFields = false; EchoResponse._() : super(); - factory EchoResponse() => create(); + factory EchoResponse({ + $core.String? message, + }) { + final _result = create(); + if (message != null) { + _result.message = message; + } + return _result; + } factory EchoResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); @@ -100,8 +116,8 @@ class EchoResponse extends $pb.GeneratedMessage { 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') EchoResponse copyWith(void Function(EchoResponse) updates) => - super.copyWith((message) => - updates(message as EchoResponse)); // ignore: deprecated_member_use + super.copyWith((message) => updates(message as EchoResponse)) + as EchoResponse; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static EchoResponse create() => EchoResponse._(); @@ -111,7 +127,7 @@ class EchoResponse extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static EchoResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static EchoResponse _defaultInstance; + static EchoResponse? _defaultInstance; @$pb.TagNumber(1) $core.String get message => $_getSZ(0); @@ -156,7 +172,23 @@ class ServerStreamingEchoRequest extends $pb.GeneratedMessage { ..hasRequiredFields = false; ServerStreamingEchoRequest._() : super(); - factory ServerStreamingEchoRequest() => create(); + factory ServerStreamingEchoRequest({ + $core.String? message, + $core.int? messageCount, + $core.int? messageInterval, + }) { + final _result = create(); + if (message != null) { + _result.message = message; + } + if (messageCount != null) { + _result.messageCount = messageCount; + } + if (messageInterval != null) { + _result.messageInterval = messageInterval; + } + return _result; + } factory ServerStreamingEchoRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); @@ -173,8 +205,9 @@ class ServerStreamingEchoRequest extends $pb.GeneratedMessage { 'Will be removed in next major version') ServerStreamingEchoRequest copyWith( void Function(ServerStreamingEchoRequest) updates) => - super.copyWith((message) => updates(message - as ServerStreamingEchoRequest)); // ignore: deprecated_member_use + super.copyWith( + (message) => updates(message as ServerStreamingEchoRequest)) + as ServerStreamingEchoRequest; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static ServerStreamingEchoRequest create() => ServerStreamingEchoRequest._(); @@ -184,7 +217,7 @@ class ServerStreamingEchoRequest extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static ServerStreamingEchoRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static ServerStreamingEchoRequest _defaultInstance; + static ServerStreamingEchoRequest? _defaultInstance; @$pb.TagNumber(1) $core.String get message => $_getSZ(0); @@ -241,7 +274,15 @@ class ServerStreamingEchoResponse extends $pb.GeneratedMessage { ..hasRequiredFields = false; ServerStreamingEchoResponse._() : super(); - factory ServerStreamingEchoResponse() => create(); + factory ServerStreamingEchoResponse({ + $core.String? message, + }) { + final _result = create(); + if (message != null) { + _result.message = message; + } + return _result; + } factory ServerStreamingEchoResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); @@ -258,8 +299,9 @@ class ServerStreamingEchoResponse extends $pb.GeneratedMessage { 'Will be removed in next major version') ServerStreamingEchoResponse copyWith( void Function(ServerStreamingEchoResponse) updates) => - super.copyWith((message) => updates(message - as ServerStreamingEchoResponse)); // ignore: deprecated_member_use + super.copyWith( + (message) => updates(message as ServerStreamingEchoResponse)) + as ServerStreamingEchoResponse; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static ServerStreamingEchoResponse create() => @@ -270,7 +312,7 @@ class ServerStreamingEchoResponse extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static ServerStreamingEchoResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static ServerStreamingEchoResponse _defaultInstance; + static ServerStreamingEchoResponse? _defaultInstance; @$pb.TagNumber(1) $core.String get message => $_getSZ(0); diff --git a/test/src/generated/echo.pbenum.dart b/test/src/generated/echo.pbenum.dart index 615a6bd..01eb863 100644 --- a/test/src/generated/echo.pbenum.dart +++ b/test/src/generated/echo.pbenum.dart @@ -2,5 +2,5 @@ // Generated code. Do not modify. // source: echo.proto // -// @dart = 2.3 +// @dart = 2.12 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields diff --git a/test/src/generated/echo.pbgrpc.dart b/test/src/generated/echo.pbgrpc.dart index c86b92e..71d4f32 100644 --- a/test/src/generated/echo.pbgrpc.dart +++ b/test/src/generated/echo.pbgrpc.dart @@ -2,7 +2,7 @@ // Generated code. Do not modify. // source: echo.proto // -// @dart = 2.3 + // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields import 'dart:async' as $async; @@ -26,18 +26,18 @@ class EchoServiceClient extends $grpc.Client { $0.ServerStreamingEchoResponse.fromBuffer(value)); EchoServiceClient($grpc.ClientChannel channel, - {$grpc.CallOptions options, - $core.Iterable<$grpc.ClientInterceptor> interceptors}) + {$grpc.CallOptions? options, + $core.Iterable<$grpc.ClientInterceptor>? interceptors}) : super(channel, options: options, interceptors: interceptors); $grpc.ResponseFuture<$0.EchoResponse> echo($0.EchoRequest request, - {$grpc.CallOptions options}) { + {$grpc.CallOptions? options}) { return $createUnaryCall(_$echo, request, options: options); } $grpc.ResponseStream<$0.ServerStreamingEchoResponse> serverStreamingEcho( $0.ServerStreamingEchoRequest request, - {$grpc.CallOptions options}) { + {$grpc.CallOptions? options}) { return $createStreamingCall( _$serverStreamingEcho, $async.Stream.fromIterable([request]), options: options); diff --git a/test/src/generated/echo.pbjson.dart b/test/src/generated/echo.pbjson.dart index 1e0d3cc..d0ba259 100644 --- a/test/src/generated/echo.pbjson.dart +++ b/test/src/generated/echo.pbjson.dart @@ -2,9 +2,11 @@ // Generated code. Do not modify. // source: echo.proto // -// @dart = 2.3 +// @dart = 2.12 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields +import 'dart:core' as $core; + const EchoRequest$json = const { '1': 'EchoRequest', '2': const [ diff --git a/test/src/server_utils.dart b/test/src/server_utils.dart index 546a2bd..bc238d0 100644 --- a/test/src/server_utils.dart +++ b/test/src/server_utils.dart @@ -27,12 +27,12 @@ class TestService extends Service { @override String get $name => 'Test'; - Future Function(ServiceCall call, Future request) unaryHandler; - Future Function(ServiceCall call, Stream request) + Future Function(ServiceCall call, Future request)? unaryHandler; + Future Function(ServiceCall call, Stream request)? clientStreamingHandler; - Stream Function(ServiceCall call, Future request) + Stream Function(ServiceCall call, Future request)? serverStreamingHandler; - Stream Function(ServiceCall call, Stream request) + Stream Function(ServiceCall call, Stream request)? bidirectionalHandler; TestService() { @@ -53,40 +53,40 @@ class TestService extends Service { if (unaryHandler == null) { fail('Should not invoke Unary'); } - return unaryHandler(call, request); + return unaryHandler!(call, request); } Future _clientStreaming(ServiceCall call, Stream request) { if (clientStreamingHandler == null) { fail('Should not invoke ClientStreaming'); } - return clientStreamingHandler(call, request); + return clientStreamingHandler!(call, request); } Stream _serverStreaming(ServiceCall call, Future request) { if (serverStreamingHandler == null) { fail('Should not invoke ServerStreaming'); } - return serverStreamingHandler(call, request); + return serverStreamingHandler!(call, request); } Stream _bidirectional(ServiceCall call, Stream request) { if (bidirectionalHandler == null) { fail('Should not invoke Bidirectional'); } - return bidirectionalHandler(call, request); + return bidirectionalHandler!(call, request); } } class TestInterceptor { - Interceptor handler; + Interceptor? handler; - FutureOr call(ServiceCall call, ServiceMethod method) { + FutureOr call(ServiceCall call, ServiceMethod method) { if (handler == null) { return null; } - return handler(call, method); + return handler!(call, method); } } @@ -112,7 +112,8 @@ class TestServerStream extends ServerTransportStream { bool get canPush => true; @override - ServerTransportStream push(List
requestHeaders) => null; + ServerTransportStream push(List
requestHeaders) => + throw 'unimplemented'; } class ServerHarness extends _Harness { @@ -144,7 +145,7 @@ abstract class _Harness { final fromServer = StreamController(); final service = TestService(); final interceptor = TestInterceptor(); - ConnectionServer _server; + ConnectionServer? _server; ConnectionServer createServer(); @@ -168,7 +169,7 @@ abstract class _Harness { fromServer.stream.listen( expectAsync1(handleMessages, count: handlers.length), - onError: expectAsync1((_) {}, count: 0), + onError: expectAsync1((dynamic _) {}, count: 0), onDone: expectAsync0(() {}, count: 1)); } @@ -185,8 +186,8 @@ abstract class _Harness { void sendRequestHeader(String path, {String authority = 'test', - Map metadata, - Duration timeout}) { + Map? metadata, + Duration? timeout}) { final headers = Http2ClientConnection.createCallHeaders( true, authority, path, timeout, metadata, null, userAgent: 'dart-grpc/1.0.0 test'); diff --git a/test/src/utils.dart b/test/src/utils.dart index 2d833cb..9c1a32d 100644 --- a/test/src/utils.dart +++ b/test/src/utils.dart @@ -31,10 +31,10 @@ Map headersToMap(List
headers) => key: (h) => ascii.decode(h.name), value: (h) => ascii.decode(h.value)); void validateRequestHeaders(Map headers, - {String path, + {String? path, String authority = 'test', - String timeout, - Map customHeaders}) { + String? timeout, + Map? customHeaders}) { expect(headers[':method'], 'POST'); expect(headers[':scheme'], 'https'); if (path != null) { @@ -54,7 +54,7 @@ void validateRequestHeaders(Map headers, void validateResponseHeaders(Map headers, {int status = 200, bool allowTrailers = false, - Map customHeaders}) { + Map? customHeaders}) { expect(headers[':status'], '200'); expect(headers['content-type'], startsWith('application/grpc')); if (!allowTrailers) { @@ -67,7 +67,7 @@ void validateResponseHeaders(Map headers, } void validateResponseTrailers(Map trailers, - {int status = 0, String message, Map customTrailers}) { + {int status = 0, String? message, Map? customTrailers}) { expect(trailers['grpc-status'], '$status'); if (message != null) { expect(trailers['grpc-message'], message); @@ -84,7 +84,7 @@ GrpcMetadata validateMetadataMessage(StreamMessage message, final decoded = GrpcHttpDecoder().convert(message); expect(decoded, TypeMatcher()); - return decoded; + return decoded as GrpcMetadata; } GrpcData validateDataMessage(StreamMessage message, {bool endStream = false}) { @@ -93,7 +93,7 @@ GrpcData validateDataMessage(StreamMessage message, {bool endStream = false}) { final decoded = GrpcHttpDecoder().convert(message); expect(decoded, TypeMatcher()); - return decoded; + return decoded as GrpcData; } void Function(StreamMessage message) headerValidator() { diff --git a/test/stream_test.dart b/test/stream_test.dart index 5246f9d..00ba1d7 100644 --- a/test/stream_test.dart +++ b/test/stream_test.dart @@ -22,8 +22,8 @@ import 'package:grpc/grpc.dart'; void main() { group('GrpcHttpDecoder', () { - StreamController input; - Stream output; + late StreamController input; + late Stream output; setUp(() { input = StreamController(); @@ -51,11 +51,12 @@ void main() { } expect(converted[0], TypeMatcher()); - verify(converted[1], [48, 49, 50, 51, 52, 53, 54, 55, 56, 57]); - verify(converted[2], [97, 98, 99, 100]); - verify(converted[3], [65]); - verify(converted[4], [48, 49, 50, 51]); - verify(converted[5], List.filled(256, 90)); + verify( + converted[1] as GrpcData, [48, 49, 50, 51, 52, 53, 54, 55, 56, 57]); + verify(converted[2] as GrpcData, [97, 98, 99, 100]); + verify(converted[3] as GrpcData, [65]); + verify(converted[4] as GrpcData, [48, 49, 50, 51]); + verify(converted[5] as GrpcData, List.filled(256, 90)); }); test('throws error if input is closed while receiving data header', diff --git a/test/timeline_test.dart b/test/timeline_test.dart index 5c6f5a6..0ae0d3d 100644 --- a/test/timeline_test.dart +++ b/test/timeline_test.dart @@ -33,7 +33,7 @@ class TestClient extends Client { path, (int value) => [value], (List value) => value[0]); TestClient(api.ClientChannel channel) : super(channel); - ResponseStream stream(int request, {CallOptions options}) { + ResponseStream stream(int request, {CallOptions? options}) { return $createStreamingCall(_$stream, Stream.fromIterable([request]), options: options); } @@ -69,12 +69,12 @@ class FakeTimelineTask extends Fake implements TimelineTask { static final List events = []; static int _idCount = 0; - final String filterKey; - final TimelineTask parent; + final String? filterKey; + final TimelineTask? parent; final int id = _idCount++; int _startFinishCount = 0; - factory FakeTimelineTask({TimelineTask parent, String filterKey}) { + factory FakeTimelineTask({TimelineTask? parent, String? filterKey}) { final task = FakeTimelineTask._(parent: parent, filterKey: filterKey); tasks.add(task); return task; @@ -84,7 +84,7 @@ class FakeTimelineTask extends Fake implements TimelineTask { bool get isComplete => _startFinishCount == 0; - void start(String name, {Map arguments}) { + void start(String name, {Map? arguments}) { events.add({ 'id': id, 'ph': 'b', @@ -98,7 +98,7 @@ class FakeTimelineTask extends Fake implements TimelineTask { ++_startFinishCount; } - void instant(String name, {Map arguments}) { + void instant(String name, {Map? arguments}) { events.add({ 'id': id, 'ph': 'i', @@ -110,7 +110,7 @@ class FakeTimelineTask extends Fake implements TimelineTask { }); } - void finish({Map arguments}) { + void finish({Map? arguments}) { events.add({ 'id': id, 'ph': 'e', @@ -124,7 +124,8 @@ class FakeTimelineTask extends Fake implements TimelineTask { } } -TimelineTask fakeTimelineTaskFactory({String filterKey, TimelineTask parent}) => +TimelineTask fakeTimelineTaskFactory( + {String? filterKey, TimelineTask? parent}) => FakeTimelineTask(filterKey: filterKey, parent: parent); testee() async { @@ -134,7 +135,7 @@ testee() async { timelineTaskFactory = fakeTimelineTaskFactory; final channel = FixedConnectionClientChannel(Http2ClientConnection( 'localhost', - server.port, + server.port!, ChannelOptions(credentials: ChannelCredentials.insecure()), )); final testClient = TestClient(channel); diff --git a/test/timeout_test.dart b/test/timeout_test.dart index 578a9d9..76cc781 100644 --- a/test/timeout_test.dart +++ b/test/timeout_test.dart @@ -28,7 +28,6 @@ void main() { group('Unit:', () { test('Timeouts are converted correctly to header string', () { - expect(toTimeoutString(null), isNull); expect(toTimeoutString(Duration(microseconds: -1)), '1n'); expect(toTimeoutString(Duration(microseconds: 0)), '0u'); expect(toTimeoutString(Duration(microseconds: 107)), '107u'); @@ -61,7 +60,7 @@ void main() { }); group('Client:', () { - ClientHarness harness; + late ClientHarness harness; setUp(() { harness = ClientHarness()..setUp(); @@ -101,7 +100,7 @@ void main() { }); group('Server:', () { - ServerHarness harness; + late ServerHarness harness; setUp(() { harness = ServerHarness()..setUp(); @@ -112,6 +111,7 @@ void main() { }); test('Calls time out if deadline is exceeded', () async { + final handlerFinished = Completer(); Future methodHandler(ServiceCall call, Future request) async { try { expect(call.isTimedOut, isFalse); @@ -126,6 +126,8 @@ void main() { fail('Did not throw'); } catch (error, stack) { registerException(error, stack); + } finally { + handlerFinished.complete(); } return dummyValue; } @@ -134,7 +136,7 @@ void main() { ..service.unaryHandler = methodHandler ..expectErrorResponse(StatusCode.deadlineExceeded, 'Deadline exceeded') ..sendRequestHeader('/Test/Unary', timeout: Duration(microseconds: 1)); - await harness.fromServer.done; + await Future.wait([handlerFinished.future, harness.fromServer.done]); }); }, testOn: 'vm'); }