mm_os
Version:
这是超级美眉服务端框架,用于快速构建应用程序。
220 lines (210 loc) • 5.2 kB
JavaScript
const fs = require("fs");
const send = require('koa-send');
const conf = require('mm_config');
const Item = require('mm_machine').Item;
/**
* Plugin插件驱动类
* @extends {Item}
* @class
*/
class Drive extends Item {
/**
* 构造函数
* @param {String} dir 当前目录
* @param {Object} config 配置
* @constructor
*/
constructor(dir) {
super(dir, __dirname);
this.default_file = "./static.json";
// 更新并重载
this.mode = 3;
/* 通用项 */
// 配置参数
this.config = {
// 名称, 由中英文和下“_”组成, 用于修改或卸载 例如: demo
"name": "",
// 状态 0未启用,1启用
"state": 1,
// 标题
"title": "",
// 应用名
"app": "",
// 插件
"plugin": "",
// 物理根目录
"root": "",
// 路由根路径
"path": "/",
// 首页
"index": "index.html",
// 重定向
"redirect": true,
// 缓存保留10分钟
"maxAge": 1000 * 60 * 10,
// 是否保持不变
"immutable": true,
// 是否启用brotli压缩
"brotli": true,
// 是否启用gizp压缩
"gzip": true,
// 允许访问的拓展名
"extensions": null,
// 处理函数
"func_file": "",
// 执行函数名
"func_name": "",
// 是否将ES6转换AMD
"convert_amd": true
};
}
}
/**
* 发送文件函数
*/
Drive.prototype.send = send;
/**
* 加载配置对象前
* @param {Object} config 配置对象
*/
Drive.prototype.set_config = function(config) {
if (config) {
if (config.maxAge) {
config.maxAge *= 1000;
}
}
this.config = conf(Object.assign({}, this.config, config || {}), this.filename);
this.run_mode(this.config.convert_amd);
};
/**
* 执行前
* @param {Object} ctx http请求上下文
* @param {Object} path 文件路径
*/
Drive.prototype.before = async function(ctx, path) {};
/**
* 执行
* @param {Object} ctx http请求上下文
* @param {Object} path 文件路径
* @return {Boolean} 成功发送返回true,失败返回false
*/
Drive.prototype.main = async function(ctx, path) {
return send(ctx, path, this.config);
};
/**
* 执行后
* @param {Object} ctx http请求上下文
* @param {Object} path 文件路径
*/
Drive.prototype.after = async function(ctx, path) {};
/**
* 切换运行模式
* @param {Boolean} convert_amd 是否将ES6转换AMD
*/
Drive.prototype.run_mode = async function(convert_amd) {
var cg = this.config;
if (convert_amd) {
this.main = async function main(ctx, path) {
if (path.endsWith('.vue') || path.endsWith('.js')) {
var file = ("." + path).fullname(this.dir);
var code;
var str = file.loadText();
try {
if (str && str.indexOf('@/') !== -1) {
var arr = ctx.request.href.split('/');
var word = arr[0] + "//" + arr[2] + "/";
str = str.replaceAll('@/', word);
}
code = $.es6_to_amd(str);
} catch (e) {
throw e
}
if (code) {
if (path.endsWith('.js')) {
ctx.response.type = "application/javascript; charset=utf-8";
} else {
ctx.response.type = "text/html; charset=utf-8";
}
ctx.body = code;
var age = cg.maxAge;
if (age) {
if (cg.immutable) {
ctx.set('Cache-Control', 'max-age=' + (age / 1000) + ",immutable");
} else {
ctx.set('Cache-Control', 'max-age=' + (age / 1000));
}
}
return file;
}
} else {
return send(ctx, path, cg);
}
}
} else {
this.main = async function(ctx, path) {
return send(ctx, path, cg);
}
}
return null;
};
/**
* 执行静态文件
* @param {Object} ctx Http请求上下文
* @param {Object} path 路由路径
* @param {Object} next 跳过当前函数
* @return {String} 执行成功返回文件路径
*/
Drive.prototype.run = async function(ctx, path, next) {
var done;
var cg = this.config;
var ph = cg.path;
try {
if (path.startWith(ph)) {
var p = path.replace(ph, '');
if (p.indexOf('.') !== -1) {
this.before(ctx, p);
try {
done = await this.main(ctx, p);
this.after(ctx, p, done);
} catch (err) {
if (err.status !== 404) {
throw err;
}
}
} else {
done = ' ';
if (ctx.status === 404) {
var file;
// 取到物理路径
var root = this.dir;
var dir = p.fullname(root);
if (!p) {
file = dir + '/' + cg.index;
} else if (p.endWith('/')) {
file = dir + cg.index;
} else {
file = dir + '.html';
}
if (file.hasFile()) {
p = file.replace(root, '');
this.before(ctx, p);
done = await this.main(ctx, p);
this.after(ctx, p, done);
} else if (cg.redirect) {
var file = root + '/index.html';
if (file.hasFile()) {
p = '/index.html';
this.before(ctx, p);
done = await this.main(ctx, p);
this.after(ctx, p, done);
}
}
}
}
}
} catch (err) {
$.log.error("静态文件执行错误", this.config.name, err);
}
return done;
};
module.exports = Drive;