Skip to content

Commit

Permalink
WIP – split out db / store / account config
Browse files Browse the repository at this point in the history
  • Loading branch information
gr2m committed May 2, 2016
1 parent e7b1ebc commit 5469ee1
Show file tree
Hide file tree
Showing 10 changed files with 172 additions and 119 deletions.
23 changes: 23 additions & 0 deletions lib/config/account/index.js
@@ -0,0 +1,23 @@
module.exports = accountConfig

var defaultsDeep = require('lodash').defaultsDeep

function accountConfig (state, callback) {
var usersDb = state.getDatabase(state.config.db.authenticationDb)
usersDb.constructor.plugin(require('pouchdb-users'))

usersDb.installUsersBehavior()

.then(function () {
defaultsDeep(state.config.account, {
admins: state.config.db.admins,
secret: state.config.db.secret,
usersDb: usersDb,
notifications: state.config.account.notifications
})

callback(null)
})

.catch(callback, state.config)
}
14 changes: 8 additions & 6 deletions lib/config/db/couchdb.js
Expand Up @@ -13,23 +13,25 @@ var request = require('request')

var internals = module.exports.internals

function couchDbConfig (config, callback) {
function couchDbConfig (state, callback) {
var couch = request.defaults({
baseUrl: config.db.url,
baseUrl: state.config.db.url,
json: true
})

async.series([
async.apply(internals.checkVendor, config, couch),
async.apply(internals.checkVendor, state.config, couch),
async.apply(internals.setConfig, couch),
async.apply(internals.getConfig, couch),
async.apply(internals.getAdmins, couch)
], function (err, results) {
if (err) return callback(err)

callback(null, _.assign({
admins: results[3]
}, results[2]))
state.config.db.admins = results[3]
state.config.db.secret = results[2].secret
state.config.db.authenticationDb = results[2].authentication_db

callback(null, state.config)
})
}

Expand Down
15 changes: 8 additions & 7 deletions lib/config/db/pouchdb.js
Expand Up @@ -2,11 +2,12 @@ module.exports = pouchDbConfig

var existsSync = require('fs').existsSync
var join = require('path').join

var jsonfile = require('jsonfile')
var randomstring = require('randomstring')

function pouchDbConfig (config, callback) {
var storePath = join(config.paths.data, 'config.json')
function pouchDbConfig (state, callback) {
var storePath = join(state.config.paths.data, 'config.json')
var storeExists = existsSync(storePath)
var store = storeExists && jsonfile.readFileSync(storePath, {
throws: false
Expand All @@ -22,9 +23,9 @@ function pouchDbConfig (config, callback) {
}), {spaces: 2})
}

callback(null, {
secret: secret,
authentication_db: '_users',
admins: {}
})
state.config.db.secret = secret
state.config.db.admins = {}
state.config.db.authenticationDb = '_users'

callback(null, state.config)
}
103 changes: 21 additions & 82 deletions lib/config/index.js
@@ -1,95 +1,34 @@
module.exports = getConfig
var internals = module.exports.internals = {
getDefaults: require('./defaults'),
accountConfig: require('./account'),
couchDbConfig: require('./db/couchdb'),
pouchDbConfig: require('./db/pouchdb')
getDatabaseFactory: require('./db/factory'),
parseOptions: require('./parse-options'),
pouchDbConfig: require('./db/pouchdb'),
storeConfig: require('./store')
}

var parseUrl = require('url').parse
var path = require('path')

var defaultsDeep = require('lodash').defaultsDeep
var log = require('npmlog')

var getDatabaseFactory = require('./db/factory')
var series = require('async').series

function getConfig (options, callback) {
var defaults = internals.getDefaults()
var config = {
paths: {
data: options.data,
public: options.public
},
app: {
hostname: options.bindAddress,
port: options.port
}
if (options.dbUrl && !parseUrl(options.dbUrl).auth) {
return callback('Authentication details missing from database URL: ' + options.dbUrl)
}
var getDbConfig

defaultsDeep(config, defaults)

if (options.dbUrl) {
config.db.url = options.dbUrl
if (!parseUrl(options.dbUrl).auth) {
return callback('Authentication details missing from database URL: ' + options.dbUrl)
}

log.info('config', 'Connecting to CouchDB at ' + removeAuth(options.dbUrl))

getDbConfig = internals.couchDbConfig
} else {
if (options.inMemory) {
log.info('config', 'Storing all data in memory')
config.db.db = require('memdown')
} else {
config.db.prefix = path.join(config.paths.data, 'data/')
log.info('config', 'No CouchDB URL provided, falling back to PouchDB')
log.info('config', 'Writing PouchDB database files to ' + config.db.prefix)
}

getDbConfig = internals.pouchDbConfig
var config = internals.parseOptions(options)
var state = {
config: config,
getDatabase: internals.getDatabaseFactory(config)
}

getDbConfig(config, function (error, couchConfig) {
if (error) {
return callback(error)
}

config.db.secret = couchConfig.secret
config.db.admins = couchConfig.admins
config.db.authenticationDb = couchConfig.authentication_db

var getDatabase = getDatabaseFactory(config)
var usersDb = getDatabase(config.db.authenticationDb)
usersDb.constructor.plugin(require('pouchdb-users'))

usersDb.installUsersBehavior()

.then(function () {
// account config
defaultsDeep(config.account, {
admins: couchConfig.admins,
secret: config.db.secret,
usersDb: usersDb,
notifications: config.account.notifications
})

// store config
if (config.db.url) {
config.store.couchdb = removeAuth(config.db.url)
} else {
config.store.PouchDB = usersDb.constructor
}

callback(null, config)
})

.catch(callback)
var dbConfig = state.config.db.url ? internals.couchDbConfig : internals.pouchDbConfig
state.getDatabase.PouchDB.plugin(require('pouchdb-users'))

series([
dbConfig.bind(null, state),
internals.accountConfig.bind(null, state),
internals.storeConfig.bind(null, state)
], function (error) {
callback(error, state.config)
})
}

function removeAuth (url) {
var parts = parseUrl(url)
return url.replace(parts.auth + '@', '')
}
41 changes: 41 additions & 0 deletions lib/config/parse-options.js
@@ -0,0 +1,41 @@
module.exports = parseOptions

var path = require('path')

var defaultsDeep = require('lodash').defaultsDeep
var log = require('npmlog')

var getDefaults = require('./defaults')
var removeAuth = require('../utils/remove-auth-from-url')

function parseOptions (options, callback) {
var config = {
db: {},
paths: {
data: options.data,
public: options.public
},
app: {
hostname: options.bindAddress,
port: options.port
}
}

defaultsDeep(config, getDefaults())

if (options.dbUrl) {
config.db.url = options.dbUrl
log.info('config', 'Connecting to CouchDB at ' + removeAuth(options.dbUrl))
} else {
if (options.inMemory) {
log.info('config', 'Storing all data in memory only')
config.db.db = require('memdown')
} else {
config.db.prefix = path.join(config.paths.data, 'data')
log.info('config', 'No CouchDB URL provided, falling back to PouchDB')
log.info('config', 'Writing PouchDB database files to ' + config.db.prefix)
}
}

return config
}
13 changes: 13 additions & 0 deletions lib/config/store/index.js
@@ -0,0 +1,13 @@
module.exports = storeConfig

var removeAuth = require('../../utils/remove-auth-from-url')

function storeConfig (state, callback) {
if (state.config.db.url) {
state.config.store.couchdb = removeAuth(state.config.db.url)
} else {
state.config.store.PouchDB = state.getDatabase.PouchDB.constructor
}

callback(null, state.config)
}
8 changes: 8 additions & 0 deletions lib/utils/remove-auth-from-url.js
@@ -0,0 +1,8 @@
module.exports = removeAuth

var parseUrl = require('url').parse

function removeAuth (url) {
var parts = parseUrl(url)
return url.replace(parts.auth + '@', '')
}
34 changes: 20 additions & 14 deletions test/unit/config-test.js
@@ -1,6 +1,5 @@
var simple = require('simple-mock')
var test = require('tap').test
var proxyquire = require('proxyquire')
require('npmlog').level = 'silent'

var cwd = process.cwd()
Expand All @@ -16,7 +15,7 @@ test('config', function (t) {
tt.ok(config.paths.data.startsWith(cwd), 'derives hoodie path from cwd')
tt.match(config.paths.public, cwd + '/public', 'falls back to hoodie/public')

tt.same(config.db.prefix, cwd + '/.hoodie/data/', 'uses default db config')
tt.same(config.db.prefix, cwd + '/.hoodie/data', 'uses default db config')
tt.same(config.app, {
hostname: '127.0.0.1',
port: 8080,
Expand All @@ -29,15 +28,15 @@ test('config', function (t) {

t.test('applies overwrites', function (tt) {
var getConfig = require('../../lib/config')
simple.mock(getConfig.internals, 'getDefaults').returnWith({
simple.mock(getConfig.internals, 'parseOptions').returnWith({
name: 'overwritten',
paths: {
data: 'data path',
public: 'public path'
data: 'data-path',
public: 'public-path'
},
app: {
hostname: 'host.name',
port: 1234,
hostname: 'hoodie-test',
port: 1337,
protocol: 'http'
},
db: {},
Expand Down Expand Up @@ -79,19 +78,26 @@ test('config', function (t) {
tt.plan(3)

var memdown = {}
var getConfig = proxyquire('../../lib/config', {
memdown: memdown,
npmlog: {
warn: function () {},
info: function () {}
}
})
var getConfig = require('../../lib/config')

simple.mock(getConfig.internals, 'couchDbConfig').callbackWith(null, {
secret: 'secret',
authentication_db: '_users',
admins: {}
})
simple.mock(getConfig.internals, 'parseOptions', function (options) {
return {
paths: {
data: 'data-path'
},
db: {
db: memdown
}
}
})
simple.mock(getConfig.internals, 'accountConfig').callbackWith(null)
simple.mock(getConfig.internals, 'pouchDbConfig').callbackWith(null)
simple.mock(getConfig.internals, 'storeConfig').callbackWith(null)

getConfig({
inMemory: true
Expand Down
14 changes: 10 additions & 4 deletions test/unit/config/db-couchdb-test.js
Expand Up @@ -22,12 +22,18 @@ nock('http://127.0.0.1:5984')
test('init couchdb', function (t) {
var couchdb = require('../../../lib/config/db/couchdb')

couchdb({db: {url: 'http://a:b@127.0.0.1:5984/'}}, function (err, result) {
couchdb({
config: {
db: {
url: 'http://a:b@127.0.0.1:5984/'
}
}
}, function (err, result) {
t.error(err)

t.is(result.secret, 'foo')
t.is(result.authentication_db, '_users')
t.same(result.admins, {
t.is(result.db.secret, 'foo')
t.is(result.db.authenticationDb, '_users')
t.same(result.db.admins, {
user: 'secret'
})

Expand Down

0 comments on commit 5469ee1

Please sign in to comment.