1 | global.Promise = require('bluebird');
|
2 | const pkg = require('../package.json');
|
3 | const http = require('http');
|
4 | const path = require('path');
|
5 | const fs = require('fs');
|
6 | const os = require('os');
|
7 | const Koa = require('koa');
|
8 | const convert = require('koa-convert');
|
9 | const koaBody = require('koa-body');
|
10 | const helmet = require('koa-helmet');
|
11 | const cors = require('koa-cors');
|
12 |
|
13 | const category = 'core.http';
|
14 |
|
15 |
|
16 | const print = Symbol('print');
|
17 | const bootstrap = Symbol('bootstrap');
|
18 |
|
19 | module.exports = class {
|
20 | |
21 |
|
22 |
|
23 | constructor () {
|
24 |
|
25 | global.share = {};
|
26 | global.share.startTime = Date.now();
|
27 |
|
28 |
|
29 | const appPath = path.resolve(process.mainModule.children[0].parent.filename);
|
30 | global.share.APP_PATH = appPath.substr(0, appPath.lastIndexOf(path.sep)).trim().replace('start', '');
|
31 | global.share.FRAMEWORK_PATH = `${share.APP_PATH}node_modules${path.sep}share-node${path.sep}`;
|
32 | global.share.ENV = appPath.substr(appPath.lastIndexOf(path.sep) + 1).trim().replace('.js', '');
|
33 |
|
34 |
|
35 |
|
36 |
|
37 | const defaultConfig = require('./config');
|
38 | const configFile = `${share.APP_PATH}config${path.sep}config.${share.ENV}.js`;
|
39 | global.share.config = fs.existsSync(configFile) ? require(configFile) : {};
|
40 | share.config.env = share.ENV;
|
41 | share.config.port = share.config.port || defaultConfig.port;
|
42 | share.config.middleware = share.config.middleware || defaultConfig.middleware;
|
43 | share.config.websocketMiddleware = share.config.websocketMiddleware || defaultConfig.websocketMiddleware;
|
44 | share.config.apiPrefix = share.config.apiPrefix || defaultConfig.apiPrefix;
|
45 | share.config.websocket = !!share.config.websocket;
|
46 | share.config.requestLog = !!share.config.requestLog;
|
47 | share.config.log4js = share.config.log4js || defaultConfig.log4js;
|
48 |
|
49 |
|
50 | require('./globals');
|
51 | this.LOG = getLogger(category);
|
52 | this.LOG.info(`config file: ${configFile}`);
|
53 |
|
54 |
|
55 | this[bootstrap]();
|
56 | }
|
57 |
|
58 | |
59 |
|
60 |
|
61 | start () {
|
62 |
|
63 | const app = new Koa();
|
64 |
|
65 |
|
66 | app.use(koaBody({multipart: true}));
|
67 | app.use(helmet());
|
68 | if (share.config.cors) {
|
69 | app.use(convert(cors()));
|
70 | }
|
71 |
|
72 |
|
73 | share.config.middleware.forEach((m) => {
|
74 | let who = 'app';
|
75 |
|
76 |
|
77 | let mFile = `${share.APP_PATH}app${path.sep}middleware${path.sep}${m}.js`;
|
78 | if (!fs.existsSync(mFile)) {
|
79 |
|
80 | mFile = `${share.APP_PATH}app${path.sep}common${path.sep}middleware${path.sep}${m}.js`;
|
81 | }
|
82 | if (!fs.existsSync(mFile)) {
|
83 | who = 'framework';
|
84 | mFile = `${share.FRAMEWORK_PATH}lib${path.sep}middleware${path.sep}${m}.js`;
|
85 | }
|
86 | app.use(require(mFile)(share.config[m]));
|
87 | this.LOG.info(`require ${who} middleware: ${m}`);
|
88 | return m;
|
89 | });
|
90 |
|
91 |
|
92 | const logger = getLogger(category);
|
93 | process.on('uncaughtException', (err) => {
|
94 | logger.error(err);
|
95 | });
|
96 |
|
97 | process.on('SIGTERM', () => {
|
98 | this.LOG.info('on SIGTERM | server is down ...');
|
99 | process.exit(0);
|
100 | });
|
101 |
|
102 | process.on('SIGINT', () => {
|
103 | this.LOG.info('on SIGINT | server is down ...');
|
104 | process.exit(0);
|
105 | });
|
106 |
|
107 |
|
108 | const server = http.createServer(app.callback());
|
109 | server.listen(share.config.port);
|
110 | this[print]();
|
111 |
|
112 |
|
113 | if (share.config.websocket) {
|
114 | require('./websocket')(server);
|
115 | }
|
116 | }
|
117 |
|
118 | |
119 |
|
120 |
|
121 | [bootstrap] () {
|
122 |
|
123 | const bootstrapPath = `${share.FRAMEWORK_PATH}lib${path.sep}bootstrap`;
|
124 | if (fs.existsSync(bootstrapPath)) {
|
125 | fs.readdirSync(bootstrapPath).filter(v => require(`${bootstrapPath}${path.sep}${v}`));
|
126 | }
|
127 |
|
128 |
|
129 | const appOneLayerBootstrapPath = `${share.APP_PATH}app${path.sep}bootstrap`;
|
130 | if (fs.existsSync(appOneLayerBootstrapPath)) {
|
131 | fs.readdirSync(appOneLayerBootstrapPath).filter(v => require(`${appOneLayerBootstrapPath}${path.sep}${v}`));
|
132 | }
|
133 |
|
134 | const appTwoLayersBootstrapPath = `${share.APP_PATH}app${path.sep}common${path.sep}bootstrap`;
|
135 | if (fs.existsSync(appTwoLayersBootstrapPath)) {
|
136 | fs.readdirSync(appTwoLayersBootstrapPath).filter(v => require(`${appTwoLayersBootstrapPath}${path.sep}${v}`));
|
137 | }
|
138 | }
|
139 |
|
140 | |
141 |
|
142 |
|
143 | [print] () {
|
144 | const appPkg = require(`${share.APP_PATH}${path.sep}package.json`) || {};
|
145 | const _app = `project name: ${appPkg.name || 'share-node framework project'} ${appPkg.version || '1.0.0'}`;
|
146 | const _version = `share node version: ${pkg.version}, node version: ${process.version}, env: ${share.ENV}, log level: ${share.config.log4js.categories.default.level}`;
|
147 | const _instance = `cpu cores: ${os.cpus().length}, server instances: 1, pid: ${process.pid}`;
|
148 | const _server = `http server start in ${((Date.now() - share.startTime) / 1000.0).toFixed(2)} s, running at http://127.0.0.1${share.config.port.toString() === '80' ? '' : `:${share.config.port}`}`;
|
149 | this.LOG.info(_app);
|
150 | this.LOG.info(_version);
|
151 | this.LOG.info(_instance);
|
152 | this.LOG.info(_server);
|
153 | }
|
154 | };
|