Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(firebase_storage, web): upgrade storage web to v9 sdk #8870

Merged
merged 7 commits into from
Jun 29, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,13 @@ class FirebaseStorageWeb extends FirebaseStoragePlatform {
@override
void setMaxOperationRetryTime(int time) {
_maxOperationRetryTime = time;
delegate.setMaxOperationRetryTime(time);
delegate.maxOperationRetryTime = time;
}

/// The new maximum upload retry time in milliseconds.
@override
void setMaxUploadRetryTime(int time) {
delegate.setMaxUploadRetryTime(time);
delegate.maxUploadRetryTime = time;
}

/// The new maximum download retry time in milliseconds.
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
import 'dart:async';

import 'package:firebase_core_web/firebase_core_web_interop.dart';
import 'package:firebase_core_web/firebase_core_web_interop.dart'
as core_interop;
import 'package:js/js.dart';

import 'firebase_interop.dart' as firebase_interop;
import 'storage_interop.dart' as storage_interop;

export 'storage_interop.dart';
Expand All @@ -23,11 +24,12 @@ enum TaskState { RUNNING, PAUSED, SUCCESS, CANCELED, ERROR }

/// Given an AppJSImp, return the Storage instance.
Storage getStorageInstance([App? app, String? bucket]) {
firebase_interop.AppStorageJsImpl appImpl =
app != null ? firebase_interop.app(app.name) : firebase_interop.app();
core_interop.App appImpl =
app != null ? core_interop.app(app.name) : core_interop.app();

return Storage.getInstance(
bucket != null ? appImpl.storage(bucket) : appImpl.storage());
return Storage.getInstance(bucket != null
? storage_interop.getStorage(appImpl.jsObject, bucket)
: storage_interop.getStorage(appImpl.jsObject));
}

/// A service for uploading and downloading large objects to and from the
Expand Down Expand Up @@ -57,25 +59,28 @@ class Storage extends JsObjectWrapper<storage_interop.StorageJsImpl> {

/// Returns a [StorageReference] for the given [path] in the default bucket.
StorageReference ref([String? path]) =>
StorageReference.getInstance(jsObject.ref(path));
StorageReference.getInstance(storage_interop.ref(jsObject, path));

/// Returns a [StorageReference] for the given absolute [url].
StorageReference refFromURL(String url) =>
StorageReference.getInstance(jsObject.refFromURL(url));
StorageReference.getInstance(storage_interop.ref(jsObject, url));

/// Sets the maximum operation retry time to a value of [time].
void setMaxOperationRetryTime(int time) =>
jsObject.setMaxOperationRetryTime(time);
set maxOperationRetryTime(int time) {
jsObject.maxOperationRetryTime = time;
}

/// Sets the maximum upload retry time to a value of [time].
void setMaxUploadRetryTime(int time) => jsObject.setMaxUploadRetryTime(time);
set maxUploadRetryTime(int time) {
jsObject.maxUploadRetryTime = time;
}

/// Configures the Storage instance to work with a local emulator.
///
/// Note: must be called before using storage methods, do not use
/// with production credentials as local connections are unencrypted
void useStorageEmulator(String host, int port) =>
jsObject.useEmulator(host, port);
storage_interop.connectStorageEmulator(jsObject, host, port);
}

/// StorageReference is a reference to a Google Cloud Storage object.
Expand Down Expand Up @@ -118,20 +123,22 @@ class StorageReference
/// Returns a child StorageReference to a relative [path]
/// from the actual reference.
StorageReference child(String path) =>
StorageReference.getInstance(jsObject.child(path));
StorageReference.getInstance(storage_interop.ref(jsObject, path));

/// Deletes the object at the actual location.
Future delete() => handleThenable(jsObject.delete());
Future delete() => handleThenable(storage_interop.deleteObject(jsObject));

/// Returns a long lived download URL for this reference.
Future<Uri> getDownloadURL() async {
var uriString = await handleThenable(jsObject.getDownloadURL());
var uriString =
await handleThenable(storage_interop.getDownloadURL(jsObject));
return Uri.parse(uriString);
}

/// Returns a [FullMetadata] from this reference at actual location.
Future<FullMetadata> getMetadata() =>
handleThenable(jsObject.getMetadata()).then(FullMetadata.getInstance);
handleThenable(storage_interop.getMetadata(jsObject))
.then(FullMetadata.getInstance);

/// List items (files) and prefixes (folders) under this storage reference.
/// List API is only available for Firebase Storage Rules Version 2.
Expand All @@ -144,7 +151,7 @@ class StorageReference
/// Firebase Storage List API will filter these unsupported objects.
/// [list()] may fail if there are too many unsupported objects in the bucket.
Future<ListResult> list(ListOptions? options) =>
handleThenable(jsObject.list(options?.jsObject))
handleThenable(storage_interop.list(jsObject, options?.jsObject))
.then(ListResult.getInstance);

/// List all items (files) and prefixes (folders) under this storage reference.
Expand All @@ -159,37 +166,19 @@ class StorageReference
/// Warning: [listAll] may potentially consume too many resources if there are
/// too many results.
Future<ListResult> listAll() =>
handleThenable(jsObject.listAll()).then(ListResult.getInstance);
handleThenable(storage_interop.listAll(jsObject))
.then(ListResult.getInstance);

/// Uploads data [blob] to the actual location with optional [metadata].
/// Returns the [UploadTask] which can be used to monitor and manage
/// the upload.
UploadTask put(dynamic blob, [UploadMetadata? metadata]) {
storage_interop.UploadTaskJsImpl taskImpl;
if (metadata != null) {
taskImpl = jsObject.put(blob, metadata.jsObject);
taskImpl = storage_interop.uploadBytesResumable(
jsObject, blob, metadata.jsObject);
} else {
taskImpl = jsObject.put(blob);
}
return UploadTask.getInstance(taskImpl);
}

/// Uploads String [data] to the actual location with optional String [format]
/// and [metadata].
///
/// See allowed [format] values in [storage_interop.StringFormat] class.
///
/// Returns the [UploadTask] which can be used to monitor and manage
/// the upload.
UploadTask putString(String data,
[String? format, UploadMetadata? metadata]) {
storage_interop.UploadTaskJsImpl taskImpl;
if (metadata != null) {
taskImpl = jsObject.putString(data, format, metadata.jsObject);
} else if (format != null) {
taskImpl = jsObject.putString(data, format);
} else {
taskImpl = jsObject.putString(data);
taskImpl = storage_interop.uploadBytesResumable(jsObject, blob);
}
return UploadTask.getInstance(taskImpl);
}
Expand All @@ -201,11 +190,30 @@ class StorageReference
/// Updates metadata from this reference at actual location with
/// the new [metadata].
Future<FullMetadata> updateMetadata(SettableMetadata metadata) async {
await handleThenable(jsObject.updateMetadata(metadata.jsObject));
await handleThenable(
storage_interop.updateMetadata(jsObject, metadata.jsObject));
return getMetadata();
}
}

