UNPKG

yf-fpm-server

Version:

yf fast-platform api server

404 lines (306 loc) 11.1 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.Biz = exports.Hook = exports.Fpm = undefined; var _koa = require('koa'); var _koa2 = _interopRequireDefault(_koa); var _koaBodyparser = require('koa-bodyparser'); var _koaBodyparser2 = _interopRequireDefault(_koaBodyparser); var _koa2Cors = require('koa2-cors'); var _koa2Cors2 = _interopRequireDefault(_koa2Cors); var _pubsubJs = require('pubsub-js'); var _pubsubJs2 = _interopRequireDefault(_pubsubJs); var _koaRouter = require('koa-router'); var _koaRouter2 = _interopRequireDefault(_koaRouter); var _path = require('path'); var _path2 = _interopRequireDefault(_path); var _fs = require('fs'); var _fs2 = _interopRequireDefault(_fs); var _https = require('https'); var _https2 = _interopRequireDefault(_https); var _koaSslify = require('koa-sslify'); var _koaSslify2 = _interopRequireDefault(_koaSslify); var _lodash = require('lodash'); var _lodash2 = _interopRequireDefault(_lodash); var _pino = require('pino'); var _pino2 = _interopRequireDefault(_pino); var _pinoMultiStream = require('pino-multi-stream'); var _debug = require('debug'); var _debug2 = _interopRequireDefault(_debug); var _response = require('../middleware/response.js'); var _response2 = _interopRequireDefault(_response); var _permission = require('../middleware/permission.js'); var _permission2 = _interopRequireDefault(_permission); var _compare = require('../middleware/compare.js'); var _compare2 = _interopRequireDefault(_compare); var _hook = require('../utils/hook.js'); var _hook2 = _interopRequireDefault(_hook); var _biz = require('../utils/biz.js'); var _biz2 = _interopRequireDefault(_biz); var _process = require('../utils/process.js'); var _plugin = require('../utils/plugin.js'); var _api = require('../router/api.js'); var _api2 = _interopRequireDefault(_api); var _ping = require('../router/ping.js'); var _ping2 = _interopRequireDefault(_ping); var _webhook = require('../router/webhook.js'); var _webhook2 = _interopRequireDefault(_webhook); var _core = require('./core'); var _core2 = _interopRequireDefault(_core); var _exception = require('../utils/exception.js'); var _exception2 = _interopRequireDefault(_exception); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const debug = (0, _debug2.default)('yf-fpm-server:app.js'); const packageInfo = require('../../package.json'); const CWD = process.cwd(); const ENV = process.env; const projectInfo = require(_path2.default.join(CWD, 'package.json')); const LOCAL = _path2.default.join(__dirname, '../../'); const configPath = _path2.default.join(CWD, 'config.json'); let config = { server: { hostname: '0.0.0.0', domain: 'localhost', port: 9999 }, defaultVersion: '0.0.1', dev: 'DEV', apps: { '123123': { appkey: '123123', approot: '*', secretkey: '123123' } }, pino: { level: 'debug', writers: 'stdio', name: 'yf-fpm-server' } }; if (_fs2.default.existsSync(configPath)) { config = _lodash2.default.assign(config, require(configPath)); } const RUN_MODE = ENV.NODE_ENV || 'dev'; const RUNTIME_CONFIG = _path2.default.join(CWD, `config.${RUN_MODE.toLowerCase()}.json`); if (_fs2.default.existsSync(RUNTIME_CONFIG)) { config = _lodash2.default.assign(config, require(RUNTIME_CONFIG)); } debug('The Finally Runtime Config: %O', config); class Fpm { constructor(options) { const logStreams = config.pino.writers === 'stdio' ? [{ stream: process.stdout }, { level: 'error', stream: process.stderr }] : [{ level: 'debug', stream: _fs2.default.createWriteStream(_path2.default.join(CWD, config.pino.logfile || 'app.log'), { flags: 'a' }) }, { level: 'error', stream: _fs2.default.createWriteStream(_path2.default.join(CWD, config.pino.errfile || 'error.log'), { flags: 'a' }) }, { level: 'fatal', stream: _fs2.default.createWriteStream(_path2.default.join(CWD, config.pino.fatalfile || 'fatal.log'), { flags: 'a' }) }]; this.logger = (0, _pino2.default)(_lodash2.default.assign(config.pino, { timestamp: () => `,"time":"${new Date(Date.now()).toISOString()}"` }), (0, _pinoMultiStream.multistream)(logStreams)); let app = new _koa2.default(); this.app = app; this._options = _lodash2.default.assign({ 'LOCAL': LOCAL, 'CWD': CWD }, options); this.doCommand = _process.doCommand; this.execShell = _process.execShell; this._biz_module = {}; this._hook = new _hook2.default(); this._action = {}; this._start_time = _lodash2.default.now(); this._counter = 0; this._prject_info = projectInfo; this._env = config.dev; this._version = packageInfo.version; this._plugins = (0, _plugin.loadPlugin)(this) || {}; this._publish_topics = []; this._webhook_events = []; this.runAction('INIT', this); this.errorHandler = (err, ctx) => { this.logger.error('server error', err, ctx); debug('Server Error Handler: %O', err); }; this.app.use(async (ctx, next) => { delete ctx.disableBodyParser; if (ctx.request.method !== 'POST') { await next(); return; } const disableBodyParser = this.get('disableBodyParser'); if (disableBodyParser) { let urls; if (_lodash2.default.isArray(disableBodyParser)) { urls = disableBodyParser; } else if (_lodash2.default.isString(disableBodyParser)) { urls = disableBodyParser.split(','); } const urlPath = ctx.request.url; _lodash2.default.map(urls, url => { if (_lodash2.default.endsWith(urlPath, url)) { ctx.disableBodyParser = true; } }); } await next(); }); this.app.use((0, _koaBodyparser2.default)()); this.app.use((0, _koa2Cors2.default)()); this.app.use(_response2.default); } set(k, v) { this._options[k] = v; } get(k, udv) { return this._options[k] === undefined ? udv : this._options[k]; } getApp() { return this.app; } getVersion() { return this._version; } getPlugins() { return this._plugins; } getPluginRef(pname) { if (!_lodash2.default.startsWith(pname, 'fpm-plugin-')) { pname = 'fpm-plugin-' + pname; } if (_lodash2.default.has(this._plugins, pname)) { return this._plugins[pname].ref; } return undefined; } isPluginInstalled(name) { return _lodash2.default.has(this._plugins, name); } createRouter() { return (0, _koaRouter2.default)(); } createBiz(version) { return new _biz2.default(version); } bindRouter(router) { this.app.use(router.routes()).use(router.allowedMethods()); } extendModule(name, module, version) { if (_lodash2.default.isFunction(module)) { module = module(this); } if (!version) { _lodash2.default.map(this._biz_module, bizModule => { bizModule[name] = module; }); } else { if (!_lodash2.default.has(this.getBizVersions(), version)) { throw new _exception2.default(_exception.E.System.BIZ_VERSION_NOT_FNOUND(version)); } this._biz_module[version][name] = module; } } getBizVersions() { return _lodash2.default.keys(this._biz_module); } addBizModules(biz) { if (biz instanceof _biz2.default) { let m = biz.convert(); this._biz_module[m.version] = m.modules; } else { throw new _exception2.default({ code: 'Biz-Load-Error', errno: -10011, message: 'Biz must be instanceof Biz' }); } } registerAction(actionName, action, priority = 100) { const _list = this._action[actionName] || []; _list.push({ priority, action }); this._action[actionName] = _list; } async runAction(actionName) { if (_lodash2.default.has(this._action, actionName)) { let _list = this._action[actionName]; const argument = _lodash2.default.drop(arguments); _list = _lodash2.default.sortBy(_list, 'priority'); for (let action of _list) { await action.action(argument); } } } async execute(method, args, v, ctx) { return await (0, _core2.default)(method, args, v || config.defaultVersion, this, ctx); } addAfterHook(method, hookHandler, v, priority) { return this._hook.addAfterHook(method, hookHandler, v || config.defaultVersion, priority); } addBeforeHook(method, hookHandler, v, priority) { return this._hook.addBeforeHook(method, hookHandler, v || config.defaultVersion, priority); } getConfig(c, defaultValue) { if (_lodash2.default.isEmpty(c)) { return config; } return config[c] || defaultValue || {}; } getEnv(key, defaultValue) { if (_lodash2.default.isEmpty(key)) { return ENV; } return ENV[key] || defaultValue; } extendConfig(c) { config = _lodash2.default.assign(config, c || {}); } getClients() { const apps = this.getConfig('apps'); return apps || {}; } bindErrorHandler(handler) { this.errorHandler = handler; } publish(topic, data) { if (!_lodash2.default.includes(this._publish_topics, topic)) { this._publish_topics.push(topic); } _pubsubJs2.default.publish(topic, data); } subscribe(topic, callback) { _pubsubJs2.default.subscribe(topic, callback); } async run() { let self = this; this.app.use(async (ctx, next) => { ctx.fpm = self; await next(); }); this.app.use(_permission2.default); this.app.use(_compare2.default); await this.runAction('FPM_MIDDLEWARE', this, this.app); this.bindRouter(_api2.default); this.bindRouter(_ping2.default); this.bindRouter(_webhook2.default); await this.runAction('ADMIN', this, this.app); await this.runAction('FPM_ROUTER', this, this.app); await this.runAction('BEFORE_SERVER_START', this, this.app); this.app.on('error', this.errorHandler); this.app.listen(config.server.port, config.server.hostname || '0.0.0.0'); if (config.ssl) { const options = { key: _fs2.default.readFileSync(_path2.default.join(CWD, `${config.ssl.key}`)), cert: _fs2.default.readFileSync(_path2.default.join(CWD, `${config.ssl.cert}`)) }; _https2.default.createServer(options, this.app.callback()).listen(config.ssl.port); } await this.runAction('AFTER_SERVER_START', this, this.app); debug(`FPM-SERVER is running on ${config.server.hostname || '0.0.0.0'}:${config.server.port}`); this.logger.info(`FPM-SERVER is running on ${config.server.hostname || '0.0.0.0'}:${config.server.port}`); if (config.server.domain) { this.logger.info(`Bind at HTTP Server: http://${config.server.domain}`); } if (config.ssl) { this.logger.info(`Bind at HTTPS Server: https://${config.server.domain || config.server.hostname}:${config.ssl.port}`); } return this; } } exports.Fpm = Fpm; exports.Hook = _hook2.default; exports.Biz = _biz2.default; exports.default = Fpm;