增加镜像源下载

This commit is contained in:
刘嘉伟 2024-08-21 13:37:42 +08:00
parent 357cc473c7
commit 1f246e3966
4 changed files with 277 additions and 230 deletions

View File

@ -1,244 +1,280 @@
import electron, {app, BrowserWindow, ipcMain, net, shell} from "electron"; import electron, { app, BrowserWindow, ipcMain, net, shell } from "electron";
import {deleteVersionById, insertVersion, listVersion} from "../storage/version"; import {
deleteVersionById,
insertVersion,
listVersion
} from "../storage/version";
const fs = require("fs"); const fs = require("fs");
const path = require("path"); const path = require("path");
const zlib = require("zlib"); const zlib = require("zlib");
const {download} = require("electron-dl"); const { download } = require("electron-dl");
const AdmZip = require('adm-zip'); const AdmZip = require("adm-zip");
const log = require('electron-log'); const log = require("electron-log");
const versionRelation = { const versionRelation = {
"win32_x64": ["window", "amd64"], win32_x64: ["window", "amd64"],
"win32_arm64": ["window", "arm64"], win32_arm64: ["window", "arm64"],
"win32_ia32": ["window", "386"], win32_ia32: ["window", "386"],
"darwin_arm64": ["darwin", "arm64"], darwin_arm64: ["darwin", "arm64"],
"darwin_x64": ["darwin", "amd64"], darwin_x64: ["darwin", "amd64"],
"darwin_amd64": ["darwin", "amd64"], darwin_amd64: ["darwin", "amd64"],
"linux_x64": ["linux", "amd64"], linux_x64: ["linux", "amd64"],
"linux_arm64": ["linux", "arm64"], linux_arm64: ["linux", "arm64"]
} };
const platform = process.platform; const platform = process.platform;
const arch = process.arch; const arch = process.arch;
let currArch = `${platform}_${arch}` let currArch = `${platform}_${arch}`;
const frpArch = versionRelation[currArch] const frpArch = versionRelation[currArch];
const unTarGZ = (tarGzPath: string, targetPath: string) => { const unTarGZ = (tarGzPath: string, targetPath: string) => {
const tar = require("tar"); const tar = require("tar");
const unzip = zlib.createGunzip(); const unzip = zlib.createGunzip();
log.debug(`开始解压tar.gz${tarGzPath} 目标目录:${targetPath}`); log.debug(`开始解压tar.gz${tarGzPath} 目标目录:${targetPath}`);
const readStream = fs.createReadStream(tarGzPath); const readStream = fs.createReadStream(tarGzPath);
if (!fs.existsSync(unzip)) { if (!fs.existsSync(unzip)) {
fs.mkdirSync(targetPath, {recursive: true}); fs.mkdirSync(targetPath, { recursive: true });
} }
readStream.pipe(unzip).pipe( readStream.pipe(unzip).pipe(
tar.extract({ tar.extract({
cwd: targetPath, cwd: targetPath,
filter: filePath => path.basename(filePath) === "frpc" filter: filePath => path.basename(filePath) === "frpc"
}) })
); );
const frpcPath = path.join("frp", path.basename(tarGzPath, ".tar.gz")); const frpcPath = path.join("frp", path.basename(tarGzPath, ".tar.gz"));
log.debug(`解压完成 解压后目录:${frpcPath}`); log.debug(`解压完成 解压后目录:${frpcPath}`);
return frpcPath; return frpcPath;
// .on("finish", () => { // .on("finish", () => {
// console.log("解压完成!"); // console.log("解压完成!");
// }); // });
}; };
const unZip = (zipPath: string, targetPath: string) => { const unZip = (zipPath: string, targetPath: string) => {
if (!fs.existsSync(path.join(targetPath, path.basename(zipPath, ".zip")))) { if (!fs.existsSync(path.join(targetPath, path.basename(zipPath, ".zip")))) {
fs.mkdirSync(path.join(targetPath, path.basename(zipPath, ".zip")), {recursive: true}); fs.mkdirSync(path.join(targetPath, path.basename(zipPath, ".zip")), {
} recursive: true
log.debug(`开始解压zip${zipPath} 目标目录:${targetPath}`); });
/** }
* unzipper解压 log.debug(`开始解压zip${zipPath} 目标目录:${targetPath}`);
*/ /**
// fs.createReadStream(zipPath) * unzipper解压
// .pipe(unzipper.Extract({ path: targetPath })) */
// // 只解压frpc.exe // fs.createReadStream(zipPath)
// // .pipe(unzipper.ParseOne('frpc')) // .pipe(unzipper.Extract({ path: targetPath }))
// // .pipe(fs.createWriteStream(path.join(targetPath, path.basename(zipPath, ".zip"), "frpc.exe"))) // // 只解压frpc.exe
// .on('finish', () => { // // .pipe(unzipper.ParseOne('frpc'))
// console.log('File extracted successfully.'); // // .pipe(fs.createWriteStream(path.join(targetPath, path.basename(zipPath, ".zip"), "frpc.exe")))
// }) // .on('finish', () => {
// .on('error', (err) => { // console.log('File extracted successfully.');
// console.error('Error extracting file:', err); // })
// }); // .on('error', (err) => {
// console.error('Error extracting file:', err);
// });
const zip = new AdmZip(zipPath) const zip = new AdmZip(zipPath);
zip.extractAllTo(targetPath, true); // 第二个参数为 true表示覆盖已存在的文件 zip.extractAllTo(targetPath, true); // 第二个参数为 true表示覆盖已存在的文件
const frpcPath = path.join("frp", path.basename(zipPath, ".zip")); const frpcPath = path.join("frp", path.basename(zipPath, ".zip"));
log.debug(`解压完成 解压后目录:${frpcPath}`); log.debug(`解压完成 解压后目录:${frpcPath}`);
return frpcPath return frpcPath;
} };
export const initGitHubApi = () => { export const initGitHubApi = () => {
// 版本 // 版本
let versions: FrpVersion[] = []; let versions: FrpVersion[] = [];
const getVersion = versionId => { const getVersion = versionId => {
return versions.find(f => f.id === versionId); return versions.find(f => f.id === versionId);
}; };
const getAdaptiveAsset = versionId => { const getAdaptiveAsset = versionId => {
const {assets} = getVersion(versionId); const { assets } = getVersion(versionId);
const asset = assets.find( const asset = assets.find(f => {
f => { // const a = versionRelation[currArch]
// const a = versionRelation[currArch] const a = frpArch;
const a = frpArch if (a) {
if (a) { const flag = a.every(item => f.name.includes(item));
const flag = a.every(item => f.name.includes(item)) return flag;
return flag; }
} return false;
return false; });
} if (asset) {
log.info(`找到对应版本 ${asset.name}`);
}
return asset;
};
const formatBytes = (bytes: number, decimals: number = 2): string => {
if (bytes === 0) return "0 Bytes";
const k = 1024; // 1 KB = 1024 Bytes
const dm = decimals < 0 ? 0 : decimals; // 确保小数位数不小于 0
const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
const i = Math.floor(Math.log(bytes) / Math.log(k)); // 计算单位索引
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i]; // 返回格式化的字符串
};
/**
* github上的frp所有版本
*/
ipcMain.on("github.getFrpVersions", async event => {
const request = net.request({
method: "get",
url: "https://api.github.com/repos/fatedier/frp/releases?page=1&per_page=1000"
});
request.on("response", response => {
let responseData: Buffer = Buffer.alloc(0);
response.on("data", (data: Buffer) => {
responseData = Buffer.concat([responseData, data]);
});
response.on("end", () => {
versions = JSON.parse(responseData.toString());
// const borderContent: Electron.WebContents =
// BrowserWindow.getFocusedWindow().webContents;
const downloadPath = path.join(app.getPath("userData"), "download");
log.info(
`开始获取frp版本 当前架构:${currArch} 对应frp架构${frpArch}`
); );
if (asset) { const returnVersionsData = versions
log.info(`找到对应版本 ${asset.name}`) .filter(f => getAdaptiveAsset(f.id))
} .map(m => {
return asset; const asset = getAdaptiveAsset(m.id);
}; const download_count = m.assets.reduce(
(sum, item) => sum + item.download_count,
/** 0
* github上的frp所有版本 );
*/ if (asset) {
ipcMain.on("github.getFrpVersions", async event => { const absPath = `${downloadPath}/${asset.name}`;
const request = net.request({ m.absPath = absPath;
method: "get", m.download_completed = fs.existsSync(absPath);
url: "https://api.github.com/repos/fatedier/frp/releases?page=1&per_page=1000" m.download_count = download_count;
}); m.size = formatBytes(asset.size);
request.on("response", response => {
let responseData: Buffer = Buffer.alloc(0);
response.on("data", (data: Buffer) => {
responseData = Buffer.concat([responseData, data]);
});
response.on("end", () => {
versions = JSON.parse(responseData.toString());
// const borderContent: Electron.WebContents =
// BrowserWindow.getFocusedWindow().webContents;
const downloadPath = path.join(app.getPath("userData"), "download");
log.info(`开始获取frp版本 当前架构:${currArch} 对应frp架构${frpArch}`)
const returnVersionsData = versions
.filter(f => getAdaptiveAsset(f.id))
.map(m => {
const asset = getAdaptiveAsset(m.id);
if (asset) {
const absPath = `${downloadPath}/${asset.name}`;
m.absPath = absPath;
m.download_completed = fs.existsSync(absPath);
}
return m;
});
// log.debug(`获取到frp版本${JSON.stringify(returnVersionsData)}`)
event.reply("Download.frpVersionHook", returnVersionsData);
});
});
request.end();
});
/**
*
*/
ipcMain.on("github.download", async (event, args) => {
const version = getVersion(args);
const asset = getAdaptiveAsset(args);
const {browser_download_url} = asset;
log.info(`开始下载frp url${browser_download_url} asset${asset.name}`)
// 数据目录
await download(BrowserWindow.getFocusedWindow(), browser_download_url, {
filename: `${asset.name}`,
directory: path.join(app.getPath("userData"), "download"),
onProgress: progress => {
event.reply("Download.frpVersionDownloadOnProgress", {
id: args,
progress: progress
});
},
onCompleted: () => {
log.info(`frp下载完成 url${browser_download_url} asset${asset.name}`)
const targetPath = path.resolve(path.join(app.getPath("userData"), "frp"));
const ext = path.extname(asset.name)
let frpcVersionPath = ""
if (ext === '.zip') {
frpcVersionPath = unZip(path.join(
path.join(app.getPath("userData"), "download"),
`${asset.name}`
),
targetPath)
} else if (ext === '.gz' && asset.name.includes(".tar.gz")) {
frpcVersionPath = unTarGZ(
path.join(
path.join(app.getPath("userData"), "download"),
`${asset.name}`
),
targetPath
);
}
version["frpcVersionPath"] = frpcVersionPath;
insertVersion(version, (err, document) => {
if (!err) {
listVersion((err, doc) => {
event.reply("Config.versions.hook", { err, data: doc });
event.reply("Download.frpVersionDownloadOnCompleted", args);
version.download_completed = true;
});
}
});
} }
}); return m;
});
// log.debug(`获取到frp版本${JSON.stringify(returnVersionsData)}`)
event.reply("Download.frpVersionHook", returnVersionsData);
});
}); });
request.end();
});
/** /**
* *
*/ */
ipcMain.on("github.deleteVersion", async (event, args) => { ipcMain.on("github.download", async (event, args) => {
const {absPath, id} = args; const { versionId, mirror } = args;
if (fs.existsSync(absPath)) { const version = getVersion(versionId);
deleteVersionById(id, () => { const asset = getAdaptiveAsset(versionId);
fs.unlinkSync(absPath) const { browser_download_url } = asset;
})
let url = browser_download_url;
if (mirror === "ghproxy") {
url = "https://mirror.ghproxy.com/" + url;
}
log.info(`开始下载frp url${url} asset${asset.name}`);
// 数据目录
await download(BrowserWindow.getFocusedWindow(), url, {
filename: `${asset.name}`,
directory: path.join(app.getPath("userData"), "download"),
onProgress: progress => {
event.reply("Download.frpVersionDownloadOnProgress", {
id: versionId,
progress: progress
});
},
onCompleted: () => {
log.info(`frp下载完成 url${url} asset${asset.name}`);
const targetPath = path.resolve(
path.join(app.getPath("userData"), "frp")
);
const ext = path.extname(asset.name);
let frpcVersionPath = "";
if (ext === ".zip") {
frpcVersionPath = unZip(
path.join(
path.join(app.getPath("userData"), "download"),
`${asset.name}`
),
targetPath
);
} else if (ext === ".gz" && asset.name.includes(".tar.gz")) {
frpcVersionPath = unTarGZ(
path.join(
path.join(app.getPath("userData"), "download"),
`${asset.name}`
),
targetPath
);
} }
listVersion((err, doc) => {
event.reply("Config.versions.hook", { err, data: doc });
event.reply("Download.deleteVersion.hook", { err: null, data: "删除成功" });
});
})
/** version["frpcVersionPath"] = frpcVersionPath;
* insertVersion(version, (err, document) => {
*/ if (!err) {
ipcMain.on("github.getFrpcDesktopLastVersions", async event => { listVersion((err, doc) => {
const request = net.request({ event.reply("Config.versions.hook", { err, data: doc });
method: "get", event.reply("Download.frpVersionDownloadOnCompleted", versionId);
url: "https://api.github.com/repos/luckjiawei/frpc-desktop/releases/latest" version.download_completed = true;
});
request.on("response", response => {
let responseData: Buffer = Buffer.alloc(0);
response.on("data", (data: Buffer) => {
responseData = Buffer.concat([responseData, data]);
});
response.on("end", () => {
versions = JSON.parse(responseData.toString());
// const borderContent: Electron.WebContents =
// BrowserWindow.getFocusedWindow().webContents;
// const downloadPath = path.join(app.getPath("userData"), "download");
// log.info(`开始获取frp版本 当前架构:${currArch} 对应frp架构${frpArch}`)
// const returnVersionsData = versions
// .filter(f => getAdaptiveAsset(f.id))
// .map(m => {
// const asset = getAdaptiveAsset(m.id);
// if (asset) {
// const absPath = `${downloadPath}/${asset.name}`;
// m.absPath = absPath;
// m.download_completed = fs.existsSync(absPath);
// }
// return m;
// });
// log.debug(`获取到frp版本${JSON.stringify(returnVersionsData)}`)
event.reply("github.getFrpcDesktopLastVersionsHook", versions);
}); });
}
}); });
request.end(); }
}) });
});
/**
*
*/
ipcMain.on("github.deleteVersion", async (event, args) => {
const { absPath, id } = args;
if (fs.existsSync(absPath)) {
deleteVersionById(id, () => {
fs.unlinkSync(absPath);
});
}
listVersion((err, doc) => {
event.reply("Config.versions.hook", { err, data: doc });
event.reply("Download.deleteVersion.hook", {
err: null,
data: "删除成功"
});
});
});
/**
*
*/
ipcMain.on("github.getFrpcDesktopLastVersions", async event => {
const request = net.request({
method: "get",
url: "https://api.github.com/repos/luckjiawei/frpc-desktop/releases/latest"
});
request.on("response", response => {
let responseData: Buffer = Buffer.alloc(0);
response.on("data", (data: Buffer) => {
responseData = Buffer.concat([responseData, data]);
});
response.on("end", () => {
versions = JSON.parse(responseData.toString());
// const borderContent: Electron.WebContents =
// BrowserWindow.getFocusedWindow().webContents;
// const downloadPath = path.join(app.getPath("userData"), "download");
// log.info(`开始获取frp版本 当前架构:${currArch} 对应frp架构${frpArch}`)
// const returnVersionsData = versions
// .filter(f => getAdaptiveAsset(f.id))
// .map(m => {
// const asset = getAdaptiveAsset(m.id);
// if (asset) {
// const absPath = `${downloadPath}/${asset.name}`;
// m.absPath = absPath;
// m.download_completed = fs.existsSync(absPath);
// }
// return m;
// });
// log.debug(`获取到frp版本${JSON.stringify(returnVersionsData)}`)
event.reply("github.getFrpcDesktopLastVersionsHook", versions);
});
});
request.end();
});
}; };