/// Returned after uploading String.
/// See: <https://firebase.google.com/docs/reference/js/firebase.storage.FullMetadata>
class UploadResult extends JsObjectWrapper<storage_interop.UploadResult> {
UploadResult._fromJsObject(storage_interop.UploadResult jsObject)
: super.fromJsObject(jsObject);

static final _expando = Expando<UploadResult>();

/// Creates a new UploadResult from a [jsObject].
static UploadResult getInstance(storage_interop.UploadResult jsObject) {
return _expando[jsObject] ??= UploadResult._fromJsObject(jsObject);
}

StorageReference get ref => StorageReference.getInstance(jsObject.ref);

FullMetadata get metadata => FullMetadata.getInstance(jsObject.metadata);
}

/// The full set of object metadata, including read-only properties.
///
/// See: <https://firebase.google.com/docs/reference/js/firebase.storage.FullMetadata>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,95 @@

// ignore_for_file: avoid_unused_constructor_parameters, non_constant_identifier_names, public_member_api_docs

@JS('firebase.storage')
@JS('firebase_storage')
library firebase.storage_interop;

import 'package:firebase_core_web/firebase_core_web_interop.dart';
import 'package:js/js.dart';

@JS('Storage')
@JS()
external StorageJsImpl getStorage([AppJsImpl? app, String? bucketUrl]);

@JS()
external void connectStorageEmulator(
StorageJsImpl storage, String host, int port,
[EmulatorOptions? options]);

@JS()
external PromiseJsImpl<void> deleteObject(ReferenceJsImpl ref);

@JS()
external PromiseJsImpl<String> getDownloadURL(ReferenceJsImpl ref);

@JS()
external PromiseJsImpl<String> getBlob(ReferenceJsImpl ref,
[int? maxDownloadSizeBytes]);

@JS()
external PromiseJsImpl<List<String>> getBytes(ReferenceJsImpl ref,
[int? maxDownloadSizeBytes]);

@JS()
external PromiseJsImpl<FullMetadataJsImpl> getMetadata(ReferenceJsImpl ref);

@JS()
external PromiseJsImpl<ListResultJsImpl> list(ReferenceJsImpl ref,
[ListOptionsJsImpl? listOptions]);

