Files
react-native-firebase/packages/storage/lib/StorageTask.js
Mike Diarmid 7f11a9e501 [v6] Implement Cloud Storage (#2043)
See the changelog for detailed changes.
2019-05-03 12:05:40 +01:00

195 lines
6.1 KiB
JavaScript

/*
* Copyright (c) 2016-present Invertase Limited & Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this library except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import { isFunction, isObject, isNull } from '@react-native-firebase/common';
import StorageStatics from './StorageStatics';
let TASK_ID = 0;
function wrapErrorEventListener(listenerFn, unsubscribe) {
return event => {
if (unsubscribe) setTimeout(() => unsubscribe(), 0); // 1 frame = 16ms, pushing to next frame
if (isFunction(listenerFn)) {
listenerFn(event.error);
}
};
}
function wrapSnapshotEventListener(task, listenerFn, unsubscribe) {
if (!isFunction(listenerFn)) return null;
return event => {
if (unsubscribe) setTimeout(() => unsubscribe(), 0); // 1 frame = 16ms, pushing to next frame
if (isFunction(listenerFn)) {
const snapshot = Object.assign({}, event);
snapshot.task = task;
snapshot.ref = task._ref;
if (snapshot.metadata) {
if (!snapshot.metadata.generation) snapshot.metadata.generation = '';
if (!snapshot.metadata.bucket) snapshot.metadata.bucket = task._ref.bucket;
if (!snapshot.metadata.metageneration) snapshot.metadata.metageneration = '';
// // TODO(salakar): these are always here, cannot repro without, remove in 6.1.0 if no issues:
// if (!snapshot.metadata.name) snapshot.metadata.name = task._ref.name;
// if (!snapshot.metadata.fullPath) snapshot.metadata.fullPath = task._ref.fullPath;
}
Object.freeze(snapshot);
listenerFn(snapshot);
}
};
}
function addTaskEventListener(task, eventName, listener) {
let _eventName = eventName;
if (_eventName !== StorageStatics.TaskEvent.STATE_CHANGED) {
_eventName = `${task._type}_${eventName}`;
}
return task._storage.emitter.addListener(
task._storage.eventNameForApp(task._id, _eventName),
listener,
);
}
function subscribeToEvents(task, nextOrObserver, error, complete) {
let _error;
let _errorSubscription;
let _next;
let _nextSubscription;
let _complete;
let _completeSubscription;
const unsubscribe = () => {
if (_nextSubscription) _nextSubscription.remove();
if (_errorSubscription) _errorSubscription.remove();
if (_completeSubscription) _completeSubscription.remove();
};
if (isFunction(nextOrObserver)) {
_error = wrapErrorEventListener(error, unsubscribe);
_next = wrapSnapshotEventListener(task, nextOrObserver);
_complete = wrapSnapshotEventListener(task, complete, unsubscribe);
} else if (isObject(nextOrObserver)) {
_error = wrapErrorEventListener(nextOrObserver.error, unsubscribe);
_next = wrapSnapshotEventListener(task, nextOrObserver.next);
_complete = wrapSnapshotEventListener(task, nextOrObserver.complete, unsubscribe);
} else if (isNull(nextOrObserver)) {
_error = wrapErrorEventListener(error, unsubscribe);
_complete = wrapSnapshotEventListener(task, complete, unsubscribe);
} else {
throw new Error(
`firebase.storage.StorageTask.on(*, _) 'nextOrObserver' must be a Function, an Object or Null.`,
);
}
if (_next) {
_nextSubscription = addTaskEventListener(task, StorageStatics.TaskEvent.STATE_CHANGED, _next);
}
if (_error) {
_errorSubscription = addTaskEventListener(task, 'failure', _error);
}
if (_complete) {
_completeSubscription = addTaskEventListener(task, 'success', _complete);
}
return unsubscribe;
}
export default class StorageTask {
constructor(type, storageRef, beginTaskFn) {
this._type = type;
this._id = TASK_ID++;
this._promise = null;
this._ref = storageRef;
this._beginTask = beginTaskFn;
this._storage = storageRef._storage;
}
/**
* @url https://firebase.google.com/docs/reference/js/firebase.storage.UploadTask#then
*/
get then() {
if (!this._promise) this._promise = this._beginTask(this);
return this._promise.then.bind(this._promise);
}
/**
* @url https://firebase.google.com/docs/reference/js/firebase.storage.UploadTask#catch
*/
get catch() {
if (!this._promise) this._promise = this._beginTask(this);
return this._promise.catch.bind(this._promise);
}
// // NOT on Web SDK
// /**
// * @url https://firebase.google.com/docs/reference/js/firebase.storage.UploadTask#finally
// */
// get finally() {
// if (!this._promise) this._promise = this._beginTask(this);
// return this._promise.finally.bind(this._promise);
// }
/**
* @url https://firebase.google.com/docs/reference/js/firebase.storage.UploadTask#on
*/
on(event, nextOrObserver, error, complete) {
if (event !== StorageStatics.TaskEvent.STATE_CHANGED) {
throw new Error(
`firebase.storage.StorageTask.on event argument must be a string with a value of '${
StorageStatics.TaskEvent.STATE_CHANGED
}'`,
);
}
if (!this._promise) this._promise = this._beginTask(this);
// if only event provided return the subscriber function
if (!nextOrObserver && !error && !complete) {
return subscribeToEvents.bind(null, this);
}
return subscribeToEvents(this, nextOrObserver, error, complete);
}
/**
* @url https://firebase.google.com/docs/reference/js/firebase.storage.UploadTask#pause
*/
pause() {
return this._storage.native.setTaskStatus(this._id, 0);
}
/**
* @url https://firebase.google.com/docs/reference/js/firebase.storage.UploadTask#resume
*/
resume() {
return this._storage.native.setTaskStatus(this._id, 1);
}
/**
* @url https://firebase.google.com/docs/reference/js/firebase.storage.UploadTask#cancel
*/
cancel() {
return this._storage.native.setTaskStatus(this._id, 2);
}
}