UNPKG

jweb

Version:

A typeScript httpServer support annotation

340 lines (339 loc) 12.4 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const Path = require("path"); const Hapi = require("@hapi/hapi"); const Inert = require("@hapi/inert"); const YAML = require("yaml"); const events_1 = require("events"); const jbean_1 = require("jbean"); const starters_1 = require("./starters"); const utils_1 = require("./utils"); const defaultOptions = { port: 3000, host: 'localhost', configNS: 'node-web', controllerDir: 'controller', viewDir: 'view', tplExt: 'html', taskDir: 'task' }; const TASK_ARG_KEY = { task: 't', loop: 'l', sleep: 's' }; var AppErrorEvent; (function (AppErrorEvent) { AppErrorEvent["REQUEST"] = "error_request"; })(AppErrorEvent = exports.AppErrorEvent || (exports.AppErrorEvent = {})); var ApplicationType; (function (ApplicationType) { ApplicationType[ApplicationType["web"] = 0] = "web"; ApplicationType[ApplicationType["task"] = 1] = "task"; })(ApplicationType = exports.ApplicationType || (exports.ApplicationType = {})); const taskMethod = 'process'; jbean_1.registerConfigParser('yml', function (content) { if (!content) { return null; } return YAML.parse(content); }); class Application extends events_1.EventEmitter { constructor() { super(); this.isDev = process.env.NODE_ENV === 'development'; this.appOptions = {}; this.applicationConfigs = {}; this.cmdArgs = {}; } static create(options) { const ins = Application.ins = new Application(); ins.appOptions = {}; jbean_1.merge(ins.appOptions, defaultOptions); jbean_1.merge(ins.appOptions, options); ins.configNS = ins.appOptions.configNS; ins.applicationConfigs = jbean_1.getApplicationConfigs(); return ins; } static getIns() { return Application.ins; } static start(options) { return __awaiter(this, void 0, void 0, function* () { jbean_1.BeanFactory.initBean(); const application = Application.create(options); application.registerExit(); application.init(); jbean_1.BeanFactory.startBean(); if (application.isDev) { console.log('Starting at dev enviroment'); } try { yield starters_1.default(application); switch (application.applicationType) { case ApplicationType.web: yield application.runWebServer(); break; case ApplicationType.task: yield application.runTask(); break; default: break; } } catch (e) { console.error(e); } return application; }); } getAppConfigs() { return this.getApplicationConfigs('app'); } getApplicationConfigs(key) { if (typeof this.applicationConfigs[this.configNS] === 'undefined' || typeof this.applicationConfigs[this.configNS].app === 'undefined') { return {}; } const appConfigs = this.applicationConfigs[this.configNS]; return key ? appConfigs[key] : appConfigs; } parseCmdArgs() { const args = process.argv; if (args.length < 3) { return; } let argName = null; for (let i = 2; i < args.length; i++) { if (args[i].substr(0, 1) === '-') { argName = args[i].replace(/^\-*/g, ''); } else { if (argName) { Object.keys(TASK_ARG_KEY).forEach(key => { if (key === argName) { argName = TASK_ARG_KEY[key]; } }); this.cmdArgs[argName] = args[i].replace(/^\-*/g, ''); } argName = null; } } } checkAppType() { if (typeof this.cmdArgs[TASK_ARG_KEY.task] !== 'undefined') { this.applicationType = ApplicationType.task; } else { this.applicationType = ApplicationType.web; } } bindEvent() { this.on(AppErrorEvent.REQUEST, err => { console.error("Request error: ", err); }); } init() { this.root = Path.dirname(require.main.filename); this.parseCmdArgs(); this.checkAppType(); this.bindEvent(); switch (this.applicationType) { case ApplicationType.web: this.initWebServer(); break; case ApplicationType.task: this.initTask(); break; default: break; } } initWebServer() { const appConfigs = this.getAppConfigs(); this.server = new Hapi.Server({ port: appConfigs.port || defaultOptions.port, host: appConfigs.host || defaultOptions.host, state: { strictHeader: false } }); if (typeof appConfigs.assets !== 'undefined') { this.assets = appConfigs.assets; if (!Path.isAbsolute(this.assets)) { this.assets = Path.join(Path.dirname(this.root), this.assets); } } this.controllerDir = appConfigs.controllerDir || defaultOptions.controllerDir; if (process.env.NODE_ENV === 'development') { this.viewDir = Path.join(Path.dirname(Path.dirname(this.root)), 'src', appConfigs.viewDir || defaultOptions.viewDir); } else { this.viewDir = appConfigs.viewDir || defaultOptions.viewDir; } this.tplExt = appConfigs.tplExt || defaultOptions.tplExt; } initTask() { let taskScript = this.cmdArgs[TASK_ARG_KEY.task]; const appConfigs = this.getAppConfigs(); this.taskDir = appConfigs.taskDir || defaultOptions.taskDir; if (taskScript.substr(0, 1) === '/') { this.taskScript = Path.join(this.root, taskScript); } else { this.taskScript = Path.join(this.root, this.taskDir, taskScript); } } runWebServer() { return __awaiter(this, void 0, void 0, function* () { yield this.server.register(Inert); if (this.assets) { this.route({ method: 'GET', path: '/{param*}', handler: { directory: { path: this.assets, redirectToSlash: false, index: true, } } }); } yield this.server.start(); console.log(`Server running at: ${this.server.info.uri}`); }); } runTask() { return __awaiter(this, void 0, void 0, function* () { //const scriptFile = require.main.filename const entryFile = process.argv[1]; let args = process.argv.slice(2).join(' '); if (args.startsWith('-')) { args = '\\' + args; } const cmd = 'ps aux | grep \'' + entryFile + '\' | grep -v grep | grep -v \'/bin/sh \\-c\' | grep \'' + args + '\''; let { err, data, message } = yield utils_1.exec(cmd, true); if (err) { console.error(message); process.emit('exit', 0); return; } data = data.replace(/^\s*|\s*$/g, ''); data = data.split("\n"); if (data.length > 1) { process.emit('exit', 0); return; } let task = require(this.taskScript); if (task.default) { task = task.default; } if (typeof task !== 'function') { console.error('typeof ' + this.taskScript + ' is not class.'); process.emit('exit', 0); return; } const methods = jbean_1.ReflectHelper.getMethods(task); if (methods.indexOf(taskMethod) < 0) { console.error(taskMethod + ' method of ' + task.name + ' is not exist.'); process.emit('exit', 0); return; } let sleepSeconds = this.cmdArgs[TASK_ARG_KEY.sleep] || 0; let loopTimes = this.cmdArgs[TASK_ARG_KEY.loop] || 1; if (sleepSeconds < 0) { sleepSeconds = 0; } if (loopTimes < 1) { loopTimes = 1; } const taskIns = new task(); for (let i = 0; i < loopTimes; i++) { if (jbean_1.checkSupportTransition(task, taskMethod)) { jbean_1.BeanFactory.genRequestId(taskIns); } const requestId = jbean_1.BeanFactory.getRequestId(taskIns); try { if (requestId) { yield jbean_1.emitBegin(requestId); } const args = {}; Object.assign(args, this.cmdArgs); Object.keys(TASK_ARG_KEY).forEach(k => { delete args[TASK_ARG_KEY[k]]; }); yield taskIns[taskMethod](this, args); if (requestId) { yield jbean_1.emitCommit(requestId); yield jbean_1.BeanFactory.releaseBeans(requestId); } } catch (e) { if (requestId) { yield jbean_1.emitRollback(requestId); yield jbean_1.BeanFactory.releaseBeans(requestId); } console.error(e); process.emit('exit', 0); return; } if (sleepSeconds > 0) { utils_1.sleep(sleepSeconds); } } process.emit('exit', 0); }); } route(option) { if (this.applicationType !== ApplicationType.web) { return this; } const appConfig = this.getAppConfigs(); if (appConfig && appConfig.cors) { option.options = { // cors: true cors: { origin: ['*'], maxAge: 86400, credentials: true } }; } this.server.route(option); return this; } registerExit() { let exitHandler = function (options, code) { if (options && options.exit) { if (this.applicationType !== ApplicationType.task) { console.log('application exit at', code); } jbean_1.BeanFactory.destroyBean(); process.exit(code); } else { console.error('exception', code); } }; process.on('exit', exitHandler.bind(this, { exit: true })); // catch ctrl+c event process.on('SIGINT', exitHandler.bind(this, { exit: true })); // catch "kill pid" process.on('SIGUSR1', exitHandler.bind(this, { exit: true })); process.on('SIGUSR2', exitHandler.bind(this, { exit: true })); // catch uncaught exceptions process.on('uncaughtException', exitHandler.bind(this, { exit: false })); } } exports.default = Application;