This repository has been archived by the owner on Oct 19, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
163 lines (144 loc) · 4.53 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
const local = require('./config/local.js')
const _ = require('lodash')
const launch = new Date()
/**
* Cubic module loader
*/
class Cubic {
constructor (options) {
global.cubic = this
cubic.hooks = {}
cubic.config = {}
cubic.nodes = {}
cubic.log = new (require('./lib/logger.js'))()
// Set up error handlers
process.on('uncaughtException', this.throwSafely)
process.on('unhandledRejection', this.throwSafely)
// Set configuration
let config = {
local,
provided: options || {}
}
if (config.provided.environment === 'production') {
process.env.NODE_ENV = 'production'
config.local.logLevel = 'monitor'
}
if (!config.provided.skipAuthCheck) {
this.auth = require('./lib/auth.js')
}
this.setConfig('local', config)
}
/**
* Attach module config to global cubic object
*/
setConfig (id, config) {
const merged = this.getConfig(config)
cubic.config[id] = {}
// Add each key to global cubic object
for (var property in merged) {
cubic.config[id][property] = merged[property]
}
}
/**
* Merge default config with provided options
*/
getConfig (config) {
let local = _.cloneDeep(config.local) // merge seems to mutate original
return _.merge(local, config.provided)
}
/**
* Throw errors only in development or if the error occured pre-boot
*/
throwSafely (err) {
if (cubic.config.local.environment.toLowerCase() === 'production' &&
cubic.config.local.throwErrors === false) {
console.error(err)
} else {
throw err
}
}
/**
* Hook functions to be executed before specific node is initialized while
* making node config available to the Hook
*/
hook (node, fn) {
let id = typeof node === 'string' ? node : node.name.toLowerCase()
let hooks = _.get(cubic.hooks, id)
// Create empty array for given node if previously empty
if (!hooks) {
_.set(cubic.hooks, id, [])
hooks = []
}
hooks.push(fn)
_.set(cubic.hooks, id, hooks)
}
/**
* Execute hooks for specific node
*/
async runHooks (id) {
let hooks = _.get(cubic.hooks, id)
if (hooks) {
hooks.forEach(async hook => {
await hook()
cubic.log.monitor(`Hooked ${hook.name} on ${id}`, true, `${new Date() - launch}ms`)
})
await Promise.all(hooks)
}
}
/**
* Let cubic handle framework modules
*/
async use (node) {
let id = node.constructor.name.toLowerCase() // Class name of entrypoint
let group = node.config.provided.group
// Ignore node if disabled
if (node.config.provided.disable) {
return
}
// Verify RSA keys being set in config and manage user credentials
if (!cubic.config.local.skipAuthCheck) {
node.config = await this.auth.verify(id, node.config)
}
// Only set initial config when no group is specified; group will already
// have the config for sub-nodes set (also follows the same schema as
// nodes, e.g. cubic.nodes.auth.api -> cubic.config.auth.api)
if (!group) {
this.setConfig(id, node.config)
}
// If sub-node does have group, we still have to merge the default config
// with what's provided by the group node.
else {
cubic.config[group] = cubic.config[group] || {}
cubic.config[group][id] = this.getConfig(node.config)
}
// Run hooks before initiating node
await this.runHooks(`${group ? group + '.' : ''}${id}`)
// Given node is a bigger one (not core or api): run init script and provide
// empty object for other nodes to attach to
if (id !== 'api' && id !== 'core') {
cubic.nodes[id] = {}
await node.init()
}
// Actual node (cubic-core or cubic-api)
else {
// Assign node directly by name or as part of bigger node
if (group) {
cubic.nodes[group] = cubic.nodes[group] || {}
cubic.nodes[group][id] = node
await cubic.nodes[group][id].init()
} else {
cubic.nodes[id] = node
await cubic.nodes[id].init()
}
let name = group ? `${group} ${id}` : id
let port = id === 'api' ? ` (Listening on :${node.config.provided.port || node.config.local.port})` : ''
cubic.log.monitor(`Loaded ${name} node${port}`, true, `${new Date() - launch}ms`)
}
}
}
/**
* Pass options to constructor on require
*/
module.exports = (options) => {
return new Cubic(options)
}