feat: 改为本地数据库 admin的功能

This commit is contained in:
熊潇 2024-10-26 10:29:33 +08:00
parent 947a8507e9
commit 7f410fbaaa
9 changed files with 143 additions and 95 deletions

View File

@ -1,5 +1,24 @@
import { App } from '@kevisual/router';
import { sequelize } from './modules/sequelize.ts';
import { emitter } from './modules/event.ts';
export { sequelize };
export const app = new App();
export const runAppRouterFn = async (key: string, params: any) => {
emitter.emit(`router.fn`, key, params);
};
const runListener = async (app: App) => {
emitter.on('router.fn', (key, params) => {
if (!app.router[key]) {
console.error('router key not found:', key);
} else {
app.router[key](params);
}
});
};
runListener(app);
export const appendTo = (realApp: App) => {
realApp.importApp(app);
runListener(realApp);
};

View File

@ -1,5 +1,5 @@
// import { router } from '../../modules/router.ts';
import { app } from '../app.ts';
import { runAppRouterFn } from '../app.ts';
import { Route } from '@kevisual/router';
import { RouterCodeModel, RouterCode } from '../models/code.ts';
@ -42,8 +42,8 @@ export const loadOne = async (item: RouterCodeModel) => {
const codeRunRoute = new Route(path, key, { id });
codeRunRoute.run = fn;
codeRunRoute.middleware = middleware;
app.router.removeById(id); // TODO:
app.router.add(codeRunRoute);
runAppRouterFn('removeById', id);
runAppRouterFn('add', codeRunRoute);
return {
...item.toJSON(),
path,
@ -92,7 +92,7 @@ export const load = async function () {
const codeRunRoute = new Route(path, key, { id });
codeRunRoute.run = fn;
codeRunRoute.middleware = middleware;
app.router.add(codeRunRoute);
runAppRouterFn('add', codeRunRoute);
return {
...item.toJSON(),
path,

View File

@ -1,6 +1,7 @@
import { EventEmitter, once } from 'stream';
import { load, CodeManager, CodeStatus, loadOne } from './load.ts';
import { RouterCodeModel, TableIsExist } from '../models/code.ts';
import { emitter } from '../modules/event.ts';
export enum LoadStatus {
LOADING = 'loading',
@ -46,10 +47,7 @@ export const startCode = async (code: RouterCodeModel) => {
}
};
// 事件
export const events = new EventEmitter();
once(events, 'loaded')
once(emitter, 'loaded')
.then(() => {
manager.loaded = LoadStatus.LOADED;
console.log('manager loaded');
@ -63,7 +61,7 @@ const init = async function () {
const r = await load();
manager.list = r;
events.emit('loaded');
emitter.emit('loaded');
};
TableIsExist().then(async (res) => {
if (res) {

View File

@ -14,18 +14,22 @@ managerRouter.run = async (ctx) => {
managerRouter.addTo(app);
// get manager list
export const managerList = new Route('admin', 'getManagerList');
managerList.run = async (ctx) => {
ctx.body = manager.list;
// TODO:
const routerList = app.router.getList().filter((r) => !r.path.startsWith('admin'));
ctx.body = {
list: manager.list,
routerList,
};
return ctx;
};
managerList.addTo(app);
app
.route({
path: 'admin',
key: 'getManagerList',
})
.define(async (ctx) => {
ctx.body = manager.list;
// TODO: routerList 可以不暴露
const routerList = ctx.queryRouter.getList().filter((r) => !r.path.startsWith('admin'));
ctx.body = {
list: manager.list,
routerList,
};
return ctx;
})
.addTo(app);
// get manager one
export const managerOne = new Route('admin', 'getManagerOne');

View File

@ -101,13 +101,15 @@ RouterCodeModel.sync({ alter: true, logging: false })
})
.catch((e) => {
console.error('RouterCodeModel sync', e.message);
RouterCodeModel.sync({ force: true })
.then((res) => {
console.log('RouterCodeModel force sync', res);
})
.catch((e) => {
console.error('RouterCodeModel force sync error');
});
if (!TableIsExist()) {
RouterCodeModel.sync({ force: true })
.then((res) => {
console.log('RouterCodeModel force sync', res);
})
.catch((e) => {
console.error('RouterCodeModel force sync error');
});
}
});
export const TableIsExist = async () => {

View File

@ -0,0 +1,20 @@
import { EventEmitter, once } from 'stream';
// 事件
export const emitter = new EventEmitter();
// 异步触发事件 demo
export const asyncEmit = (emitter: EventEmitter, eventName: string) => {
return new Promise((resolve) => {
emitter.once(eventName, (value: any) => resolve(value));
});
};
async function main() {
setTimeout(() => {
emitter.emit('asyncEvent', '监听器中的值');
}, 1000);
asyncEmit(emitter, 'asyncEvent').then((result) => {
console.log(result); // 监听器中的值
});
}

View File

@ -14,7 +14,7 @@ const checkFileExistsSync = (filePath: string) => {
};
const config = useConfig<{ flowPath: string }>();
export const envisionPath = path.join(os.homedir(), '.config', 'envision');
const configPath = path.join(os.homedir(), '.config', 'envision', 'flow.sqlite');
const configPath = path.join(os.homedir(), '.config', 'envision', 'db.sqlite');
if (!checkFileExistsSync(envisionPath)) {
fs.mkdirSync(envisionPath, { recursive: true });
@ -24,7 +24,7 @@ if (!path.isAbsolute(flowPath)) {
flowPath = path.join(process.cwd(), flowPath);
}
if (!flowPath.endsWith('.sqlite')) {
flowPath = path.join(flowPath, 'flow.sqlite');
flowPath = path.join(flowPath, 'db.sqlite');
}
// connect to db
export const sequelize = new Sequelize({

View File

@ -1,30 +1,30 @@
// admin router manger
import { CustomError, Route } from '@kevisual/router';
import { app } from './app.ts';
import { app, runAppRouterFn } from './app.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) => {
// TODO:
ctx.body = app.router.getList().filter((r) => !r.path.startsWith('admin'));
// ctx.body = router.getList().filter((r) => r.path.startsWith('admin'));
return ctx;
};
getRouterList.addTo(app);
app
.route({
path: 'admin',
key: 'getRouterList',
})
.define(async (ctx) => {
// TODO: routerList 可以不暴露
ctx.body = ctx.queryRouter.getList().filter((r) => !r.path.startsWith('admin'));
// ctx.body = router.getList().filter((r) => r.path.startsWith('admin'));
return ctx;
})
.addTo(app);
// remove router
export const removeRouter = new Route('admin', 'removeRouter');
removeRouter.run = async (ctx) => {
const { path, key } = ctx.query;
// TODO:
// router.remove({ path, key });
app.router.remove({ path, key });
runAppRouterFn('remove', { path, key });
const routerCode = await RouterCodeModel.findOne({ where: { path, key } });
if (routerCode) {
const id = routerCode.id;
@ -49,9 +49,8 @@ removeRouter.addTo(app);
export const removeRouterById = new Route('admin', 'removeRouterById');
removeRouterById.run = async (ctx) => {
const { id } = ctx.query;
// router.removeById(id);
// TODO:
app.router.removeById(id);
runAppRouterFn('removeById', id);
removeCode(id);
await RouterCodeModel.destroy({ where: { id } });
ctx.body = 'success';
@ -68,8 +67,7 @@ removeRouterById.addTo(app);
export const stopRouterById = new Route('admin', 'stopRouterById');
stopRouterById.run = async (ctx) => {
const { id } = ctx.query;
// TODO
app.router.removeById(id);
runAppRouterFn('removeById', id);
const routerCode = await RouterCodeModel.findByPk(id);
if (routerCode) {
routerCode.active = false;
@ -159,42 +157,45 @@ updateRouter.run = async (ctx) => {
};
updateRouter.addTo(app);
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();
// TODO:
const routerList = app.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,
app
.route({
path: 'admin',
key: 'getRouterApi',
description: 'get all router api list, and you can use this api to get router detail by path and key',
validator: {
origin: {
type: 'string',
required: false,
},
},
})
.define(async (ctx) => {
const { origin = 'http://localhost:4000' } = ctx.query;
// const routerList = router.getList();
// TODO: routerList 可以不暴露
const routerList = ctx.queryRouter.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,
};
});
const apiKeyObject = apiList.reduce((pre: any, cur: any) => {
pre[cur.key] = {
path: cur.path,
key: cur.key,
description: cur.description || '',
validator: cur.validator || {},
};
return pre;
}, {});
ctx.body = {
list: apiList,
keyObject: apiKeyObject,
};
});
const apiKeyObject = apiList.reduce((pre: any, cur: any) => {
pre[cur.key] = {
path: cur.path,
key: cur.key,
description: cur.description || '',
validator: cur.validator || {},
};
return pre;
}, {});
ctx.body = {
list: apiList,
keyObject: apiKeyObject,
};
return ctx;
};
getRouterApi.validator = {
origin: {
type: 'string',
required: false,
},
};
getRouterApi.addTo(app);
return ctx;
})
.addTo(app);

View File

@ -101,17 +101,21 @@ RouterCodeModel.sync({ alter: true, logging: false })
})
.catch((e) => {
console.error('RouterCodeModel sync', e.message);
RouterCodeModel.sync({ force: true })
.then((res) => {
console.log('RouterCodeModel force sync', res);
})
.catch((e) => {
console.error('RouterCodeModel force sync error');
});
if (!TableIsExist()) {
RouterCodeModel.sync({ force: true })
.then((res) => {
console.log('RouterCodeModel force sync', res);
})
.catch((e) => {
console.error('RouterCodeModel force sync error');
});
}
});
export const TableIsExist = async () => {
// 判断cf_router_code表是否存在
const tableIsExist = await sequelize.getQueryInterface().showAllTables();
const tableIsExist = await sequelize.getQueryInterface().showAllTables({
logging: false,
});
return tableIsExist.includes('cf_router_code');
};