Skip to content

Commit

Permalink
feat: use Hoodie as hapi plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
gr2m committed Jul 19, 2016
1 parent 402af03 commit e79254d
Show file tree
Hide file tree
Showing 13 changed files with 242 additions and 193 deletions.
141 changes: 5 additions & 136 deletions bin/start.js
Original file line number Diff line number Diff line change
@@ -1,145 +1,14 @@
#!/usr/bin/env node

var url = require('url')
var cli = require('../cli')

var _ = require('lodash')
var emoji = require('node-emoji')
var log = require('npmlog')
var path = require('path')
var rc = require('rc')
var semver = require('semver')
var yargs = require('yargs')

var defaults = require('../server/config/defaults')()
var getHoodieServer = require('../server')

var useEmoji = process.platform === 'darwin'

log.style = {
silly: {inverse: true, bold: true},
verbose: {fg: 'brightBlue', bold: true},
info: {fg: 'brightGreen', bold: true},
http: {fg: 'brightGreen', bold: true},
warn: {fg: 'brightYellow', bold: true},
error: {fg: 'brightRed', bold: true},
silent: undefined
}
log.prefixStyle = {fg: 'magenta'}
log.headingStyle = {}
log.disp = {
silly: 'Sill',
verbose: 'Verb',
info: 'Info',
http: 'HTTP',
warn: 'Warn',
error: 'Err!',
silent: 'silent'
}
log.heading = (useEmoji ? emoji.get('dog') + ' ' : '') + 'Hoodie'

if (semver.lt(process.versions.node, '4.0.0')) {
log.error('env', 'A node version >=4 is required to run Hoodie')
process.exit(1)
}

var args = yargs
.options({
loglevel: {
choices: [
'silly',
'verbose',
'info',
'http',
'warn',
'error',
'silent'
],
default: function () {
if ('s' in yargs.argv || 'ddd' in yargs.argv) return 'silly'
if ('d' in yargs.argv) return 'info'
if ('dd' in yargs.argv || 'verbose' in yargs.argv) return 'verbose'
if ('silent' in yargs.argv) return 'silent'
return 'warn'
}
},
port: {
type: 'number',
default: defaults.connection.port,
describe: 'Port-number to run the Hoodie App on'
},
'bind-address': {
type: 'string',
default: defaults.connection.host,
describe: 'Address that Hoodie binds to'
},
public: {
type: 'string',
default: defaults.paths.public.replace(process.cwd() + path.sep, ''),
describe: 'Path to static assets'
},
m: {
alias: 'in-memory',
type: 'boolean',
default: false,
describe: 'Whether to start the PouchDB Server in memory'
},
data: {
type: 'string',
default: defaults.paths.data.replace(process.cwd() + path.sep, ''),
describe: 'Data path'
},
'db-url': {
type: 'string',
default: undefined,
describe: 'If provided, uses external CouchDB. URL has to contain credentials.'
},
plugins: {
type: 'boolean',
default: {},
describe: 'Define options, keyed by their name'
}
})
.help('h', 'Show this help message')
.alias('h', 'help')
.alias('h', 'usage')
.showHelpOnFail(false, 'Specify --help for available options')
.version(function () {
try {
var pkg = require('../package.json')
console.log(pkg.version, '\n')
process.exit(0)
} catch (e) {
process.exit(1)
}
})
.alias('v', 'version')
.env('hoodie')
.epilogue('Options can also be specified as environment variables (prefixed with "hoodie_") or inside a ".hoodierc" file (json or ini).')
.wrap(Math.min(150, yargs.terminalWidth()))
.argv

// merge args with rc config
// rc generates 'config' and 'configs', which we don't need
var options = _.omit(rc('hoodie', args, null), ['config', 'configs'])

log.level = options.loglevel || 'warn'

log.verbose('app', 'Initialising')

