正在显示
11 个修改的文件
包含
199 行增加
和
159 行删除
@@ -24,19 +24,6 @@ eskimo --help | @@ -24,19 +24,6 @@ eskimo --help | ||
24 | ``` | 24 | ``` |
25 | 25 | ||
26 | 26 | ||
27 | -## Components | ||
28 | - | ||
29 | -Using `electrolyte`, you an inject the following dependencies into your app with `eskimo`: | ||
30 | - | ||
31 | -* `app` - returns an instance of `express()` | ||
32 | -* `error-handler` - returns an error handler that can be used via `app.use` | ||
33 | -* `db` - returns connection to MongoDB | ||
34 | -* `logger` - returns a Winston logger instance | ||
35 | -* `model-common-plugin` - returns a Mongoose plugin for common schema paths | ||
36 | -* `sessions` - returns connection to Redis | ||
37 | -* `settings` - returns config | ||
38 | - | ||
39 | - | ||
40 | ## Contributors | 27 | ## Contributors |
41 | 28 | ||
42 | * Nick Baugh <niftylettuce@gmail.com> | 29 | * Nick Baugh <niftylettuce@gmail.com> |
1 | 1 | ||
2 | -// # db | 2 | +// # boot - db |
3 | 3 | ||
4 | var mongoose = require('mongoose') | 4 | var mongoose = require('mongoose') |
5 | var _ = require('underscore') | 5 | var _ = require('underscore') |
@@ -30,4 +30,4 @@ exports = module.exports = function(logger, settings) { | @@ -30,4 +30,4 @@ exports = module.exports = function(logger, settings) { | ||
30 | } | 30 | } |
31 | 31 | ||
32 | exports['@singleton'] = true | 32 | exports['@singleton'] = true |
33 | -exports['@require'] = [ 'logger', 'settings' ] | 33 | +exports['@require'] = [ 'igloo/logger', 'igloo/settings' ] |
1 | 1 | ||
2 | -// # error handler | 2 | +// # boot - error handler |
3 | 3 | ||
4 | var _ = require('underscore') | 4 | var _ = require('underscore') |
5 | var util = require('util') | 5 | var util = require('util') |
6 | 6 | ||
7 | exports = module.exports = function(logger, settings) { | 7 | exports = module.exports = function(logger, settings) { |
8 | 8 | ||
9 | - return function(err, req, res, next) { | ||
10 | - | ||
11 | - // set default error status code | ||
12 | - res.statusCode = (_.isNumber(err.status)) ? err.status : 500 | ||
13 | - | ||
14 | - if (!_.isString(err.message)) | ||
15 | - err.message = 'An unknown error has occured, please try again' | ||
16 | - | ||
17 | - if (_.isObject(err) && _.isNumber(err.code) && err.code === 11000) { | ||
18 | - // <https://github.com/LearnBoost/mongoose/issues/2129> | ||
19 | - var field = err.message.split('index: test.')[1].split('.$')[1] | ||
20 | - // now we have `email_1 dup key` | ||
21 | - field = field.split(' dup key')[0] | ||
22 | - field = field.substring(0, field.lastIndexOf('_')) | ||
23 | - err.message = util.format('Duplicate %s already exists in database, try making a more unique value', field) | ||
24 | - err.param = field | ||
25 | - } | ||
26 | - | ||
27 | - // if we pass an error object, then we want to simply return the message... | ||
28 | - // if we pass an object, then we want to do a stack trace, and then return the object + stack | ||
29 | - var error = {} | ||
30 | - | ||
31 | - // set error type | ||
32 | - error.type = _.isString(err.param) ? 'invalid_request_error' : 'api_error' | ||
33 | - | ||
34 | - if (error.type === 'invalid_request_error' && res.statusCode === 500) | ||
35 | - res.statusCode = 400 | ||
36 | - | ||
37 | - // set error message and stack trace | ||
38 | - if (util.isError(err)) { | ||
39 | - error.message = err.message | ||
40 | - } else { | ||
41 | - _.extend(error, err) | ||
42 | - } | ||
43 | - | ||
44 | - // set status code for BadRequestError | ||
45 | - if (_.isString(error.name) && error.name === 'BadRequestError') { | ||
46 | - error.type = 'invalid_request_error' | ||
47 | - res.statusCode = 400 | ||
48 | - delete error.name | ||
49 | - } | ||
50 | - | ||
51 | - if (settings.showStack) | ||
52 | - error.stack = _.isUndefined(err.stack) ? new Error(err.message).stack : err.stack | ||
53 | - | ||
54 | - // set error level | ||
55 | - var level = (res.statusCode < 500) ? 'warn' : 'error' | ||
56 | - logger[level](error) | ||
57 | - | ||
58 | - // set error back to warning if it was warn | ||
59 | - // logger level type = "warn" | ||
60 | - // req.flash messages type = "warning" | ||
61 | - if (level === 'warn') | ||
62 | - level = 'warning' | ||
63 | - | ||
64 | - // if we have a mongoose validation err | ||
65 | - // then we know to output all the errors | ||
66 | - if (_.isObject(error.errors) && !_.isEmpty(error.errors)) { | ||
67 | - var messages = [] | ||
68 | - _.each(error.errors, function(errMsg) { | ||
69 | - if (_.isString(errMsg.message)) | ||
70 | - messages.push(errMsg.message) | ||
71 | - }) | ||
72 | - if (!_.isEmpty(messages)) | ||
73 | - error.message = messages.join(' ') | ||
74 | - } | ||
75 | - | ||
76 | - res.format({ | ||
77 | - text: function() { | ||
78 | - res.send(error.message) | ||
79 | - }, | ||
80 | - html: function() { | ||
81 | - req.flash(level, error.message) | ||
82 | - res.redirect('back') | ||
83 | - }, | ||
84 | - json: function() { | ||
85 | - res.json({ error: error }) | 9 | + return function() { |
10 | + | ||
11 | + var app = this | ||
12 | + | ||
13 | + app.use(function(err, req, res, next) { | ||
14 | + | ||
15 | + // set default error status code | ||
16 | + res.statusCode = (_.isNumber(err.status)) ? err.status : 500 | ||
17 | + | ||
18 | + if (!_.isString(err.message)) | ||
19 | + err.message = 'An unknown error has occured, please try again' | ||
20 | + | ||
21 | + if (_.isObject(err) && _.isNumber(err.code) && err.code === 11000) { | ||
22 | + // <https://github.com/LearnBoost/mongoose/issues/2129> | ||
23 | + var field = err.message.split('index: test.')[1].split('.$')[1] | ||
24 | + // now we have `email_1 dup key` | ||
25 | + field = field.split(' dup key')[0] | ||
26 | + field = field.substring(0, field.lastIndexOf('_')) | ||
27 | + err.message = util.format('Duplicate %s already exists in database, try making a more unique value', field) | ||
28 | + err.param = field | ||
29 | + } | ||
30 | + | ||
31 | + // if we pass an error object, then we want to simply return the message... | ||
32 | + // if we pass an object, then we want to do a stack trace, and then return the object + stack | ||
33 | + var error = {} | ||
34 | + | ||
35 | + // set error type | ||
36 | + error.type = _.isString(err.param) ? 'invalid_request_error' : 'api_error' | ||
37 | + | ||
38 | + if (error.type === 'invalid_request_error' && res.statusCode === 500) | ||
39 | + res.statusCode = 400 | ||
40 | + | ||
41 | + // set error message and stack trace | ||
42 | + if (util.isError(err)) { | ||
43 | + error.message = err.message | ||
44 | + } else { | ||
45 | + _.extend(error, err) | ||
86 | } | 46 | } |
47 | + | ||
48 | + // set status code for BadRequestError | ||
49 | + if (_.isString(error.name) && error.name === 'BadRequestError') { | ||
50 | + error.type = 'invalid_request_error' | ||
51 | + res.statusCode = 400 | ||
52 | + delete error.name | ||
53 | + } | ||
54 | + | ||
55 | + if (settings.showStack) | ||
56 | + error.stack = _.isUndefined(err.stack) ? new Error(err.message).stack : err.stack | ||
57 | + | ||
58 | + // set error level | ||
59 | + var level = (res.statusCode < 500) ? 'warn' : 'error' | ||
60 | + logger[level](error) | ||
61 | + | ||
62 | + // set error back to warning if it was warn | ||
63 | + // logger level type = "warn" | ||
64 | + // req.flash messages type = "warning" | ||
65 | + if (level === 'warn') | ||
66 | + level = 'warning' | ||
67 | + | ||
68 | + // if we have a mongoose validation err | ||
69 | + // then we know to output all the errors | ||
70 | + if (_.isObject(error.errors) && !_.isEmpty(error.errors)) { | ||
71 | + var messages = [] | ||
72 | + _.each(error.errors, function(errMsg) { | ||
73 | + if (_.isString(errMsg.message)) | ||
74 | + messages.push(errMsg.message) | ||
75 | + }) | ||
76 | + if (!_.isEmpty(messages)) | ||
77 | + error.message = messages.join(' ') | ||
78 | + } | ||
79 | + | ||
80 | + res.format({ | ||
81 | + text: function() { | ||
82 | + res.send(error.message) | ||
83 | + }, | ||
84 | + html: function() { | ||
85 | + req.flash(level, error.message) | ||
86 | + res.redirect('back') | ||
87 | + }, | ||
88 | + json: function() { | ||
89 | + res.json({ error: error }) | ||
90 | + } | ||
91 | + }) | ||
92 | + | ||
87 | }) | 93 | }) |
88 | 94 | ||
89 | } | 95 | } |
@@ -91,4 +97,4 @@ exports = module.exports = function(logger, settings) { | @@ -91,4 +97,4 @@ exports = module.exports = function(logger, settings) { | ||
91 | } | 97 | } |
92 | 98 | ||
93 | exports['@singleton'] = true | 99 | exports['@singleton'] = true |
94 | -exports['@require'] = [ 'logger', 'settings' ] | 100 | +exports['@require'] = [ 'igloo/logger', 'igloo/settings' ] |
1 | 1 | ||
2 | -// # logger | 2 | +// # boot - logger |
3 | 3 | ||
4 | var mergeDefaults = require('merge-defaults') | 4 | var mergeDefaults = require('merge-defaults') |
5 | var winston = require('winston') | 5 | var winston = require('winston') |
@@ -46,4 +46,4 @@ exports = module.exports = function(settings) { | @@ -46,4 +46,4 @@ exports = module.exports = function(settings) { | ||
46 | } | 46 | } |
47 | 47 | ||
48 | exports['@singleton'] = true | 48 | exports['@singleton'] = true |
49 | -exports['@require'] = [ 'settings' ] | 49 | +exports['@require'] = [ 'igloo/settings' ] |
1 | 1 | ||
2 | -// # boot - model common plugin | 2 | +// # boot - mongoose plugin |
3 | 3 | ||
4 | var _ = require('underscore') | 4 | var _ = require('underscore') |
5 | var jsonSelect = require('mongoose-json-select') | 5 | var jsonSelect = require('mongoose-json-select') |
@@ -58,4 +58,4 @@ exports = module.exports = function(settings) { | @@ -58,4 +58,4 @@ exports = module.exports = function(settings) { | ||
58 | } | 58 | } |
59 | 59 | ||
60 | exports['@singleton'] = true | 60 | exports['@singleton'] = true |
61 | -exports['@require'] = [ 'settings' ] | 61 | +exports['@require'] = [ 'igloo/settings' ] |
lib/boot/server.js
0 → 100644
1 | + | ||
2 | +// # boot - server | ||
3 | + | ||
4 | +// Inspired by `bixby-server` by Jared Hanson | ||
5 | + | ||
6 | +var https = require('https') | ||
7 | +var http = require('http') | ||
8 | +var cluster = require('cluster') | ||
9 | +var os = require('os') | ||
10 | +var path = require('path') | ||
11 | + | ||
12 | +exports = module.exports = function(logger, settings) { | ||
13 | + | ||
14 | + return function(done) { | ||
15 | + | ||
16 | + if (cluster.isMaster && settings.server.cluster) { | ||
17 | + | ||
18 | + var size = settings.server.cluster.size || os.cpus().length | ||
19 | + | ||
20 | + logger.info('creating cluster with %d workers', size) | ||
21 | + | ||
22 | + for (var i=0; i<size; i++) { | ||
23 | + logger.info('spawning worker #%d', i + 1) | ||
24 | + cluster.fork() | ||
25 | + } | ||
26 | + | ||
27 | + cluster.on('fork', function(worker) { | ||
28 | + logger.info('worker #%s with pid %d spawned', worker.id, worker.process.pid) | ||
29 | + }) | ||
30 | + | ||
31 | + cluster.on('online', function(worker) { | ||
32 | + logger.info('worker #%s with pid %d online', worker.id, worker.process.pid) | ||
33 | + }) | ||
34 | + | ||
35 | + cluster.on('listening', function(worker, addr) { | ||
36 | + logger.info('worker #%s with pid %d listening on %s:%d', worker.id, worker.process.pid, addr.address, addr.port) | ||
37 | + }) | ||
38 | + | ||
39 | + cluster.on('disconnect', function(worker) { | ||
40 | + logger.info('worker #%s with pid %d disconnected', worker.id, worker.process.pid) | ||
41 | + }) | ||
42 | + | ||
43 | + cluster.on('exit', function(worker, code, signal) { | ||
44 | + logger.error('worker #%s with pid %d exited with code/signal', worker.id, worker.process.pid, signal, code) | ||
45 | + if (worker.suicide) return | ||
46 | + logger.info('worker #%s restarting', worker.id) | ||
47 | + cluster.fork() | ||
48 | + }) | ||
49 | + | ||
50 | + } else { | ||
51 | + | ||
52 | + if (settings.server.ssl.enabled) | ||
53 | + this.server = https.createServer(settings.server.ssl.options, this) | ||
54 | + else | ||
55 | + this.server = http.createServer(this) | ||
56 | + | ||
57 | + this.server.listen(settings.server.port, settings.server.host, function() { | ||
58 | + var addr = this.address() | ||
59 | + logger.info('app listening on %s:%d', addr.address, addr.port) | ||
60 | + done() | ||
61 | + }) | ||
62 | + | ||
63 | + } | ||
64 | + | ||
65 | + } | ||
66 | + | ||
67 | +} | ||
68 | + | ||
69 | +exports['@singleton'] = true | ||
70 | +exports['@require'] = [ 'igloo/logger', 'igloo/settings' ] |
1 | 1 | ||
2 | -// # sessions | 2 | +// # boot - sessions |
3 | 3 | ||
4 | var session = require('express-session') | 4 | var session = require('express-session') |
5 | var RedisStore = require('connect-redis')(session) | 5 | var RedisStore = require('connect-redis')(session) |
@@ -19,4 +19,4 @@ exports = module.exports = function(logger, settings) { | @@ -19,4 +19,4 @@ exports = module.exports = function(logger, settings) { | ||
19 | } | 19 | } |
20 | 20 | ||
21 | exports['@singleton'] = true | 21 | exports['@singleton'] = true |
22 | -exports['@require'] = [ 'logger', 'settings' ] | 22 | +exports['@require'] = [ 'igloo/logger', 'igloo/settings' ] |
1 | 1 | ||
2 | -// # settings | 2 | +// # boot - settings |
3 | 3 | ||
4 | +var _ = require('underscore') | ||
5 | +var util = require('util') | ||
4 | var mergeDefaults = require('merge-defaults') | 6 | var mergeDefaults = require('merge-defaults') |
5 | 7 | ||
6 | exports = module.exports = function(config) { | 8 | exports = module.exports = function(config) { |
@@ -9,6 +11,9 @@ exports = module.exports = function(config) { | @@ -9,6 +11,9 @@ exports = module.exports = function(config) { | ||
9 | 11 | ||
10 | var env = process.env.NODE_ENV || 'development' | 12 | var env = process.env.NODE_ENV || 'development' |
11 | 13 | ||
14 | + if (!_.isObject(config[env])) | ||
15 | + throw new Error(util.format('Unknown environment %s', env)) | ||
16 | + | ||
12 | mergeDefaults(settings, config[env], config.defaults) | 17 | mergeDefaults(settings, config[env], config.defaults) |
13 | 18 | ||
14 | return settings | 19 | return settings |
1 | 1 | ||
2 | -// # app | 2 | +// # boot - update notifier |
3 | 3 | ||
4 | -var express = require('express') | ||
5 | -var winstonRequestLogger = require('winston-request-logger') | ||
6 | -var bootable = require('bootable') | ||
7 | var _ = require('underscore') | 4 | var _ = require('underscore') |
8 | var updateNotifier = require('update-notifier') | 5 | var updateNotifier = require('update-notifier') |
9 | -var path = require('path') | ||
10 | -var expressResource = require('express-resource') | ||
11 | 6 | ||
12 | exports = module.exports = function(logger, settings) { | 7 | exports = module.exports = function(logger, settings) { |
13 | 8 | ||
14 | - // check for updates to all packages when not in production | ||
15 | - if (settings.updateNotifier.enabled) | ||
16 | - _.each(settings.pkg.dependencies, function(version, name) { | ||
17 | - var notifier = updateNotifier({ | ||
18 | - packageName: name, | ||
19 | - packageVersion: version, | ||
20 | - optOut: settings.updateNotifier.dependencies[name] || false, | ||
21 | - updateCheckInterval: settings.updateNotifier.updateCheckInterval | 1000 * 60 * 60, // hourly | ||
22 | - updateCheckTimeout: settings.updateNotifier.updateCheckTimeout | 1000 * 20 // 20 seconds | 9 | + return function() { |
10 | + | ||
11 | + // check for updates to all packages when not in production | ||
12 | + if (settings.updateNotifier.enabled) | ||
13 | + _.each(settings.pkg.dependencies, function(version, name) { | ||
14 | + var notifier = updateNotifier({ | ||
15 | + packageName: name, | ||
16 | + packageVersion: version, | ||
17 | + optOut: settings.updateNotifier.dependencies[name] || false, | ||
18 | + updateCheckInterval: settings.updateNotifier.updateCheckInterval | 1000 * 60 * 60, // hourly | ||
19 | + updateCheckTimeout: settings.updateNotifier.updateCheckTimeout | 1000 * 20 // 20 seconds | ||
20 | + }) | ||
21 | + if (_.isUndefined(notifier.update) || !_.isString(notifier.update.latest)) return | ||
22 | + logger.warn( | ||
23 | + '%s of %s released (current: %s), run `npm install -S %s@%s` to upgrade', | ||
24 | + notifier.update.latest, | ||
25 | + name, | ||
26 | + version, | ||
27 | + name, | ||
28 | + notifier.update.latest | ||
29 | + ) | ||
23 | }) | 30 | }) |
24 | - if (_.isUndefined(notifier.update) || !_.isString(notifier.update.latest)) return | ||
25 | - logger.warn( | ||
26 | - '%s of %s released (current: %s), run `npm install -S %s@%s` to upgrade', | ||
27 | - notifier.update.latest, | ||
28 | - name, | ||
29 | - version, | ||
30 | - name, | ||
31 | - notifier.update.latest | ||
32 | - ) | ||
33 | - }) | ||
34 | - | ||
35 | - // create the app | ||
36 | - var app = bootable(express()) | ||
37 | - | ||
38 | - // winston request logger before everything else | ||
39 | - // but only if it was enabled in settings | ||
40 | - if (settings.logger.requests) | ||
41 | - app.use(winstonRequestLogger.create(logger)) | ||
42 | - | ||
43 | - // integrate express-resource | ||
44 | - app = expressResource(app) | ||
45 | - | ||
46 | - return app | 31 | + |
32 | + } | ||
47 | 33 | ||
48 | } | 34 | } |
49 | 35 | ||
50 | exports['@singleton'] = true | 36 | exports['@singleton'] = true |
51 | -exports['@require'] = [ 'logger', 'settings' ] | 37 | +exports['@require'] = [ 'igloo/logger', 'igloo/settings' ] |
@@ -15,18 +15,7 @@ | @@ -15,18 +15,7 @@ | ||
15 | // # igloo | 15 | // # igloo |
16 | 16 | ||
17 | var path = require('path') | 17 | var path = require('path') |
18 | -var os = require('os') | ||
19 | -var cluster = require('cluster') | ||
20 | 18 | ||
21 | -var bootDir = path.join(__dirname, 'boot') | ||
22 | - | ||
23 | -module.exports = { | ||
24 | - loader: function(id) { | ||
25 | - return require(path.join(bootDir, id)) | ||
26 | - }, | ||
27 | - app: function(IoC) { | ||
28 | - IoC.loader(IoC.node(bootDir)) | ||
29 | - var app = IoC.create('app') | ||
30 | - return app | ||
31 | - } | 19 | +module.exports = function(id) { |
20 | + return require(path.join(__dirname, 'boot', id)) | ||
32 | } | 21 | } |
1 | { | 1 | { |
2 | "name": "igloo", | 2 | "name": "igloo", |
3 | - "version": "0.0.4", | 3 | + "version": "0.0.4-patch", |
4 | "description": "Igloo is a lightweight, fast, and minimal framework for rapid development", | 4 | "description": "Igloo is a lightweight, fast, and minimal framework for rapid development", |
5 | - "main": "./index.js", | 5 | + "main": "./lib", |
6 | "repository": { | 6 | "repository": { |
7 | "type": "git", | 7 | "type": "git", |
8 | "url": "git://github.com/niftylettuce/igloo.git" | 8 | "url": "git://github.com/niftylettuce/igloo.git" |
@@ -18,8 +18,6 @@ | @@ -18,8 +18,6 @@ | ||
18 | "chalk": "^0.4.0", | 18 | "chalk": "^0.4.0", |
19 | "commander": "^2.2.0", | 19 | "commander": "^2.2.0", |
20 | "connect-redis": "~2.0.0", | 20 | "connect-redis": "~2.0.0", |
21 | - "express": "~4.2.0", | ||
22 | - "express-resource": "git://github.com/niftylettuce/express-resource", | ||
23 | "express-session": "^1.2.1", | 21 | "express-session": "^1.2.1", |
24 | "merge-defaults": "^0.1.0", | 22 | "merge-defaults": "^0.1.0", |
25 | "mongoose": "~3.8.7", | 23 | "mongoose": "~3.8.7", |
@@ -28,7 +26,6 @@ | @@ -28,7 +26,6 @@ | ||
28 | "underscore": "~1.6.0", | 26 | "underscore": "~1.6.0", |
29 | "update-notifier": "git://github.com/niftylettuce/update-notifier", | 27 | "update-notifier": "git://github.com/niftylettuce/update-notifier", |
30 | "winston": "git://github.com/niftylettuce/winston", | 28 | "winston": "git://github.com/niftylettuce/winston", |
31 | - "winston-mongodb": "~0.4.3", | ||
32 | - "winston-request-logger": "^1.0.5" | 29 | + "winston-mongodb": "~0.4.3" |
33 | } | 30 | } |
34 | } | 31 | } |
请
注册
或
登录
后发表评论