Files
app-db-agent/agent/apps/nocodb.ts
2025-11-23 04:19:43 +08:00

152 lines
4.4 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os from "node:os";
import fs from "node:fs";
import path from "node:path";
import https from "node:https";
import { pipeline } from "node:stream/promises";
import { createWriteStream, createReadStream } from "node:fs";
import { createGunzip } from "node:zlib";
import { extract } from "tar";
const base = "https://api.github.com/repos/nocodb/nocodb/releases/latest";
const program = 'program';
const proxy = 'https://gh-proxy.org/';
const directory = program + '/' + 'nocodb';
// 获取平台和架构对应的文件名
function getPlatformFileName(): string {
const platform = os.platform();
const arch = os.arch();
if (platform === 'darwin') {
return arch === 'arm64' ? 'Noco-macos-arm64' : 'Noco-macos-x64';
} else if (platform === 'linux') {
return arch === 'arm64' ? 'Noco-linux-arm64' : 'Noco-linux-x64';
} else if (platform === 'win32') {
return arch === 'arm64' ? 'Noco-win-arm64.exe' : 'Noco-win-x64.exe';
}
throw new Error(`Unsupported platform: ${platform}-${arch}`);
}
// 下载文件
async function downloadFile(url: string, dest: string): Promise<void> {
return new Promise((resolve, reject) => {
https.get(url, {
headers: {
'User-Agent': 'nocodb-installer'
}
}, (response) => {
if (response.statusCode === 302 || response.statusCode === 301) {
// 处理重定向
downloadFile(response.headers.location!, dest).then(resolve).catch(reject);
return;
}
if (response.statusCode !== 200) {
reject(new Error(`Failed to download: ${response.statusCode}`));
return;
}
const fileStream = createWriteStream(dest);
response.pipe(fileStream);
fileStream.on('finish', () => {
fileStream.close();
resolve();
});
fileStream.on('error', reject);
}).on('error', reject);
});
}
// 解压 tar.gz 文件
async function extractTarGz(filePath: string, destDir: string): Promise<void> {
await pipeline(
createReadStream(filePath),
createGunzip(),
extract({ cwd: destDir })
);
}
// 主函数
export async function download() {
try {
console.log('正在获取最新版本信息...');
// 获取 latest release 信息
const releaseData = await new Promise<any>((resolve, reject) => {
https.get(proxy+base, {
headers: {
'User-Agent': 'nocodb-installer'
}
}, (response) => {
let data = '';
response.on('data', chunk => data += chunk);
response.on('end', () => resolve(JSON.parse(data)));
response.on('error', reject);
}).on('error', reject);
});
const version = releaseData.tag_name;
console.log(`最新版本: ${version}`);
const fileName = getPlatformFileName();
console.log(`平台文件: ${fileName}`);
// 查找对应的 asset
const asset = releaseData.assets.find((a: any) => a.name === fileName);
if (!asset) {
throw new Error(`找不到对应的文件: ${fileName}`);
}
// 创建目录
if (!fs.existsSync(directory)) {
fs.mkdirSync(directory, { recursive: true });
}
const downloadPath = path.join(directory, fileName);
// 下载文件
console.log('正在下载...');
await downloadFile(asset.browser_download_url, downloadPath);
console.log(`下载完成: ${downloadPath}`);
// 确定最终文件名
const finalFileName = os.platform() === 'win32' ? 'nocodb.exe' : 'nocodb';
const finalPath = path.join(directory, finalFileName);
// 如果是 tar.gz 文件,进行解压
if (fileName === 'nocodb.tar.gz') {
console.log('正在解压...');
await extractTarGz(downloadPath, directory);
console.log('解压完成');
// 删除压缩包
fs.unlinkSync(downloadPath);
} else {
// 重命名为统一的可执行文件名
if (downloadPath !== finalPath) {
fs.renameSync(downloadPath, finalPath);
console.log(`重命名为: ${finalFileName}`);
}
// 给可执行文件添加执行权限(非 Windows
if (os.platform() !== 'win32') {
fs.chmodSync(finalPath, 0o755);
console.log('已添加执行权限');
}
}
console.log('安装完成!');
} catch (error) {
console.error('安装失败:', error);
process.exit(1);
}
}
// 如果直接运行此文件
if (require.main === module) {
download();
}