Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,5 @@
"default": "flutterfire-e2e-tests"
},
"targets": {},
"etags": {},
"dataconnectEmulatorConfig": {
"postgres": {
"localConnectionString": "postgresql://postgres:postgres@localhost:5432/postgres?sslmode=disable"
}
}
"etags": {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ library firebase_data_connect_common;
import 'dart:convert';

import 'package:firebase_app_check/firebase_app_check.dart';
import 'package:firebase_auth/firebase_auth.dart';

part 'dataconnect_error.dart';
part 'dataconnect_options.dart';
Expand Down Expand Up @@ -59,9 +58,6 @@ abstract class DataConnectTransport {
/// DataConnect backend configuration.
DataConnectOptions options;

/// FirebaseAuth to use to get auth token.
FirebaseAuth? auth;

/// FirebaseAppCheck to use to get app check token.
FirebaseAppCheck? appCheck;

Expand All @@ -76,12 +72,14 @@ abstract class DataConnectTransport {
String queryName,
Deserializer<Data> deserializer,
Serializer<Variables> serializer,
Variables? vars);
Variables? vars,
String? token);

/// Invokes corresponding mutation endpoint.
Future<Data> invokeMutation<Data, Variables>(
String queryName,
Deserializer<Data> deserializer,
Serializer<Variables> serializer,
Variables? vars);
Variables? vars,
String? token);
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,36 @@ abstract class OperationRef<Data, Variables> {
DataConnectTransport _transport;
Deserializer<Data> deserializer;
Serializer<Variables> serializer;
String? _lastToken;

FirebaseDataConnect dataConnect;

Future<OperationResult<Data, Variables>> execute();
Future<OperationResult<Data, Variables>> execute() {
return this._executeWithRetry();
}

Future<OperationResult<Data, Variables>> _executeOperation(String? token);

Future<OperationResult<Data, Variables>> _executeWithRetry() async {
String? newToken =
await this.dataConnect.auth?.currentUser?.getIdToken(false);
bool shouldRetry = newToken != null && _lastToken != newToken;
_lastToken = newToken;
try {
OperationResult<Data, Variables> r =
await this._executeOperation(newToken);
return r;
} on DataConnectError catch (e) {
if (shouldRetry &&
e.code == DataConnectErrorCode.unauthorized.toString()) {
return this._executeWithRetry();
} else {
throw e;
}
} catch (e) {
throw e;
}
}
}

/// Tracks currently active queries, and emits events when a new query is executed.
Expand Down Expand Up @@ -112,11 +138,16 @@ class QueryRef<Data, Variables> extends OperationRef<Data, Variables> {
variables);

QueryManager _queryManager;