@JS()
external PromiseJsImpl<ListResultJsImpl> listAll(ReferenceJsImpl ref);

@JS()
/* if 2nd arg is `url`, first arg has to be StorageJsImpl */
/* if 2nd arg is `path`, first arg can be StorageJsImpl || ReferenceJsImpl */
external ReferenceJsImpl ref(Object storageOrRef, [String? urlOrPath]);

@JS()
external PromiseJsImpl<FullMetadataJsImpl> updateMetadata(
ReferenceJsImpl ref, SettableMetadataJsImpl settableMetadata);

// TODO - new API.
@JS()
external PromiseJsImpl<UploadResult> uploadBytes(
ReferenceJsImpl ref,
dynamic /* Blob | Uint8Array | ArrayBuffer */ data,
UploadMetadataJsImpl metadata);

@JS()
external UploadTaskJsImpl uploadBytesResumable(
ReferenceJsImpl ref, dynamic /* Blob | Uint8Array | ArrayBuffer */ data,
[UploadMetadataJsImpl? metadata]);

@JS()
external PromiseJsImpl<UploadResult> uploadString(
ReferenceJsImpl ref, String value,
[String? format, UploadMetadataJsImpl uploadMetadata]);

@JS()
@anonymous
class UploadResult {
external ReferenceJsImpl get ref;
external FullMetadataJsImpl get metadata;
}

@JS()
@anonymous
class EmulatorOptions {
external factory EmulatorOptions({mockUserToken});
external String get mockUserToken;
}

@JS('FirebaseStorage')
abstract class StorageJsImpl {
external AppJsImpl get app;
external set app(AppJsImpl a);
external int get maxOperationRetryTime;
external set maxOperationRetryTime(int t);
external int get maxUploadRetryTime;
external set maxUploadRetryTime(int t);
external ReferenceJsImpl ref([String? path]);
external ReferenceJsImpl refFromURL(String url);
external void setMaxOperationRetryTime(int time);
external void setMaxUploadRetryTime(int time);
external void useEmulator(String host, int port);
}

@JS('Reference')
@JS('StorageReference')
abstract class ReferenceJsImpl {
external String get bucket;
external set bucket(String s);
Expand All @@ -40,19 +107,9 @@ abstract class ReferenceJsImpl {
external set root(ReferenceJsImpl r);
external StorageJsImpl get storage;
external set storage(StorageJsImpl s);
external ReferenceJsImpl child(String path);
external PromiseJsImpl<void> delete();
external PromiseJsImpl<String> getDownloadURL();
external PromiseJsImpl<FullMetadataJsImpl> getMetadata();
external PromiseJsImpl<ListResultJsImpl> list([ListOptionsJsImpl? options]);
external PromiseJsImpl<ListResultJsImpl> listAll();
external UploadTaskJsImpl put(dynamic blob, [UploadMetadataJsImpl? metadata]);
external UploadTaskJsImpl putString(String value,
[String? format, UploadMetadataJsImpl? metadata]);

@override
external String toString();
external PromiseJsImpl<Object?> updateMetadata(
SettableMetadataJsImpl metadata);
}

//@JS('FullMetadata')
Expand All @@ -69,6 +126,10 @@ class FullMetadataJsImpl extends UploadMetadataJsImpl {
dynamic customMetadata});

external String get bucket;
// TODO - new API.
external List<String>? get downloadTokens;
// TODO - new API.
external ReferenceJsImpl? get ref;
external String? get fullPath;
external String? get generation;
external String? get metageneration;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// for details. 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:convert';
import 'dart:html' as html;
import 'dart:typed_data';

Expand Down Expand Up @@ -185,13 +186,21 @@ class ReferenceWeb extends ReferencePlatform {
PutStringFormat format, [
SettableMetadata? metadata,
]) {
dynamic _data = data;

// The universal package is converting raw to base64, so we need to convert
// Any base64 string values into a Uint8List.
if (format == PutStringFormat.base64) {
_data = base64Decode(data);
}

return TaskWeb(
this,
_ref.putString(
data,
putStringFormatToString(format),
_ref.put(
_data,
settableMetadataToFbUploadMetadata(
_cache.store(metadata),
// md5 is computed server-side, so we don't have to unpack a potentially huge Blob.
),
),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// BSD-style license that can be found in the LICENSE file.

import 'package:firebase_storage_platform_interface/firebase_storage_platform_interface.dart';

import '../interop/storage.dart' as storage_interop;

/// Converts FullMetadata coming from the JS Interop layer to FullMetadata for the plugin.
Expand Down