orbitdb/src/OrbitDB.js

143 lines
4.2 KiB
JavaScript

'use strict';
const EventEmitter = require('events').EventEmitter;
const logger = require('logplease').create("orbit-db.Client");
const PubSub = require('./PubSub');
const CounterStore = require('./stores/counters/CounterStore');
const KeyValueStore = require('./stores/kvstore/KeyValueStore');
const EventStore = require('./stores/eventlog/EventStore');
class OrbitDB {
constructor(ipfs, options) {
this._ipfs = ipfs;
this._pubsub = null;
this.user = null;
this.network = null;
this.events = new EventEmitter();
this.stores = {};
}
eventlog(dbname, options) {
if(!options) options = { subscribe: true };
const store = new EventStore(this._ipfs, dbname, options);
return this._subscribe(store, dbname, options.subscribe)
.then(() => this.stores[dbname] = store)
.then(() => store);
}
kvstore(dbname, options) {
if(!options) options = { subscribe: true };
const store = new KeyValueStore(this._ipfs, dbname, options);
if(this.stores[dbname]) this.stores[dbname].close();
return this._subscribe(store, dbname, options.subscribe)
.then(() => this.stores[dbname] = store)
.then(() => store);
}
counter(dbname, options) {
if(!options) options = { subscribe: true };
const store = new CounterStore(this._ipfs, dbname, options);
return this._subscribe(store, dbname, options.subscribe)
.then(() => this.stores[dbname] = store)
.then(() => store);
}
disconnect() {
this._pubsub.disconnect();
this._store = {};
this.user = null;
this.network = null;
}
_subscribe(store, dbname, subscribe, callback) {
if(subscribe === undefined) subscribe = true;
return store.use(this.user.username).then((events) => {
events.on('readable', this._onSync.bind(this));
events.on('data', this._onWrite.bind(this));
events.on('load', this._onLoad.bind(this));
events.on('close', this._onClose.bind(this));
if(subscribe)
this._pubsub.subscribe(dbname, '', this._onMessage.bind(this));
return;
});
}
_onMessage(dbname, message) {
const store = this.stores[dbname];
store.sync(message).catch((e) => logger.error(e.stack));
}
// TODO: FIX EVENTS!!
_onWrite(channel, hash) {
this._pubsub.publish(channel, hash);
this.events.emit('data', channel, hash);
}
_onSync(channel, hash) {
this.events.emit('readable', channel, hash);
}
_onLoad(channel, hash) {
this.events.emit('load', channel, hash);
}
_onClose(dbname) {
this._pubsub.unsubscribe(dbname);
delete this.stores[dbname];
this.events.emit('closed', dbname);
}
_connect(host, port, username, password, allowOffline) {
return new Promise((resolve, reject) => {
if(allowOffline === undefined) allowOffline = false;
this._pubsub = new PubSub(this._ipfs);
this._pubsub.connect(host, port, username, password).then(() => {
logger.debug(`Connected to Pubsub at '${host}:${port}'`);
this.user = { username: username, id: username } // TODO: user id from ipfs hash
this.network = { host: host, port: port, name: 'TODO: network name' }
resolve();
}).catch((e) => {
logger.warn("Couldn't connect to Pubsub:", e.message);
if(!allowOffline) {
logger.debug("'allowOffline' set to false, terminating");
this._pubsub.disconnect();
reject(e);
return;
}
this.user = { username: username, id: username } // TODO: user id from ipfs hash
this.network = { host: host, port: port, name: 'TODO: network name' }
resolve();
});
});
}
}
class OrbitClientFactory {
static connect(host, port, username, password, ipfs, options) {
const createClient =(ipfs) => {
return new Promise((resolve, reject) => {
const client = new OrbitDB(ipfs, options);
client._connect(host, port, username, password, options.allowOffline)
.then(() => resolve(client))
.catch(reject);
});
}
options = options ? options : {};
if(!ipfs) {
logger.error("IPFS instance not provided");
throw new Error("IPFS instance not provided");
}
return createClient(ipfs);
}
}
module.exports = OrbitClientFactory;