From de6cfdb1da63928729dbad3fa033c901eaf7daa2 Mon Sep 17 00:00:00 2001 From: haad Date: Thu, 14 Nov 2019 13:17:42 +0200 Subject: [PATCH] Add offline mode option --- API.md | 4 ++- src/OrbitDB.js | 14 +++++--- test/offline-mode.js | 78 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 5 deletions(-) create mode 100644 test/offline-mode.js diff --git a/API.md b/API.md index 8db47c0..c2ced49 100644 --- a/API.md +++ b/API.md @@ -81,10 +81,12 @@ Creates and returns an instance of OrbitDB. Use the optional `options` argument - `keystore` (Keystore Instance) : By default creates an instance of [Keystore](https://github.com/orbitdb/orbit-db-keystore). A custom keystore instance can be used, see [this](https://github.com/orbitdb/orbit-db/blob/master/test/utils/custom-test-keystore.js) for an example. -- 'cache' (Cache Instance) : By default creates an instance of [Cache](https://github.com/orbitdb/orbit-db-cache). A custom cache instance can also be used. +- `cache` (Cache Instance) : By default creates an instance of [Cache](https://github.com/orbitdb/orbit-db-cache). A custom cache instance can also be used. - `identity` (Identity Instance): By default it creates an instance of [Identity](https://github.com/orbitdb/orbit-db-identity-provider/blob/master/src/identity.js) +- `offline` (boolean): Start the OrbitDB instance in offline mode. Databases are not be replicated when the instance is started in offline mode. If the OrbitDB instance was started offline mode and you want to start replicating databases, the OrbitDB instance needs to be re-created. Default: `false`. + After creating an `OrbitDB` instance, you can access the different data stores. Creating a database instance, eg. with `orbitdb.keyvalue(...)`, returns a *Promise* that resolves to a [database instance](#store-api). See the [Store](#store-api) section for details of common methods and properties. *For further details, see usage for [kvstore](https://github.com/orbitdb/orbit-db-kvstore#usage), [eventlog](https://github.com/orbitdb/orbit-db-eventstore#usage), [feed](https://github.com/orbitdb/orbit-db-feedstore#usage), [docstore](https://github.com/orbitdb/orbit-db-docstore#usage) and [counter](https://github.com/orbitdb/orbit-db-counterstore#usage).* diff --git a/src/OrbitDB.js b/src/OrbitDB.js index 6011350..7bf1d86 100644 --- a/src/OrbitDB.js +++ b/src/OrbitDB.js @@ -40,9 +40,11 @@ class OrbitDB { this._ipfs = ipfs this.identity = identity this.id = options.peerId - this._pubsub = options && options.broker - ? new options.broker(this._ipfs) // eslint-disable-line - : new Pubsub(this._ipfs, this.id) + this._pubsub = !options.offline + ? options.broker + ? new options.broker(this._ipfs) // eslint-disable-line + : new Pubsub(this._ipfs, this.id) + : null this.directory = options.directory || './orbitdb' this.storage = options.storage this._directConnections = {} @@ -110,6 +112,10 @@ class OrbitDB { options.cache = new Cache(cacheStorage) } + if (options.offline === undefined) { + options.offline = false + } + const finalOptions = Object.assign({}, options, { peerId: id }) return new OrbitDB(ipfs, options.identity, finalOptions) } @@ -228,7 +234,7 @@ class OrbitDB { // Subscribe to pubsub to get updates from peers, // this is what hooks us into the message propagation layer // and the p2p network - if (opts.replicate && this._pubsub) { this._pubsub.subscribe(addr, this._onMessage.bind(this), this._onPeerConnected.bind(this)) } + if (opts.replicate && this._pubsub) { await this._pubsub.subscribe(addr, this._onMessage.bind(this), this._onPeerConnected.bind(this)) } return store } diff --git a/test/offline-mode.js b/test/offline-mode.js new file mode 100644 index 0000000..b1a93d2 --- /dev/null +++ b/test/offline-mode.js @@ -0,0 +1,78 @@ +'use strict' + +const fs = require('fs') +const path = require('path') +const assert = require('assert') +const mapSeries = require('p-map-series') +const rmrf = require('rimraf') +const IPFS = require('ipfs') +const OrbitDB = require('../src/OrbitDB') +const Identities = require('orbit-db-identity-provider') +const Keystore = require('orbit-db-keystore') +const leveldown = require('leveldown') +const storage = require('orbit-db-storage-adapter')(leveldown) + +// Include test utilities +const { + config, + startIpfs, + stopIpfs, + testAPIs, +} = require('./utils') + +const dbPath1 = './orbitdb/tests/offline/db1' +const dbPath2 = './orbitdb/tests/offline/db2' +const ipfsPath = './orbitdb/tests/offline/ipfs' + +Object.keys(testAPIs).forEach(API => { + describe(`orbit-db - Offline mode (${API})`, function() { + this.timeout(config.timeout) + + let ipfsd1, ipfsd2, ipfs1, ipfs2, orbitdb, db, keystore + let identity1, identity2 + let localDataPath + + before(async () => { + config.daemon1.repo = path.join(ipfsPath, '/1') + config.daemon2.repo = path.join(ipfsPath, '/2') + rmrf.sync(config.daemon1.repo) + rmrf.sync(config.daemon2.repo) + rmrf.sync(path.join(ipfsPath, '/2')) + rmrf.sync('./orbitdb/tests/offline') + rmrf.sync(dbPath1) + rmrf.sync(dbPath2) + ipfsd1 = await startIpfs(API, config.daemon1) + ipfsd2 = await startIpfs(API, config.daemon2) + ipfs1 = ipfsd1.api + ipfs2 = ipfsd2.api + }) + + after(async () => { + if(orbitdb) + await orbitdb.stop() + + if (ipfsd1) + await stopIpfs(ipfsd1) + if (ipfsd2) + await stopIpfs(ipfsd2) + }) + + it('starts in offline mode', async () => { + orbitdb = await OrbitDB.createInstance(ipfs1, { offline: true, directory: dbPath1 }) + assert.equal(orbitdb._pubsub, null) + await orbitdb.stop() + }) + + it('does not start in offline mode', async () => { + orbitdb = await OrbitDB.createInstance(ipfs1, { offline: false, directory: dbPath1 }) + assert.notEqual(orbitdb._pubsub, null) + await orbitdb.stop() + }) + + it('does not start in offline mode - default', async () => { + orbitdb = await OrbitDB.createInstance(ipfs1, { directory: dbPath1 }) + assert.notEqual(orbitdb._pubsub, null) + await orbitdb.stop() + }) + }) +})