-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: move feiyun-handler to this project, rename to @feiyun/handler
- Loading branch information
Showing
13 changed files
with
983 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from 'class-transformer'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from 'class-validator'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/types |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from 'class-transformer' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"type": "module", | ||
"main": "./dist/index.cjs", | ||
"module": "./dist/index.mjs", | ||
"types": "../types/class-transformer/index.d.ts" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from 'class-validator' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"type": "module", | ||
"main": "./dist/index.cjs", | ||
"module": "./dist/index.mjs", | ||
"types": "../types/class-validator/index.d.ts" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
{ | ||
"name": "feiyun-handler", | ||
"version": "0.0.21", | ||
"license": "MIT", | ||
"type": "module", | ||
"main": "./src/index.ts", | ||
"publishConfig": { | ||
"main": "./dist/index.cjs", | ||
"module": "./dist/index.mjs", | ||
"types": "./types/src/index.d.ts", | ||
"exports": { | ||
".": { | ||
"types": "./types/src/index.d.ts", | ||
"import": "./dist/index.mjs", | ||
"require": "./dist/index.cjs" | ||
}, | ||
"./class-validator": { | ||
"types": "./types/class-validator/index.d.ts", | ||
"import": "./class-validator/dist/index.mjs", | ||
"require": "./class-validator/dist/index.cjs" | ||
}, | ||
"./class-transformer": { | ||
"types": "./types/class-transformer/index.d.ts", | ||
"import": "./class-transformer/dist/index.mjs", | ||
"require": "./class-transformer/dist/index.cjs" | ||
} | ||
} | ||
}, | ||
"files": [ | ||
"dist", | ||
"class-validator/dist", | ||
"class-validator/package.json", | ||
"class-transformer/dist", | ||
"class-transformer/package.json", | ||
"types" | ||
], | ||
"exports": { | ||
".": { | ||
"import": "./src/index.ts" | ||
}, | ||
"./class-validator": { | ||
"import": "./class-validator/index.ts" | ||
}, | ||
"./class-transformer": { | ||
"import": "./class-transformer/index.ts" | ||
} | ||
}, | ||
"scripts": { | ||
"build": "rimraf **/dist && tsc && rollup -c", | ||
"prepublishOnly": "pnpm build" | ||
}, | ||
"devDependencies": { | ||
"@feiyun/server": "workspace:^", | ||
"@rollup/plugin-node-resolve": "^15.2.3", | ||
"@rollup/plugin-typescript": "^11.1.6", | ||
"@types/node": "^20.11.19", | ||
"feiyun": "^0.2.3", | ||
"reflect-metadata": "^0.2.1", | ||
"rollup": "^4.12.0", | ||
"rollup-plugin-ts": "^3.4.5", | ||
"tslib": "^2.6.2", | ||
"typescript": "^5.3.3" | ||
}, | ||
"dependencies": { | ||
"class-transformer": "^0.5.1", | ||
"class-validator": "^0.14.0", | ||
"glob": "^10.3.10" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import typescript from '@rollup/plugin-typescript'; | ||
import resolve from '@rollup/plugin-node-resolve'; | ||
|
||
import { defineConfig } from 'rollup'; | ||
export default defineConfig([{ | ||
input: 'src/index.ts', | ||
output: [{ | ||
file: 'dist/index.cjs', | ||
format: 'cjs' | ||
}, { | ||
file: 'dist/index.mjs', | ||
format: 'esm' | ||
}], | ||
plugins: [typescript({ | ||
compilerOptions: { | ||
outDir: "./dist", | ||
declaration: false, | ||
declarationDir: undefined | ||
} | ||
})] | ||
}, { | ||
input: 'class-transformer/index.ts', | ||
output: [{ | ||
file: 'class-transformer/dist/index.cjs', | ||
format: 'cjs' | ||
}, { | ||
file: 'class-transformer/dist/index.mjs', | ||
format: 'esm' | ||
}], | ||
plugins: [typescript({ | ||
compilerOptions: { | ||
outDir: "./class-validator/dist", | ||
declaration: false, | ||
declarationDir: undefined | ||
} | ||
})] | ||
}, { | ||
input: 'class-validator/index.ts', | ||
output: [{ | ||
file: 'class-validator/dist/index.cjs', | ||
format: 'cjs' | ||
}, { | ||
file: 'class-validator/dist/index.mjs', | ||
format: 'esm' | ||
}], | ||
plugins: [typescript({ | ||
compilerOptions: { | ||
outDir: "./class-validator/dist", | ||
declaration: false, | ||
declarationDir: undefined | ||
} | ||
})] | ||
}]); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
import "reflect-metadata"; | ||
import { glob } from "glob"; | ||
import path from "node:path"; | ||
import { plainToInstance } from "class-transformer"; | ||
import { validate } from "class-validator"; | ||
|
||
import type { Context, FeiyunMiddleware } from 'feiyun' | ||
const PATH_METADATA = 'path'; | ||
const METHOD_METADATA = 'method'; | ||
const PARAM_METADATA = 'param'; | ||
const PARAM_VALIDATE_METADATA = 'param_validate' | ||
|
||
/** | ||
* 类装饰 | ||
* @param path 路径 | ||
* @returns | ||
*/ | ||
export const Handler = (path?: string): ClassDecorator => { | ||
return target => { | ||
path = typeof path === 'undefined' ? target.name : path; | ||
Reflect.defineMetadata(PATH_METADATA, path, target); | ||
} | ||
} | ||
|
||
/** | ||
* 方法装饰 | ||
* @param path 路径 | ||
* @returns | ||
*/ | ||
export const Method = (path?: string): MethodDecorator => { | ||
return (target, key, descriptor: any) => { | ||
if (typeof key === 'string') { | ||
path = typeof path === 'undefined' ? key : path; | ||
Reflect.defineMetadata(METHOD_METADATA, path, descriptor.value); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* 参数装饰 | ||
* @param name 参数名 | ||
* @param checker 检查器/处理器 | ||
* @returns | ||
*/ | ||
export const Param = (name: string, checker?: (val: any) => void): ParameterDecorator => { | ||
return (target, key, index) => { | ||
if (!key) { | ||
return; | ||
} | ||
|
||
const param = Reflect.get(target, key); | ||
let params = Reflect.getMetadata(PARAM_METADATA, param); | ||
if (!params) { | ||
params = []; | ||
} | ||
params.push([index, name, checker]); | ||
Reflect.defineMetadata(PARAM_METADATA, params, param); | ||
} | ||
} | ||
|
||
/** | ||
* 声明参数需要进行校验,并用目标类型重新实例 | ||
* @param target | ||
* @param key | ||
* @param index | ||
*/ | ||
export const ParamType: ParameterDecorator = (target, key, index) => { | ||
if (!key) { | ||
return; | ||
} | ||
const types = Reflect.getMetadata("design:paramtypes", target, key); | ||
// console.log(Object.getOwnPropertyDescriptors(Reflect.ownKeys(types[index].prototype))); | ||
Reflect.defineMetadata(PARAM_VALIDATE_METADATA, types[index], Reflect.get(target, key)); | ||
} | ||
|
||
|
||
const METHOD_DOC_METADATA = 'method_doc'; | ||
|
||
type Options = { | ||
/** | ||
* 标题 | ||
*/ | ||
title: string | ||
/** | ||
* 描述 | ||
*/ | ||
description: string | ||
} | ||
/** | ||
* 文档 | ||
*/ | ||
export const ApiDoc = (options: Options): MethodDecorator => { | ||
return (target, key, descriptor: any) => { | ||
Reflect.defineMetadata(METHOD_DOC_METADATA, options, descriptor.value); | ||
} | ||
} | ||
|
||
|
||
export const useMapRoute = (handlers: any[]) => { | ||
|
||
const all = new Map(); | ||
|
||
for (let i = 0; i < handlers.length; i++) { | ||
console.log(handlers[i]); | ||
const handler = new handlers[i](); | ||
const prototype = Object.getPrototypeOf(handler) as ClassDecorator; | ||
// 取出路径 | ||
const handlerPathMeta = Reflect.getMetadata(PATH_METADATA, prototype.constructor); | ||
const methods = Object.getOwnPropertyNames(prototype).filter(item => { | ||
// 构造函数,暂时不处理 | ||
if (item === 'constructor') { | ||
return false; | ||
} | ||
return typeof Reflect.get(prototype, item) === 'function'; | ||
}); | ||
|
||
methods.forEach(methodName => { | ||
const method = Reflect.get(prototype, methodName); | ||
const methodPath = Reflect.getMetadata(METHOD_METADATA, method); | ||
if (!methodPath) { | ||
return; | ||
} | ||
const path = handlerPathMeta + '/' + methodPath; | ||
|
||
all.set(path, { | ||
method: method.bind(handler), | ||
validate: Reflect.getMetadata(PARAM_VALIDATE_METADATA, method), | ||
doc: Reflect.getMetadata(METHOD_DOC_METADATA, method), | ||
}); | ||
}) | ||
} | ||
|
||
return all; | ||
} | ||
|
||
/** | ||
* 异常抛出基类 | ||
*/ | ||
export class ResponseError extends Error { | ||
constructor(msg: string, public code = 500) { | ||
super(msg); | ||
} | ||
} | ||
|
||
const runHandler = async (handler: any, ctx: Context) => { | ||
if (handler.validate) { | ||
const errors = await validate(plainToInstance(handler.validate, ctx.request.data)); | ||
if (errors.length > 0) { | ||
console.error(errors); | ||
ctx.response.data = { | ||
code: 500, | ||
msg: Object.values(errors![0].constraints!)[0] | ||
} | ||
} | ||
return; | ||
} | ||
|
||
try { | ||
const res = await handler.method(ctx.request.data, ctx.socket); | ||
if (res) { | ||
ctx.response.data = { | ||
data: res | ||
}; | ||
} | ||
} catch (e) { | ||
if (e instanceof ResponseError) { | ||
ctx.response.data = { | ||
code: e.code, | ||
msg: e.message | ||
} | ||
} else { | ||
console.error(e); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* 自动导入应用文件 | ||
* @param baseDir 应用文件夹 | ||
* @param rule 导入路径规则 | ||
* @returns | ||
*/ | ||
export const include = async (baseDir: string, rule = '**/*.handler.ts'): Promise<FeiyunMiddleware> => { | ||
// const dirs = await readdir(path); | ||
// const files = await findUp(path + '/' + rule); | ||
// console.log(files); | ||
console.log(path.resolve(baseDir, rule)); | ||
const handlerPaths = await glob(path.resolve(baseDir, rule)); | ||
|
||
const handlers = []; | ||
|
||
for (let i = 0; i < handlerPaths.length; i++) { | ||
const handler = await import(handlerPaths[i]); | ||
if (handler.default) { | ||
handlers.push(handler.default); | ||
} | ||
} | ||
|
||
const mapRoute = useMapRoute(handlers); | ||
|
||
return async (ctx, next) => { | ||
const handler = mapRoute.get(ctx.request.url); | ||
if (handler) { | ||
await runHandler(handler, ctx); | ||
} | ||
next(); | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"extends": "../../tsconfig.json", | ||
"compilerOptions": { | ||
"noUnusedLocals": false, | ||
"noUnusedParameters": false, | ||
"noImplicitReturns": false, | ||
"declaration": true, | ||
"declarationDir": "./types", | ||
}, | ||
"include": [ | ||
"src", | ||
"class-validator", | ||
"class-transformer", | ||
] | ||
} |
Oops, something went wrong.