🐛 fix version handling and improve IPC communication for downloads

This commit is contained in:
刘嘉伟 2025-02-23 02:11:17 +08:00
parent 8d56faeb80
commit 2edbbcb871
19 changed files with 447 additions and 251 deletions

View File

@ -11,7 +11,9 @@ class ServerController extends BaseController {
}
saveConfig(req: ControllerParam) {
console.log("save", req.args);
this._serverService.saveServerConfig(req.args).then(() => {
req.event.reply(req.channel, success());
})
}
getServerConfig(req: ControllerParam) {

View File

@ -1,13 +1,16 @@
import BaseController from "./BaseController";
import VersionService from "../service/VersionService";
import { success } from "../utils/response";
import { fail, success } from "../utils/response";
import VersionDao from "../dao/VersionDao";
class VersionController extends BaseController {
private readonly _versionService: VersionService;
private readonly _versionDao: VersionDao;
constructor(versionService: VersionService) {
constructor(versionService: VersionService, versionDao: VersionDao) {
super();
this._versionService = versionService;
this._versionDao = versionDao;
}
getVersions(req: ControllerParam) {
@ -22,6 +25,43 @@ class VersionController extends BaseController {
});
});
}
getDownloadedVersions(req: ControllerParam) {
this._versionDao.findAll().then(data => {
req.event.reply(req.channel, success(data));
});
}
downloadFrpVersion(req: ControllerParam) {
this._versionService
.downloadFrpVersion(req.args.githubReleaseId, progress => {
req.event.reply(
req.channel,
success({
percent: progress.percent,
githubReleaseId: req.args.githubReleaseId,
completed: progress.percent >= 1
})
);
})
.then(r => {
console.log(2);
})
.catch(err => {
console.log(1);
});
}
deleteDownloadedVersion(req: ControllerParam) {
this._versionService
.deleteFrpVersion(req.args.githubReleaseId)
.then(() => {
req.event.reply(req.channel, success());
})
.catch(err => {
req.event.reply(req.channel, fail());
});
}
}
export default VersionController;

View File

@ -0,0 +1,26 @@
/**
* todo DI
*/
class BeanFactory {
private static _beans: Map<string, any> = new Map<string, any>();
private static registerBean(name: string, instance: any): void {
if (!this._beans.has(name)) {
this._beans.set(name, instance);
}
}
public static getBean<T>(name: string): T {
return this._beans.get(name);
}
public static hasBean(name: string): boolean {
return this._beans.has(name);
}
public static clear(): void {
this._beans.clear();
}
}
export default BeanFactory;

View File

@ -1,13 +1,22 @@
import path from "path";
import { app } from "electron";
import SecureUtils from "../utils/SecureUtils";
class GlobalConstant {
public static FRPC_STORAGE_FOLDER = "";
public static APP_NAME = "Frpc Desktop";
public static ZIP_EXT = ".zip";
public static GZ_EXT = ".gz";
public static TAR_GZ_EXT = ".tar.gz";
public static FRP_ARCH_VERSION_MAPPING = {
win32_x64: ["window", "amd64"],
win32_arm64: ["window", "arm64"],
win32_ia32: ["window", "386"],
darwin_arm64: ["darwin", "arm64"],
darwin_x64: ["darwin", "amd64"],
darwin_amd64: ["darwin", "amd64"],
linux_x64: ["linux", "amd64"],
linux_arm64: ["linux", "arm64"]
};
public static FRPC_PROCESS_STATUS_CHECK_INTERVAL = 3000;
// public static APP_DATA_PATH = app.getPath("userData");
// public static DOWNLOAD_STORAGE_PATH = path.join(

View File

@ -35,6 +35,18 @@ export const ipcRouters: IpcRouters = {
getVersions: {
path: "version/getVersions",
controller: "versionController.getVersions"
},
downloadVersion: {
path: "version/downloadVersion",
controller: "versionController.downloadFrpVersion"
},
getDownloadedVersions: {
path: "version/getDownloadedVersions",
controller: "versionController.getDownloadedVersions"
},
deleteDownloadedVersion: {
path: "version/deleteDownloadedVersion",
controller: "versionController.deleteDownloadedVersion"
}
}
};
@ -68,7 +80,7 @@ class IpcRouterConfigurate {
);
const logService = new LogService(fileService);
const serverController = new ServerController(serverService);
const versionController = new VersionController(versionService);
const versionController = new VersionController(versionService, versionDao);
const logController = new LogController(logService);
this._beans.set("serverDao", serverDao);

