UNPKG

7.45 kBJavaScriptView Raw
1
2import Emittery from 'emittery'
3
4import utils from '@midgar/utils'
5import Config from './libs/config'
6import Logger from './libs/logger'
7import PluginManager from './libs/plugin-manager'
8
9/**
10 * Midgar Class
11 * Manage Config, plugin manager, logeer and events
12 * @class
13 */
14class Midgar extends Emittery {
15 constructor () {
16 super()
17
18 /**
19 * Config instance
20 * @type {Config}
21 */
22 this.config = null
23
24 /**
25 * Logger instance
26 * @type {Logger}
27 */
28 this.logger = null
29
30 /**
31 * Plugin manager instance
32 * @type {PluginManager}
33 */
34 this.pm = null
35
36 /**
37 * Commander instance
38 * @type {Commander}
39 * @see {@link https://www.npmjs.com/package/commander|commander doc}
40 */
41 this.cli = null
42
43 // watch process to prevent crash and gracefull exit
44 this._watchProcessExit()
45 }
46
47 /**
48 * Start Midgar
49 *
50 * Load the config, init logger and plugin manager
51 *
52 * @param {Sting} configPath config dir path
53 */
54 async start (configPath) {
55 await this.loadConfig(configPath)
56 await this.initLogger()
57 await this.initPluginManager()
58 }
59
60 /**
61 * load the config
62 */
63 async loadConfig (dirPath) {
64 // set the config dir
65 this.configPath = dirPath
66 this.config = new Config(this)
67
68 // Load the configs
69 await this.config.loadConfigs(dirPath, 'config', true)
70
71 process.env.TZ = this.config.tz || 'Europe/Paris'
72
73 this.config.log.level = this.config.log && this.config.log.level ? this.config.log.level : 'warn'
74
75 if (!this.config.pm) this.config.pm = {}
76 if (this.config.pm.localPath && typeof this.config.pm.localPath !== 'string') throw new TypeError('@midgar/midgar: Invalid pm.localPath type in Midgar config !')
77
78 // Flag config loaded
79 this._isConfigLoaded = true
80 }
81
82 /**
83 * Create logger instace and init
84 */
85 async initLogger () {
86 // Check config is loaded
87 if (this.config === null) throw new Error('@midgar/midgar: Load config before init logger !')
88
89 this.logger = this.config.logger ? this.config.logger(this.config.log) : new Logger(this.config.log)
90 await this.logger.init()
91
92 // Flag logger is init
93 this._isLoggerInit = true
94 }
95
96 /**
97 * @description Init plugin manager
98 */
99 async initPluginManager () {
100 // Check load stat
101 if (this.config === null) throw new Error('@midgar/midgar: Load config before init pm !')
102 if (this.logger === null) throw new Error('@midgar/midgar: Init logger before init pm !')
103
104 utils.timer.start('midgar-init')
105 this.debug('@midgar/midgar: init PluginManager...')
106
107 // Init the plugin manager
108 await this._initPluginManager()
109
110 /**
111 * afterInit event.
112 * @event @midgar/midgar:afterInit
113 */
114 await this.emit('@midgar/midgar:afterInit')
115
116 const time = utils.timer.getTime('midgar-init')
117 this.debug(`@midgar:midgar: PluginManager has init in ${time} ms.`)
118 }
119
120 /**
121 * Init plugin manager
122 * @private
123 */
124 async _initPluginManager () {
125 this.pm = new PluginManager(this)
126 await this.pm.init()
127 }
128
129 /**
130 * Add a plugin in the plugins.json config file
131 * Return true if the plugin was added or false
132 *
133 * @param {String} name Plugin name
134 *
135 * @return {Boolean}
136 */
137 addPlugin (name) {
138 // Instance pm if not exist for plugin cli command
139 const pm = this.pm ? this.pm : new PluginManager(this)
140 return pm.addPlugin(name)
141 }
142
143 /**
144 * Remove a plugin from the plugins.json config file
145 * Return true if the plugin was removed or false
146 *
147 * @param {String} name Plugin name
148 *
149 * @return {Boolean}
150 */
151 async removePlugin (name) {
152 // Instance pm if not exist for plugin cli command
153 const pm = this.pm ? this.pm : new PluginManager(this)
154 return pm.removePlugin(name)
155 }
156
157 /**
158 * Enable a plugin in the plugins.json config file
159 * Return true if the plugin was enabled or false
160 *
161 * @param {String} name Plugin name
162 *
163 * @return {Boolean}
164 */
165 async enablePlugin (name) {
166 // Instance pm if not exist for plugin cli command
167 const pm = this.pm ? this.pm : new PluginManager(this)
168 return pm.enablePlugin(name)
169 }
170
171 /**
172 * Disable a plugin in the plugins.json config file
173 * Return true if the plugin was enabled or false
174 *
175 * @param {String} name Plugin name
176 *
177 * @return {Boolean}
178 */
179 async disablePlugin (name) {
180 // Instance pm if not exist for plugin cli command
181 const pm = this.pm ? this.pm : new PluginManager(this)
182 return pm.disablePlugin(name)
183 }
184
185 /**
186 * Return the node env code
187 * @return {string}
188 */
189 getNodeEnv () {
190 return process.env.NODE_ENV
191 }
192
193 /**
194 * Exit
195 * Wait for the logger gracefull exit the process
196 */
197 async exit () {
198 // Check load stat
199 if (this.pm === null) throw new Error('@midgar/midgar: Start Midgar before stop !')
200
201 // Stop servers if there a runing
202 await this.stop()
203
204 if (this.logger && this.logger.exit && !this._hasExitLogger) {
205 this._hasExitLogger = true
206 await this.logger.exit()
207 }
208
209 // exit process
210 process.exit(0)
211 }
212
213 /**
214 * Stop Midgar
215 */
216 async stop () {
217 /**
218 * stop event.
219 * @event @midgar/midgar:stop
220 */
221 await this.emit('@midgar/midgar:stop')
222 }
223
224 /**
225 * listen process exit signal signal and graceful exit
226 * @private
227 */
228 _watchProcessExit () {
229 process.stdin.resume()// prevent program close instantly
230
231 // exit handler
232 const exitHandler = () => {
233 // flag exit to prevent multiple exit signals
234 if (!this._exit) { this._exit = true } else { return }
235 // start exit sequence
236 this.exit()
237 }
238
239 // Catch uncaught Exceptions
240 const uncaughtExceptionHandler = (error) => {
241 if (this.logger) {
242 // log exception
243 this.logger.error('Uncaught Exception :(')
244 this.logger.error(error)
245 } else {
246 console.error(error)
247 }
248 process.exit()
249 }
250 // Catch uncaught Exceptions
251 const uncaughtRejectionHandler = (error) => {
252 if (this.logger) {
253 // log exception
254 this.logger.error('Uncaught Rejection :(')
255 this.logger.error(error)
256 } else {
257 console.error(error)
258 }
259
260 process.exit()
261 }
262
263 // app is closing like process.exit()
264 process.on('exit', exitHandler.bind(null))
265 // ctrl+c event
266 process.on('SIGINT', exitHandler.bind(null))
267 // kill pid
268 process.on('SIGUSR1', exitHandler.bind(null))
269 process.on('SIGUSR2', exitHandler.bind(null))
270 // uncaught exceptions
271 process.on('uncaughtException', uncaughtExceptionHandler.bind(null))
272 process.on('unhandledRejection', uncaughtRejectionHandler.bind(null))
273 }
274
275 /**
276 * Log an error message
277 * @param {...any} args
278 */
279 error (...args) {
280 this.logger.error(...args)
281 }
282
283 /**
284 * Log a warning message
285 * @param {...any} args
286 */
287 warn (...args) {
288 this.logger.warn(...args)
289 }
290
291 /**
292 * Log an info message
293 * @param {...any} args
294 */
295 info (...args) {
296 this.logger.info(...args)
297 }
298
299 /**
300 * Log a verbose message
301 * @param {...any} args
302 */
303 verbose (...args) {
304 this.logger.verbose(...args)
305 }
306
307 /**
308 * Log a debug message
309 * @param {...any} args
310 */
311 debug (...args) {
312 this.logger.debug(...args)
313 }
314
315 /**
316 * Log a silly message
317 * @param {...any} args
318 */
319 silly (...args) {
320 this.logger.silly(...args)
321 }
322}
323
324export default Midgar