feat: perfect router lib add validator

This commit is contained in:
xion 2024-06-29 23:09:32 +08:00
parent c92f42933e
commit f3c0707666
7 changed files with 274 additions and 184 deletions

20
package-lock.json generated
View File

@ -9,7 +9,7 @@
"version": "0.0.2", "version": "0.0.2",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@abearxiong/router": "^0.0.1-alpha.8", "@abearxiong/router": "^0.0.1-alpha.12",
"@abearxiong/use-config": "^0.0.1", "@abearxiong/use-config": "^0.0.1",
"@babel/core": "^7.24.7", "@babel/core": "^7.24.7",
"@babel/preset-env": "^7.24.7", "@babel/preset-env": "^7.24.7",
@ -50,12 +50,14 @@
} }
}, },
"node_modules/@abearxiong/router": { "node_modules/@abearxiong/router": {
"version": "0.0.1-alpha.8", "version": "0.0.1-alpha.12",
"resolved": "https://npm.pkg.github.com/download/@abearxiong/router/0.0.1-alpha.8/772276fc4290291f845b0bb7198acc1c439f72e3", "resolved": "https://npm.pkg.github.com/download/@abearxiong/router/0.0.1-alpha.12/ca2bf4832b4f032965b4c579b7bbde04a05f893a",
"integrity": "sha512-uX9YkeS+TDKKH8y1fShTKgxcXWeawaoLLi/kdX04M84o3sg1vZSic4wxEMuznAjESX/iYIc94vXyE6cevoWVLQ==", "integrity": "sha512-Hqe8HdxUTCjl31ExVpb1Ro4KuvqsjcbZwcISyzImDe5xN4yMBh3zZCZOTrbSB9OsxukX5rqQ4kvufLWbbfp46g==",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"nanoid": "^5.0.6" "lodash": "^4.17.21",
"nanoid": "^5.0.6",
"zod": "^3.23.8"
} }
}, },
"node_modules/@abearxiong/use-config": { "node_modules/@abearxiong/use-config": {
@ -8141,6 +8143,14 @@
"funding": { "funding": {
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
},
"node_modules/zod": {
"version": "3.23.8",
"resolved": "https://registry.npmmirror.com/zod/-/zod-3.23.8.tgz",
"integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
} }
} }
} }

View File

@ -24,7 +24,7 @@
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@abearxiong/router": "^0.0.1-alpha.8", "@abearxiong/router": "^0.0.1-alpha.12",
"@abearxiong/use-config": "^0.0.1", "@abearxiong/use-config": "^0.0.1",
"@babel/core": "^7.24.7", "@babel/core": "^7.24.7",
"@babel/preset-env": "^7.24.7", "@babel/preset-env": "^7.24.7",

View File

