forked from firebase/flutterfire
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[cloud_functions] web plugin implementation (firebase#1890)
* Initial release of cloud_functions_web
- Loading branch information
Showing
10 changed files
with
429 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,3 +40,5 @@ build/ | |
.project | ||
.classpath | ||
.settings | ||
.flutter-plugins-dependencies | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
.flutter-plugins-dependencies |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
## 1.0.0 | ||
|
||
Initial release |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// Copyright 2017-2020 The Chromium Authors. All rights reserved. | ||
// | ||
// Redistribution and use in source and binary forms, with or without | ||
// modification, are permitted provided that the following conditions are | ||
// met: | ||
// | ||
// * Redistributions of source code must retain the above copyright | ||
// notice, this list of conditions and the following disclaimer. | ||
// * Redistributions in binary form must reproduce the above | ||
// copyright notice, this list of conditions and the following disclaimer | ||
// in the documentation and/or other materials provided with the | ||
// distribution. | ||
// * Neither the name of Google Inc. nor the names of its | ||
// contributors may be used to endorse or promote products derived from | ||
// this software without specific prior written permission. | ||
// | ||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
# cloud_functions_web | ||
|
||
The web implementation of [`cloud_functions`][1]. | ||
|
||
## Usage | ||
|
||
### Import the package | ||
|
||
**TODO(sbeitzel) - update the versions here so that it's correct, once this package actually _is_ an endorsed implementation of `package:cloud_functions`** | ||
|
||
This package is the endorsed implementation of `cloud_functions` for the web platform since version `0.0.1`, so it gets automatically added to your dependencies by depending on `cloud_functions: ^0.0.1`. | ||
|
||
No modifications to your `pubspec.yaml` should be required in a recent enough version of Flutter (`>=1.12.13+hotfix.4`): | ||
|
||
```yaml | ||
... | ||
dependencies: | ||
... | ||
cloud_functions: ^0.0.1 | ||
... | ||
``` | ||
|
||
### Updating `index.html` | ||
|
||
Due to [this bug in dartdevc][2], you will need to manually add the Firebase JavaScript file to your `index.html` file. | ||
|
||
In your app directory, edit `web/index.html` to add the line: | ||
|
||
```html | ||
<html> | ||
... | ||
<body> | ||
<script src="https://www.gstatic.com/firebasejs/7.6.2/firebase-app.js"></script> | ||
<script src="https://www.gstatic.com/firebasejs/7.6.2/firebase-functions.js"></script> | ||
<!-- Other firebase SDKs/config here --> | ||
<script src="main.dart.js"></script> | ||
</body> | ||
</html> | ||
``` | ||
|
||
### Initialize Firebase | ||
|
||
If your app is using the "default" Firebase app _(this means that you're not doing any `package:firebase_core` initialization yourself)_, you need to initialize it now, following the steps in the [Firebase Web Setup][3] docs. | ||
|
||
Specifically, you'll want to add the following lines to your `web/index.html` file: | ||
|
||
```html | ||
<body> | ||
<!-- Previously loaded Firebase SDKs --> | ||
|
||
<!-- ADD THIS BEFORE YOUR main.dart.js SCRIPT --> | ||
<script> | ||
// TODO: Replace the following with your app's Firebase project configuration. | ||
// See: https://support.google.com/firebase/answer/7015592 | ||
var firebaseConfig = { | ||
apiKey: "...", | ||
authDomain: "[YOUR_PROJECT].firebaseapp.com", | ||
databaseURL: "https://[YOUR_PROJECT].firebaseio.com", | ||
projectId: "[YOUR_PROJECT]", | ||
storageBucket: "[YOUR_PROJECT].appspot.com", | ||
messagingSenderId: "...", | ||
appId: "1:...:web:...", | ||
measurementId: "G-..." | ||
}; | ||
// Initialize Firebase | ||
firebase.initializeApp(firebaseConfig); | ||
</script> | ||
<!-- END OF FIREBASE INIT CODE --> | ||
|
||
<script src="main.dart.js"></script> | ||
</body> | ||
``` | ||
|
||
### Using the plugin | ||
|
||
Once you have modified your `web/index.html` file you should be able to use `package:cloud_functions` as normal. | ||
|
||
#### Examples | ||
|
||
* The `example` app in `package:cloud_functions` has an implementation of this instructions. | ||
|
||
[1]: ../cloud_functions | ||
[2]: https://github.com/dart-lang/sdk/issues/33979 | ||
[3]: https://firebase.google.com/docs/web/setup#add-sdks-initialize |
63 changes: 63 additions & 0 deletions
63
packages/cloud_functions/cloud_functions_web/lib/cloud_functions_web.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
// Copyright 2020 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
import 'dart:async'; | ||
|
||
import 'package:cloud_functions_platform_interface/cloud_functions_platform_interface.dart'; | ||
import 'package:firebase/firebase.dart' as firebase; | ||
import 'package:flutter/foundation.dart'; | ||
import 'package:flutter_web_plugins/flutter_web_plugins.dart'; | ||
|
||
/// Web implementation of [CloudFunctionsPlatform]. | ||
class CloudFunctionsWeb extends CloudFunctionsPlatform { | ||
/// Create the default instance of the [CloudFunctionsPlatform] as a [CloudFunctionsWeb] | ||
static void registerWith(Registrar registrar) { | ||
CloudFunctionsPlatform.instance = CloudFunctionsWeb(); | ||
} | ||
|
||
/// Invokes the specified cloud function. | ||
/// | ||
/// The required parameters, [appName] and [functionName], specify which | ||
/// cloud function will be called. | ||
/// | ||
/// The rest of the parameters are optional and used to invoke the function | ||
/// with something other than the defaults. [region] defaults to `us-central1` | ||
/// and [timeout] defaults to 60 seconds. | ||
/// | ||
/// The [origin] parameter may be used to provide the base URL for the function. | ||
/// This can be used to send requests to a local emulator. | ||
/// | ||
/// The data passed into the cloud function via [parameters] can be any of the following types: | ||
/// | ||
/// `null` | ||
/// `String` | ||
/// `num` | ||
/// [List], where the contained objects are also one of these types. | ||
/// [Map], where the values are also one of these types. | ||
@override | ||
Future<dynamic> callCloudFunction({ | ||
@required String appName, | ||
@required String functionName, | ||
String region, | ||
String origin, | ||
Duration timeout, | ||
dynamic parameters, | ||
}) { | ||
firebase.App app = firebase.app(appName); | ||
firebase.Functions functions = app.functions(region); | ||
if (origin != null) { | ||
functions.useFunctionsEmulator(origin); | ||
} | ||
firebase.HttpsCallable hc; | ||
if (timeout != null) { | ||
hc = functions.httpsCallable(functionName, | ||
firebase.HttpsCallableOptions(timeout: timeout.inMicroseconds)); | ||
} else { | ||
hc = functions.httpsCallable(functionName); | ||
} | ||
return hc.call(parameters).then((result) { | ||
return result.data; | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
name: cloud_functions_web | ||
description: The web implementation of cloud_functions | ||
homepage: https://github.com/FirebaseExtended/flutterfire/tree/master/packages/cloud_functions/cloud_functions_web | ||
version: 1.0.0 | ||
|
||
flutter: | ||
plugin: | ||
platforms: | ||
web: | ||
pluginClass: CloudFunctionsWeb | ||
fileName: cloud_functions_web.dart | ||
|
||
dependencies: | ||
cloud_functions_platform_interface: ^1.0.0 | ||
flutter: | ||
sdk: flutter | ||
flutter_web_plugins: | ||
sdk: flutter | ||
firebase: ^7.0.0 | ||
http_parser: ^3.1.3 | ||
meta: ^1.1.7 | ||
|
||
dev_dependencies: | ||
flutter_test: | ||
sdk: flutter | ||
firebase_core_platform_interface: ^1.0.2 | ||
firebase_core_web: ^0.1.1+2 | ||
mockito: ^4.1.1 | ||
js: ^0.6.0 | ||
|
||
environment: | ||
sdk: ">=2.0.0-dev.28.0 <3.0.0" | ||
flutter: ">=1.12.13+hotfix.4 <2.0.0" | ||
|
134 changes: 134 additions & 0 deletions
134
packages/cloud_functions/cloud_functions_web/test/cloud_functions_web_test.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
// Copyright 2020 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
@TestOn('chrome') | ||
|
||
import 'dart:js' show allowInterop; | ||
|
||
import 'package:cloud_functions_platform_interface/cloud_functions_platform_interface.dart'; | ||
import 'package:cloud_functions_web/cloud_functions_web.dart'; | ||
import 'package:firebase/firebase.dart' as firebase; | ||
import 'package:firebase_core_platform_interface/firebase_core_platform_interface.dart'; | ||
import 'package:firebase_core_web/firebase_core_web.dart'; | ||
import 'package:flutter_test/flutter_test.dart'; | ||
import 'package:meta/meta.dart'; | ||
|
||
import 'mock/firebase_mock.dart'; | ||
|
||
void main() { | ||
TestWidgetsFlutterBinding.ensureInitialized(); | ||
|
||
group('$CloudFunctionsWeb', () { | ||
final List<Map<String, dynamic>> log = <Map<String, dynamic>>[]; | ||
|
||
Map<String, dynamic> loggingCall( | ||
{@required String appName, | ||
@required String functionName, | ||
String region, | ||
dynamic parameters}) { | ||
log.add(<String, dynamic>{ | ||
'appName': appName, | ||
'functionName': functionName, | ||
'region': region | ||
}); | ||
return <String, dynamic>{ | ||
'foo': 'bar', | ||
}; | ||
} | ||
|
||
setUp(() async { | ||
firebaseMock = FirebaseMock( | ||
app: allowInterop( | ||
(String name) => FirebaseAppMock( | ||
name: name, | ||
options: FirebaseAppOptionsMock(appId: '123'), | ||
functions: allowInterop(([region]) => FirebaseFunctionsMock( | ||
httpsCallable: allowInterop((functionName, [options]) { | ||
final String appName = name == null ? '[DEFAULT]' : name; | ||
return allowInterop(([data]) { | ||
Map<String, dynamic> result = loggingCall( | ||
appName: appName, | ||
functionName: functionName, | ||
region: region); | ||
return _jsPromise(FirebaseHttpsCallableResultMock( | ||
data: allowInterop((_) => result))); | ||
}); | ||
}), | ||
useFunctionsEmulator: allowInterop((url) { | ||
print('Unimplemented. Supposed to emulate at $url'); | ||
}), | ||
))), | ||
)); | ||
|
||
FirebaseCorePlatform.instance = FirebaseCoreWeb(); | ||
CloudFunctionsPlatform.instance = CloudFunctionsWeb(); | ||
|
||
// install loggingCall on the HttpsCallable mock as the thing that gets | ||
// executed when its call method is invoked | ||
firebaseMock.functions = allowInterop(([app]) => FirebaseFunctionsMock( | ||
httpsCallable: allowInterop((functionName, [options]) { | ||
final String appName = app == null ? '[DEFAULT]' : app.name; | ||
return allowInterop(([data]) { | ||
Map<String, dynamic> result = | ||
loggingCall(appName: appName, functionName: functionName); | ||
return _jsPromise(FirebaseHttpsCallableResultMock( | ||
data: allowInterop((_) => result))); | ||
}); | ||
}), | ||
useFunctionsEmulator: allowInterop((url) { | ||
print('Unimplemented. Supposed to emulate at $url'); | ||
}), | ||
)); | ||
}); | ||
|
||
test('setUp wires up mock objects properly', () async { | ||
log.clear(); | ||
|
||
firebase.App app = firebase.app('[DEFAULT]'); | ||
expect(app.options.appId, equals('123')); | ||
firebase.Functions fs = firebase.functions(app); | ||
firebase.HttpsCallable callable = fs.httpsCallable('foobie'); | ||
await callable.call(); | ||
expect(log, <Matcher>[ | ||
equals(<String, dynamic>{ | ||
'appName': '[DEFAULT]', | ||
'functionName': 'foobie', | ||
'region': null | ||
}), | ||
]); | ||
}); | ||
|
||
test('callCloudFunction calls down to Firebase API', () async { | ||
log.clear(); | ||
|
||
CloudFunctionsPlatform cfp = CloudFunctionsPlatform.instance; | ||
expect(cfp, isA<CloudFunctionsWeb>()); | ||
|
||
await cfp.callCloudFunction( | ||
appName: '[DEFAULT]', functionName: 'baz', region: 'space'); | ||
await cfp.callCloudFunction(appName: 'mock', functionName: 'mumble'); | ||
|
||
expect( | ||
log, | ||
<Matcher>[ | ||
equals(<String, dynamic>{ | ||
'appName': '[DEFAULT]', | ||
'functionName': 'baz', | ||
'region': 'space' | ||
}), | ||
equals(<String, dynamic>{ | ||
'appName': 'mock', | ||
'functionName': 'mumble', | ||
'region': null | ||
}), | ||
], | ||
); | ||
}); | ||
}); | ||
} | ||
|
||
Promise _jsPromise(dynamic value) { | ||
return Promise(allowInterop((void resolve(dynamic result), Function reject) { | ||
resolve(value); | ||
})); | ||
} |
Oops, something went wrong.