import { minioClient } from '@/app.ts'; import { bucketName } from '@/modules/minio.ts'; import { fileIsExist } from '@kevisual/use-config'; import fs from 'fs'; import path from 'path'; import * as tar from 'tar'; import { appsPath } from '../lib/index.ts'; export type InstallAppOpts = { path?: string; key?: string; }; /** * 检测路径是否存在 * @param opts * @returns */ export const appPathCheck = async (opts: InstallAppOpts) => { const { key } = opts; const directory = path.join(appsPath, key); if (fileIsExist(directory)) { return true; } return false; }; export const installApp = async (opts: InstallAppOpts) => { const { key } = opts; const fileStream = await minioClient.getObject(bucketName, opts.path); const pathName = opts.path.split('/').pop(); const directory = path.join(appsPath, key); if (!fileIsExist(directory)) { fs.mkdirSync(directory, { recursive: true }); } const filePath = path.join(directory, pathName); const writeStream = fs.createWriteStream(filePath); fileStream.pipe(writeStream); await new Promise((resolve, reject) => { writeStream.on('finish', resolve); writeStream.on('error', reject); }); // 解压 tgz文件 const extractPath = path.join(directory); await tar.x({ file: filePath, cwd: extractPath, }); 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)) { throw new Error('Invalid package.json'); } const json = fs.readFileSync(pkgs, 'utf-8'); const pkg = JSON.parse(json); const { name, version, app } = pkg; if (!name || !version || !app) { throw new Error('Invalid package.json'); } const readmeFile = path.join(directory, 'README.md'); let readmeDesc = ''; if (fileIsExist(readmeFile)) { readmeDesc = fs.readFileSync(readmeFile, 'utf-8'); } let showAppInfo = { key, status: 'inactive', type: app?.type || 'system-app', description: readmeDesc || '', version, // entry: app?.entry || '', path: directory, origin: app, }; app.key = key; fs.writeFileSync(pkgs, JSON.stringify(pkg, null, 2)); return { 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; };