View File

@ -20,3 +20,20 @@
html { html {
} }
.h2 {
color: #5a3daa;
font-size: 16px;
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB",
"Microsoft YaHei", "微软雅黑", Arial, sans-serif;
font-weight: 700;
padding: 6px 10px 6px 15px;
border-left: 5px solid #5a3daa;
border-radius: 4px;
background-color: #eeebf6;
margin-bottom: 18px;
}
.left-border {
border-left: 5px solid #5a3daa;
}

View File

@ -950,19 +950,6 @@ onUnmounted(() => {
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
.h2 {
color: #5a3daa;
font-size: 16px;
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB",
"Microsoft YaHei", "微软雅黑", Arial, sans-serif;
font-weight: 700;
padding: 6px 10px 6px 15px;
border-left: 5px solid #5a3daa;
border-radius: 4px;
background-color: #eeebf6;
margin-bottom: 18px;
}
.button-input { .button-input {
width: calc(100% - 68px); width: calc(100% - 68px);
} }

7
types/global.d.ts vendored
View File

@ -45,6 +45,8 @@ declare global {
name: string; name: string;
published_at: string; published_at: string;
download_completed: boolean; download_completed: boolean;
size: string;
download_count: number;
absPath: string; absPath: string;
assets: Asset[] assets: Asset[]
}; };
@ -75,6 +77,11 @@ declare global {
transportHeartbeatTimeout: number; transportHeartbeatTimeout: number;
}; };
type GitHubMirror = {
id: string;
name: string;
}
} }
export {}; export {};