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