@ -1,168 +1,2 @@
// admin 需要最后运行并在route中进行过滤。 import './router.ts';
import { Route } from '@abearxiong/router'; import './manager.ts';
import { router } from '../modules/router.ts';
import { manager, updateNewCode, removeCode, stopCode, startCode } from './dashboard/manager.ts';
import { loadOne } from './dashboard/load.ts';
import { RouterCodeModel } from '../models/code.ts';
import { nanoid } from 'nanoid';
import { convertTsToJs as transform } from '../lib/ts2js.ts';
export const getRouterList = new Route('admin', 'getRouterList');
getRouterList.run = async (ctx) => {
ctx.body = router.getList().filter((r) => !r.path.startsWith('admin'));
// ctx.body = router.getList().filter((r) => r.path.startsWith('admin'));
return ctx;
};
router.add(getRouterList);
// remove router
export const removeRouter = new Route('admin', 'removeRouter');
removeRouter.run = async (ctx) => {
const { path, key } = ctx.query;
router.remove({ path, key });
const routerCode = await RouterCodeModel.findOne({ where: { path, key } });
if (routerCode) {
const id = routerCode.id;
removeCode(id);
await RouterCodeModel.destroy({ where: { id } });
}
ctx.body = 'success';
return ctx;
};
router.add(removeRouter);
// remove router by id
export const removeRouterById = new Route('admin', 'removeRouterById');
removeRouterById.run = async (ctx) => {
const { id } = ctx.query;
router.removeById(id);
removeCode(id);
await RouterCodeModel.destroy({ where: { id } });
ctx.body = 'success';
return ctx;
};
router.add(removeRouterById);
// stop router by id
export const stopRouterById = new Route('admin', 'stopRouterById');
stopRouterById.run = async (ctx) => {
const { id } = ctx.query;
router.removeById(id);
const routerCode = await RouterCodeModel.findByPk(id);
if (routerCode) {
routerCode.active = false;
await routerCode.save();
}
stopCode(id);
ctx.body = 'success';
return ctx;
};
router.add(stopRouterById);
// start router by id
export const startRouterById = new Route('admin', 'startRouterById');
startRouterById.run = async (ctx) => {
const { id } = ctx.query;
const routerCode = await RouterCodeModel.findByPk(id);
console.log('routerCode', id, routerCode.toJSON());
if (routerCode) {
routerCode.active = true;
await routerCode.save();
startCode(routerCode);
}
ctx.body = 'success';
return ctx;
};
router.add(startRouterById);
// add or update router
export const updateRouter = new Route('admin', 'updateRouter');
updateRouter.run = async (ctx) => {
let { path, key, id, code, type = 'route' } = ctx.query;
if (!path && !key) {
ctx.body = 'path and key is required';
ctx.code = 500;
return ctx;
}
let codeRouter: RouterCodeModel | null = null;
const codeRouteCheck = await RouterCodeModel.findOne({ where: { path, key } }); // 检查是否存在
if (codeRouteCheck && codeRouteCheck.id !== id) {
key = `${key}-${nanoid(6)}`;
}
if (id) {
codeRouter = await RouterCodeModel.findByPk(id);
codeRouter.path = path;
codeRouter.key = key;
codeRouter.code = code;
try {
codeRouter.exec = await transform(code);
} catch (e) {
ctx.body = e.message.toString();
ctx.code = 500;
return ctx;
}
codeRouter.type = type;
await codeRouter.save();
} else {
try {
const exec = await transform(code);
const newCodeRouter = new RouterCodeModel({ path, key, code, exec, type });
await newCodeRouter.save();
codeRouter = newCodeRouter;
} catch (e) {
ctx.body = e.message.toString();
ctx.code = 500;
return ctx;
}
}
const codeOne = await loadOne(codeRouter);
updateNewCode(codeOne);
ctx.body = 'success';
return ctx;
};
router.add(updateRouter);
// get manager status
export const managerRouter = new Route('admin', 'getManagerStatus');
managerRouter.run = async (ctx) => {
ctx.body = {
status: manager.loaded,
msg: 'system is running, and load manager success.',
};
return ctx;
};
router.add(managerRouter);
// get manager list
export const managerList = new Route('admin', 'getManagerList');
managerList.run = async (ctx) => {
ctx.body = manager.list;
const routerList = router.getList().filter((r) => !r.path.startsWith('admin'));
ctx.body = {
list: manager.list,
routerList,
};
return ctx;
};
router.add(managerList);
// get manager one
export const managerOne = new Route('admin', 'getManagerOne');
managerOne.run = async (ctx) => {
const { id } = ctx.query;
const code = manager.list.find((c) => c.id === id);
if (code) {
ctx.body = code;
} else {
ctx.body = 'not found';
ctx.code = 404;
}
return ctx;
};
router.add(managerOne);

55
src/admin/manager.ts Normal file
View File

@ -0,0 +1,55 @@
// admin 需要最后运行并在route中进行过滤。
import { Route } from '@abearxiong/router';
import { router } from '../modules/router.ts';
import { manager, updateNewCode, removeCode, stopCode, startCode } from './dashboard/manager.ts';
import { loadOne } from './dashboard/load.ts';
import { RouterCodeModel } from '../models/code.ts';
// get manager status
export const managerRouter = new Route('admin', 'getManagerStatus');
managerRouter.run = async (ctx) => {
ctx.body = {
status: manager.loaded,
msg: 'system is running, and load manager success.',
};
return ctx;
};
router.add(managerRouter);
// get manager list
export const managerList = new Route('admin', 'getManagerList');
managerList.run = async (ctx) => {
ctx.body = manager.list;
const routerList = router.getList().filter((r) => !r.path.startsWith('admin'));
ctx.body = {
list: manager.list,
routerList,
};
return ctx;
};
router.add(managerList);
// get manager one
export const managerOne = new Route('admin', 'getManagerOne');
managerOne.run = async (ctx) => {
const verfiy = ctx.currentRoute.verify(ctx);
if (verfiy) return;
const { id } = ctx.query;
const code = manager.list.find((c) => c.id === id);
if (code) {
ctx.body = code;
} else {
ctx.body = 'not found';
ctx.code = 404;
}
return ctx;
};
managerOne.validator = {
id: {
type: 'string',
required: true,
},
};
router.add(managerOne);

