2017-04-07 15:15:53 +00:00
|
|
|
/* @flow */
|
|
|
|
import { statics as StorageStatics } from './';
|
|
|
|
import { isObject, isFunction } from './../../utils';
|
|
|
|
import StorageReference from './reference';
|
|
|
|
|
2017-02-14 11:31:42 +00:00
|
|
|
export const UPLOAD_TASK = 'upload';
|
|
|
|
export const DOWNLOAD_TASK = 'download';
|
|
|
|
|
2017-04-07 15:15:53 +00:00
|
|
|
declare type UploadTaskSnapshotType = {
|
|
|
|
bytesTransferred: number,
|
|
|
|
downloadURL: string|null,
|
|
|
|
metadata: Object, // TODO flow type def for https://firebase.google.com/docs/reference/js/firebase.storage.FullMetadata.html
|
|
|
|
ref: StorageReference,
|
2017-04-28 09:27:29 +00:00
|
|
|
state: (
|
|
|
|
typeof StorageStatics.TaskState.RUNNING
|
|
|
|
| typeof StorageStatics.TaskState.PAUSED
|
|
|
|
| typeof StorageStatics.TaskState.SUCCESS
|
|
|
|
| typeof StorageStatics.TaskState.CANCELLED
|
|
|
|
| typeof StorageStatics.TaskState.ERROR
|
|
|
|
),
|
2017-04-07 15:15:53 +00:00
|
|
|
task: StorageTask,
|
|
|
|
totalBytes: number,
|
|
|
|
};
|
|
|
|
|
|
|
|
declare type FuncSnapshotType = null|(snapshot: UploadTaskSnapshotType) => any;
|
|
|
|
|
|
|
|
declare type FuncErrorType = null|(error: Error) => any;
|
|
|
|
|
2017-04-28 10:03:12 +00:00
|
|
|
declare type NextOrObserverType = null |
|
|
|
|
{
|
|
|
|
next?: FuncSnapshotType,
|
|
|
|
error?: FuncErrorType,
|
|
|
|
complete?:FuncSnapshotType
|
|
|
|
} |
|
|
|
|
FuncSnapshotType;
|
2017-04-07 15:15:53 +00:00
|
|
|
|
2017-02-14 11:31:42 +00:00
|
|
|
/**
|
|
|
|
* @url https://firebase.google.com/docs/reference/js/firebase.storage.UploadTask
|
|
|
|
*/
|
|
|
|
export default class StorageTask {
|
2017-04-28 09:27:29 +00:00
|
|
|
type: typeof UPLOAD_TASK | typeof DOWNLOAD_TASK
|
|
|
|
ref: StorageReference
|
|
|
|
storage: StorageReference.storage
|
|
|
|
path: StorageReference.path
|
2017-05-14 12:24:10 +00:00
|
|
|
then: () => Promise<*>
|
2017-04-28 09:27:29 +00:00
|
|
|
catch: () => Promise<*>
|
|
|
|
|
|
|
|
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);
|
2017-03-22 23:23:48 +00:00
|
|
|
this.catch = promise.catch.bind(promise);
|
2017-02-14 11:31:42 +00:00
|
|
|
}
|
|
|
|
|
2017-04-07 15:15:53 +00:00
|
|
|
/**
|
|
|
|
* Intercepts a native snapshot result object attaches ref / task instances
|
|
|
|
* and calls the original function
|
|
|
|
* @returns {Promise.<T>}
|
|
|
|
* @private
|
|
|
|
*/
|
2017-04-28 09:27:29 +00:00
|
|
|
_interceptSnapshotEvent(f: ?Function): null | () => * {
|
2017-04-07 15:15:53 +00:00
|
|
|
if (!isFunction(f)) return null;
|
|
|
|
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);
|
2017-04-07 15:15:53 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Intercepts a error object form native and converts to a JS Error
|
|
|
|
* @param f
|
|
|
|
* @returns {*}
|
|
|
|
* @private
|
|
|
|
*/
|
2017-04-28 09:27:29 +00:00
|
|
|
_interceptErrorEvent(f: ?Function): null | (Error) => * {
|
2017-04-07 15:15:53 +00:00
|
|
|
if (!isFunction(f)) return null;
|
|
|
|
return (error) => {
|
|
|
|
const _error = new Error(error.message);
|
2017-04-28 09:27:29 +00:00
|
|
|
// $FlowFixMe
|
2017-04-07 15:15:53 +00:00
|
|
|
_error.code = error.code;
|
2017-04-28 09:27:29 +00:00
|
|
|
return f && f(_error);
|
2017-04-07 15:15:53 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2017-02-14 11:31:42 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param nextOrObserver
|
|
|
|
* @param error
|
|
|
|
* @param complete
|
|
|
|
* @returns {function()}
|
2017-04-07 15:15:53 +00:00
|
|
|
* @private
|
2017-02-14 11:31:42 +00:00
|
|
|
*/
|
2017-04-07 15:15:53 +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-07 15:15:53 +00:00
|
|
|
|
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-07 15:15:53 +00:00
|
|
|
|
2017-04-28 10:03:12 +00:00
|
|
|
if (_next) {
|
|
|
|
this.storage._addListener(
|
|
|
|
this.path,
|
|
|
|
StorageStatics.TaskEvent.STATE_CHANGED,
|
|
|
|
_next
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (_error) {
|
|
|
|
this.storage._addListener(
|
|
|
|
this.path,
|
|
|
|
`${this.type}_failure`,
|
|
|
|
_error
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (_complete) {
|
|
|
|
this.storage._addListener(
|
|
|
|
this.path,
|
|
|
|
`${this.type}_success`,
|
|
|
|
_complete
|
|
|
|
);
|
|
|
|
}
|
2017-04-07 15:15:53 +00:00
|
|
|
|
2017-02-14 11:31:42 +00:00
|
|
|
return () => {
|
2017-04-07 15:15:53 +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
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2017-04-07 15:15:53 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param event
|
|
|
|
* @param nextOrObserver
|
|
|
|
* @param error
|
|
|
|
* @param complete
|
|
|
|
* @returns {function()}
|
|
|
|
*/
|
|
|
|
on(event: string = StorageStatics.TaskEvent.STATE_CHANGED, nextOrObserver: NextOrObserverType, error: FuncErrorType, complete: FuncSnapshotType): Function {
|
|
|
|
if (!event) {
|
|
|
|
throw new Error('StorageTask.on listener is missing required string argument \'event\'.');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event !== StorageStatics.TaskEvent.STATE_CHANGED) {
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2017-04-07 16:57:57 +00:00
|
|
|
return this._subscribe(nextOrObserver, error, complete);
|
2017-04-07 15:15:53 +00:00
|
|
|
}
|
|
|
|
|
2017-02-14 11:31:42 +00:00
|
|
|
pause() {
|
|
|
|
throw new Error('.pause() is not currently supported by react-native-firebase');
|
|
|
|
}
|
|
|
|
|
|
|
|
resume() {
|
|
|
|
// todo
|
|
|
|
throw new Error('.resume() is not currently supported by react-native-firebase');
|
|
|
|
}
|
|
|
|
|
|
|
|
cancel() {
|
|
|
|
// todo
|
|
|
|
throw new Error('.cancel() is not currently supported by react-native-firebase');
|
|
|
|
}
|
|
|
|
}
|