View File

@ -1,8 +1,7 @@
import Datastore from "nedb";
import path from "path";
import Snowflakify from "snowflakify";
import GlobalConstant from "../core/GlobalConstant";
import PathUtils from "../utils/PathUtils";
import IdUtils from "../utils/IdUtils";
// interface BaseDaoInterface<T> {
// db: Datastore;
@ -25,10 +24,7 @@ class BaseDao<T> {
protected readonly db: Datastore;
constructor(dbName: string) {
const dbFilename = path.join(
PathUtils.getAppData(),
`${dbName}-v2.db`
);
const dbFilename = path.join(PathUtils.getAppData(), `${dbName}-v2.db`);
this.db = new Datastore({
autoload: true,
filename: dbFilename
@ -83,10 +79,17 @@ class BaseDao<T> {
});
}
//
// deleteById(id: string): void {
// return null;
// }
deleteById(id: string): Promise<void> {
return new Promise<void>((resolve, reject) => {
this.db.remove({ _id: id }, err => {
if (err) {
reject(err);
} else {
resolve();
}
});
});
}
//
// findAll(): T[] {
// return null;
@ -103,6 +106,18 @@ class BaseDao<T> {
});
});
}
findAll(): Promise<Array<T>> {
return new Promise<Array<T>>((resolve, reject) => {
this.db.find({}, (err, document) => {
if (err) {
reject(err);
} else {
resolve(document);
}
});
});
}
}
export default BaseDao;

View File