183
src/admin/router.ts Normal file
View File

@ -0,0 +1,183 @@
// admin router manger
import { Route } from '@abearxiong/router';
import { router } from '../modules/router.ts';
import { manager, updateNewCode, removeCode, stopCode, startCode } from './dashboard/manager.ts';
import { loadOne } from './dashboard/load.ts';
import { RouterCodeModel } from '../models/code.ts';
import { nanoid } from 'nanoid';
import { convertTsToJs as transform } from '../lib/ts2js.ts';
export const getRouterList = new Route('admin', 'getRouterList');
getRouterList.run = async (ctx) => {
ctx.body = router.getList().filter((r) => !r.path.startsWith('admin'));
// ctx.body = router.getList().filter((r) => r.path.startsWith('admin'));
return ctx;
};
router.add(getRouterList);
// remove router
export const removeRouter = new Route('admin', 'removeRouter');
removeRouter.run = async (ctx) => {
const { path, key } = ctx.query;
router.remove({ path, key });
const routerCode = await RouterCodeModel.findOne({ where: { path, key } });
if (routerCode) {
const id = routerCode.id;
removeCode(id);
await RouterCodeModel.destroy({ where: { id } });
}
ctx.body = 'success';
return ctx;
};
removeRouter.validator = {
path: {
type: 'string',
required: true,
},
key: {
type: 'string',
required: true,
},
};
router.add(removeRouter);
// remove router by id
export const removeRouterById = new Route('admin', 'removeRouterById');
removeRouterById.run = async (ctx) => {
const { id } = ctx.query;
router.removeById(id);
removeCode(id);
await RouterCodeModel.destroy({ where: { id } });
ctx.body = 'success';
return ctx;
};
removeRouterById.validator = {
id: {
type: 'string',
required: true,
},
};
router.add(removeRouterById);
// stop router by id
export const stopRouterById = new Route('admin', 'stopRouterById');
stopRouterById.run = async (ctx) => {
const { id } = ctx.query;
router.removeById(id);
const routerCode = await RouterCodeModel.findByPk(id);
if (routerCode) {
routerCode.active = false;
await routerCode.save();
}
stopCode(id);
ctx.body = 'success';
return ctx;
};
stopRouterById.validator = {
id: {
type: 'string',
required: true,
},
};
router.add(stopRouterById);
// start router by id
export const startRouterById = new Route('admin', 'startRouterById');
startRouterById.run = async (ctx) => {
const { id } = ctx.query;
const routerCode = await RouterCodeModel.findByPk(id);
console.log('routerCode', id, routerCode.toJSON());
if (routerCode) {
routerCode.active = true;
await routerCode.save();
startCode(routerCode);
}
ctx.body = 'success';
return ctx;
};
startRouterById.validator = {
id: {
type: 'string',
required: true,
},
};
router.add(startRouterById);
// add or update router
export const updateRouter = new Route('admin', 'updateRouter');
updateRouter.run = async (ctx) => {
let { path, key, id, code, type = 'route' } = ctx.query;
if (!path && !key) {
ctx.body = 'path and key is required';
ctx.code = 500;
return ctx;
}
let codeRouter: RouterCodeModel | null = null;
const codeRouteCheck = await RouterCodeModel.findOne({ where: { path, key } }); // 检查是否存在
if (codeRouteCheck && codeRouteCheck.id !== id) {
key = `${key}-${nanoid(6)}`;
}
if (id) {
codeRouter = await RouterCodeModel.findByPk(id);
codeRouter.path = path;
codeRouter.key = key;
codeRouter.code = code;
try {
codeRouter.exec = await transform(code);
} catch (e) {
ctx.body = e.message.toString();
ctx.code = 500;
return ctx;
}
codeRouter.type = type;
await codeRouter.save();
} else {
try {
const exec = await transform(code);
const newCodeRouter = new RouterCodeModel({ path, key, code, exec, type });
await newCodeRouter.save();
codeRouter = newCodeRouter;
} catch (e) {
ctx.body = e.message.toString();
ctx.code = 500;
return ctx;
}
}
const codeOne = await loadOne(codeRouter);
updateNewCode(codeOne);
ctx.body = 'success';
return ctx;
};
router.add(updateRouter);
export const getRouterApi = new Route('admin', 'getRouterApi');
getRouterApi.description = 'get all router api list, and you can use this api to get router detail by path and key';
getRouterApi.run = async (ctx) => {
const { origin = 'http://localhost:4000' } = ctx.query;
const routerList = router.getList();
const apiList = routerList.map((item: any) => {
return {
path: item.path,
key: item.key,
query: `${origin}/api/router?path=${item.path}&key=${item.key}`,
description: item.description,
validator: item.validator,
};
});
ctx.body = apiList;
return ctx;
};
getRouterApi.validator = {
origin: {
type: 'string',
required: false,
},
};
router.add(getRouterApi);

