10 changed files with 1470 additions and 1097 deletions
File diff suppressed because it is too large
@ -0,0 +1,190 @@ |
|||||
|
// @ts-nocheck
|
||||
|
|
||||
|
import { walkDir, removeIndex, isIndexEnd } from "./util" |
||||
|
import * as Joi from "joi" |
||||
|
const path = require("path") |
||||
|
const fs = require("fs") |
||||
|
|
||||
|
class routePlugin { |
||||
|
public name: string = "routePlugin" |
||||
|
public version: string = "0.0.1" |
||||
|
public register(server: any, opts: any) { |
||||
|
const sourceDir = opts.sourceDir |
||||
|
const type = opts.type || "jwt" |
||||
|
const auth = opts.auth || [] |
||||
|
let array = [] |
||||
|
for (let i = 0; i < sourceDir.length; i++) { |
||||
|
const dir = sourceDir[i] |
||||
|
console.log(dir) |
||||
|
array.push(dir.dir + "对应路径:") |
||||
|
array = array.concat(this.registerRoute(server, dir.dir, dir.prefix || "", auth, type)) |
||||
|
} |
||||
|
fs.writeFileSync(path.resolve(process.cwd(), "route.txt"), array.join("\n"), { |
||||
|
encoding: "utf-8", |
||||
|
}) |
||||
|
} |
||||
|
registerRoute(server, sourceDir, prefix, auth, type) { |
||||
|
const files = walkDir(sourceDir) |
||||
|
const routes = [] |
||||
|
files.forEach(file => { |
||||
|
let filename = file.relativeFileNoExt |
||||
|
let array = filename.split(path.sep).slice(1) |
||||
|
let fileNoExt = removeIndex("/" + array.join("/")) |
||||
|
const moduleName = path.resolve(sourceDir, filename) |
||||
|
const obj = require(moduleName) |
||||
|
if (obj.default) { |
||||
|
const func = new (obj.default || obj)() |
||||
|
const prototype = Object.getPrototypeOf(func) |
||||
|
const keys = Reflect.ownKeys(prototype) |
||||
|
for (const key of keys) { |
||||
|
if (key !== "constructor") { |
||||
|
let ff = func[key] |
||||
|
let handler: () => void = undefined |
||||
|
// 默认方法
|
||||
|
const method = ff.$method || "GET" |
||||
|
// 路由收集规则
|
||||
|
let route = "" |
||||
|
if (ff.$route) { |
||||
|
if (isIndexEnd(fileNoExt)) { |
||||
|
route = ff.$route |
||||
|
} else { |
||||
|
route = fileNoExt + ff.$route |
||||
|
} |
||||
|
} else { |
||||
|
if (isIndexEnd(fileNoExt)) { |
||||
|
route = fileNoExt + key.toString() |
||||
|
} else { |
||||
|
route = fileNoExt + "/" + key.toString() |
||||
|
} |
||||
|
} |
||||
|
route = removeIndex(route) |
||||
|
route = prefix ? route[0] + prefix + "/" + route.slice(1) : route |
||||
|
// 配置规则
|
||||
|
const options = ff.$options ? ff.$options : {} |
||||
|
if (!options.auth) { |
||||
|
if (ff.$auth == undefined) { |
||||
|
if (auth && auth.length && auth.filter(v => route.startsWith(v)).length) { |
||||
|
options.auth = type |
||||
|
} else { |
||||
|
options.auth = false |
||||
|
} |
||||
|
} else if (ff.$auth) { |
||||
|
options.auth = |
||||
|
typeof ff.$auth === "boolean" |
||||
|
? type |
||||
|
: { |
||||
|
strategy: type, |
||||
|
mode: ff.$auth, |
||||
|
} |
||||
|
} else { |
||||
|
options.auth = false |
||||
|
} |
||||
|
} |
||||
|
if (!options.validate) { |
||||
|
let validateObj = ff.$validate || {} |
||||
|
if (options.auth && type === "jwt") { |
||||
|
if (validateObj.headers) { |
||||
|
validateObj.headers = validateObj.headers.keys({ |
||||
|
Authorization: Joi.string(), |
||||
|
}) |
||||
|
} else { |
||||
|
validateObj.headers = Joi.object({ |
||||
|
headers: Joi.object({ |
||||
|
Authorization: Joi.string(), |
||||
|
}).unknown(), // 注意加上这个
|
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
if (validateObj && !!Object.keys(validateObj).length) { |
||||
|
const failReason = validateObj.failReason |
||||
|
delete validateObj.failReason |
||||
|
if (validateObj.failAction === "log") { |
||||
|
if (!options.log) options.log = {} |
||||
|
options.log.collect = true |
||||
|
let errto = validateObj.$errto |
||||
|
handler = async function (...argus) { |
||||
|
const request = argus[0] |
||||
|
const h = argus[1] |
||||
|
if (request.logs && !!request.logs.length && errto) { |
||||
|
// request.yar.flash('error', request.logs.map((v: any)=>v.error.message));
|
||||
|
request.yar.flash("error", failReason || request.logs.map((v: any)=>v.error.message)) |
||||
|
return h.redirect(errto) |
||||
|
} |
||||
|
return await ff.call(this, ...argus) |
||||
|
} |
||||
|
} |
||||
|
if (validateObj.failAction === "function") { |
||||
|
let errto = validateObj.$errto |
||||
|
validateObj.failAction = async function (request, h, err) { |
||||
|
if (err.details) { |
||||
|
request.$joi_error = err.details.map(v => v.message) |
||||
|
} |
||||
|
return h.continue |
||||
|
} |
||||
|
handler = async function (...argus) { |
||||
|
const request = argus[0] |
||||
|
const h = argus[1] |
||||
|
if (request.$joi_error) { |
||||
|
loggerSite.debug("传输参数错误: ", request.$joi_error) |
||||
|
request.yar.flash("error", failReason || request.$joi_error) |
||||
|
delete request.$joi_error |
||||
|
return h.redirect(errto) |
||||
|
} |
||||
|
return await ff.call(this, ...argus) |
||||
|
} |
||||
|
} |
||||
|
options.validate = validateObj |
||||
|
} |
||||
|
} |
||||
|
// && route.startsWith("/api")
|
||||
|
if (ff.$swagger) { |
||||
|
options.description = ff.$swagger[0] |
||||
|
options.notes = ff.$swagger[1] |
||||
|
options.tags = ff.$swagger[2] |
||||
|
} |
||||
|
let str = route |
||||
|
if ( |
||||
|
(typeof options.auth === "string" && options.auth) || |
||||
|
(typeof options.auth === "object" && options.auth.mode === "required") |
||||
|
) { |
||||
|
str = " 需要权限 : " + " " + full(method) + " " + str |
||||
|
} else if (typeof options.auth === "object" && options.auth.mode === "optional") { |
||||
|
str = " 不需权限(提供即需验证): " + " " + full(method) + " " + str |
||||
|
} else if (typeof options.auth === "object" && options.auth.mode === "try") { |
||||
|
str = " 不需权限(提供无需验证): " + " " + full(method) + " " + str |
||||
|
} else { |
||||
|
str = " 不需权限 : " + " " + full(method) + " " + str |
||||
|
} |
||||
|
routes.push(str) |
||||
|
|
||||
|
if (options.validate && options.validate.$errto) { |
||||
|
delete options.validate.$errto |
||||
|
} |
||||
|
if (!handler) { |
||||
|
handler = ff |
||||
|
} |
||||
|
server.route({ |
||||
|
method: method, |
||||
|
path: route, |
||||
|
handler: handler, |
||||
|
options: options, |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
return routes |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function full(str: string, length = 10) { |
||||
|
let len = str.length |
||||
|
let need = length - len |
||||
|
if (need <= 0) return str |
||||
|
return str + [...Array(need)].map((v, i) => " ").join("") |
||||
|
} |
||||
|
|
||||
|
const plugin = new routePlugin() |
||||
|
|
||||
|
export { plugin } |
||||
|
export * from "./util/decorators" |
@ -0,0 +1,40 @@ |
|||||
|
// @ts-nocheck
|
||||
|
/** |
||||
|
* 方法 |
||||
|
* @param opts 参数 |
||||
|
*/ |
||||
|
type TMethod = "GET" | "POST" | "PUT" | "DELETE" |
||||
|
export function method(opts?: TMethod | Array<TMethod>) { |
||||
|
return function (target, propertyKey: string, descriptor: PropertyDescriptor) { |
||||
|
target[propertyKey].$method = opts |
||||
|
} |
||||
|
} |
||||
|
export function route(route?: string) { |
||||
|
return function (target, propertyKey: string, descriptor: PropertyDescriptor) { |
||||
|
target[propertyKey].$route = route |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export function config(options: Object) { |
||||
|
return function (target, propertyKey: string, descriptor: PropertyDescriptor) { |
||||
|
target[propertyKey].$options = options |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export function auth(isAuth: boolean | "try" | "required" | "optional" = true) { |
||||
|
return function (target, propertyKey: string, descriptor: PropertyDescriptor) { |
||||
|
target[propertyKey].$auth = isAuth |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export function validate(validate: Object) { |
||||
|
return function (target, propertyKey: string, descriptor: PropertyDescriptor) { |
||||
|
target[propertyKey].$validate = validate |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export function swagger(desc, notes, tags) { |
||||
|
return function (target, propertyKey: string, descriptor: PropertyDescriptor) { |
||||
|
target[propertyKey].$swagger = [desc, notes, tags] |
||||
|
} |
||||
|
} |
@ -0,0 +1,81 @@ |
|||||
|
// @ts-nocheck
|
||||
|
|
||||
|
const path = require("path") |
||||
|
const fs = require("fs") |
||||
|
|
||||
|
export function removeIndex(ss: any) { |
||||
|
const remove = (str: any) => { |
||||
|
if (str.endsWith("/index")) { |
||||
|
return str.slice(0, -6) |
||||
|
} |
||||
|
if (str.endsWith("index")) { |
||||
|
return str.slice(0, -5) |
||||
|
} |
||||
|
return str ? str : "/" |
||||
|
} |
||||
|
let r = true |
||||
|
let rr = ss |
||||
|
while (r) { |
||||
|
if (rr.endsWith("/index")) { |
||||
|
rr = remove(rr) |
||||
|
} else { |
||||
|
r = false |
||||
|
} |
||||
|
} |
||||
|
return rr ? rr : "/" |
||||
|
} |
||||
|
|
||||
|
export function isIndexEnd(str: any) { |
||||
|
return str.length == 1 && str.endsWith("/") |
||||
|
} |
||||
|
|
||||
|
export function walkDir( |
||||
|
filePath: any, |
||||
|
exclude = ["node_modules", "^_", ".git", ".idea", ".gitignore", "client", ".txt$", ".test.js$", ".test.ts$"], |
||||
|
) { |
||||
|
let files: any[] = [] |
||||
|
function Data(opts: any) { |
||||
|
this.relativeDir = opts.relativeDir |
||||
|
this.relativeFile = opts.relativeFile |
||||
|
this.filename = opts.filename |
||||
|
this.file = opts.file |
||||
|
this.absoluteFile = opts.absoluteFile |
||||
|
this.relativeFileNoExt = opts.relativeFileNoExt |
||||
|
this.absoluteDir = opts.absoluteDir |
||||
|
} |
||||
|
function readDir(filePath, dirname = ".") { |
||||
|
let res = fs.readdirSync(filePath) |
||||
|
res.forEach(filename => { |
||||
|
const filepath = path.resolve(filePath, filename) |
||||
|
const stat = fs.statSync(filepath) |
||||
|
const name = filepath.split(path.sep).slice(-1)[0] |
||||
|
if (typeof exclude === "string" && new RegExp(exclude).test(name)) { |
||||
|
return |
||||
|
} |
||||
|
if (Array.isArray(exclude)) { |
||||
|
for (let i = 0; i < exclude.length; i++) { |
||||
|
const excludeItem = exclude[i] |
||||
|
if (new RegExp(excludeItem).test(name)) { |
||||
|
return |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
if (!stat.isFile()) { |
||||
|
readDir(filepath, dirname + path.sep + name) |
||||
|
} else { |
||||
|
const data = new Data({ |
||||
|
relativeDir: dirname, |
||||
|
relativeFile: dirname + path.sep + path.parse(filepath).base, |
||||
|
relativeFileNoExt: dirname + path.sep + path.parse(filepath).name, |
||||
|
file: path.parse(filepath).base, |
||||
|
filename: path.parse(filepath).name, |
||||
|
absoluteFile: filepath, |
||||
|
absoluteDir: path.parse(filepath).dir, |
||||
|
}) |
||||
|
files.push(data) |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
readDir(filePath) |
||||
|
return files |
||||
|
} |
Loading…
Reference in new issue