1 |
|
2 | const path = require('path');
|
3 | const glob = require('glob');
|
4 | const favicon = require('serve-favicon');
|
5 | const _ = require("lodash");
|
6 | const debug = require('debug')('motif:process');
|
7 |
|
8 | const Macro = require('node-macro');
|
9 |
|
10 | const http = require( 'http' );
|
11 | const express = require('express');
|
12 |
|
13 | const session = require('express-session');
|
14 | const cookieParser = require('cookie-parser');
|
15 | const bodyParser = require('body-parser');
|
16 | const helmet = require('helmet');
|
17 | const cors = require('cors');
|
18 | const formidable = require('formidable');
|
19 |
|
20 | const Context = require('./Context');
|
21 | const Swagger = require('./Swagger');
|
22 |
|
23 | class Process {
|
24 |
|
25 | get app() {
|
26 | return this._app;
|
27 | }
|
28 |
|
29 | get context() {
|
30 | return this._context;
|
31 | }
|
32 |
|
33 | _loadService( file ) {
|
34 | debug("_loadService", file);
|
35 | delete require.cache[require.resolve(path.resolve(this._context.appPath, file))];
|
36 | return require(path.resolve(this._context.appPath, file));
|
37 | }
|
38 |
|
39 | _loadServices() {
|
40 |
|
41 | debug("_loadServices");
|
42 |
|
43 | const macro = new Macro();
|
44 |
|
45 | let serviceFiles = [];
|
46 |
|
47 | macro.add("CREATE-APP", (action) => {
|
48 |
|
49 | let app = express();
|
50 | app.use(helmet());
|
51 | app.use(bodyParser.urlencoded({ extended: false }));
|
52 | app.use(bodyParser.json());
|
53 | app.use(cors());
|
54 |
|
55 | if (this._context.useCookie === true) {
|
56 | app.use(cookieParser());
|
57 | }
|
58 |
|
59 | if (this._context.useFavicon === true) {
|
60 | app.use(favicon(path.join(this._context.appPath, 'public', 'favicon.ico')));
|
61 | }
|
62 |
|
63 | if (this._context.useProxy === true) {
|
64 | app.set('trust proxy', true);
|
65 | }
|
66 |
|
67 | app.on('uncaughtException', this.onException);
|
68 |
|
69 |
|
70 | app.use(function (req, res, next) {
|
71 | if (req.headers['content-type'] && req.headers['content-type'].indexOf('multipart/form-data') > -1) {
|
72 |
|
73 | const form = new formidable.IncomingForm({
|
74 | encoding: 'utf-8',
|
75 | multiples: true,
|
76 | type: 'multipart',
|
77 | maxFieldsSize: 20 * 1024 * 1024,
|
78 | maxFileSize: 200 * 1024 * 1024,
|
79 | maxFields: 1000,
|
80 | hash: true,
|
81 | keepExtensions: false
|
82 | });
|
83 | form.parse(req, function (err, fields) {
|
84 | _.merge(req.body, fields);
|
85 | req.openedFiles = [];
|
86 | });
|
87 | form.on('file', function (name, file) {
|
88 | if (!req.files) {
|
89 | req.files = {};
|
90 | }
|
91 | req.files[name] = file;
|
92 | req.body[name] = file;
|
93 | });
|
94 | form.on('end', function () {
|
95 | req.openedFiles = this.openedFiles;
|
96 | next();
|
97 | });
|
98 | } else {
|
99 | next();
|
100 | }
|
101 | });
|
102 |
|
103 | this._app = app;
|
104 | action.complete();
|
105 | });
|
106 |
|
107 | macro.add("LOAD-SERVICE-FILES", (action) => {
|
108 | glob("services/*/*Service.js", { cwd: this._context.appPath }, (err, files) => {
|
109 | if (err) {
|
110 | action.error(err);
|
111 | return;
|
112 | }
|
113 |
|
114 | serviceFiles = files;
|
115 | action.complete();
|
116 | });
|
117 | });
|
118 |
|
119 | macro.add("LOAD-SERVICES", (action) => {
|
120 | _.each(serviceFiles, (file) => {
|
121 | this._services.push(
|
122 | this._loadService( file )
|
123 | );
|
124 | });
|
125 |
|
126 | action.complete();
|
127 | });
|
128 |
|
129 | if (this._context.createDoc === true) {
|
130 |
|
131 | macro.add("CRAETE-SWAGGER-DOCS", async (action) => {
|
132 |
|
133 | try {
|
134 | let app = this._app;
|
135 | let swagger = new Swagger( this._context );
|
136 |
|
137 | let json = swagger.buildJSON( this._routerPaths, false );
|
138 | let swaggerPath = path.join(this._context.appPath, "public/swagger");
|
139 |
|
140 | await swagger.jsonWriteAsync( path.join(swaggerPath, "/data/swag.json"), json );
|
141 |
|
142 | app.use(express.static(path.join(this._context.appPath, 'public', 'swagger')));
|
143 |
|
144 | app.get('/doc/data', (req, res) => {
|
145 | res.sendFile('data/swag.json', {root: swaggerPath });
|
146 | });
|
147 |
|
148 | app.get('/doc', (req, res) => {
|
149 | res.sendFile('index.html', {root: swaggerPath });
|
150 | });
|
151 | }
|
152 | catch(e) {
|
153 | console.log( e );
|
154 | }
|
155 |
|
156 | action.complete();
|
157 | });
|
158 |
|
159 | macro.add("CRAETE-SWAGGER-ADMIN-DOCS", async (action) => {
|
160 |
|
161 | try {
|
162 | let app = this._app;
|
163 | let swagger = new Swagger( this._context );
|
164 |
|
165 | let json = swagger.buildJSON( this._routerPaths, true );
|
166 | let swaggerPath = path.join(this._context.appPath, "public/swagger");
|
167 |
|
168 | await swagger.jsonWriteAsync( path.join(swaggerPath, "/data/swag.admin.json"), json );
|
169 |
|
170 | app.use(express.static(path.join(this._context.appPath, 'public', 'swagger')));
|
171 |
|
172 | app.get('/doc/data-admin', (req, res) => {
|
173 | res.sendFile('data/swag.admin.json', {root: swaggerPath });
|
174 | });
|
175 |
|
176 | app.get('/doc-admin', (req, res) => {
|
177 | res.sendFile('index.admin.html', {root: swaggerPath });
|
178 | });
|
179 | }
|
180 | catch(e) {
|
181 | console.log( e );
|
182 | }
|
183 |
|
184 | action.complete();
|
185 | });
|
186 | }
|
187 |
|
188 | macro.add("RUN-SERVER", (action) => {
|
189 |
|
190 | let server = http.createServer( this._app );
|
191 | server.listen( this.context.port, () => {
|
192 | debug( `Server is running on port ${this.context.port}` );
|
193 | });
|
194 | server.on('error', this.onError);
|
195 | server.on('listening', this.onListening);
|
196 |
|
197 | this._server = server;
|
198 |
|
199 | action.complete();
|
200 | });
|
201 |
|
202 | macro.start((error) => {
|
203 | if (error) {
|
204 | debug(error);
|
205 | }
|
206 | });
|
207 | }
|
208 |
|
209 | _attachExceptionHandlers() {
|
210 | process.on('uncaughtException', async function (err) {
|
211 | console.error(err.stack);
|
212 | process.exit(1);
|
213 | });
|
214 |
|
215 | process.on('unhandledRejection', async function (err) {
|
216 | console.error(err.stack);
|
217 | process.exit(1);
|
218 | });
|
219 | }
|
220 |
|
221 | constructor( options ) {
|
222 |
|
223 | this._context = new Context({
|
224 | appPath: path.resolve(process.env.PWD, '.'),
|
225 | ...options
|
226 | });
|
227 |
|
228 | this._app = null;
|
229 | this._server = null;
|
230 | this._services = [];
|
231 | this._views = [];
|
232 | this._routerPaths = [];
|
233 |
|
234 | process.motif = this;
|
235 | }
|
236 |
|
237 | run( ) {
|
238 |
|
239 | this._attachExceptionHandlers();
|
240 |
|
241 | this._loadServices();
|
242 | }
|
243 |
|
244 | onListening() {
|
245 | debug( "onListening" );
|
246 | }
|
247 |
|
248 | onException(req, res, route, err) {
|
249 | debug( "onException", err );
|
250 | }
|
251 |
|
252 | onError(error) {
|
253 | debug( "onError", error );
|
254 | }
|
255 |
|
256 | };
|
257 |
|
258 | module.exports = Process;
|