update
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { Manager } from '@kevisual/local-app-manager/manager';
|
import { Manager } from '../../local-apps/src/modules/manager.ts';
|
||||||
import type { AssistantConfig } from '@/module/assistant/index.ts';
|
import type { AssistantConfig } from '@/module/assistant/index.ts';
|
||||||
import { parseIfJson } from '@/module/assistant/index.ts';
|
import { parseIfJson } from '@/module/assistant/index.ts';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
|
|||||||
3
assistant/src/module/local-apps/mod.ts
Normal file
3
assistant/src/module/local-apps/mod.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export { Pm2Manager, Pm2Opts } from "./src/modules/pm2.ts";
|
||||||
|
|
||||||
|
export { Manager } from "./src/modules/manager.ts";
|
||||||
@@ -7,6 +7,9 @@ import './routes/list.ts';
|
|||||||
|
|
||||||
export { app, manager, loadManager };
|
export { app, manager, loadManager };
|
||||||
|
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const DEV_SERVER = import.meta.env?.DEV_SERVER || false;
|
||||||
if (DEV_SERVER) {
|
if (DEV_SERVER) {
|
||||||
app
|
app
|
||||||
.route({
|
.route({
|
||||||
|
|||||||
@@ -28,6 +28,6 @@
|
|||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"typings.d.ts",
|
"typings.d.ts",
|
||||||
"src/**/*.ts",
|
"src/**/*.ts", "mod.ts",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
@@ -1,237 +0,0 @@
|
|||||||
import { program, Command } from '@/program.ts';
|
|
||||||
import { checkFileExists, envisionPath, getConfig, writeConfig } from '@/module/index.ts';
|
|
||||||
import path from 'path';
|
|
||||||
import fs from 'fs';
|
|
||||||
import { chalk } from '@/module/chalk.ts';
|
|
||||||
import inquirer from 'inquirer';
|
|
||||||
import { spawn, spawnSync } from 'child_process';
|
|
||||||
import { checkPm2, installDep, installDeps } from '@/uitls/npm.ts';
|
|
||||||
|
|
||||||
const command = new Command('init').description('初始化应用').action((optison) => {
|
|
||||||
console.log('init');
|
|
||||||
}); //
|
|
||||||
|
|
||||||
program.addCommand(command);
|
|
||||||
|
|
||||||
const setMainAppConfig = async (mainAppPath: string) => {
|
|
||||||
const config = getConfig();
|
|
||||||
config.mainAppPath = mainAppPath;
|
|
||||||
writeConfig(config);
|
|
||||||
};
|
|
||||||
|
|
||||||
const initMain = async () => {
|
|
||||||
const mainAppPath = path.join(envisionPath, 'main-app');
|
|
||||||
const pkgPath = path.join(mainAppPath, 'package.json');
|
|
||||||
if (!checkFileExists(pkgPath)) {
|
|
||||||
fs.mkdirSync(mainAppPath, { recursive: true });
|
|
||||||
const pkg = {
|
|
||||||
name: 'main-app',
|
|
||||||
version: '1.0.0',
|
|
||||||
type: 'module',
|
|
||||||
main: 'dist/app.mjs',
|
|
||||||
scripts: {
|
|
||||||
start: 'node dist/app.mjs',
|
|
||||||
pm2: 'pm2 start dist/app.mjs --name main-app',
|
|
||||||
},
|
|
||||||
dependencies: {
|
|
||||||
'@kevisual/router': 'latest',
|
|
||||||
'@kevisual/local-app-manager': 'latest',
|
|
||||||
'@kevisual/use-config': 'latest',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
|
|
||||||
console.log(chalk.green('初始化 main-app 成功'));
|
|
||||||
}
|
|
||||||
// 在对应的路径,安装依赖
|
|
||||||
installDeps({ appPath: mainAppPath, sync: true });
|
|
||||||
// 创建 dist/app.mjs
|
|
||||||
const code = `import { App } from '@kevisual/router';
|
|
||||||
import { app as LocalApp } from '@kevisual/local-app-manager';
|
|
||||||
import { useConfig } from '@kevisual/use-config';
|
|
||||||
const config = useConfig();
|
|
||||||
const host = config.host || '127.0.0.1';
|
|
||||||
LocalApp.listen(config.port, host, () => {
|
|
||||||
console.log(\`LocalApp is running on http://\${host}:\${config.port}\`);
|
|
||||||
});
|
|
||||||
`;
|
|
||||||
const codeDistPath = path.join(mainAppPath, 'dist');
|
|
||||||
if (!checkFileExists(codeDistPath)) {
|
|
||||||
fs.mkdirSync(codeDistPath, { recursive: true });
|
|
||||||
}
|
|
||||||
fs.writeFileSync(path.join(codeDistPath, 'app.mjs'), code);
|
|
||||||
console.log(chalk.green('创建 app.mjs 成功'));
|
|
||||||
// 创建 app.config.json5
|
|
||||||
const answers = await inquirer.prompt([
|
|
||||||
{
|
|
||||||
type: 'input',
|
|
||||||
name: 'port',
|
|
||||||
message: '请输入端口号',
|
|
||||||
default: '11015',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'input',
|
|
||||||
name: 'host',
|
|
||||||
message: '请输入host',
|
|
||||||
default: '127.0.0.1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'input',
|
|
||||||
name: 'appsPath',
|
|
||||||
message: '请输入apps路径',
|
|
||||||
default: path.join(mainAppPath, 'apps'),
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
const json5 = {
|
|
||||||
port: Number(answers.port),
|
|
||||||
host: answers.host,
|
|
||||||
appsPath: answers.appsPath,
|
|
||||||
};
|
|
||||||
fs.writeFileSync(path.join(mainAppPath, 'app.config.json5'), JSON.stringify(json5, null, 2));
|
|
||||||
//
|
|
||||||
console.log(chalk.green('创建 app.config.json5 成功'));
|
|
||||||
setMainAppConfig(mainAppPath);
|
|
||||||
writeConfig({ ...getConfig(), appsPath: answers.appsPath });
|
|
||||||
};
|
|
||||||
const checkPid = (pid: number) => {
|
|
||||||
try {
|
|
||||||
process.kill(pid, 0);
|
|
||||||
return true;
|
|
||||||
} catch (err) {
|
|
||||||
if (err.code === 'ESRCH') {
|
|
||||||
// 进程不存在
|
|
||||||
console.log(`进程 ${pid} 不存在`);
|
|
||||||
return false;
|
|
||||||
} else if (err.code === 'EPERM') {
|
|
||||||
// 没有权限访问该进程
|
|
||||||
console.log(`没有权限检查进程 ${pid}`);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
// 其他错误
|
|
||||||
console.error(`检查进程 ${pid} 时出错:`, err);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const mainApp = new Command('main')
|
|
||||||
.description('初始化main的应用') //
|
|
||||||
.option('-i, --init', '初始化main应用')
|
|
||||||
.option('-s, --start', '启动main应用')
|
|
||||||
.option('-r, --restart', '重启main应用')
|
|
||||||
.option('-e, --exit', '停止main应用')
|
|
||||||
.option('-p, --pm2', '使用pm2管理,只作为启动')
|
|
||||||
.action(async (options) => {
|
|
||||||
if (options.init) {
|
|
||||||
await initMain();
|
|
||||||
return;
|
|
||||||
} else if (!options.start && !options.restart && !options.exit && !options.pm2) {
|
|
||||||
console.warn(chalk.yellow('请使用 --init 初始化 main 应用'));
|
|
||||||
}
|
|
||||||
const runChild = () => {
|
|
||||||
const logDir = path.join(envisionPath, 'log');
|
|
||||||
const logFile = path.join(logDir, 'child.log');
|
|
||||||
// 确保日志目录存在
|
|
||||||
fs.mkdirSync(logDir, { recursive: true });
|
|
||||||
// 如果日志文件不存在,创建一个
|
|
||||||
if (!checkFileExists(logFile)) {
|
|
||||||
fs.writeFileSync(logFile, '');
|
|
||||||
}
|
|
||||||
// 如果日志文件大于 10M,重命名
|
|
||||||
const stats = fs.statSync(logFile);
|
|
||||||
if (stats.size > 1024 * 1024 * 10) {
|
|
||||||
fs.renameSync(logFile, path.join(logDir, `child-${Date.now()}.log`));
|
|
||||||
fs.writeFileSync(logFile, '');
|
|
||||||
}
|
|
||||||
// 打开日志文件(追加模式)
|
|
||||||
const logStream = fs.openSync(logFile, 'a');
|
|
||||||
if (options.pm2) {
|
|
||||||
if (!checkPm2()) {
|
|
||||||
console.log('安装pm2');
|
|
||||||
installDep({ isGlobal: true, sync: true, dep: 'pm2' });
|
|
||||||
console.log(chalk.green('安装pm2成功'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let comm = options.pm2 ? 'pm2' : 'node';
|
|
||||||
const args = options.pm2 ? ['start', 'dist/app.mjs', '--name', 'main-app'] : ['dist/app.mjs'];
|
|
||||||
const childProcess = spawn(comm, args, {
|
|
||||||
cwd: getConfig().mainAppPath,
|
|
||||||
stdio: ['ignore', logStream, logStream], // 忽略 stdio, 重定向到文件
|
|
||||||
detached: true, // 使子进程独立运行
|
|
||||||
});
|
|
||||||
childProcess.unref(); // 使子进程独立运行
|
|
||||||
if (!options.pm2) {
|
|
||||||
writeConfig({ ...getConfig(), mainAppPid: childProcess.pid });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const config = getConfig();
|
|
||||||
if (!config.mainAppPath) {
|
|
||||||
console.log('请先初始化 main 应用');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (options.start) {
|
|
||||||
if (config.mainAppPid) {
|
|
||||||
// 检查是否有进程
|
|
||||||
if (checkPid(config.mainAppPid)) {
|
|
||||||
console.log('main app 已经启动');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
runChild();
|
|
||||||
}
|
|
||||||
if (options.restart) {
|
|
||||||
if (config.mainAppPid) {
|
|
||||||
// 检查是否有进程
|
|
||||||
if (checkPid(config.mainAppPid)) {
|
|
||||||
process.kill(config.mainAppPid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
runChild();
|
|
||||||
} else if (options.exit) {
|
|
||||||
if (config.mainAppPid) {
|
|
||||||
// 检查是否有进程
|
|
||||||
if (checkPid(config.mainAppPid)) {
|
|
||||||
process.kill(config.mainAppPid);
|
|
||||||
}
|
|
||||||
writeConfig({ ...config, mainAppPid: null });
|
|
||||||
console.log('main app 已经停止');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const mainPathCommand = new Command('path').action(() => {
|
|
||||||
const config = getConfig();
|
|
||||||
const appPath = path.resolve(config.mainAppPath);
|
|
||||||
|
|
||||||
console.log(`cd ${appPath}`);
|
|
||||||
});
|
|
||||||
mainApp.addCommand(mainPathCommand);
|
|
||||||
|
|
||||||
const mainLogCommand = new Command('log')
|
|
||||||
.option('-t, --tail', '查看日志')
|
|
||||||
.option('-f, --follow', '跟踪日志')
|
|
||||||
.description('查看main的日志')
|
|
||||||
.action((options) => {
|
|
||||||
const logDir = path.join(envisionPath, 'log');
|
|
||||||
const logFile = path.join(logDir, 'child.log');
|
|
||||||
if (!checkFileExists(logFile)) {
|
|
||||||
console.log('日志文件不存在');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (options.tail) {
|
|
||||||
const childProcess = spawn('tail', ['-n', '20', '-f', logFile]);
|
|
||||||
childProcess.stdout?.pipe(process.stdout);
|
|
||||||
childProcess.stderr?.pipe(process.stderr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (options.follow) {
|
|
||||||
const childProcess = spawn('tail', ['-n', '50', '-f', logFile]);
|
|
||||||
childProcess.stdout?.pipe(process.stdout);
|
|
||||||
childProcess.stderr?.pipe(process.stderr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const log = fs.readFileSync(logFile, 'utf-8');
|
|
||||||
console.log(log);
|
|
||||||
});
|
|
||||||
|
|
||||||
mainApp.addCommand(mainLogCommand);
|
|
||||||
|
|
||||||
program.addCommand(mainApp);
|
|
||||||
@@ -6,7 +6,6 @@ import './command/config.ts';
|
|||||||
import './command/router.ts';
|
import './command/router.ts';
|
||||||
import './command/npm.ts';
|
import './command/npm.ts';
|
||||||
import './command/publish.ts';
|
import './command/publish.ts';
|
||||||
import './command/init.ts';
|
|
||||||
import './command/proxy.ts';
|
import './command/proxy.ts';
|
||||||
import './command/update.ts';
|
import './command/update.ts';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user