This commit is contained in:
2025-11-23 04:19:43 +08:00
parent ba2056ba29
commit ffc20eb34a
14 changed files with 805 additions and 22 deletions

151
agent/apps/nocodb.ts Normal file
View File

@@ -0,0 +1,151 @@
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();
}