react-native-firebase/lib/firebase.js

215 lines
5.2 KiB
JavaScript

/**
* @providesModule Firebase
* @flow
*/
import { NativeModules, NativeEventEmitter } from 'react-native';
import Log from './utils/log';
import { promisify } from './utils';
import Singleton from './utils/singleton';
// modules
import Auth from './modules/auth';
import Storage from './modules/storage';
import Database from './modules/database';
import Messaging from './modules/messaging';
import Analytics from './modules/analytics';
let log;
const instances = { default: null };
const FirebaseModule = NativeModules.RNFirebase;
const FirebaseModuleEvt = new NativeEventEmitter(FirebaseModule);
/**
* @class Firebase
*/
export default class Firebase extends Singleton {
/**
*
* @param options
*/
constructor(options: Object = {}) {
const instance = super(options);
instance.options = Object.assign({ errorOnMissingPlayServices: true }, options);
instance._debug = instance.options.debug || false;
Log.enable(instance._debug);
log = instance._log = new Log('firebase');
log.info('Creating new firebase instance');
instance._remoteConfig = instance.options.remoteConfig || {};
delete instance.options.remoteConfig;
instance.configured = instance.options.configure || false;
instance.eventHandlers = {};
log.info('Calling configure with options', instance.options);
instance.configurePromise = instance.configure(instance.options);
instance._auth = new Auth(instance, instance.options);
if (instance.options.errorOnMissingPlayServices && !this.googleApiAvailability.isAvailable) {
throw new Error(`Google Play Services is required to run this application but no valid installation was found (Code ${this.googleApiAvailability.status}).`);
}
}
_db: ?Object;
_log: ?Object;
_auth: ?Object;
_store: ?Object;
_storage: ?Object;
_presence: ?Object;
_analytics: ?Object;
_constants: ?Object;
_messaging: ?Object;
_remoteConfig: ?Object;
/**
* Support web version of initApp.
* @param options
* @param name
* @returns {*}
*/
static initializeApp(options: Object = {}, name: string = 'default') {
if (!instances[name]) instances[name] = new Firebase(options);
return instances[name];
}
/**
*
* @param opts
* @returns {Promise.<TResult>|*|Promise.<T>}
*/
configure(opts: Object = {}) {
if (!this.configurePromise) {
const firebaseOptions = Object.assign({}, this.options, opts);
this.configurePromise = promisify('configureWithOptions', FirebaseModule)(firebaseOptions)
.then((configuredProperties) => {
log.info('Native configureWithOptions success', configuredProperties);
this.configured = true;
this.firebaseOptions = configuredProperties;
return configuredProperties;
}).catch((err) => {
log.info('Native error occurred while calling configure', err);
});
}
return this.configurePromise;
}
onReady(cb: Function) {
// TODO wut o.O
return this.configurePromise = this.configurePromise.then(cb);
}
/**
* Wrappers
* We add methods from each wrapper to this instance
* when they are needed. Not sure if this is a good
* idea or not (imperative vs. direct manipulation/proxy)
*/
auth() {
return this._auth;
}
database() {
if (!this._db) {
this._db = new Database(this);
}
return this._db;
}
analytics() {
if (!this._analytics) {
this._analytics = new Analytics(this);
}
return this._analytics;
}
// storage
storage() {
if (!this._storage) {
this._storage = new Storage(this);
}
return this._storage;
}
messaging() {
if (!this._messaging) {
this._messaging = new Messaging(this);
}
return this._messaging;
}
get apps(): Array<string> {
return Object.keys(instances);
}
/**
* Returns androids GoogleApiAvailability status and message if available.
* @returns {GoogleApiAvailabilityType|{isAvailable: boolean, status: number}}
*/
get googleApiAvailability(): GoogleApiAvailabilityType {
// if not available then return a fake object for ios - saves doing platform specific logic.
return FirebaseModule.googleApiAvailability || { isAvailable: true, status: 0 };
}
/**
* Logger
*/
get log(): Log {
return this._log;
}
/**
* Redux store
**/
get store(): ?Object {
return this._store;
}
get constants(): Object {
if (!this._constants) {
this._constants = Object.assign({}, Storage.constants);
}
return this._constants;
}
/**
* Set the redux store helper
*/
setStore(store: Object) {
if (store) {
this.log.info('Setting the store for Firebase instance');
this._store = store;
}
}
/**
* Global event handlers for the single Firebase instance
*/
on(name: string, cb: Function, nativeModule: Object = FirebaseModuleEvt) {
if (!this.eventHandlers[name]) {
this.eventHandlers[name] = [];
}
const sub = nativeModule.addListener(name, cb);
this.eventHandlers[name].push(sub);
return sub;
}
off(name: string) {
if (this.eventHandlers[name]) {
this.eventHandlers[name]
.forEach(subscription => subscription.remove());
}
}
}