更新依赖并增强应用管理命令功能

This commit is contained in:
2025-12-29 03:33:11 +08:00
parent 9647fcf48f
commit a90f98ef3f
7 changed files with 356 additions and 92 deletions

View File

@@ -40,7 +40,3 @@ if (DEV_SERVER) {
});
loadManager({ configFilename: 'b.json' });
}
export const loadApp = (mainApp: App, appInfo?: any) => {
//
};

View File

@@ -53,6 +53,7 @@ export type AppInfo = {
path?: string; // 文件路径
env?: Record<string, any>; // 环境变量
engine?: string; // runtime, python node deno bun etc
init?: boolean; // 是否需要初始化安装npm等依赖
/**
* pm2 选项, 仅仅当是AppType.Pm2SystemApp的时候生效
* pm2 选项可以参考 https://pm2.keymetrics.io/docs/usage/application-declaration/
@@ -125,71 +126,7 @@ export class Manager<T extends AppInfo = AppInfo> {
async loadApp(app: T) {
const mainApp = this.mainApp;
this.apps.set(app.key, app);
if (app.status !== 'running') {
return;
}
if (!fileIsExist(app.path)) {
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;
}
const entry = app.entry + `?timestamp=${app?.timestamp}`;
// 注册路由
if (app.type === AppType.MicroApp) {
const childProcess = fork(app.entry, [], {
stdio: 'inherit', // 共享主进程的标准输入输出
cwd: app.path,
env: {
...process.env,
...app.env,
APP_KEY: app.key,
APP_PATH: app.path,
APP_ENTRY: entry
}
});
app.process = childProcess;
} else if (app.type === AppType.SystemApp) {
const pathEntryAndTimestamp = path.join(app.path, entry);
// Windows下需要使用file://协议,并将反斜杠转换为正斜杠
const importPath = process.platform === 'win32'
? 'file:///' + pathEntryAndTimestamp.replace(/\\/g, '/')
: pathEntryAndTimestamp;
const module = await import(importPath);
if (module.loadApp && mainApp) {
await module.loadApp?.(mainApp, app);
}
} else if (app.type === AppType.GatewayApp) {
console.log('gateway app not support');
} else if (app.type === AppType.Pm2SystemApp) {
const pathEntry = path.join(app.path, app.entry);
const pm2Manager = new Pm2Manager({
appName: app.key,
script: pathEntry,
pm2Connect: this.#pm2Connect
});
// const isInstall = await checkInstall(app);
// if (!isInstall) {
// console.log('install failed');
// return;
// }
const pm2Options: StartOptions = app.pm2Options || {};
if (app?.engine) {
pm2Options.interpreter = pm2Options.interpreter || app?.engine;
}
if (!pm2Options.cwd) {
pm2Options.cwd = path.join(app.path, '../..');
}
await pm2Manager.start(pm2Options);
} else {
console.error('app type not support', app.type);
}
console.log(`load ${app.type} success`, app.key);
return true;
return await LoadApp(app, { mainApp, pm2Connect: this.#pm2Connect });
}
/**
* create new app info
@@ -308,24 +245,7 @@ export class Manager<T extends AppInfo = AppInfo> {
if (!app) {
return;
}
if (app.status === 'stop' && app.type === AppType.SystemApp) {
console.log(`app ${key} is stopped`);
return;
}
app.status = 'stop';
if (app.type === AppType.MicroApp) {
if (app.process) {
app.process.kill();
}
}
if (app.type === AppType.Pm2SystemApp) {
const pm2Manager = new Pm2Manager({
appName: app.key,
script: app.entry,
pm2Connect: this.#pm2Connect
});
await pm2Manager.stop();
}
await StopApp(app, { pm2Connect: this.#pm2Connect, todo: 'stop' });
await this.saveAppInfo(app);
}
async restart(key: string) {
@@ -393,8 +313,9 @@ export class Manager<T extends AppInfo = AppInfo> {
* @param key
* @returns
*/
async removeApp(key: string) {
async removeApp(key: string, opts?: { deleteFile?: boolean }) {
const app = this.apps.get(key);
const deleteFile = opts?.deleteFile ?? true;
if (!app) {
return false;
}
@@ -414,6 +335,9 @@ export class Manager<T extends AppInfo = AppInfo> {
} catch (e) {
console.log('delete pm2 process error', e);
}
if (!deleteFile) {
return true;
}
try {
deleteFileAppInfo(key, this.appsPath);
} catch (e) {
@@ -485,7 +409,105 @@ export class Manager<T extends AppInfo = AppInfo> {
}
}
}
export const LoadApp = async (app: AppInfo, opts?: { mainApp?: any, pm2Connect?: any }) => {
const mainApp = opts?.mainApp;
const pm2Connect = opts?.pm2Connect;
if (app.status !== 'running') {
return false;
}
if (!fileIsExist(app.path)) {
console.error('app is not found');
return false;
}
const pathEntry = path.join(app.path, app.entry);
if (!fileIsExist(pathEntry)) {
console.error('file entry not found');
return false;
}
const entry = app.entry + `?timestamp=${app?.timestamp}`;
// 注册路由
if (app.type === AppType.MicroApp) {
const childProcess = fork(app.entry, [], {
stdio: 'inherit', // 共享主进程的标准输入输出
cwd: app.path,
env: {
...process.env,
...app.env,
APP_KEY: app.key,
APP_PATH: app.path,
APP_ENTRY: entry
}
});
app.process = childProcess;
} else if (app.type === AppType.SystemApp) {
const pathEntryAndTimestamp = path.join(app.path, entry);
// Windows下需要使用file://协议,并将反斜杠转换为正斜杠
const importPath = process.platform === 'win32'
? 'file:///' + pathEntryAndTimestamp.replace(/\\/g, '/')
: pathEntryAndTimestamp;
const module = await import(importPath);
if (module.loadApp && mainApp) {
await module.loadApp?.(mainApp, app);
}
} else if (app.type === AppType.GatewayApp) {
console.log('gateway app not support');
} else if (app.type === AppType.Pm2SystemApp) {
const pathEntry = path.join(app.path, app.entry);
console.log('pm2 system app start', pathEntry);
const pm2Manager = new Pm2Manager({
appName: app.key,
script: pathEntry,
pm2Connect: pm2Connect
});
if (app?.init) {
const isInstall = await checkInstall(app);
if (!isInstall) {
console.log('install failed');
return false;
}
}
const pm2Options: StartOptions = app.pm2Options || {};
if (app?.engine) {
pm2Options.interpreter = pm2Options.interpreter || app?.engine;
}
if (!pm2Options.cwd) {
pm2Options.cwd = path.join(app.path, '../..');
}
console.log('pm2 start options', pm2Options);
await pm2Manager.start(pm2Options);
} else if (app.type === AppType.ScriptApp) {
// console.log('script app 直接运行,不需要启动');
return true;
} else {
console.error('app type not support', app.type);
}
console.log(`load ${app.type} success`, app.key);
return true;
}
export const StopApp = async (app: AppInfo, opts?: { pm2Connect?: Pm2Connect, todo?: 'stop' | 'remove' | 'restart' }) => {
const key = app.key;
const pm2Connect = opts?.pm2Connect;
const todo = opts?.todo || 'stop';
if (app.status === 'stop' && app.type === AppType.SystemApp) {
console.log(`app ${key} is stopped`);
return;
}
app.status = 'stop';
if (app.type === AppType.MicroApp) {
if (app.process) {
app.process.kill();
}
}
if (app.type === AppType.Pm2SystemApp) {
const pm2Manager = new Pm2Manager({
appName: app.key,
script: app.entry,
pm2Connect: pm2Connect
});
await pm2Manager[todo]?.();
}
}
/**
* 安装app通过key
* @param key

View File

@@ -108,6 +108,9 @@ export class Pm2Connect {
}
}
type RunOptions = {
/**
* 是否在操作完成后退出连接
*/
needExit?: boolean;
};
export class Pm2Manager {
@@ -226,6 +229,9 @@ export class Pm2Manager {
this.pm2Connect.checkDisconnect(runOpts);
}
}
async remove(runOpts?: RunOptions) {
this.deleteProcess(runOpts);
}
async deleteProcess(runOpts?: RunOptions) {
try {
await this.pm2Connect.checkConnect();