getHoodieServer(options, function (error, server, config) {
cli(function (error, server) {
if (error) {
var stack = new Error().stack.split('\n').slice(2).join('\n')
return log.error('app', 'Failed to initialise:\n' + stack, error)
throw error
}

log.verbose('app', 'Starting')

server.start(function () {
console.log((useEmoji ? emoji.get('dog') + ' ' : '') + 'Your Hoodie app has started on ' + url.format({
protocol: 'http',
hostname: config.connection.host,
port: config.connection.port
}))
console.log('Stop server with control + c')
})
console.log((process.platform === 'darwin' ? emoji.get('dog') + ' ' : '') + 'Your Hoodie app has started on:', server.info.uri)
console.log('Stop server with control + c')
})
5 changes: 2 additions & 3 deletions server/config/app-options.js → cli/app-defaults.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
module.exports = getAppOptions
module.exports = getAppDefaults

var join = require('path').join

function getAppOptions () {
var projectPath = process.cwd()
function getAppDefaults (projectPath) {
var pkg = require(join(projectPath, 'package.json'))
var appOptions = pkg.hoodie || {}

Expand Down
11 changes: 11 additions & 0 deletions cli/compatibility-check.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module.exports = compatibilityCheck

var semver = require('semver')

function compatibilityCheck (callback) {
if (semver.lt(process.versions.node, '4.0.0')) {
return callback(new Error('A node version >=4 is required to run Hoodie'))
}

callback(null)
}
26 changes: 26 additions & 0 deletions cli/hapi-options.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module.exports = getHapiOptions

var url = require('url')

function getHapiOptions (options) {
var hapiOptions = {
server: {},
connection: {
port: options.port,
address: options.bindAddress
}
}

if (options.loglevel === 'debug') {
hapiOptions.server.debug = {
request: ['error'],
log: ['error']
}
}

if (options.url) {
hapiOptions.connection.host = url.parse(options.url).hostname
}

return hapiOptions
}
14 changes: 14 additions & 0 deletions cli/hoodie-defaults.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module.exports = getHoodieDefaults

function getHoodieDefaults () {
return {
bindAddress: '127.0.0.1',
port: 8080,
data: '.hoodie',
public: 'public',
dbUrl: undefined,
inMemory: false,
loglevel: 'warn',
url: undefined
}
}
43 changes: 43 additions & 0 deletions cli/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
module.exports = run

var log = require('npmlog')
var Hapi = require('hapi')

var compatibilityCheck = require('./compatibility-check.js')
var getOptions = require('./options')
var getHapiOptions = require('./hapi-options')
var parseOptions = require('./parse-options')

var hoodie = require('../server').register

function run (callback) {
compatibilityCheck(function (error) {
if (error) {
log.error('env', error.message)
return callback(error)
}

var projectPath = process.cwd()
var options = getOptions(projectPath)

log.level = options.loglevel || 'warn'
log.verbose('app', 'Initialising')

var hapiOptions = getHapiOptions(options)
var server = new Hapi.Server(hapiOptions.server)
server.connection(hapiOptions.connection)

server.register({
register: hoodie,
options: parseOptions(options)
}, function (error) {
if (error) {
return callback(error)
}

server.start(function (error) {
callback(error, server)
})
})
})
}
26 changes: 26 additions & 0 deletions cli/log.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
var emoji = require('node-emoji')
var log = require('npmlog')

var headingPrefix = process.platform === 'darwin' ? emoji.get('dog') + ' ' : ''

log.style = {
silly: {inverse: true, bold: true},
verbose: {fg: 'brightBlue', bold: true},
info: {fg: 'brightGreen', bold: true},
http: {fg: 'brightGreen', bold: true},
warn: {fg: 'brightYellow', bold: true},
error: {fg: 'brightRed', bold: true},
silent: undefined
}
log.prefixStyle = {fg: 'magenta'}
log.headingStyle = {}
log.disp = {
silly: 'Sill',
verbose: 'Verb',
info: 'Info',
http: 'HTTP',
warn: 'Warn',
error: 'Err!',
silent: 'silent'
}
log.heading = headingPrefix + 'Hoodie'
94 changes: 94 additions & 0 deletions cli/options.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
module.exports = getCliOptions

var pick = require('lodash').pick
var rc = require('rc')
var yargs = require('yargs')

var getAppDefaults = require('./app-defaults')
var getHoodieDefaults = require('./hoodie-defaults')

function getCliOptions (projectPath) {
var hoodieDefaults = getHoodieDefaults()
var appDefaults = getAppDefaults(projectPath)

// Order of defaults
//
// 1. Hoodie defaults
// 2. App defaults
// 3. rc (https://www.npmjs.com/package/rc) – note we don’t read CLI through rc
var defaults = rc('hoodie', hoodieDefaults, appDefaults)

var options = yargs
.options({
loglevel: {
choices: [
'silly',
'verbose',
'info',
'http',
'warn',
'error',
'silent'
],
default: defaults.loglevel
},
port: {
type: 'number',
default: defaults.port,
describe: 'Port-number to run the Hoodie App on'
},
bindAddress: {
type: 'string',
default: defaults.bindAddress,
describe: 'Address that Hoodie binds to'
},
data: {
type: 'string',
default: defaults.data,
describe: 'Data path'
},
public: {
type: 'string',
default: defaults.public,
describe: 'Path to static assets'
},
m: {
alias: 'in-memory',
type: 'boolean',
default: defaults.inMemory,
describe: 'Whether to start the PouchDB Server in memory'
},
dbUrl: {
type: 'string',
default: defaults.dbUrl,
describe: 'If provided, uses external CouchDB. URL has to contain credentials.'
},
url: {
type: 'string',
default: defaults.url,
describe: 'URL at which Hoodie Server is accessible (e.g. http://myhoodieapp.com)'
}
})
.help('h', 'Show this help message')
.alias('h', 'help')
.alias('h', 'usage')
.showHelpOnFail(false, 'Specify --help for available options')
.version(function () {
try {
var pkg = require('../package.json')
console.log(pkg.version, '\n')
process.exit(0)
} catch (e) {
process.exit(1)
}
})
.alias('v', 'version')
.env('hoodie')
.epilogue('Options can also be specified as environment variables (prefixed with "hoodie_") or inside a ".hoodierc" file (json or ini).')
.wrap(Math.min(150, yargs.terminalWidth()))
.argv

// rc & yargs are setting keys we are not interested in, like in-memory or _
// so we only pick the relevant ones based on they keys of the default options.
return pick(options, Object.keys(hoodieDefaults))
}
Loading

0 comments on commit e79254d

Please sign in to comment.