Migrate grpc to null safety (#432)

This commit is contained in:
Ivan Inozemtsev 2021-01-29 12:40:52 +01:00 committed by GitHub
parent d3f0ec7f37
commit 1e1831a187
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
73 changed files with 1121 additions and 676 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -9,4 +9,4 @@ dependencies:
async: ^2.2.0
grpc:
path: ../../
protobuf: ^1.0.1
protobuf: ^2.0.0-nullsafety

View File

@ -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

View File

@ -9,4 +9,4 @@ dependencies:
async: ^2.2.0
grpc:
path: ../../
protobuf: ^1.0.1
protobuf: ^2.0.0-nullsafety

View File

@ -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

View File

@ -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<void> authenticate(Map<String, String> 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<void> _call;
Future<void>? _call;
Future<void> obtainAccessCredentials(String uri) {
if (_call == null) {
@ -68,7 +69,7 @@ abstract class HttpBasedAuthenticator extends BaseAuthenticator {
authClient.close();
});
}
return _call;
return _call!;
}
Future<auth.AccessCredentials> 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<String, dynamic> 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<void> 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<String> scopes}) {
auth.ServiceAccountCredentials credentials, String? keyId, String uri,
{String? user, List<String>? scopes}) {
// Subtracting 20 seconds from current timestamp to allow for clock skew among
// servers.
final timestamp =

View File

@ -13,18 +13,22 @@ class ComputeEngineAuthenticator extends HttpBasedAuthenticator {
}
class ServiceAccountAuthenticator extends HttpBasedAuthenticator {
auth.ServiceAccountCredentials _serviceAccountCredentials;
late auth.ServiceAccountCredentials _serviceAccountCredentials;
final List<String> _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<String, dynamic> serviceAccountJson, this._scopes)
: _serviceAccountCredentials =
auth.ServiceAccountCredentials.fromJson(serviceAccountJson),
_projectId = serviceAccountJson['project_id'];
String get projectId => _projectId;
factory ServiceAccountAuthenticator(
String serviceAccountJsonString, List<String> scopes) =>
ServiceAccountAuthenticator.fromJson(
jsonDecode(serviceAccountJsonString), scopes);
String? get projectId => _projectId;
Future<auth.AccessCredentials> 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<HttpBasedAuthenticator> applicationDefaultCredentialsAuthenticator(
List<String> 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<HttpBasedAuthenticator> 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.

View File

@ -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();

View File

@ -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<void> MetadataProvider(
/// Runtime options for an RPC.
class CallOptions {
final Map<String, String> metadata;
final Duration timeout;
final Duration? timeout;
final List<MetadataProvider> 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<String, String> metadata,
Duration timeout,
List<MetadataProvider> providers,
Codec compression,
Map<String, String>? metadata,
Duration? timeout,
List<MetadataProvider>? providers,
Codec? compression,
}) {
return CallOptions._(
Map.unmodifiable(metadata ?? {}),
@ -89,7 +90,7 @@ class CallOptions {
factory CallOptions.from(Iterable<CallOptions> 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<String, String> metadata, Duration timeout,
WebCallOptions._(Map<String, String> metadata, Duration? timeout,
List<MetadataProvider> 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<String, String> metadata,
Duration timeout,
List<MetadataProvider> providers,
bool bypassCorsPreflight,
bool withCredentials}) {
{Map<String, String>? metadata,
Duration? timeout,
List<MetadataProvider>? 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<Q, R> implements Response {
final _trailers = Completer<Map<String, String>>();
bool _hasReceivedResponses = false;
Map<String, String> _headerMetadata;
late Map<String, String> _headerMetadata;
GrpcTransportStream _stream;
StreamController<R> _responses;
StreamSubscription<List<int>> _requestSubscription;
StreamSubscription<GrpcMessage> _responseSubscription;
GrpcTransportStream? _stream;
final _responses = StreamController<R>();
StreamSubscription<List<int>>? _requestSubscription;
StreamSubscription<GrpcMessage>? _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<Q, R> implements Response {
final metadata = Map<String, String>.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<Q, R> implements Response {
}
void _sendRequest(ClientConnection connection, Map<String, String> metadata) {
late final GrpcTransportStream stream;
try {
_stream = connection.makeRequest(
stream = connection.makeRequest(
_method.path,
options.timeout,
metadata,
@ -287,16 +287,17 @@ class ClientCall<Q, R> 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<Q, R> 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<Q, R> 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 <GeneratedMessage>[]
: decodeStatusDetails(statusDetails)));
}
}
@ -444,7 +450,7 @@ class ClientCall<Q, R> 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<Q, R> implements Response {
_responses.close();
_requestSubscription?.cancel();
_responseSubscription?.cancel();
_stream.terminate();
_stream!.terminate();
}
Stream<R> get response => _responses.stream;
@ -492,10 +498,10 @@ class ClientCall<Q, R> implements Response {
_stream?.terminate();
final futures = <Future>[];
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);
}

View File

@ -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<void> shutdown() async {
if (_isShutdown) return;
_isShutdown = true;
if (_connection != null) await _connection.shutdown();
if (_connected) {
await _connection.shutdown();
}
}
@override
Future<void> 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<ClientConnection> getConnection() async {
if (_isShutdown) throw GrpcError.unavailable('Channel shutting down.');
return _connection ??= createConnection();
if (!_connected) {
_connection = createConnection();
_connected = true;
}
return _connection;
}
@override

View File

@ -27,7 +27,7 @@ class Client {
/// Interceptors will be applied in direct order before making a request.
Client(this._channel,
{CallOptions options, Iterable<ClientInterceptor> interceptors})
{CallOptions? options, Iterable<ClientInterceptor>? 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<Q, R> $createCall<Q, R>(
ClientMethod<Q, R> method, Stream<Q> requests,
{CallOptions options}) {
{CallOptions? options}) {
return _channel.createCall(method, requests, _options.mergedWith(options));
}
ResponseFuture<R> $createUnaryCall<Q, R>(ClientMethod<Q, R> method, Q request,
{CallOptions options}) {
{CallOptions? options}) {
ClientUnaryInvoker<Q, R> invoker = (method, request, options) =>
ResponseFuture<R>(
_channel.createCall<Q, R>(method, Stream.value(request), options));
@ -60,7 +60,7 @@ regenerate these stubs using protobuf compiler plugin version 19.2.0 or newer.
ResponseStream<R> $createStreamingCall<Q, R>(
ClientMethod<Q, R> method, Stream<Q> requests,
{CallOptions options}) {
{CallOptions? options}) {
ClientStreamingInvoker<Q, R> invoker = (method, request, options) =>
ResponseStream<R>(_channel.createCall<Q, R>(method, requests, options));

View File

@ -46,21 +46,21 @@ class ResponseFuture<R> extends DelegatingFuture<R>
with _ResponseMixin<dynamic, R> {
final ClientCall<dynamic, R> _call;
static R _ensureOnlyOneResponse<R>(R previous, R element) {
static R _ensureOnlyOneResponse<R>(R? previous, R element) {
if (previous != null) {
throw GrpcError.unimplemented('More than one response received');
}
return element;
}
static R _ensureOneResponse<R>(R value) {
static R _ensureOneResponse<R>(R? value) {
if (value == null) throw GrpcError.unimplemented('No responses received');
return value;
}
ResponseFuture(this._call)
: super(_call.response
.fold(null, _ensureOnlyOneResponse)
.fold<R?>(null, _ensureOnlyOneResponse)
.then(_ensureOneResponse));
}

View File

@ -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<String, String> metadata, ErrorHandler onRequestFailure,
{CallOptions callOptions});
{required CallOptions callOptions});
/// Shuts down this connection.
///

View File

@ -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 = <ClientCall>[];
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<void>((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<String, String> 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<Header> createCallHeaders(
bool useTls,
String authority,
String path,
Duration timeout,
Map<String, String> metadata,
Codec compressionCodec, {
String userAgent,
String grpcAcceptEncodings,
Duration? timeout,
Map<String, String>? 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<ClientTransportConnection> 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();
}

View File

@ -3,10 +3,10 @@ import 'common.dart';
import 'method.dart';
typedef ClientUnaryInvoker<Q, R> = ResponseFuture<R> Function(
ClientMethod method, Q request, CallOptions options);
ClientMethod<Q, R> method, Q request, CallOptions options);
typedef ClientStreamingInvoker<Q, R> = ResponseStream<R> Function(
ClientMethod method, Stream<Q> requests, CallOptions options);
ClientMethod<Q, R> method, Stream<Q> requests, CallOptions options);
/// ClientInterceptors intercepts client calls before they are executed.
///

View File

@ -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;

View File

@ -29,17 +29,24 @@ class QueryParameter implements Comparable<QueryParameter> {
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<String> 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

View File

@ -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<int> _certificateBytes;
final String _certificatePassword;
final BadCertificateHandler onBadCertificate;
final String? authority;
final List<int>? _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<int> certificates,
String password,
String authority,
BadCertificateHandler onBadCertificate})
{List<int>? 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);

View File

@ -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)) {

View File

@ -47,10 +47,10 @@ class _GrpcWebConversionSink extends ChunkedConversionSink<ByteBuffer> {
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<ByteBuffer> {
}
void _parseMessage(List<int> 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<ByteBuffer> {
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<ByteBuffer> {
Map<String, String> _parseHttp1Headers(String stringData) {
final trimmed = stringData.trim();
final chunks = trimmed == '' ? [] : trimmed.split('\r\n');
final chunks = trimmed == '' ? <String>[] : trimmed.split('\r\n');
final headers = <String, String>{};
for (final chunk in chunks) {
final pos = chunk.indexOf(':');

View File

@ -51,7 +51,8 @@ class XhrTransportStream implements GrpcTransportStream {
@override
StreamSink<List<int>> 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<String, String> 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<String, String> 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<void> shutdown() async {}
}
MapEntry<String, String> _getContentTypeHeader(Map<String, String> metadata) {
MapEntry<String, String>? _getContentTypeHeader(Map<String, String> metadata) {
for (var entry in metadata.entries) {
if (entry.key.toLowerCase() == _contentTypeKey.toLowerCase()) {
return entry;

View File

@ -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<Any>(create);
static Any _defaultInstance;
static Any? _defaultInstance;
@$pb.TagNumber(1)
$core.String get typeUrl => $_getSZ(0);

View File

@ -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

View File

@ -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 [

View File

@ -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<Duration>(create);
static Duration _defaultInstance;
static Duration? _defaultInstance;
@$pb.TagNumber(1)
$fixnum.Int64 get seconds => $_getI64(0);

View File

@ -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

View File

@ -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 [

View File

@ -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;

View File

@ -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);
}

View File

@ -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 [

View File

@ -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<RetryInfo>(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<DebugInfo>(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<QuotaFailure_Violation>(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<QuotaFailure_Violation>? 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<QuotaFailure>(create);
static QuotaFailure _defaultInstance;
static QuotaFailure? _defaultInstance;
@$pb.TagNumber(1)
$core.List<QuotaFailure_Violation> 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<ErrorInfo>(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<PreconditionFailure_Violation>(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<PreconditionFailure_Violation>? 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<PreconditionFailure>(create);
static PreconditionFailure _defaultInstance;
static PreconditionFailure? _defaultInstance;
@$pb.TagNumber(1)
$core.List<PreconditionFailure_Violation> 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<BadRequest_FieldViolation>(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<BadRequest_FieldViolation>? 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<BadRequest>(create);
static BadRequest _defaultInstance;
static BadRequest? _defaultInstance;
@$pb.TagNumber(1)
$core.List<BadRequest_FieldViolation> 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<RequestInfo>(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<ResourceInfo>(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<Help_Link>(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<Help_Link>? 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<Help>(create);
static Help _defaultInstance;
static Help? _defaultInstance;
@$pb.TagNumber(1)
$core.List<Help_Link> 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<LocalizedMessage>(create);
static LocalizedMessage _defaultInstance;
static LocalizedMessage? _defaultInstance;
@$pb.TagNumber(1)
$core.String get locale => $_getSZ(0);

View File

@ -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

View File

@ -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 [

View File

@ -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<Status>(create);
static Status _defaultInstance;
static Status? _defaultInstance;
@$pb.TagNumber(1)
$core.int get code => $_getIZ(0);

View File

@ -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

View File

@ -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 [

View File

@ -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<String, String> get clientMetadata;
Map<String, String>? 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<String, String> get headers;
Map<String, String>? get headers;
/// Custom metadata to be sent to the client after all response messages.
Map<String, String> get trailers;
Map<String, String>? 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});
}

View File

@ -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<Interceptor> _interceptors;
final CodecRegistry _codecRegistry;
final CodecRegistry? _codecRegistry;
StreamSubscription<GrpcMessage> _incomingSubscription;
// ignore: cancel_subscriptions
StreamSubscription<GrpcMessage>? _incomingSubscription;
Service _service;
ServiceMethod _descriptor;
late Service _service;
late ServiceMethod _descriptor;
Map<String, String> _clientMetadata;
Codec _callEncodingCodec;
Map<String, String>? _clientMetadata;
Codec? _callEncodingCodec;
StreamController _requests;
StreamController? _requests;
bool _hasReceivedRequest = false;
Stream _responses;
StreamSubscription _responseSubscription;
late Stream _responses;
StreamSubscription? _responseSubscription;
bool _headersSent = false;
Map<String, String> _customHeaders = {};
Map<String, String> _customTrailers = {};
Map<String, String>? _customHeaders = {};
Map<String, String>? _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<String, String> get clientMetadata => _clientMetadata;
Map<String, String>? get clientMetadata => _clientMetadata;
Map<String, String> get headers => _customHeaders;
Map<String, String>? get headers => _customHeaders;
Map<String, String> get trailers => _customTrailers;
Map<String, String>? 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<GrpcError> _applyInterceptors() async {
Future<GrpcError?> _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 = <String, String>{
':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 = <Header>[];
@ -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 = <String, String>{};
@ -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<Interceptor> interceptors = const <Interceptor>[],
CodecRegistry codecRegistry,
CodecRegistry? codecRegistry,
]) : super(serviceLookup, stream, interceptors, codecRegistry);
}

View File

@ -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<GrpcError> Function(
typedef Interceptor = FutureOr<GrpcError?> Function(
ServiceCall call, ServiceMethod method);

View File

@ -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<int> certificate;
final String certificatePassword;
final List<int> privateKey;
final String privateKeyPassword;
final List<int>? certificate;
final String? certificatePassword;
final List<int>? 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<String, Service> _services = {};
final List<Interceptor> _interceptors;
final CodecRegistry _codecRegistry;
final CodecRegistry? _codecRegistry;
final _connections = <ServerTransportConnection>[];
@ -92,7 +92,7 @@ class ConnectionServer {
ConnectionServer(
List<Service> services, [
List<Interceptor> interceptors = const <Interceptor>[],
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<void> 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<Service> services, [
List<Interceptor> interceptors = const <Interceptor>[],
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<void> 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<Socket> server;
Stream<Socket>? 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<void> 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;

View File

@ -56,36 +56,39 @@ class ServiceMethod<Q, R> {
return handler(call, _toSingleFuture(requests));
}
} else {
Future<R> 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<Q> _toSingleFuture(Stream<Q> 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<Q?>(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<Q>(Future<Q> 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];
}

View File

@ -36,7 +36,7 @@ class IdentityCodec implements Codec {
const IdentityCodec();
@override
String get encodingName => "identity";
final encodingName = 'identity';
@override
List<int> compress(List<int> data) {
@ -54,11 +54,11 @@ class GzipCodec implements Codec {
const GzipCodec();
@override
String get encodingName => "gzip";
final encodingName = "gzip";
@override
List<int> compress(List<int> data) {
return GZipEncoder().encode(data);
return GZipEncoder().encode(data)!;
}
@override

View File

@ -18,8 +18,7 @@ import 'codec.dart';
/// Encloses classes related to the compression and decompression of messages.
class CodecRegistry {
CodecRegistry({List<Codec> 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<String, Codec> _codecs;
final String _supportedEncodings;
Codec lookup(String codecName) {
Codec? lookup(String codecName) {
return _codecs[codecName];
}

View File

@ -33,32 +33,36 @@ class GrpcMetadata extends GrpcMessage {
class GrpcData extends GrpcMessage {
final List<int> 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> {
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<int> frame(List<int> rawPayload, [Codec codec]) {
List<int> frame(List<int> rawPayload, [Codec? codec]) {
final compressedPayload =
codec == null ? rawPayload : codec.compress(rawPayload);
final payloadLength = compressedPayload.length;
@ -71,9 +75,9 @@ List<int> frame(List<int> rawPayload, [Codec codec]) {
}
StreamTransformer<GrpcMessage, GrpcMessage> grpcDecompressor({
CodecRegistry codecRegistry,
CodecRegistry? codecRegistry,
}) {
Codec codec;
Codec? codec;
return StreamTransformer<GrpcMessage, GrpcMessage>.fromHandlers(
handleData: (GrpcMessage value, EventSink<GrpcMessage> sink) {
if (value is GrpcData && value.isCompressed) {
@ -83,12 +87,12 @@ StreamTransformer<GrpcMessage, GrpcMessage> 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);
});

View File

@ -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';

View File

@ -125,9 +125,9 @@ class StatusCode {
class GrpcError implements Exception {
final int code;
final String codeName;
final String message;
final List<GeneratedMessage> details;
final Object rawResponse;
final String? message;
final Object? rawResponse;
final List<GeneratedMessage>? details;
/// Custom error code.
GrpcError.custom(this.code, [this.message, this.details, this.rawResponse])

View File

@ -58,7 +58,7 @@ class _GrpcMessageConversionSink extends ChunkedConversionSink<StreamMessage> {
final Sink<GrpcMessage> _out;
final _dataHeader = Uint8List(5);
Uint8List _data;
Uint8List? _data;
int _dataOffset = 0;
_GrpcMessageConversionSink(this._out);
@ -87,17 +87,17 @@ class _GrpcMessageConversionSink extends ChunkedConversionSink<StreamMessage> {
}
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;

View File

@ -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));

View File

@ -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

View File

@ -16,7 +16,7 @@ class TestClient extends grpc.Client {
(List<int> value) => value[0]);
TestClient(ClientChannel channel) : super(channel);
grpc.ResponseStream<int> stream(int request, {grpc.CallOptions options}) {
grpc.ResponseStream<int> 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 = <grpc.ConnectionState>[];
channel.clientConnection.onStateChanged =

View File

@ -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 = <ConnectionState>[];
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 = <ConnectionState>[];
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<List<GeneratedMessage>>());
expect(decodedDetails.length, 0);
});
test('parseGeneratedMessage should parse out a valid Any type', () {
final status = Status.fromBuffer(base64Url.decode(
'CAMSEGFtb3VudCB0b28gc21hbGwafgopdHlwZS5nb29nbGVhcGlzLmNvbS9nb29nbGUucnBjLkJhZFJlcXVlc3QSUQpPCgZhbW91bnQSRVRoZSByZXF1aXJlZCBjdXJyZW5jeSBjb252ZXJzaW9uIHdvdWxkIHJlc3VsdCBpbiBhIHplcm8gdmFsdWUgcGF5bWVudA=='));

View File

@ -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 = <ConnectionState>[];
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 = <ConnectionState>[];
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');
});
}

View File

@ -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<Event> readyStateChangeController =
StreamController<Event>();
@ -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<String, String> get responseHeaders => super
.noSuchMethod(Invocation.getter(#responseHeaders), <String, String>{});
}
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 = <String, String>{
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<GrpcMetadata>());
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(<int>[])));
// 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 = <String, String>{
final requestHeaders = {'parameter_1': 'value_1'};
final responseTrailers = <String, String>{
'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<GrpcMetadata>());
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<GrpcMetadata>().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<GrpcMetadata>());
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<GrpcMetadata>().toList();
expect(messages.length, 2);
expect(messages.first.metadata, isEmpty);
expect(messages.last.metadata, isEmpty);
});
test('Stream deserializes data properly', () async {
final metadata = <String, String>{
final requestHeaders = <String, String>{
'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<int>.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<GrpcData>().single;
expect(message.data, data);
});
test('GrpcError with error details in response', () async {
final metadata = <String, String>{
'parameter_1': 'value_1',
'parameter_2': 'value_2'
};
final connection = MockXhrClientConnection(code: 400);
final errorStream = StreamController<GrpcError>();
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<GrpcError>()
.having((e) => e.rawResponse, 'rawResponse', errorDetails));
count++;
if (count == 2) {
errorStream.close();
}
final errors = <GrpcError>[];
// The incoming messages stream never completes when there's an error, so
// using completer.
final errorReceived = Completer<void>();
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<int>.filled(10, 224),
List<int>.filled(5, 124)
];
final encoded = data.map((d) => frame(d));
final encodedStrings = encoded.map((e) => String.fromCharCodes(e)).toList();
final expectedMessages = <GrpcMessage>[
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);
});
}

View File

@ -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))

View File

@ -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();

View File

@ -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';

View File

@ -16,7 +16,7 @@ class TestClient extends Client {
(int value) => [value], (List<int> value) => value[0]);
TestClient(api.ClientChannel channel) : super(channel);
ResponseStream<int> stream(int request, {CallOptions options}) {
ResponseStream<int> 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);

View File

@ -14,7 +14,7 @@ class TestClient extends grpc.Client {
TestClient(grpc.ClientChannel channel) : super(channel);
grpc.ResponseStream<int> 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<int, int>('infiniteStream', infiniteStream,
false, true, (List<int> value) => value[0], (int value) => [value]));
}
Stream<int> infiniteStream(grpc.ServiceCall call, Future request) async* {
Stream<int> infiniteStream(
grpc.ServiceCall call, Future<int> 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<grpc.GrpcError>());

View File

@ -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))

View File

@ -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<int, int> _$unary;
ClientMethod<int, int> _$clientStreaming;
ClientMethod<int, int> _$serverStreaming;
ClientMethod<int, int> _$bidirectional;
late ClientMethod<int, int> _$unary;
late ClientMethod<int, int> _$clientStreaming;
late ClientMethod<int, int> _$serverStreaming;
late ClientMethod<int, int> _$bidirectional;
final int Function(List<int> value) decode;
TestClient(base.ClientChannel channel,
{CallOptions options,
Iterable<ClientInterceptor> interceptors,
{CallOptions? options,
Iterable<ClientInterceptor>? interceptors,
this.decode: mockDecode})
: super(channel, options: options, interceptors: interceptors) {
_$unary = ClientMethod<int, int>('/Test/Unary', mockEncode, decode);
@ -118,34 +117,34 @@ class TestClient extends Client {
ClientMethod<int, int>('/Test/Bidirectional', mockEncode, decode);
}
ResponseFuture<int> unary(int request, {CallOptions options}) {
ResponseFuture<int> unary(int request, {CallOptions? options}) {
return $createUnaryCall(_$unary, request, options: options);
}
ResponseFuture<int> clientStreaming(Stream<int> request,
{CallOptions options}) {
{CallOptions? options}) {
return $createStreamingCall(_$clientStreaming, request, options: options)
.single;
}
ResponseStream<int> serverStreaming(int request, {CallOptions options}) {
ResponseStream<int> serverStreaming(int request, {CallOptions? options}) {
return $createStreamingCall(_$serverStreaming, Stream.value(request),
options: options);
}
ResponseStream<int> bidirectional(Stream<int> 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<StreamMessage> fromClient;
StreamController<StreamMessage> toClient;
late StreamController<StreamMessage> fromClient;
late StreamController<StreamMessage> toClient;
Iterable<ClientInterceptor> interceptors;
Iterable<ClientInterceptor>? 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<void> runTest(
{Future clientCall,
{Future? clientCall,
dynamic expectedResult,
String expectedPath,
Duration expectedTimeout,
Map<String, String> expectedCustomHeaders,
String? expectedPath,
Duration? expectedTimeout,
Map<String, String>? expectedCustomHeaders,
List<MessageHandler> 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<void> expectThrows(Future future, dynamic exception) async {
Future<void> expectThrows(Future? future, dynamic exception) async {
try {
await future;
fail('Did not throw');
@ -293,11 +295,11 @@ abstract class _Harness {
}
Future<void> runFailureTest(
{Future clientCall,
{Future? clientCall,
dynamic expectedException,
String expectedPath,
Duration expectedTimeout,
Map<String, String> expectedCustomHeaders,
String? expectedPath,
Duration? expectedTimeout,
Map<String, String>? expectedCustomHeaders,
List<MessageHandler> serverHandlers = const [],
bool expectDone = true}) async {
return runTest(

View File

@ -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<S> extends _i1.Fake implements _i3.StreamSink<S> {}
/// 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<void> get onInitialPeerSettingsReceived => (super.noSuchMethod(
Invocation.getter(#onInitialPeerSettingsReceived), Future.value(null))
as _i3.Future<void>);
@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<dynamic> ping() =>
(super.noSuchMethod(Invocation.method(#ping, []), Future.value(null))
as _i3.Future<dynamic>);
@override
_i3.Future<dynamic> finish() =>
(super.noSuchMethod(Invocation.method(#finish, []), Future.value(null))
as _i3.Future<dynamic>);
@override
_i3.Future<dynamic> terminate() =>
(super.noSuchMethod(Invocation.method(#terminate, []), Future.value(null))
as _i3.Future<dynamic>);
}
/// 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<int>? bytes, {bool? endStream = false}) =>
super.noSuchMethod(
Invocation.method(#sendData, [bytes], {#endStream: endStream}));
}

View File

@ -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<EchoRequest>(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<EchoResponse>(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<ServerStreamingEchoRequest>(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<ServerStreamingEchoResponse>(create);
static ServerStreamingEchoResponse _defaultInstance;
static ServerStreamingEchoResponse? _defaultInstance;
@$pb.TagNumber(1)
$core.String get message => $_getSZ(0);

View File

@ -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

View File

@ -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);

View File

@ -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 [

View File

@ -27,12 +27,12 @@ class TestService extends Service {
@override
String get $name => 'Test';
Future<int> Function(ServiceCall call, Future<int> request) unaryHandler;
Future<int> Function(ServiceCall call, Stream<int> request)
Future<int> Function(ServiceCall call, Future<int> request)? unaryHandler;
Future<int> Function(ServiceCall call, Stream<int> request)?
clientStreamingHandler;
Stream<int> Function(ServiceCall call, Future<int> request)
Stream<int> Function(ServiceCall call, Future<int> request)?
serverStreamingHandler;
Stream<int> Function(ServiceCall call, Stream<int> request)
Stream<int> Function(ServiceCall call, Stream<int> 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<int> _clientStreaming(ServiceCall call, Stream<int> request) {
if (clientStreamingHandler == null) {
fail('Should not invoke ClientStreaming');
}
return clientStreamingHandler(call, request);
return clientStreamingHandler!(call, request);
}
Stream<int> _serverStreaming(ServiceCall call, Future<int> request) {
if (serverStreamingHandler == null) {
fail('Should not invoke ServerStreaming');
}
return serverStreamingHandler(call, request);
return serverStreamingHandler!(call, request);
}
Stream<int> _bidirectional(ServiceCall call, Stream<int> request) {
if (bidirectionalHandler == null) {
fail('Should not invoke Bidirectional');
}
return bidirectionalHandler(call, request);
return bidirectionalHandler!(call, request);
}
}
class TestInterceptor {
Interceptor handler;
Interceptor? handler;
FutureOr<GrpcError> call(ServiceCall call, ServiceMethod method) {
FutureOr<GrpcError?> 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<Header> requestHeaders) => null;
ServerTransportStream push(List<Header> requestHeaders) =>
throw 'unimplemented';
}
class ServerHarness extends _Harness {
@ -144,7 +145,7 @@ abstract class _Harness {
final fromServer = StreamController<StreamMessage>();
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<String, String> metadata,
Duration timeout}) {
Map<String, String>? metadata,
Duration? timeout}) {
final headers = Http2ClientConnection.createCallHeaders(
true, authority, path, timeout, metadata, null,
userAgent: 'dart-grpc/1.0.0 test');

View File

@ -31,10 +31,10 @@ Map<String, String> headersToMap(List<Header> headers) =>
key: (h) => ascii.decode(h.name), value: (h) => ascii.decode(h.value));
void validateRequestHeaders(Map<String, String> headers,
{String path,
{String? path,
String authority = 'test',
String timeout,
Map<String, String> customHeaders}) {
String? timeout,
Map<String, String>? customHeaders}) {
expect(headers[':method'], 'POST');
expect(headers[':scheme'], 'https');
if (path != null) {
@ -54,7 +54,7 @@ void validateRequestHeaders(Map<String, String> headers,
void validateResponseHeaders(Map<String, String> headers,
{int status = 200,
bool allowTrailers = false,
Map<String, String> customHeaders}) {
Map<String, String>? customHeaders}) {
expect(headers[':status'], '200');
expect(headers['content-type'], startsWith('application/grpc'));
if (!allowTrailers) {
@ -67,7 +67,7 @@ void validateResponseHeaders(Map<String, String> headers,
}
void validateResponseTrailers(Map<String, String> trailers,
{int status = 0, String message, Map<String, String> customTrailers}) {
{int status = 0, String? message, Map<String, String>? 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<GrpcMetadata>());
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<GrpcData>());
return decoded;
return decoded as GrpcData;
}
void Function(StreamMessage message) headerValidator() {

View File

@ -22,8 +22,8 @@ import 'package:grpc/grpc.dart';
void main() {
group('GrpcHttpDecoder', () {
StreamController<StreamMessage> input;
Stream<GrpcMessage> output;
late StreamController<StreamMessage> input;
late Stream<GrpcMessage> output;
setUp(() {
input = StreamController();
@ -51,11 +51,12 @@ void main() {
}
expect(converted[0], TypeMatcher<GrpcMetadata>());
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',

View File

@ -33,7 +33,7 @@ class TestClient extends Client {
path, (int value) => [value], (List<int> value) => value[0]);
TestClient(api.ClientChannel channel) : super(channel);
ResponseStream<int> stream(int request, {CallOptions options}) {
ResponseStream<int> 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<Map> 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);

View File

@ -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<void>();
Future<int> methodHandler(ServiceCall call, Future<int> 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');
}