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