This commit is contained in:
robin
2022-05-21 06:48:12 +08:00
parent b5f918776e
commit 96333ae7a9
45 changed files with 650 additions and 64 deletions
@@ -7,4 +7,8 @@ module.exports = {
"event2": (args) => { "event2": (args) => {
console.log(args || 'event2') console.log(args || 'event2')
}, },
//status定义的有限状态机
"start.ling": (args) => {
console.log(args || 'event2')
},
} }
+13
View File
@@ -0,0 +1,13 @@
'use strict';
const Smf = require('bamboo_smf');
const smf = new Smf()
// 测试状态
smf.init('test', 'start')
.push('start', 'start.ling')
.push('ling', 'start.end')
.push('end')
module.exports = smf.getSmfData()
@@ -2,14 +2,14 @@
module.exports = { module.exports = {
doc : "默认页面", doc : "默认页面",
path : "/", path : "cms/index/",
method : ["get", "post"], method : ["get", "post"],
middleware: [], middleware: [],
params : { params : {
"age": "int?" "age": "int?"
}, },
return : {}, return : {},
controller: async (ctx, app) => { fun: async (ctx, app) => {
console.log(ctx.request.body); console.log(ctx.request.body);
// app.err.ParameterException() // app.err.ParameterException()
// app.event.emit('test.event2') // app.event.emit('test.event2')
@@ -59,6 +59,7 @@ module.exports = {
// }, "save": "" // }, "save": ""
// }, // },
{ {
"as": "user_info",
"table" : "UserInfo", "table" : "UserInfo",
"where" : { "where" : {
"uid": "$as.user_data.id",//根据别名 user_data 返回的结果中的id值作为条件查询 "uid": "$as.user_data.id",//根据别名 user_data 返回的结果中的id值作为条件查询
View File
+1 -1
View File
@@ -1,8 +1,8 @@
module.exports = { module.exports = {
doc : "用户", doc : "用户",
api : true,//是否需要生成api接口
model: { model: {
uid: {type: "STRING", comment: '用户id'}, uid: {type: "STRING", comment: '用户id'},
age: {type: "INTEGER", comment: '年龄', defaultValue: 0,}, age: {type: "INTEGER", comment: '年龄', defaultValue: 0,},
} }
} }
-4
View File
@@ -1,4 +0,0 @@
'use strict';
const bodyParser = require('koa-bodyparser')
// 错误处理
module.exports = bodyParser()
-12
View File
@@ -1,12 +0,0 @@
'use strict';
const error = require('koa-json-error')
// 错误处理
module.exports = error((err) => {
return {
status : err.status,
message : err.message,
code : err.code,
res : false,
// postFormat: (e, obj) => process.env.NODE_ENV === 'production' ? _.omit(obj, 'stack') : obj
}
})
-3
View File
@@ -1,3 +0,0 @@
'use strict';
const logger = require('koa-logger')
module.exports = logger()
-10
View File
@@ -1,10 +0,0 @@
'use strict';
/*响应时间*/
module.exports = async (ctx, next, app) => {
// console.log(ctx, next, options);
// const timetaken = `${ctx.request.method}${ctx.request.url} 响应时间`
// console.time(timetaken)
// app.logger.debug("123")
await next()
// console.timeEnd(timetaken)
}
View File
View File
View File
Binary file not shown.
View File
+23 -3
View File
@@ -1,6 +1,6 @@
/*数据库配置*/ /*数据库配置*/
module.exports = { module.exports = {
mysql: { mysql : {
database: "bamboo", database: "bamboo",
username: "bamboo", username: "bamboo",
password: "bamboo", password: "bamboo",
@@ -46,11 +46,31 @@ module.exports = {
}, },
}, },
}, },
redis:{}, redis : {},
sqlite:{ sqlite: {
dialect: 'sqlite', dialect: 'sqlite',
storage: 'app/sqlite/database.sqlite', storage: 'app/sqlite/database.sqlite',
logging: false, logging: false,
// model的全局配置
define : {
// 添加create,update,delete时间戳
timestamps: true,
// 添加软删除
paranoid: false,
// 防止修改表名为复数
freezeTableName: true,
// 防止驼峰式字段被默认转为下划线
underscored: false,
},
dialectOptions: {
typeCast(field, next) {// 让读取date类型数据时返回字符串而不是UTC时间
if (field.type === 'DATETIME') {
// console.log(field);
return field.string();
}
return next();
},
},
}, },
+13
View File
@@ -0,0 +1,13 @@
module.exports = {
dir: {
"event" : "app/*/event/*.js",
"status" : "app/*/status/*.js",
"controller": "app/*/controller/*.js",
"model" : "app/*/model/*.js",
"middleware": "middleware/*.js",
"extend" : "extend/*.js",
"schedule" : "schedule/*.js",
"sqlite" : "sqlite/model/*.js",
"config" : "config/*.js",
}
}
+1 -4
View File
@@ -1,7 +1,4 @@
'use strict'; 'use strict';
module.exports = { module.exports = {
register: ["bodyparser", "error", "time", "koaLogger", "verify"],
time : {
params: '123'
},
} }
+4
View File
@@ -0,0 +1,4 @@
//加载配置文件
module.exports = (app) => {
}
+123
View File
@@ -0,0 +1,123 @@
const Koa = require("koa")
const load = require("./load")
const path = require('path')
const xe = require("xe-utils")
const EventEmitter = require('events');
const Router = require("koa-router");
const Parameter = require('parameter');
const error = require('./errorException');
const log4js = require("log4js");
const Smf = require('./smf/smf');
module.exports = class Bamboo extends Koa {
constructor() {
super();
this.init()
}
path(args) {
return this.isPath + '/' + (args || "")
}
isPath(args) {
return path.resolve('./' + (args || ""))
}
get xe() {
return xe
}
async init() {
this.config = {}
await this.loadConfig()
this.event = new EventEmitter()
this.parameter = new Parameter();
this.error = error;
this.smf = new Smf()
log4js.configure(this.config['log']);
this.logger = log4js.getLogger();
// await this.loadEvent()
// await this.loadStatus()
// await this.loadMiddleware()
// await this.loadController()
}
/**
* 加载配置
*/
async loadConfig() {
this.config = {}
const config = await load(this.isPath(), "config")
config.forEach(item => {
this.config[item.file_name] = item.res
})
}
//
// /**
// * 加载事件
// */
// async loadEvent() {
// const event = await load(this.isPath(), "event")
// event.forEach(item => {
// Object.keys(item.res).forEach(key => {
// this.event.on(key, item.res[key])
// })
// })
// }
//
// /**
// * 加载状态
// */
// async loadStatus() {
// const status = await load(this.isPath(), "status")
// const setSmfDataList = []
// status.forEach(item => {
// setSmfDataList.push(item.res)
// })
// this.smf.setSmfDataList(setSmfDataList)
// //监听流程变更
// this.smf.on((e, paras) => {
// this.event.emit(e.currentState, paras)
// })
// }
//
// /**
// * 加载控制器路由
// */
// async loadController() {
// const controller = await load(this.isPath(), "controller")
// const router = new Router();
// controller.forEach(item => {
// item.res.method.forEach(method => {
// router[method](item.res.path, async (ctx, next) => {
// const validate = this.parameter.validate(item.res.params, ctx.request.body);
// if (validate) {
// console.error(validate);
// this.error.ParameterException(validate);
// }
// else {
// await item.res.fun(ctx, this.application)
// await next();
// }
// })
// })
// })
// }
//
// /**
// * 加载中间件
// */
// async loadMiddleware() {
// const middleware = await load(this.isPath(), "middleware")
// let hashList = xe.toArray(middleware)
// hashList = xe.orderBy(hashList, "fun.sort")
// hashList = hashList.filter(item => item.res.use)
// hashList.forEach(item => {
// this.use(async (ctx, next) => {
// ctx['logger'] = this.logger
// return await item.res.fun(ctx, next, this.application)
// })
// })
// }
}
@@ -11,7 +11,7 @@ class HttpException extends Error {
class ParameterException extends HttpException { class ParameterException extends HttpException {
constructor(message, code, status) { constructor(message, code, status) {
super() super()
this.status = status || 402 this.status = status || 402
this.code = code this.code = code
this.message = message || '参数错误' this.message = message || '参数错误'
} }
@@ -20,7 +20,7 @@ class ParameterException extends HttpException {
class NotFound extends HttpException { class NotFound extends HttpException {
constructor(message, code, status) { constructor(message, code, status) {
super() super()
this.status = status || 404 this.status = status || 404
this.code = 404 this.code = 404
this.message = message || '资源未找到' this.message = message || '资源未找到'
} }
@@ -29,7 +29,7 @@ class NotFound extends HttpException {
class AuthFailed extends HttpException { class AuthFailed extends HttpException {
constructor(message, code, status) { constructor(message, code, status) {
super() super()
this.status = status || 401 this.status = status || 401
this.message = message || '授权失败' this.message = message || '授权失败'
this.code = 401 this.code = 401
} }
@@ -38,16 +38,16 @@ class AuthFailed extends HttpException {
class Forbidden extends HttpException { class Forbidden extends HttpException {
constructor(message, code, status) { constructor(message, code, status) {
super() super()
this.status = status || 403 this.status = status || 403
this.message = message || '禁止访问' this.message = message || '禁止访问'
this.code = 403 this.code = 403
} }
} }
module.exports = { module.exports = {
HttpException, HttpException: (message, code, status) => {throw new HttpException(message, code, status)},
ParameterException, ParameterException: (message, code, status) => {throw new ParameterException(message, code, status)},
NotFound, NotFound: (message, code, status) => {throw new NotFound(message, code, status)},
AuthFailed, AuthFailed: (message, code, status) => {throw new AuthFailed(message, code, status)},
Forbidden, Forbidden: (message, code, status) => {throw new Forbidden(message, code, status)},
} }
+22 -14
View File
@@ -92,7 +92,7 @@ module.exports = class Bamboo extends Koa {
registeredError() { registeredError() {
console.log('注册 错误'); console.log('注册 错误');
this.errorException = {} this.errorException = {}
const hash = requireDirectory(module, this.path('app/err'), { const hash = requireDirectory(module, this.path('lib/bamboo/err'), {
visit: (obj) => { visit: (obj) => {
for (let key of Object.keys(obj)) { for (let key of Object.keys(obj)) {
this.errorException[key] = (message, code) => { this.errorException[key] = (message, code) => {
@@ -308,9 +308,8 @@ module.exports = class Bamboo extends Koa {
const parse = path.parse(filename); const parse = path.parse(filename);
// super.on(parse.name, obj); // super.on(parse.name, obj);
for (let key of Object.keys(obj)) { for (let key of Object.keys(obj)) {
this.event.on(`${parse.name}.${key}`, obj[key]); this.event.on(`${parse.name}.${key}`, e[key]);
} }
return obj return obj
} }
}); });
@@ -338,18 +337,27 @@ module.exports = class Bamboo extends Koa {
console.log('注册 middleware'); console.log('注册 middleware');
const hash = requireDirectory(module, this.path('app/middleware'), { const hash = requireDirectory(module, this.path('app/middleware'), {
visit: (obj, joined, filename) => { visit: (obj, joined, filename) => {
console.log(obj, joined, filename); // console.log(obj, joined, filename);
const parse = path.parse(filename); // const parse = path.parse(filename);
const config = this.config.middleware[parse.name] // const config = this.config.middleware[parse.name]
// super.use(obj(config || {})) // // super.use(obj(config || {}))
super.use(async (ctx, next) => { // super.use(async (ctx, next) => {
ctx['logger'] = this.logger // ctx['logger'] = this.logger
return await obj(ctx, next, this.application) // return await obj.fun(ctx, next, this.application)
}) // })
return obj return obj
} }
}); });
// console.log(hash); let hashList = xe.toArray(hash)
hashList = xe.orderBy(hashList,"sort")
hashList = hashList.filter(item=>item.use)
hashList.forEach(item=>{
super.use(async (ctx, next) => {
ctx['logger'] = this.logger
return await item.fun(ctx, next, this.application)
})
})
console.log(hashList);
} }
//注册 utils //注册 utils
@@ -938,7 +946,7 @@ module.exports = class Bamboo extends Koa {
const tkKeys = Object.keys(tk) const tkKeys = Object.keys(tk)
for (let key of tkKeys) { for (let key of tkKeys) {
if (key === "as") { continue; } if (key === "as") { continue; }
if (key === "where"||key === "data") { if (key === "where" || key === "data") {
const findJsonRes = this.findJsonValue(tk[key], (n) => { const findJsonRes = this.findJsonValue(tk[key], (n) => {
if (typeof n === "string") { if (typeof n === "string") {
// console.log(tk[key],n); // console.log(tk[key],n);
@@ -996,7 +1004,7 @@ module.exports = class Bamboo extends Koa {
} }
path = path || [] path = path || []
// 获取所有的子节点,并遍历 // 获取所有的子节点,并遍历
if (typeof n ==="object") { if (typeof n === "object") {
const nkeys = Object.keys(n) const nkeys = Object.keys(n)
for (let k of nkeys) { for (let k of nkeys) {
// concat() 方法用于连接两个或多个数组 // concat() 方法用于连接两个或多个数组
+41
View File
@@ -0,0 +1,41 @@
const glob = require("glob")
const path = require('path')
/**
* 项目文件加载
*/
const list = {
"event" : "app/*/event/*.js",
"status" : "app/*/status/*.js",
"controller": "app/*/controller/*.js",
"model" : "app/*/model/*.js",
"middleware": "middleware/*.js",
"extend" : "extend/*.js",
"schedule" : "schedule/*.js",
"sqlite" : "sqlite/model/*.js",
"config" : "config/*.js",
}
module.exports = function load(directory, key) {
return new Promise((resolve, reject) => {
const options = {
root: directory
}
glob(list[key], options, function (er, files) {
if (er) { reject(er) }
console.log(files);
files = files.map(item => {
const parse = path.parse(item);
return {
dir : parse.dir,
file_name: parse.name,
res : require(path.resolve(directory + "/" + item))
}
})
resolve(files)
})
})
}
+227
View File
@@ -0,0 +1,227 @@
const xe = require("xe-utils")
/**
* 状态机-编排复杂的流程状态业务
* @param {string} listName 列名.
*/
module.exports = class Status {
constructor(listName, status, data) {
this.data = data
this.status = status
this.listName = listName
this.list = []
}
/**
* 返回上个状态
*/
back() {
let index = this.getStatusIndex(this.listName, this.status)
const res = this.getList(this.listName)
if ((index - 1) < 0) {
return null
}
const status = res.status[index - 1]
if (res.listName && status.name) {
this.go(res.listName, status.name)
}
return this
}
/**
* 下一个状态
*/
next() {
let index = this.getStatusIndex(this.listName, this.status)
const res = this.getList(this.listName)
if (res.status.length <= (index + 1)) {
return null
}
const status = res.status[index + 1]
if (res.listName && status.name) {
this.go(res.listName, status.name)
}
return this
}
/**
* 触发成功事件
*/
success() {
const index = this.getStatusIndex(this.listName, this.status)
const res = this.getList(this.listName)
const status = res.status[index]
if (status.success.event) { this.emitEvent(status.success.event) }
if (status.success.listName && status.success.status) {
this.go(status.success.listName, status.success.status)
}
return this
}
emitEvent(eventName) {
console.log("emitEvent:", eventName);
}
fail() {
const index = this.getStatusIndex(this.listName, this.status)
const res = this.getList(this.listName)
const status = res.status[index]
if (status.fail.event) { this.emitEvent(status.fail.event) }
if (status.fail.listName && status.fail.status) {
this.go(status.fail.listName, status.fail.status)
}
return this
}
go(listName, status) {
this.status = status
this.listName = listName
return this
}
getStatusIndex(listName, status) {
const res = this.getList(listName)
let index = xe.findKey(res.status, item => item.name === status)
return index ? Number(index) : null
}
getList(listName) {
const res = this.list.filter(item => item.listName === listName)
if (res.length <= 0) { return false }
return res[0]
}
push({status, success, fail}) {
const res = this.getList(this.listName)
if (res) {
success = success || {}
success["listName"] = success["listName"] || ""
success["status"] = success["status"] || ""
success["event"] = success["event"] || ""
fail = fail || {}
fail["listName"] = fail["listName"] || ""
fail["status"] = fail["status"] || ""
fail["event"] = fail["event"] || ""
res.status.push({
name : status,
success: success,
fail : fail,
})
}
else {return false}
return this
}
create(listName) {
if (!listName) { return false }
const res = this.getList(listName)
if (res) { return false }
this.list.push({
listName: listName,
status : []
})
this.listName = listName
return this
}
}
//
// const s = new Status()
//
// s.create("ord")
// .push({
// status : "start",
// success: {
// listName: "ord", //成功后切换到的listName
// status : "pay", //成功后切换到的status
// event : "ord.start",
// },
// fail : {
// listName: "", //失败后切换到的listName
// status : "", //失败后切换到的status
// event : "",
// },
// })
// .push({
// status : "pay",
// success: {
// listName: "ord", //成功后切换到的listName
// status : "end", //成功后切换到的status
// event : "ord.pay",
// },
// fail : {
// listName: "refund", //失败后切换到的listName
// status : "start", //失败后切换到的status
// event : "",
// },
// })
// .push({
// status : "end",
// success: {
// listName: "", //成功后切换到的listName
// status : "", //成功后切换到的status
// event : "ord.end",
// },
// fail : {
// listName: "", //失败后切换到的listName
// status : "", //失败后切换到的status
// event : "",
// },
// })
// s.create("refund")
// .push({
// status : "start",
// success: {
// listName: "refund", //成功后切换到的listName
// status : "ret", //成功后切换到的status
// event : "refund.start",
// },
// fail : {
// listName: "", //失败后切换到的listName
// status : "", //失败后切换到的status
// event : "",
// },
// })
// .push({
// status : "ret",
// success: {
// listName: "refund", //成功后切换到的listName
// status : "end", //成功后切换到的status
// event : "refund.ret",
// },
// fail : {
// listName: "", //失败后切换到的listName
// status : "", //失败后切换到的status
// event : "",
// },
// })
// .push({
// status : "end",
// success: {
// listName: "", //成功后切换到的listName
// status : "", //成功后切换到的status
// event : "refund.end",
// },
// fail : {
// listName: "", //失败后切换到的listName
// status : "", //失败后切换到的status
// event : "",
// },
// })
// // console.log(s);
//
// s.go("ord", "start")
// console.log(s.listName, s.status);
// s.success()
// console.log(s.listName, s.status);
// s.fail()
// console.log(s.listName, s.status);
// s.success()
// console.log(s.listName, s.status);
// s.success()
// console.log(s.listName, s.status);
// s.success()
// console.log(s.listName, s.status);
// s.next()
// console.log(s.listName, s.status);
+1 -1
View File
@@ -13,6 +13,6 @@ require('@babel/register')({
] ]
}) })
require('@babel/polyfill') require('@babel/polyfill')
const bamboo = require('./bamboo/index') const bamboo = require('./bamboo/bamboo')
const app = new bamboo(); const app = new bamboo();
// app.listen(3000); // app.listen(3000);
+8
View File
@@ -0,0 +1,8 @@
'use strict';
const bodyParser = require('koa-bodyparser')
// 错误处理
module.exports = {
sort: 4, //排序
use : true, // 是否使用
fun : bodyParser()
}
+16
View File
@@ -0,0 +1,16 @@
'use strict';
const error = require('koa-json-error')
// 错误处理
module.exports = {
sort: 3, //排序
use : true, // 是否使用
fun : error((err) => {
return {
status : err.status,
message: err.message,
code : err.code,
res : false,
// postFormat: (e, obj) => process.env.NODE_ENV === 'production' ? _.omit(obj, 'stack') : obj
}
})
}
+7
View File
@@ -0,0 +1,7 @@
'use strict';
const logger = require('koa-logger')
module.exports = {
sort: 2, //排序
use : true, // 是否使用
fun : logger()
}
+14
View File
@@ -0,0 +1,14 @@
'use strict';
/*响应时间*/
module.exports = {
sort: 1, //排序
use : true, // 是否使用
fun : async (ctx, next, app) => {
// console.log(ctx, next, options);
// const timetaken = `${ctx.request.method}${ctx.request.url} 响应时间`
// console.time(timetaken)
// app.logger.debug("123")
await next()
// console.timeEnd(timetaken)
}
}
+3
View File
@@ -39,13 +39,16 @@
"dependencies": { "dependencies": {
"@babel/core": "^7.16.7", "@babel/core": "^7.16.7",
"@babel/node": "^7.16.8", "@babel/node": "^7.16.8",
"@babel/plugin-proposal-decorators": "^7.17.9",
"@babel/polyfill": "^7.4.4", "@babel/polyfill": "^7.4.4",
"@babel/preset-env": "^7.16.8", "@babel/preset-env": "^7.16.8",
"@babel/runtime": "^7.5.5", "@babel/runtime": "^7.5.5",
"ajv": "^8.11.0", "ajv": "^8.11.0",
"babel-loader": "^8.2.3", "babel-loader": "^8.2.3",
"bamboo_smf": "^1.0.5",
"clean-webpack-plugin": "^4.0.0", "clean-webpack-plugin": "^4.0.0",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"glob": "^8.0.1",
"koa-bodyparser": "^4.3.0", "koa-bodyparser": "^4.3.0",
"koa-json-error": "^3.1.2", "koa-json-error": "^3.1.2",
"koa-logger": "^2.0.1", "koa-logger": "^2.0.1",
+12
View File
@@ -0,0 +1,12 @@
'use strict';
// 定时任务
module.exports = [
{
name : "",
time : "*/3 * * * * *",
run : true,//系统启动时立即执行一次
schedule: (app) => {
// console.log('每3秒我执行一次' + app.utils.VERSION)
}
},
]
View File
Binary file not shown.
@@ -3,6 +3,5 @@ module.exports = {
model: { model: {
fileName: {type: "STRING", comment: '文件名称'}, fileName: {type: "STRING", comment: '文件名称'},
md5 : {type: "TEXT", comment: 'md5记录'}, md5 : {type: "TEXT", comment: 'md5记录'},
md5json : {type: "JSON", comment: 'md5记录'},
} }
} }
+25
View File
@@ -0,0 +1,25 @@
module.exports = {
doc : "数据权限表(只在默认api生效)",
model: {
code : {type: "STRING", comment: '角色代码'},
table: {type: "STRING", comment: '表名'},
key : {type: "STRING", comment: '表字段'},
crud: {
type : "ENUM", comment: 'crud权限',
values: [
"C", // 创建
"R", // 读取
"U", // 更新
"D", // 删除
]
},
value: {
type : "ENUM", comment: '状态',
values: [
0, // 禁止
1, //通行
],
defaultValue: 0,
},
}
}
+16
View File
@@ -0,0 +1,16 @@
module.exports = {
doc : "页面元素是否显示权限表",
model: {
code : {type: "STRING", comment: '角色代码'},
key : {type: "STRING", comment: '元素id', unique: true},
value: {
type : "ENUM", comment: '状态',
values : [
//注意,一般页面元素会很多,默认是显示状态
0, // 通行
1, //禁止
],
defaultValue: 0,
},
}
}
+15
View File
@@ -0,0 +1,15 @@
module.exports = {
doc : "页面权限表",
model: {
code : {type: "STRING", comment: '角色代码'},
key : {type: "STRING", comment: '页面标识,一般是页面url',unique: true},
value: {
type : "ENUM", comment: '状态',
values: [
0, // 禁止
1, //通行
],
defaultValue: 0,
},
}
}
+16
View File
@@ -0,0 +1,16 @@
module.exports = {
doc : "角色",
model: {
cname: {type: "STRING", comment: '角色别名'},
code : {type: "STRING", comment: '角色代码'},
super: {
type : "ENUM", comment: '是否为超级管理员(不校验权限)',
values : [
0, // api地址
1, //url地址
],
defaultValue: 0,
},
doc : {type: "TEXT", comment: '说明'},
}
}
+14
View File
@@ -0,0 +1,14 @@
module.exports = {
doc : "路由表表",
model: {
name: {type: "STRING", comment: '路由名称'},
key : {type: "STRING", comment: '路由标识,一般是路由url或页面url'},
type: {
type : "ENUM", comment: '字段类型',
values: [
'api', // api地址
'url', //url地址
]
},
}
}
+19
View File
@@ -0,0 +1,19 @@
module.exports = {
doc : "系统设置",
model: {
title: {type: "STRING", comment: '字段标题'},
doc : {type: "TEXT", comment: '字段说明'},
type : {
type : "ENUM", comment: '字段类型',
values: [
'int', // 整数
'string', //字符串
'json', // json
'rich' // 富文本
],
defaultValue: 'string',
},
code : {type: "STRING", comment: '字段code'},
value: {type: "TEXT", comment: '值'},
}
}