feat: add detect app micro

This commit is contained in:
xion 2024-11-24 20:50:22 +08:00
parent 4bbc531ac7
commit ce6037ead9
5 changed files with 91 additions and 13 deletions

View File

@ -23,7 +23,7 @@ export const loadAppInfo = async (): Promise<AppInfoConfig> => {
const basePath = path.dirname(pkgs); const basePath = path.dirname(pkgs);
if (!configFile) { if (!configFile) {
configFile = path.join(basePath, 'apps.config.json'); configFile = path.join(basePath, 'apps.config.json');
fs.writeFileSync(configFile, JSON.stringify({})); fs.writeFileSync(configFile, JSON.stringify({ list: [] }));
return { list: [] }; return { list: [] };
} }
const config = fs.readFileSync(configFile, 'utf-8'); const config = fs.readFileSync(configFile, 'utf-8');

View File

@ -1,6 +1,6 @@
import { app } from '@/app.ts'; import { app } from '@/app.ts';
import { MicroAppModel } from './models.ts'; import { MicroAppModel } from './models.ts';
import { appPathCheck, installApp } from './module/install-app.ts'; import { appPathCheck, getAppPathKeys, installApp, installAppFromKey } from './module/install-app.ts';
import { loadApp } from './module/load-app.ts'; import { loadApp } from './module/load-app.ts';
import { manager } from './manager-app.ts'; import { manager } from './manager-app.ts';
@ -10,6 +10,7 @@ app
path: 'micro-app', path: 'micro-app',
key: 'upload', key: 'upload',
middleware: ['auth'], middleware: ['auth'],
description: 'Upload micro app',
}) })
.define(async (ctx) => { .define(async (ctx) => {
const { files, collection } = ctx.query?.data; const { files, collection } = ctx.query?.data;
@ -48,6 +49,7 @@ app
.route({ .route({
path: 'micro-app', path: 'micro-app',
key: 'deploy', key: 'deploy',
description: 'Deploy micro app',
}) })
.define(async (ctx) => { .define(async (ctx) => {
// const { id, key} = ctx.query?.data; // const { id, key} = ctx.query?.data;
@ -80,6 +82,7 @@ app
.route({ .route({
path: 'micro-app', path: 'micro-app',
key: 'load', key: 'load',
description: 'Load micro app, no use',
}) })
.define(async (ctx) => { .define(async (ctx) => {
// const { key } = ctx.query?.data; // const { key } = ctx.query?.data;
@ -95,8 +98,7 @@ app
} catch (e) { } catch (e) {
ctx.throw(400, e.message); ctx.throw(400, e.message);
} }
}) });
.addTo(app);
// curl http://localhost:4002/api/router?path=micro-app&key=unload // curl http://localhost:4002/api/router?path=micro-app&key=unload
app app
@ -115,3 +117,39 @@ app
ctx.body = main; ctx.body = main;
}) })
.addTo(app); .addTo(app);
app
.route({
path: 'micro-app',
key: 'detect',
description: 'Detect micro app,检测apps的没有加载进来的app模块',
})
.define(async (ctx) => {
const list = manager.getAllAppShowInfo();
const appPathKeys = await getAppPathKeys();
const notIn = appPathKeys.filter((key) => !list.find((item) => item.key === key));
console.log('Not in', notIn);
const loadInfo = [];
if (notIn.length <= 0) {
loadInfo.push('ok');
ctx.body = {
data: loadInfo,
};
ctx.message = 'All apps are loaded';
return;
}
for (const key of notIn) {
try {
const { showAppInfo } = await installAppFromKey(key);
await manager.add(showAppInfo);
loadInfo.push(`Load ${key} success`);
} catch (e) {
loadInfo.push(`Load ${key} error`);
}
}
ctx.body = {
data: loadInfo,
notIn,
};
})
.addTo(app);

View File

@ -47,7 +47,14 @@ export const installApp = async (opts: InstallAppOpts) => {
file: filePath, file: filePath,
cwd: extractPath, cwd: extractPath,
}); });
const pkgs = path.join(extractPath, 'package.json'); return installAppFromKey(key);
};
export const installAppFromKey = async (key: string) => {
const directory = path.join(appsPath, key);
if (!fileIsExist(directory)) {
throw new Error('App not found');
}
const pkgs = path.join(directory, 'package.json');
if (!fileIsExist(pkgs)) { if (!fileIsExist(pkgs)) {
throw new Error('Invalid package.json'); throw new Error('Invalid package.json');
} }
@ -57,8 +64,7 @@ export const installApp = async (opts: InstallAppOpts) => {
if (!name || !version || !app) { if (!name || !version || !app) {
throw new Error('Invalid package.json'); throw new Error('Invalid package.json');
} }
const readmeFile = path.join(directory, 'README.md');
const readmeFile = path.join(extractPath, 'README.md');
let readmeDesc = ''; let readmeDesc = '';
if (fileIsExist(readmeFile)) { if (fileIsExist(readmeFile)) {
readmeDesc = fs.readFileSync(readmeFile, 'utf-8'); readmeDesc = fs.readFileSync(readmeFile, 'utf-8');
@ -71,11 +77,19 @@ export const installApp = async (opts: InstallAppOpts) => {
version, version,
// //
entry: app?.entry || '', entry: app?.entry || '',
path: extractPath, path: directory,
origin: app, origin: app,
}; };
app.key = key; app.key = key;
fs.writeFileSync(pkgs, JSON.stringify(pkg, null, 2)); fs.writeFileSync(pkgs, JSON.stringify(pkg, null, 2));
// fs.unlinkSync(filePath); return { pkg, showAppInfo };
return { path: filePath, pkg, showAppInfo }; };
export const getAppPathKeys = async () => {
let files = fs.readdirSync(appsPath);
files = files.filter((file) => {
const stat = fs.statSync(path.join(appsPath, file));
if (file === 'node_modules') return false;
return stat.isDirectory();
});
return files;
}; };

View File

@ -4,6 +4,7 @@ import { fork } from 'child_process';
import { merge } from 'lodash-es'; import { merge } from 'lodash-es';
import { deleteFileAppInfo } from './load-app.ts'; import { deleteFileAppInfo } from './load-app.ts';
import { fileIsExist } from '@kevisual/use-config'; import { fileIsExist } from '@kevisual/use-config';
import path from 'path';
// 共享 // 共享
export const existDenpend = [ export const existDenpend = [
'sequelize', // commonjs 'sequelize', // commonjs
@ -82,8 +83,13 @@ export class Manager<T extends AppInfo = any> {
if (app.status !== 'running') { if (app.status !== 'running') {
return; return;
} }
if (!fileIsExist(app.entry)) { if (!fileIsExist(app.path)) {
console.error('file not found'); console.error('app is not found');
return;
}
const pathEntry = path.join(app.path, app.entry);
if (!fileIsExist(pathEntry)) {
console.error('file entry not found');
return; return;
} }
const entry = app.entry + `?timestamp=${app?.timestamp}`; const entry = app.entry + `?timestamp=${app?.timestamp}`;
@ -102,6 +108,7 @@ export class Manager<T extends AppInfo = any> {
} else if (app.type === AppType.GatewayApp) { } else if (app.type === AppType.GatewayApp) {
console.log('gateway app not support'); console.log('gateway app not support');
} }
return true;
} }
/** /**
* create new app info * create new app info
@ -124,10 +131,21 @@ export class Manager<T extends AppInfo = any> {
async load() { async load() {
// 从apps文件夹列表当中中加载app信息 // 从apps文件夹列表当中中加载app信息
const appInfos = await loadAppInfo(); const appInfos = await loadAppInfo();
this.appInfo = appInfos;
const list = appInfos?.list || []; const list = appInfos?.list || [];
for (const app of list) { for (const app of list) {
try { try {
this.loadApp(app); const loaded = await this.loadApp(app);
if (!loaded) {
// 加载失败如果是running状态设置为error
if (app.status === 'running') {
app.status = 'error';
console.log('load app error', app); // save app error info
await this.saveAppInfo(app);
}
} else {
// console.log('load app success', app);
}
} catch (e) { } catch (e) {
console.error('load app', e); console.error('load app', e);
} }

View File

@ -0,0 +1,8 @@
import { getAppPathKeys } from '../module/install-app.ts';
const main = () => {
const keys = getAppPathKeys();
console.log('Keys', keys);
};
main();