kcola
Version:
一个基于koa2,小而美的RESTful API+MVC的web开发框架!
178 lines (156 loc) • 4.42 kB
JavaScript
/* eslint-disable prefer-spread */
/* eslint-disable valid-jsdoc */
const fs = require('fs');
const path = require('path');
const http = require('http');
const https = require('https');
const EventEmitter = require('events').EventEmitter;
const handleRoute = require('./handleRoute');
const handleWebSocket = require('./handleWebSocket');
const handleSpaMode = require('./handleHistoryMode');
const handleMiddleware = require('./handleMiddleware');
const {traverseDir, existsSync} = require('../../utils');
const defaultAppConfig = {
route_meta_data: [],
enable_spa_history_mode: true,
enable_load_middleware: false,
enable_https: false,
certificate: {
certPath: null,
keyPath: null,
},
enable_websocket: true,
max_pool_size: 16,
};
/**
*
*
* @class Kcola
* @extends {EventEmitter}
*/
class App extends EventEmitter {
/**
*Creates an instance of App.
* @param {*} config
* @param {*} app
* @memberof App
*/
constructor(config, app) {
super();
const appConfig = require(path.join(process.cwd(), './package.json')).appConfig || defaultAppConfig;
process.env.UV_THREADPOOL_SIZE = appConfig.max_pool_size; // 设置libuv线程池线程数大小
if (appConfig.enable_https) {
const enforceHttps = require('koa-sslify');
app.use(enforceHttps(), 'koa-sslify');
}
if (appConfig.enable_spa_history_mode) {
app.use(handleSpaMode(config.historyMode), 'spa');
}
app.use(
require('koa-static')(path.join(global.__kcola_workdir, config.publicDir || './public'), {defer: true}),
'koa-static'
);
app.use(
require('koa-body')({multipart: true, parsedMethods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']}),
'koa-body'
);
if (appConfig.enable_load_middleware) {
handleMiddleware(config.middlewareOpts, app, 4);
}
const routeDir = validateCoreDirectory(config.routeDir, './routes');
if (!routeDir) {
throw new Error('[kcola error] "routes" directory not found, please create');
}
const ctrlDir = validateCoreDirectory(config.controllerDir, './controllers');
if (!ctrlDir) {
throw new Error('[kcola error] "controllers" directory not found, please create');
}
const ctrls = generateCtrlFiles(ctrlDir);
const router = handleRoute(ctrls, {
info: appConfig.route_meta_data || appConfig.app_routes,
dir: routeDir,
});
app.use(router.routes(), 'koa-router').use(router.allowedMethods(), 'koa-router-allowed-methods');
app.routeMatcher = router.stack.map((value) => {
return {
regexp: value.regexp,
path: value.path,
ignoreauth: value.ignoreauth,
};
});
let server = null;
if (appConfig.enable_https) {
server = https.createServer(
{
cert: fs.readFileSync(appConfig.certificate.certPath),
key: fs.readFileSync(appConfig.certificate.keyPath),
},
app.callback()
);
} else {
server = http.createServer(app.callback());
}
if (appConfig.enable_websocket) {
handleWebSocket(server, router.wsRouter);
}
app.listen = function listen(...args) {
server.listen.apply(server, args);
return server;
};
app.server = server;
}
}
module.exports = (config, app) => {
return new App(config, app);
};
/**
*
* 生成 controller 对象
* @param {*} ctrlRoot
* @returns
*/
function generateCtrlFiles(ctrlRoot) {
let ctrlFiles = [];
try {
ctrlFiles = traverseDir(ctrlRoot);
} catch (error) {
console.error(error);
}
return ctrlFiles;
}
/**
*
* 检验配置文件并返回其路径
* @param {*} filepath
* @param {*} defaultPath
* @returns
*/
function validateConfigFile(filepath, defaultPath) {
if (!filepath) {
filepath = defaultPath;
}
if (!path.isAbsolute(filepath)) {
filepath = path.join(global.__kcola_workdir, filepath);
}
const stat = fs.statSync(filepath);
if (stat.isDirectory()) {
filepath = path.join(filepath, './index.js');
}
return existsSync(filepath) ? filepath : null;
}
/**
*
*检验框架核心目录
* @param {*} dir
* @param {*} defaultDir
* @returns
*/
function validateCoreDirectory(dir, defaultDir) {
if (!dir) {
dir = defaultDir;
}
if (!path.isAbsolute(dir)) {
dir = path.join(global.__kcola_workdir, dir);
}
return existsSync(dir) ? dir : null;
}