@override
Future<QueryResult<Data, Variables>> execute() async {
Future<QueryResult<Data, Variables>> execute() {
return _executeWithRetry() as Future<QueryResult<Data, Variables>>;
}

Future<QueryResult<Data, Variables>> _executeOperation(String? token) async {
try {
Data data = await _transport.invokeQuery<Data, Variables>(
operationName, deserializer, serializer, variables);
operationName, deserializer, serializer, variables, token);
QueryResult<Data, Variables> res = QueryResult(dataConnect, data, this);
await _queryManager.triggerCallback<Data, Variables>(operationName,
serializer(variables as Variables), this, res.data, null);
Expand All @@ -135,7 +166,7 @@ class QueryRef<Data, Variables> extends OperationRef<Data, Variables> {
.cast<QueryResult<Data, Variables>>();
if (_queryManager.containsQuery(operationName, variables, varsSerialized)) {
try {
this.execute();
this._executeWithRetry();
} catch (_) {
// Call to `execute` should properly pass the error to the Stream.
log("Error thrown by execute. The error will propagate via onError.");
Expand All @@ -156,9 +187,10 @@ class MutationRef<Data, Variables> extends OperationRef<Data, Variables> {
) : super(dataConnect, operationName, transport, deserializer, serializer,
variables);
@override
Future<OperationResult<Data, Variables>> execute() async {
Future<OperationResult<Data, Variables>> _executeOperation(
String? token) async {
Data data = await _transport.invokeMutation<Data, Variables>(
operationName, deserializer, serializer, variables);
operationName, deserializer, serializer, variables, token);
return OperationResult(dataConnect, data, this);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ class GRPCTransport implements DataConnectTransport {
this.options,
this.appId,
this.sdkType,
this.auth,
this.appCheck,
) {
bool isSecure =
Expand All @@ -38,10 +37,6 @@ class GRPCTransport implements DataConnectTransport {
'projects/${options.projectId}/locations/${options.location}/services/${options.serviceId}/connectors/${options.connector}';
}

/// FirebaseAuth
@override
FirebaseAuth? auth;

/// FirebaseAppCheck
@override
FirebaseAppCheck? appCheck;
Expand Down Expand Up @@ -70,13 +65,7 @@ class GRPCTransport implements DataConnectTransport {
@override
String appId;

Future<Map<String, String>> getMetadata() async {
String? authToken;
try {
authToken = await auth?.currentUser?.getIdToken();
} catch (e) {
log('Unable to get auth token: $e');
}
Future<Map<String, String>> getMetadata(String? authToken) async {
String? appCheckToken;
try {
appCheckToken = await appCheck?.getToken();
Expand All @@ -101,11 +90,11 @@ class GRPCTransport implements DataConnectTransport {
/// Invokes GPRC query endpoint.
@override
Future<Data> invokeQuery<Data, Variables>(
String queryName,
Deserializer<Data> deserializer,
Serializer<Variables>? serializer,
Variables? vars,
) async {
String queryName,
Deserializer<Data> deserializer,
Serializer<Variables>? serializer,
Variables? vars,
String? authToken) async {
ExecuteQueryResponse response;

ExecuteQueryRequest request =
Expand All @@ -115,9 +104,13 @@ class GRPCTransport implements DataConnectTransport {
}
try {
response = await stub.executeQuery(request,
options: CallOptions(metadata: await getMetadata()));
options: CallOptions(metadata: await getMetadata(authToken)));
return deserializer(jsonEncode(response.data.toProto3Json()));
} on Exception catch (e) {
if (e.toString().contains("invalid Firebase Auth Credentials")) {
throw DataConnectError(DataConnectErrorCode.unauthorized,
'Failed to invoke operation: ${e.toString()}');
}
throw DataConnectError(DataConnectErrorCode.other,
'Failed to invoke operation: ${e.toString()}');
}
Expand All @@ -137,7 +130,8 @@ class GRPCTransport implements DataConnectTransport {
String queryName,
Deserializer<Data> deserializer,
Serializer<Variables>? serializer,
Variables? vars) async {
Variables? vars,
String? authToken) async {
ExecuteMutationResponse response;
ExecuteMutationRequest request =
ExecuteMutationRequest(name: name, operationName: queryName);
Expand All @@ -146,7 +140,7 @@ class GRPCTransport implements DataConnectTransport {
}
try {
response = await stub.executeMutation(request,
options: CallOptions(metadata: await getMetadata()));
options: CallOptions(metadata: await getMetadata(authToken)));
if (response.errors.isNotEmpty) {
throw Exception(response.errors);
}
Expand All @@ -166,4 +160,4 @@ DataConnectTransport getTransport(
CallerSDKType sdkType,
FirebaseAuth? auth,
FirebaseAppCheck? appCheck) =>
GRPCTransport(transportOptions, options, appId, sdkType, auth, appCheck);
GRPCTransport(transportOptions, options, appId, sdkType, appCheck);
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import 'dart:convert';
import 'dart:developer';

import 'package:firebase_app_check/firebase_app_check.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ part of firebase_data_connect_rest;
class RestTransport implements DataConnectTransport {
/// Initializes necessary protocol and port.
RestTransport(this.transportOptions, this.options, this.appId, this.sdkType,
this.auth, this.appCheck) {
this.appCheck) {
String protocol = 'http';
if (transportOptions.isSecure == null ||
transportOptions.isSecure == true) {
Expand All @@ -34,9 +34,6 @@ class RestTransport implements DataConnectTransport {
'$protocol://$host:$port/v1beta/projects/$project/locations/$location/services/$service/connectors/$connector';
}

@override
FirebaseAuth? auth;

@override
FirebaseAppCheck? appCheck;

Expand Down Expand Up @@ -67,11 +64,13 @@ class RestTransport implements DataConnectTransport {

/// Invokes the current operation, whether its a query or mutation.
Future<Data> invokeOperation<Data, Variables>(
String queryName,
Deserializer<Data> deserializer,
Serializer<Variables>? serializer,
Variables? vars,
String endpoint) async {
String queryName,
String endpoint,
Deserializer<Data> deserializer,
Serializer<Variables>? serializer,
Variables? vars,
String? authToken,
) async {
String project = options.projectId;
String location = options.location;
String service = options.serviceId;
Expand All @@ -81,12 +80,6 @@ class RestTransport implements DataConnectTransport {
'Accept': 'application/json',
'x-goog-api-client': getGoogApiVal(sdkType, packageVersion)
};
String? authToken;
try {
authToken = await auth?.currentUser?.getIdToken();
} catch (e) {
log('Unable to get auth token: $e');
}
String? appCheckToken;
try {
appCheckToken = await appCheck?.getToken();
Expand Down Expand Up @@ -148,25 +141,25 @@ class RestTransport implements DataConnectTransport {
/// Invokes query REST endpoint.
@override
Future<Data> invokeQuery<Data, Variables>(
String queryName,
Deserializer<Data> deserializer,
Serializer<Variables>? serializer,
Variables? vars,
) async {
String queryName,
Deserializer<Data> deserializer,
Serializer<Variables>? serializer,
Variables? vars,
String? token) async {
return invokeOperation(
queryName, deserializer, serializer, vars, 'executeQuery');
queryName, 'executeQuery', deserializer, serializer, vars, token);
}

/// Invokes mutation REST endpoint.
@override
Future<Data> invokeMutation<Data, Variables>(
String queryName,
Deserializer<Data> deserializer,
Serializer<Variables>? serializer,
Variables? vars,
) async {
String queryName,
Deserializer<Data> deserializer,
Serializer<Variables>? serializer,
Variables? vars,
String? token) async {
return invokeOperation(
queryName, deserializer, serializer, vars, 'executeMutation');
queryName, 'executeMutation', deserializer, serializer, vars, token);
}
}

Expand All @@ -176,6 +169,5 @@ DataConnectTransport getTransport(
DataConnectOptions options,
String appId,
CallerSDKType sdkType,
FirebaseAuth? auth,
FirebaseAppCheck? appCheck) =>
RestTransport(transportOptions, options, appId, sdkType, auth, appCheck);
RestTransport(transportOptions, options, appId, sdkType, appCheck);
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,11 @@ class TransportStub implements DataConnectTransport {
this.options,
this.appId,
this.sdkType,
this.auth,
this.appCheck,
);

/// FirebaseAuth
@override
FirebaseAuth? auth;

/// FirebaseAppCheck
@override
Expand All @@ -55,7 +53,8 @@ class TransportStub implements DataConnectTransport {
String queryName,
Deserializer<Data> deserializer,
Serializer<Variables>? serializer,
Variables? vars) async {
Variables? vars,
String? token) async {
// TODO: implement invokeMutation
throw UnimplementedError();
}
Expand All @@ -66,7 +65,8 @@ class TransportStub implements DataConnectTransport {
String queryName,
Deserializer<Data> deserializer,
Serializer<Variables>? serialize,
Variables? vars) async {
Variables? vars,
String? token) async {
// TODO: implement invokeQuery
throw UnimplementedError();
}
Expand All @@ -80,4 +80,4 @@ DataConnectTransport getTransport(
FirebaseAuth? auth,
FirebaseAppCheck? appCheck,
) =>
TransportStub(transportOptions, options, appId, sdkType, auth, appCheck);
TransportStub(transportOptions, options, appId, sdkType, appCheck);
Loading