react-native-firebase/lib/modules/storage/task.js

216 lines
5.4 KiB
JavaScript
Raw Normal View History

/**
* @flow
* UploadTask representation wrapper
*/
import { statics as StorageStatics } from './';
import { isFunction } from './../../utils';
import type Storage from './';
import type StorageReference from './reference';
2017-02-14 11:31:42 +00:00
export const UPLOAD_TASK = 'upload';
export const DOWNLOAD_TASK = 'download';
declare type UploadTaskSnapshotType = {
bytesTransferred: number,
2018-01-25 18:25:39 +00:00
downloadURL: string | null,
metadata: Object, // TODO flow type def for https://firebase.google.com/docs/reference/js/firebase.storage.FullMetadata.html
ref: StorageReference,
2018-01-25 18:25:39 +00:00
state:
| typeof StorageStatics.TaskState.RUNNING
2017-04-28 09:27:29 +00:00
| typeof StorageStatics.TaskState.PAUSED
| typeof StorageStatics.TaskState.SUCCESS
| typeof StorageStatics.TaskState.CANCELLED
2018-01-25 18:25:39 +00:00
| typeof StorageStatics.TaskState.ERROR,
task: StorageTask,
totalBytes: number,
};
2018-01-25 18:25:39 +00:00
declare type FuncSnapshotType =
| null
| ((snapshot: UploadTaskSnapshotType) => any);
2018-01-25 18:25:39 +00:00
declare type FuncErrorType = null | ((error: Error) => any);
2018-01-25 18:25:39 +00:00
declare type NextOrObserverType =
| null
| {
next?: FuncSnapshotType,
error?: FuncErrorType,
complete?: FuncSnapshotType,
}
| FuncSnapshotType;
2017-02-14 11:31:42 +00:00
/**
* @url https://firebase.google.com/docs/reference/js/firebase.storage.UploadTask
*/
export default class StorageTask {
type: typeof UPLOAD_TASK | typeof DOWNLOAD_TASK;
ref: StorageReference;
storage: Storage;
path: string;
then: () => Promise<*>;
catch: () => Promise<*>;
2017-04-28 09:27:29 +00:00
2018-01-25 18:25:39 +00:00
constructor(
type: typeof UPLOAD_TASK | typeof DOWNLOAD_TASK,
promise: Promise<*>,
storageRef: StorageReference
) {
2017-02-14 11:31:42 +00:00
this.type = type;
this.ref = storageRef;
this.storage = storageRef._storage;
2017-03-22 19:57:42 +00:00
this.path = storageRef.path;
2017-02-14 11:31:42 +00:00
// 'proxy' original promise
2017-05-14 12:24:10 +00:00
this.then = promise.then.bind(promise);
this.catch = promise.catch.bind(promise);
2017-02-14 11:31:42 +00:00
}
/**
* Intercepts a native snapshot result object attaches ref / task instances
* and calls the original function
* @returns {Promise.<T>}
* @private
*/
2018-01-25 18:25:39 +00:00
_interceptSnapshotEvent(f: ?Function): null | (() => *) {
if (!isFunction(f)) return null;
2018-01-25 18:25:39 +00:00
return snapshot => {
const _snapshot = Object.assign({}, snapshot);
_snapshot.task = this;
_snapshot.ref = this.ref;
2017-04-28 09:27:29 +00:00
return f && f(_snapshot);
};
}
/**
* Intercepts a error object form native and converts to a JS Error
* @param f
* @returns {*}
* @private
*/
2018-01-25 18:25:39 +00:00
_interceptErrorEvent(f: ?Function): null | (Error => *) {
if (!isFunction(f)) return null;
2018-01-25 18:25:39 +00:00
return error => {
const _error = new Error(error.message);
2018-02-17 12:55:19 +00:00
// $FlowExpectedError
_error.code = error.code;
2017-04-28 09:27:29 +00:00
return f && f(_error);
};
}
2017-02-14 11:31:42 +00:00
/**
*
* @param nextOrObserver
* @param error
* @param complete
* @returns {function()}
* @private
2017-02-14 11:31:42 +00:00
*/
2018-01-25 18:25:39 +00:00
_subscribe(
nextOrObserver: NextOrObserverType,
error: FuncErrorType,
complete: FuncSnapshotType
): Function {
2017-04-28 10:03:12 +00:00
let _error;
let _next;
let _complete;
2017-04-28 10:03:12 +00:00
if (typeof nextOrObserver === 'function') {
_error = this._interceptErrorEvent(error);
_next = this._interceptSnapshotEvent(nextOrObserver);
_complete = this._interceptSnapshotEvent(complete);
} else if (nextOrObserver) {
_error = this._interceptErrorEvent(nextOrObserver.error);
_next = this._interceptSnapshotEvent(nextOrObserver.next);
_complete = this._interceptSnapshotEvent(nextOrObserver.complete);
}
2017-04-28 10:03:12 +00:00
if (_next) {
this.storage._addListener(
this.path,
StorageStatics.TaskEvent.STATE_CHANGED,
2018-01-25 18:25:39 +00:00
_next
2017-04-28 10:03:12 +00:00
);
}
if (_error) {
2018-01-25 18:25:39 +00:00
this.storage._addListener(this.path, `${this.type}_failure`, _error);
2017-04-28 10:03:12 +00:00
}
if (_complete) {
2018-01-25 18:25:39 +00:00
this.storage._addListener(this.path, `${this.type}_success`, _complete);
2017-04-28 10:03:12 +00:00
}
2017-02-14 11:31:42 +00:00
return () => {
2018-01-25 18:25:39 +00:00
if (_next)
this.storage._removeListener(
this.path,
StorageStatics.TaskEvent.STATE_CHANGED,
_next
);
if (_error)
this.storage._removeListener(this.path, `${this.type}_failure`, _error);
if (_complete)
this.storage._removeListener(
this.path,
`${this.type}_success`,
_complete
);
2017-02-14 11:31:42 +00:00
};
}
/**
*
* @param event
* @param nextOrObserver
* @param error
* @param complete
* @returns {function()}
*/
2018-01-25 18:25:39 +00:00
on(
event: string = StorageStatics.TaskEvent.STATE_CHANGED,
nextOrObserver: NextOrObserverType,
error: FuncErrorType,
complete: FuncSnapshotType
): Function {
if (!event) {
2018-01-25 18:25:39 +00:00
throw new Error(
"StorageTask.on listener is missing required string argument 'event'."
);
}
if (event !== StorageStatics.TaskEvent.STATE_CHANGED) {
2018-01-25 18:25:39 +00:00
throw new Error(
`StorageTask.on event argument must be a string with a value of '${
StorageStatics.TaskEvent.STATE_CHANGED
}'`
);
}
// if only event provided return the subscriber function
if (!nextOrObserver && !error && !complete) {
return this._subscribe.bind(this);
}
return this._subscribe(nextOrObserver, error, complete);
}
2017-02-14 11:31:42 +00:00
pause() {
2018-01-25 18:25:39 +00:00
throw new Error(
'.pause() is not currently supported by react-native-firebase'
);
2017-02-14 11:31:42 +00:00
}
resume() {
// todo
2018-01-25 18:25:39 +00:00
throw new Error(
'.resume() is not currently supported by react-native-firebase'
);
2017-02-14 11:31:42 +00:00
}
cancel() {
// todo
2018-01-25 18:25:39 +00:00
throw new Error(
'.cancel() is not currently supported by react-native-firebase'
);
2017-02-14 11:31:42 +00:00
}
}