View File

@ -13,6 +13,7 @@ export type RouterCode = {
middleware: string[]; middleware: string[];
next: string; next: string;
data: any; data: any;
validator: any;
}; };
export enum RouterCodeType { export enum RouterCodeType {
@ -31,7 +32,8 @@ export class RouterCodeModel extends Model {
declare type: RouterCodeType; declare type: RouterCodeType;
declare middleware: string[]; declare middleware: string[];
declare next: string; // 如果是中间件,不存在 declare next: string; // 如果是中间件,不存在
declare data: any; declare data: any; // 内容
declare validator: any;
} }
RouterCodeModel.init( RouterCodeModel.init(
{ {
@ -81,6 +83,10 @@ RouterCodeModel.init(
type: DataTypes.JSON, type: DataTypes.JSON,
defaultValue: {}, defaultValue: {},
}, },
validator: {
type: DataTypes.JSON,
defaultValue: {},
},
}, },
{ {
sequelize, sequelize,

View File

@ -2,12 +2,14 @@
# yarn lockfile v1 # yarn lockfile v1
"@abearxiong/router@^0.0.1-alpha.8": "@abearxiong/router@^0.0.1-alpha.12":
version "0.0.1-alpha.8" version "0.0.1-alpha.12"
resolved "https://npm.pkg.github.com/download/@abearxiong/router/0.0.1-alpha.8/772276fc4290291f845b0bb7198acc1c439f72e3" resolved "https://npm.pkg.github.com/download/@abearxiong/router/0.0.1-alpha.12/ca2bf4832b4f032965b4c579b7bbde04a05f893a"
integrity sha512-uX9YkeS+TDKKH8y1fShTKgxcXWeawaoLLi/kdX04M84o3sg1vZSic4wxEMuznAjESX/iYIc94vXyE6cevoWVLQ== integrity sha512-Hqe8HdxUTCjl31ExVpb1Ro4KuvqsjcbZwcISyzImDe5xN4yMBh3zZCZOTrbSB9OsxukX5rqQ4kvufLWbbfp46g==
dependencies: dependencies:
lodash "^4.17.21"
nanoid "^5.0.6" nanoid "^5.0.6"
zod "^3.23.8"
"@abearxiong/use-config@^0.0.1": "@abearxiong/use-config@^0.0.1":
version "0.0.1" version "0.0.1"
@ -2625,11 +2627,6 @@ fs.realpath@^1.0.0:
resolved "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz" resolved "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz"
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
fsevents@^2.3.2, fsevents@~2.3.2:
version "2.3.3"
resolved "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz"
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
function-bind@^1.1.2: function-bind@^1.1.2:
version "1.1.2" version "1.1.2"
resolved "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz" resolved "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz"
@ -4776,3 +4773,8 @@ yocto-queue@^0.1.0:
version "0.1.0" version "0.1.0"
resolved "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz" resolved "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
zod@^3.23.8:
version "3.23.8"
resolved "https://registry.npmmirror.com/zod/-/zod-3.23.8.tgz"
integrity sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==