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

View File

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

View File

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

View File

@ -101,13 +101,15 @@ RouterCodeModel.sync({ alter: true, logging: false })
}) })
.catch((e) => { .catch((e) => {
console.error('RouterCodeModel sync', e.message); console.error('RouterCodeModel sync', e.message);
RouterCodeModel.sync({ force: true }) if (!TableIsExist()) {
.then((res) => { RouterCodeModel.sync({ force: true })
console.log('RouterCodeModel force sync', res); .then((res) => {
}) console.log('RouterCodeModel force sync', res);
.catch((e) => { })
console.error('RouterCodeModel force sync error'); .catch((e) => {
}); console.error('RouterCodeModel force sync error');
});
}
}); });
export const TableIsExist = async () => { 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 }>(); const config = useConfig<{ flowPath: string }>();
export const envisionPath = path.join(os.homedir(), '.config', 'envision'); 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)) { if (!checkFileExistsSync(envisionPath)) {
fs.mkdirSync(envisionPath, { recursive: true }); fs.mkdirSync(envisionPath, { recursive: true });
@ -24,7 +24,7 @@ if (!path.isAbsolute(flowPath)) {
flowPath = path.join(process.cwd(), flowPath); flowPath = path.join(process.cwd(), flowPath);
} }
if (!flowPath.endsWith('.sqlite')) { if (!flowPath.endsWith('.sqlite')) {
flowPath = path.join(flowPath, 'flow.sqlite'); flowPath = path.join(flowPath, 'db.sqlite');
} }
// connect to db // connect to db
export const sequelize = new Sequelize({ export const sequelize = new Sequelize({

View File

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

View File

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