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

171 lines
4.6 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/pocketbase/pocketbase/releases/latest";
const proxy = 'https://gh-proxy.org/';
const program = 'program';
const directory = program + '/' + 'pocketbase';
// 获取系统平台和架构
function getPlatformInfo() {
const platform = os.platform(); // 'darwin', 'linux', 'win32'
const arch = os.arch(); // 'x64', 'arm64', etc.
let platformName = '';
let archName = '';
// 映射平台名称
switch (platform) {
case 'darwin':
platformName = 'darwin';
break;
case 'linux':
platformName = 'linux';
break;
case 'win32':
platformName = 'windows';
break;
default:
throw new Error(`Unsupported platform: ${platform}`);
}
// 映射架构名称
switch (arch) {
case 'x64':
archName = 'amd64';
break;
case 'arm64':
archName = 'arm64';
break;
default:
throw new Error(`Unsupported architecture: ${arch}`);
}
return { platformName, archName };
}
// 下载文件
async function downloadFile(url: string, destPath: string): Promise<void> {
return new Promise((resolve, reject) => {
https.get(url, (response) => {
// 处理重定向
if (response.statusCode === 302 || response.statusCode === 301) {
const redirectUrl = response.headers.location;
if (redirectUrl) {
downloadFile(redirectUrl, destPath).then(resolve).catch(reject);
return;
}
}
if (response.statusCode !== 200) {
reject(new Error(`Failed to download: ${response.statusCode}`));
return;
}
const fileStream = createWriteStream(destPath);
response.pipe(fileStream);
fileStream.on('finish', () => {
fileStream.close();
resolve();
});
fileStream.on('error', reject);
}).on('error', reject);
});
}
// 解压 zip 文件 (Windows)
async function extractZip(zipPath: string, destDir: string): Promise<void> {
const AdmZip = require('adm-zip');
const zip = new AdmZip(zipPath);
zip.extractAllTo(destDir, true);
}
// 提取 tar.gz 文件 (Linux/macOS)
export async function extractTarGz(tarGzPath: string, destDir: string): Promise<void> {
await fs.promises.mkdir(destDir, { recursive: true });
await pipeline(
createReadStream(tarGzPath),
createGunzip(),
extract({ cwd: destDir })
);
}
// 主函数:下载并解压 PocketBase
export async function download(): Promise<void> {
try {
const { platformName, archName } = getPlatformInfo();
console.log(`检测到系统: ${platformName} ${archName}`);
// 获取最新版本信息
const response = await fetch(base);
if (!response.ok) {
throw new Error(`Failed to fetch release info: ${response.status}`);
}
const releaseData = await response.json();
const tagName = releaseData.tag_name.replace(/^v/, '');
const assets = releaseData.assets;
// 查找匹配的资源文件
const fileExtension = '.zip';
const assetPattern = `pocketbase_${tagName}_${platformName}_${archName}${fileExtension}`;
const asset = assets.find((a: any) => a.name.includes(assetPattern));
if (!asset) {
throw new Error(`No matching asset found for ${platformName} ${archName}`);
}
console.log(`找到资源: ${asset.name}`);
console.log(`下载链接: ${asset.browser_download_url}`);
// 创建目录
await fs.promises.mkdir(directory, { recursive: true });
const downloadPath = path.join(directory, asset.name);
// 下载文件
console.log('开始下载...');
await downloadFile(asset.browser_download_url, downloadPath);
console.log('下载完成');
// 解压文件
console.log('开始解压...');
await extractZip(downloadPath, directory);
console.log('解压完成');
// 给可执行文件添加执行权限(非 Windows
if (os.platform() !== 'win32') {
const finalPath = path.join(directory, 'pocketbase');
fs.chmodSync(finalPath, 0o755);
console.log('已添加执行权限');
}
// 删除压缩包
await fs.promises.unlink(downloadPath);
console.log('清理完成');
console.log(`PocketBase 已安装到: ${path.resolve(directory)}`);
} catch (error) {
console.error('下载或解压失败:', error);
throw error;
}
}
// 如果直接运行此文件
if (require.main === module) {
download();
}