@ -18,7 +18,7 @@ class VersionDao extends BaseDao<FrpcVersion> {
}
exists(githubReleaseId: number): Promise<boolean> {
return new Promise((resolve, reject) => {
return new Promise(( resolve, reject) => {
this.db.count({ githubReleaseId: githubReleaseId }, (err, count) => {
if (err) {
reject(err);

View File

@ -4,8 +4,9 @@ import fs from "fs";
import zlib from "zlib";
import admZip from "adm-zip";
import GlobalConstant from "../core/GlobalConstant";
import { logError, logInfo, LogModule } from "../utils/log";
// import tar from "tar";
const tar = require("tar");
class FileService {
constructor() {}
@ -49,37 +50,40 @@ class FileService {
// const frpcPath = path.join("frp", path.basename(zipFilePath, zipExt));
}
decompressTarGzFile(tarGzPath: string, targetPath: string) {
decompressTarGzFile(tarGzPath: string, targetPath: string, finish: Function) {
// const targetFolder = path.join(targetPath, targetPath);
const unzip = zlib.createGunzip();
const readStream = fs.createReadStream(tarGzPath);
// if (!fs.existsSync(unzip)) {
// fs.mkdirSync(targetPath, { recursive: true, mode: 0o777 });
// }
if (!fs.existsSync(targetPath)) {
fs.mkdirSync(targetPath, { recursive: true, mode: 0o777 });
}
readStream
.pipe(unzip)
.on("error", err => {
logError(LogModule.APP, `Error during gunzip: ${err.message}`);
// logError(LogModule.APP, `Error during gunzip: ${err.message}`);
})
// .pipe(
// tar
// .extract({
// cwd: targetPath,
// filter: filePath => path.basename(filePath) === "frpc"
// })
// .on("error", err => {
// logError(
// LogModule.APP,
// `Error extracting tar file: ${err.message}`
// );
// })
// )
.pipe(
tar
.extract({
cwd: targetPath,
strip: 1,
filter: filePath => path.basename(filePath) === "frpc"
})
.on("error", err => {
// logError(
// LogModule.APP,
// `Error extracting tar file: ${err.message}`
// );
})
)
.on("finish", () => {
const frpcPath = path.join("frp", path.basename(tarGzPath, ".tar.gz"));
logInfo(
LogModule.APP,
`Extraction completed. Extracted directory: ${frpcPath}`
);
finish();
// const frpcPath = path.join("frp", path.basename(tarGzPath, ".tar.gz"));
// logInfo(
// LogModule.APP,
// `Extraction completed. Extracted directory: ${frpcPath}`
// );
});
}
}

View File

@ -0,0 +1,74 @@
import ServerService from "./ServerService";
import VersionDao from "../dao/VersionDao";
import PathUtils from "../utils/PathUtils";
import { frpcProcess } from "../api/frpc";
import GlobalConstant from "../core/GlobalConstant";
import { Notification } from "electron";
const { exec, spawn } = require("child_process");
class FrpProcessService {
private readonly _serverService: ServerService;
private readonly _versionDao: VersionDao;
private _frpcProcess: any;
private _FrpcProcessListener: any;
constructor(serverService: ServerService, versionDao: VersionDao) {
this._serverService = serverService;
this._versionDao = versionDao;
}
isRunning(): boolean {
return false;
}
async startFrpcProcess() {
const config = await this._serverService.getServerConfig();
const version = await this._versionDao.findByGithubReleaseId(
config.frpcVersion
);
// todo genConfigfile.
const configPath = "";
const command = `${PathUtils.getFrpcFilename()} -c ${configPath}`;
this._frpcProcess = spawn(command, {
cwd: version.localPath,
shell: true
});
frpcProcess.stdout.on("data", data => {
// logDebug(LogModule.FRP_CLIENT, `Frpc process output: ${data}`);
});
frpcProcess.stdout.on("error", data => {
// logError(LogModule.FRP_CLIENT, `Frpc process error: ${data}`);
// stopFrpcProcess(() => {});
this.stopFrpcProcess();
});
}
stopFrpcProcess() {}
watchFrpcProcess(listenerParam: ListenerParam) {
this._FrpcProcessListener = setInterval(() => {
const running = this.isRunning();
// todo return status to view.
// logDebug(
// LogModule.FRP_CLIENT,
// `Monitoring frpc process status: ${status}, Listener ID: ${frpcStatusListener}`
// );
if (!running) {
new Notification({
title: GlobalConstant.APP_NAME,
body: "Connection lost, please check the logs for details."
}).show();
// logError(
// LogModule.FRP_CLIENT,
// "Frpc process status check failed. Connection lost."
// );
clearInterval(this._FrpcProcessListener);
}
}, GlobalConstant.FRPC_PROCESS_STATUS_CHECK_INTERVAL);
}
}
export default FrpProcessService;

View File

@ -8,26 +8,14 @@ class ServerService extends BaseService<FrpcDesktopServer> {
this._serverDao = serverDao;
}
saveServerConfig(frpcServer: FrpcDesktopServer): Promise<void> {
return new Promise((resolve, reject) => {
this._serverDao
.updateById("1", frpcServer)
.then(() => {
resolve();
})
.catch(err => reject(err));
});
async saveServerConfig(
frpcServer: FrpcDesktopServer
): Promise<FrpcDesktopServer> {
return await this._serverDao.updateById("1", frpcServer);
}
getServerConfig(): Promise<FrpcDesktopServer> {
return new Promise((resolve, reject) => {
this._serverDao
.findById("1")
.then((frpcServer: FrpcDesktopServer) => {
resolve(frpcServer);
})
.catch(err => reject(err));
});
async getServerConfig(): Promise<FrpcDesktopServer> {
return await this._serverDao.findById("1");
}
hasServerConfig(): Promise<boolean> {

View File

@ -8,23 +8,9 @@ import { BrowserWindow } from "electron";
import GlobalConstant from "../core/GlobalConstant";
import path from "path";
import fs from "fs";
import FileUtils from "../utils/FileUtils";
import SecureUtils from "../utils/SecureUtils";
import PathUtils from "../utils/PathUtils";
/**
* arch mapping
*/
const versionMapping = {
win32_x64: ["window", "amd64"],
win32_arm64: ["window", "arm64"],
win32_ia32: ["window", "386"],
darwin_arm64: ["darwin", "arm64"],
darwin_x64: ["darwin", "amd64"],
darwin_amd64: ["darwin", "amd64"],
linux_x64: ["linux", "amd64"],
linux_arm64: ["linux", "arm64"]
};
import FileUtils from "../utils/FileUtils";
class VersionService extends BaseService<FrpcVersion> {
private readonly _versionDao: VersionDao;
@ -43,7 +29,7 @@ class VersionService extends BaseService<FrpcVersion> {
this._gitHubService = gitHubService;
this._fileService = fileService;
const nodeVersion = `${process.platform}_${process.arch}`;
this._currFrpArch = versionMapping[nodeVersion];
this._currFrpArch = GlobalConstant.FRP_ARCH_VERSION_MAPPING[nodeVersion];
}
downloadFrpVersion(githubReleaseId: number, onProgress: Function) {
@ -65,6 +51,9 @@ class VersionService extends BaseService<FrpcVersion> {
SecureUtils.calculateMD5(version.name)
);
if (fs.existsSync(versionFilePath)) {
fs.rmSync(versionFilePath, { recursive: true, force: true });
}
// const targetPath = path.resolve();
download(BrowserWindow.getFocusedWindow(), url, {
filename: `${version.assetName}`,
@ -73,42 +62,78 @@ class VersionService extends BaseService<FrpcVersion> {
onProgress(progress);
},
onCompleted: () => {
if (fs.existsSync(versionFilePath)) {
fs.rmSync(versionFilePath, { recursive: true, force: true });
}
const ext = path.extname(version.assetName);
if (ext === GlobalConstant.ZIP_EXT) {
this._fileService.decompressZipFile(
downloadedFilePath,
versionFilePath
);
// todo delete frps and other file.
} else if (
ext === GlobalConstant.GZ_EXT &&
version.assetName.includes(GlobalConstant.TAR_GZ_EXT)
) {
this._fileService.decompressTarGzFile(
downloadedFilePath,
versionFilePath
versionFilePath,
() => {
// rename frpc.
const frpcFilePath = path.join(versionFilePath, "frpc");
if (fs.existsSync(frpcFilePath)) {
const newFrpcFilePath = path.join(
versionFilePath,
PathUtils.getFrpcFilename()
);
fs.renameSync(frpcFilePath, newFrpcFilePath);
}
// delete downloaded file.
// todo has bug.
const downloadedFile = path.join(
PathUtils.getDownloadStoragePath(),
version.assetName
);
if (fs.existsSync(downloadedFile)) {
fs.rmSync(downloadedFile, { recursive: true, force: true });
}
}
);
}
// todo 2025-02-23 delete downloaded file.
version.localPath = versionFilePath;
this._versionDao.insert(version).then(data => {
resolve(data);
});
version.downloaded = true;
this._versionDao
.insert(version)
.then(data => {
resolve(data);
})
.catch(err => reject(err));
}
});
});
}
deleteFrpVersion() {}
async deleteFrpVersion(githubReleaseId: number) {
if (!githubReleaseId) {
return;
}
const version = await this._versionDao.findByGithubReleaseId(
githubReleaseId
);
if (this.frpcVersionExists(version)) {
fs.rmSync(version.localPath, { recursive: true, force: true });
await this._versionDao.deleteById(version._id);
}
}
getFrpVersionsByGitHub(): Promise<Array<FrpcVersion>> {
async getFrpVersionsByGitHub(): Promise<Array<FrpcVersion>> {
return new Promise<Array<FrpcVersion>>((resolve, reject) => {
this._gitHubService
.getGithubRepoAllReleases("fatedier/frp")
.then((releases: Array<GithubRelease>) => {
.then(async (releases: Array<GithubRelease>) => {
const versions: Array<FrpcVersion> =
this.githubRelease2FrpcVersion(releases);
await this.githubRelease2FrpcVersion(releases);
// const versions: Array<FrpcVersion> = (this.versions = versions);
this.versions = versions;
resolve(versions);
})
@ -116,11 +141,8 @@ class VersionService extends BaseService<FrpcVersion> {
});
}
getFrpVersionByLocalJson(): Promise<Array<FrpcVersion>> {
return new Promise<Array<FrpcVersion>>(resolve => {
const versions = this.githubRelease2FrpcVersion(frpReleasesJson);
resolve(versions);
});
async getFrpVersionByLocalJson(): Promise<Array<FrpcVersion>> {
return this.githubRelease2FrpcVersion(frpReleasesJson);
}
getFrpVersion() {}
@ -131,34 +153,24 @@ class VersionService extends BaseService<FrpcVersion> {
});
}
private githubRelease2FrpcVersion(
private async githubRelease2FrpcVersion(
releases: Array<GithubRelease>
): Array<FrpcVersion> {
): Promise<Array<FrpcVersion>> {
const allVersions = await this._versionDao.findAll();
return releases
.filter(release => {
return this.findCurrentArchitectureAsset(release.assets);
})
.map(m => {
const asset = this.findCurrentArchitectureAsset(m.assets);
// m.assets.forEach((ma: GithubAsset) => {
// // if (asset) {
// // const absPath = path.join(
// // frpPath,
// // asset.name.replace(/(\.tar\.gz|\.zip)$/, "")
// // );
// // m.absPath = absPath;
// // m.download_completed = fs.existsSync(absPath);
// m.download_count = download_count;
// m.size = formatBytes(ma.size);
// // }
// });
// const asset = getAdaptiveAsset(m.id);
const download_count = m.assets.reduce(
(sum, item) => sum + item.download_count,
0
);
const currVersion = allVersions.find(ff => ff.githubReleaseId === m.id);
const v: FrpcVersion = {
_id: "",
githubReleaseId: m.id,
githubAssetId: asset.id,
githubCreatedAt: asset.created_at,
@ -167,25 +179,24 @@ class VersionService extends BaseService<FrpcVersion> {
versionDownloadCount: download_count,
assetDownloadCount: asset.download_count,
browserDownloadUrl: asset.browser_download_url,
downloaded: false,
localPath: "",
downloaded: this.frpcVersionExists(currVersion),
localPath: currVersion && currVersion.localPath,
size: FileUtils.formatBytes(asset.size)
};
return v;
});
}
// private async frpcVersionExists(githubReleaseId: number): boolean {
// const version = await this._versionDao.findByGithubReleaseId(
// githubReleaseId
// );
//
// if (version) {
// return fs.existsSync(version.localPath);
// }
// return false;
// }
private frpcVersionExists(version: FrpcVersion): boolean {
// const version = await this._versionDao.findByGithubReleaseId(
// githubReleaseId
// );
if (version) {
return fs.existsSync(version.localPath);
}
return false;
}
}
export default VersionService;

View File

@ -1,39 +1,21 @@
class IdUtils {
public static genUUID() {
if (typeof crypto === "object") {
if (typeof crypto.randomUUID === "function") {
return crypto.randomUUID();
}
if (
typeof crypto.getRandomValues === "function" &&
typeof Uint8Array === "function"
) {
const callback = c => {
const num = Number(c);
return (
num ^
(crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (num / 4)))
).toString(16);
};
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, callback);
let uuidValue = "",
k,
randomValue;
for (k = 0; k < 32; k++) {
randomValue = (Math.random() * 16) | 0;
if (k == 8 || k == 12 || k == 16 || k == 20) {
uuidValue += "-";
}
uuidValue += (
k == 12 ? 4 : k == 16 ? (randomValue & 3) | 8 : randomValue
).toString(16);
}
let timestamp = new Date().getTime();
let perforNow =
(typeof performance !== "undefined" &&
performance.now &&
performance.now() * 1000) ||
0;
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, c => {
let random = Math.random() * 16;
if (timestamp > 0) {
random = (timestamp + random) % 16 | 0;
timestamp = Math.floor(timestamp / 16);
} else {
random = (perforNow + random) % 16 | 0;
perforNow = Math.floor(perforNow / 16);
}
return (c === "x" ? random : (random & 0x3) | 0x8).toString(16);
});
return uuidValue;
}
}
export default IdUtils;

View File

@ -18,6 +18,10 @@ class PathUtils {
);
}
public static getFrpcFilename() {
return SecureUtils.calculateMD5("frpc")
}
public static getAppData() {
return app.getPath("userData");
}

View File

@ -1,4 +1,4 @@
export function success<T>(data: any, message?: string) {
export function success<T>(data?: any, message?: string) {
const resp: ApiResponse<T> = {
success: true,
data: data,
@ -7,6 +7,15 @@ export function success<T>(data: any, message?: string) {
return resp;
}
// export function success(message?: string) {
// const resp: ApiResponse<void> = {
// success: true,
// data: null,
// message: message || "successful."
// };
// return resp;
// }
export function fail(message?: string) {
const resp: ApiResponse<any> = {
success: false,

View File

@ -1,8 +1,8 @@
import { ipcRenderer } from "electron";
export const send = (router: IpcRouter) => {
export const send = (router: IpcRouter, params?: any) => {
console.log(router, "send.router");
ipcRenderer.send(router.path);
ipcRenderer.send(router.path, params);
};
export const on = (router: IpcRouter, listerHandler: (data: any) => void) => {

View File

@ -179,7 +179,7 @@ const rules = reactive<FormRules>({
]
});
const versions = ref<Array<FrpVersion>>([]);
const versions = ref<Array<FrpcVersion>>([]);
const copyServerConfigBase64 = ref();
const pasteServerConfigBase64 = ref();
@ -234,13 +234,28 @@ const checkAndResetVersion = () => {
}
};
onMounted(() => {
const handleLoadDownloadedVersion = () => {
send(ipcRouters.VERSION.getDownloadedVersions);
};
const handleLoadSavedConfig = () => {
send(ipcRouters.SERVER.getServerConfig);
};
onMounted(() => {
handleLoadDownloadedVersion();
handleLoadSavedConfig();
on(ipcRouters.SERVER.getServerConfig, data => {
console.log("data", data);
loading.value--;
});
on(ipcRouters.VERSION.getDownloadedVersions, data => {
console.log("versions", data);
versions.value = data;
// checkAndResetVersion();
});
// ipcRenderer.send("config.getConfig");
// handleLoadVersions();
// ipcRenderer.on("Config.getConfig.hook", (event, args) => {
@ -541,13 +556,13 @@ onUnmounted(() => {
>
<el-option
v-for="v in versions"
:key="v.id"
:key="v.githubReleaseId"
:label="v.name"
:value="v.id"
></el-option>
:value="v.githubReleaseId"
/>
</el-select>
<div class="w-full flex justify-end">
<el-link type="primary" @click="handleLoadVersions">
<el-link type="primary" @click="handleLoadDownloadedVersion">
<iconify-icon-offline class="mr-1" icon="refresh-rounded" />
手动刷新
</el-link>

View File

@ -7,13 +7,13 @@ import { ElMessage, ElMessageBox } from "element-plus";
import { useDebounceFn } from "@vueuse/core";
import IconifyIconOffline from "@/components/IconifyIcon/src/iconifyIconOffline";
import { on, send } from "@/utils/ipcUtils";
import ipcRouter, { ipcRouters } from "../../../electron/core/IpcRouter";
import { ipcRouters } from "../../../electron/core/IpcRouter";
defineComponent({
name: "Download"
});
const versions = ref<Array<FrpVersion>>([]);
const versions = ref<Array<FrpcVersion>>([]);
const loading = ref(1);
const downloadPercentage = ref(0);
const downloading = ref<Map<number, number>>(new Map<number, number>());
@ -28,28 +28,25 @@ const mirrors = ref<Array<GitHubMirror>>([
/**
* 获取版本
*/
const handleLoadVersions = () => {
ipcRenderer.send("github.getFrpVersions", currMirror.value);
const handleLoadAllVersions = () => {
send(ipcRouters.VERSION.getVersions);
};
/**
* 下载
* @param version
*/
const handleDownload = useDebounceFn((version: FrpVersion) => {
// console.log(version, currMirror.value);
ipcRenderer.send("github.download", {
versionId: version.id,
mirror: currMirror.value
const handleDownload = useDebounceFn((version: FrpcVersion) => {
send(ipcRouters.VERSION.downloadVersion, {
githubReleaseId: version.githubReleaseId
});
downloading.value.set(version.id, 0);
}, 300);
/**
* 删除下载
* @param version
*/
const handleDeleteVersion = useDebounceFn((version: FrpVersion) => {
const handleDeleteVersion = useDebounceFn((version: FrpcVersion) => {
ElMessageBox.alert(
`确认要删除 <span class="text-primary font-bold">${version.name} </span> 吗?`,
"提示",
@ -60,85 +57,86 @@ const handleDeleteVersion = useDebounceFn((version: FrpVersion) => {
confirmButtonText: "删除"
}
).then(() => {
ipcRenderer.send("github.deleteVersion", {
id: version.id,
absPath: version.absPath
send(ipcRouters.VERSION.deleteDownloadedVersion, {
githubReleaseId: version.githubReleaseId
});
// ipcRenderer.send("github.deleteVersion", {
// id: version.id,
// absPath: version.absPath
// });
});
}, 300);
const handleInitDownloadHook = () => {
ipcRenderer.on("Download.frpVersionHook", (event, args) => {
loading.value--;
versions.value = args.map(m => {
m.published_at = moment(m.published_at).format("YYYY-MM-DD");
return m as FrpVersion;
}) as Array<FrpVersion>;
console.log(versions, "versions");
});
//
ipcRenderer.on("Download.frpVersionDownloadOnProgress", (event, args) => {
const { id, progress } = args;
downloading.value.set(
id,
Number(Number(progress.percent * 100).toFixed(2))
);
});
ipcRenderer.on("Download.frpVersionDownloadOnCompleted", (event, args) => {
downloading.value.delete(args);
const version: FrpVersion | undefined = versions.value.find(
f => f.id === args
);
if (version) {
version.download_completed = true;
}
});
ipcRenderer.on("Download.deleteVersion.hook", (event, args) => {
const { err, data } = args;
if (!err) {
loading.value++;
ElMessage({
type: "success",
message: "删除成功"
});
handleLoadVersions();
}
});
ipcRenderer.on("Download.importFrpFile.hook", (event, args) => {
const { success, data } = args;
console.log(args);
// if (err) {
loading.value++;
ElMessage({
type: success ? "success" : "error",
message: data
});
handleLoadVersions();
// }
});
};
// const handleInitDownloadHook = () => {
// ipcRenderer.on("Download.deleteVersion.hook", (event, args) => {
// const { err, data } = args;
// if (!err) {
// loading.value++;
// ElMessage({
// type: "success",
// message: ""
// });
// handleLoadVersions();
// }
// });
// ipcRenderer.on("Download.importFrpFile.hook", (event, args) => {
// const { success, data } = args;
// console.log(args);
//
// // if (err) {
// loading.value++;
// ElMessage({
// type: success ? "success" : "error",
// message: data
// });
// handleLoadVersions();
// // }
// });
// };
const handleMirrorChange = () => {
handleLoadVersions();
handleLoadAllVersions();
};
onMounted(() => {
handleLoadAllVersions();
send(ipcRouters.VERSION.getVersions);
on(ipcRouters.VERSION.getVersions, (data) => {
console.log('versionData', data);
// versions.value = args.map(m => {
// m.published_at = moment(m.published_at).format("YYYY-MM-DD");
// return m as FrpVersion;
// }) as Array<FrpVersion>;
on(ipcRouters.VERSION.getVersions, data => {
console.log("versionData", data);
versions.value = data.map(m => {
m.githubCreatedAt = moment(m.githubCreatedAt).format("YYYY-MM-DD");
return m as FrpcVersion;
}) as Array<FrpcVersion>;
loading.value--;
});
on(ipcRouters.VERSION.downloadVersion, data => {
console.log("downloadData", data);
const { githubReleaseId, completed, percent } = data;
if (completed) {
downloading.value.delete(githubReleaseId);
const version: FrpcVersion | undefined = versions.value.find(
f => f.githubReleaseId === githubReleaseId
);
if (version) {
version.downloaded = true;
}
} else {
downloading.value.set(
githubReleaseId,
Number(Number(percent * 100).toFixed(2))
);
}
});
on(ipcRouters.VERSION.deleteDownloadedVersion, () => {
loading.value++;
ElMessage({
type: "success",
message: "删除成功"
});
handleLoadAllVersions();
});
// handleLoadVersions();
// handleInitDownloadHook();
// ipcRenderer.invoke("process").then((r: any) => {
// console.log(r, "rrr");
// });
});
const handleImportFrp = () => {
@ -211,7 +209,7 @@ onUnmounted(() => {
<!-- </el-col>-->
<el-col
v-for="version in versions"
:key="version.id"
:key="version.githubAssetId"
:lg="6"
:md="8"
:sm="12"
@ -235,19 +233,19 @@ onUnmounted(() => {
<span class="text-primary font-bold"
>{{
// moment(version.published_at).format("YYYY-MM-DD HH:mm:ss")
version.download_count
version.versionDownloadCount
}}
</span>
</div>
<div class="text-[12px]">
发布时间<span class="text-primary font-bold">{{
// moment(version.published_at).format("YYYY-MM-DD HH:mm:ss")
version.published_at
version.githubCreatedAt
}}</span>
</div>
</div>
<div class="right">
<div v-if="version.download_completed">
<div v-if="version.downloaded">
<!-- <span class="text-[12px] text-primary font-bold mr-2"-->
<!-- >已下载</span-->
<!-- >-->
@ -276,9 +274,12 @@ onUnmounted(() => {
</div>
<template v-else>
<div class="w-32" v-if="downloading.has(version.id)">
<div
class="w-32"
v-if="downloading.has(version.githubReleaseId)"
>
<el-progress
:percentage="downloading.get(version.id)"
:percentage="downloading.get(version.githubReleaseId)"
:text-inside="false"
/>
</div>

2
types/core.d.ts vendored
View File

@ -8,7 +8,7 @@ interface ControllerParam {
win: BrowserWindow;
channel: string;
event: Electron.IpcMainEvent;
args: any[];
args: any;
}
interface ListenerParam {

View File

@ -1,5 +1,9 @@
type FrpcDesktopProxy = FrpcProxyConfig & {};
interface BaseEntity {
_id: string;
};
interface FrpcSystemConfiguration {
launchAtStartup: boolean;
silentStartup: boolean;
@ -10,7 +14,7 @@ type FrpcDesktopServer = FrpcCommonConfig & {
frpcVersion: number;
};
type FrpcVersion = {
type FrpcVersion = BaseEntity & {
githubReleaseId: number;
githubAssetId: number;
githubCreatedAt: string;