🏗️ refactor configuration management and implement system service features
This commit is contained in:
parent
6d9f9269b7
commit
ff8b01c360
@ -1,27 +0,0 @@
|
||||
import { app, ipcMain, shell } from "electron";
|
||||
import { logError, logInfo, LogModule, logWarn } from "../utils/log";
|
||||
|
||||
export const initCommonApi = () => {
|
||||
ipcMain.on("common.openUrl", async (event, args) => {
|
||||
if (args) {
|
||||
logInfo(LogModule.APP, `Attempting to open URL: ${args}`);
|
||||
try {
|
||||
await shell.openExternal(args);
|
||||
logInfo(LogModule.APP, `Successfully opened URL: ${args}`);
|
||||
} catch (error) {
|
||||
logError(
|
||||
LogModule.APP,
|
||||
`Failed to open URL: ${args}. Error: ${error.message}`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
logWarn(LogModule.APP, "No URL provided to open.");
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on("common.relaunch", () => {
|
||||
logInfo(LogModule.APP, "Application is relaunching.");
|
||||
app.relaunch();
|
||||
app.quit();
|
||||
});
|
||||
};
|
80
electron/controller/ConfigController.ts
Normal file
80
electron/controller/ConfigController.ts
Normal file
@ -0,0 +1,80 @@
|
||||
import BaseController from "./BaseController";
|
||||
import ServerService from "../service/ServerService";
|
||||
import { success } from "../utils/response";
|
||||
import PathUtils from "../utils/PathUtils";
|
||||
import fs from "fs";
|
||||
import FrpcProcessService from "../service/FrpcProcessService";
|
||||
import SystemService from "../service/SystemService";
|
||||
|
||||
class ConfigController extends BaseController {
|
||||
private readonly _serverService: ServerService;
|
||||
private readonly _systemService: SystemService;
|
||||
private readonly _frpcProcessService: FrpcProcessService;
|
||||
|
||||
constructor(
|
||||
serverService: ServerService,
|
||||
systemService: SystemService,
|
||||
frpcProcessService: FrpcProcessService
|
||||
) {
|
||||
super();
|
||||
this._serverService = serverService;
|
||||
this._systemService = systemService;
|
||||
this._frpcProcessService = frpcProcessService;
|
||||
}
|
||||
|
||||
saveConfig(req: ControllerParam) {
|
||||
this._serverService.saveServerConfig(req.args).then(() => {
|
||||
req.event.reply(req.channel, success());
|
||||
});
|
||||
}
|
||||
|
||||
getServerConfig(req: ControllerParam) {
|
||||
this._serverService.getServerConfig().then(data => {
|
||||
req.event.reply(req.channel, success(data));
|
||||
});
|
||||
}
|
||||
|
||||
openAppData(req: ControllerParam) {
|
||||
this._systemService.openLocalPath(PathUtils.getAppData()).then(data => {
|
||||
req.event.reply(req.channel, success(data));
|
||||
});
|
||||
}
|
||||
|
||||
async resetAllConfig(req: ControllerParam) {
|
||||
// await this._serverDao.truncate();
|
||||
// await this._proxyDao.truncate();
|
||||
// await this._versionDao.truncate();
|
||||
await this._frpcProcessService.stopFrpcProcess();
|
||||
fs.rmSync(PathUtils.getDataBaseStoragePath(), {
|
||||
recursive: true,
|
||||
force: true
|
||||
});
|
||||
|
||||
fs.rmSync(PathUtils.getDownloadStoragePath(), {
|
||||
recursive: true,
|
||||
force: true
|
||||
});
|
||||
|
||||
fs.rmSync(PathUtils.getVersionStoragePath(), {
|
||||
recursive: true,
|
||||
force: true
|
||||
});
|
||||
|
||||
fs.rmSync(PathUtils.getFrpcLogStoragePath(), {
|
||||
recursive: true,
|
||||
force: true
|
||||
});
|
||||
|
||||
req.event.reply(req.channel, success());
|
||||
}
|
||||
|
||||
exportConfig(req: ControllerParam) {
|
||||
this._systemService.openDirectory().then(folder => {
|
||||
this._serverService.genTomlConfig(folder.filePaths[0]).then(() => {
|
||||
req.event.reply(req.channel, success());
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default ConfigController;
|
@ -11,9 +11,14 @@ class LaunchController extends BaseController {
|
||||
}
|
||||
|
||||
launch(req: ControllerParam) {
|
||||
this._frpcProcessService.startFrpcProcess().then(r => {
|
||||
req.event.reply(req.channel, success());
|
||||
});
|
||||
this._frpcProcessService
|
||||
.startFrpcProcess()
|
||||
.then(r => {
|
||||
req.event.reply(req.channel, success());
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err, "1");
|
||||
});
|
||||
}
|
||||
|
||||
terminate(req: ControllerParam) {
|
||||
|
@ -1,37 +0,0 @@
|
||||
import BaseController from "./BaseController";
|
||||
import ServerService from "../service/ServerService";
|
||||
import { success } from "../utils/response";
|
||||
import FileService from "../service/FileService";
|
||||
import PathUtils from "../utils/PathUtils";
|
||||
|
||||
class ServerController extends BaseController {
|
||||
private readonly _serverService: ServerService;
|
||||
private readonly _fileService: FileService;
|
||||
|
||||
constructor(serverService: ServerService, fileService: FileService) {
|
||||
super();
|
||||
this._serverService = serverService;
|
||||
this._fileService = fileService;
|
||||
}
|
||||
|
||||
saveConfig(req: ControllerParam) {
|
||||
this._serverService.saveServerConfig(req.args).then(() => {
|
||||
req.event.reply(req.channel, success());
|
||||
});
|
||||
}
|
||||
|
||||
getServerConfig(req: ControllerParam) {
|
||||
console.log("get", req.args);
|
||||
this._serverService.getServerConfig().then(data => {
|
||||
req.event.reply(req.channel, success(data));
|
||||
});
|
||||
}
|
||||
|
||||
openAppData(req: ControllerParam) {
|
||||
this._fileService.openLocalPath(PathUtils.getAppData()).then(data => {
|
||||
req.event.reply(req.channel, success(data));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default ServerController;
|
36
electron/controller/SystemController.ts
Normal file
36
electron/controller/SystemController.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import SystemService from "../service/SystemService";
|
||||
import { fail, success } from "../utils/response";
|
||||
import PathUtils from "../utils/PathUtils";
|
||||
|
||||
class SystemController {
|
||||
private readonly _systemService: SystemService;
|
||||
|
||||
constructor(systemService: SystemService) {
|
||||
this._systemService = systemService;
|
||||
}
|
||||
|
||||
openUrl(req: ControllerParam) {
|
||||
this._systemService
|
||||
.openUrl(req.args.url)
|
||||
.then(() => {
|
||||
req.event.reply(req.channel, success());
|
||||
})
|
||||
.catch(err => {
|
||||
req.event.reply(req.channel, fail());
|
||||
});
|
||||
}
|
||||
|
||||
relaunchApp(req: ControllerParam) {
|
||||
this._systemService.relaunch().then(() => {
|
||||
req.event.reply(req.channel, success());
|
||||
});
|
||||
}
|
||||
|
||||
openAppData(req: ControllerParam) {
|
||||
this._systemService.openLocalPath(PathUtils.getAppData()).then(() => {
|
||||
req.event.reply(req.channel, success());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default SystemController;
|
@ -1,4 +1,4 @@
|
||||
import ServerController from "../controller/ServerController";
|
||||
import ConfigController from "../controller/ConfigController";
|
||||
import ServerDao from "../dao/ServerDao";
|
||||
import ServerService from "../service/ServerService";
|
||||
import LogService from "../service/LogService";
|
||||
@ -6,7 +6,6 @@ import VersionService from "../service/VersionService";
|
||||
import { BrowserWindow, ipcMain } from "electron";
|
||||
import LogController from "../controller/LogController";
|
||||
import VersionController from "../controller/VersionController";
|
||||
import FileService from "../service/FileService";
|
||||
import VersionDao from "../dao/VersionDao";
|
||||
import GitHubService from "../service/GitHubService";
|
||||
import FrpcProcessService from "../service/FrpcProcessService";
|
||||
@ -14,16 +13,26 @@ import LaunchController from "../controller/LaunchController";
|
||||
import ProxyDao from "../dao/ProxyDao";
|
||||
import ProxyService from "../service/ProxyService";
|
||||
import ProxyController from "../controller/ProxyController";
|
||||
import SystemService from "../service/SystemService";
|
||||
import SystemController from "../controller/SystemController";
|
||||
|
||||
export const ipcRouters: IpcRouters = {
|
||||
SERVER: {
|
||||
saveConfig: {
|
||||
path: "server/saveConfig",
|
||||
controller: "serverController.saveConfig"
|
||||
controller: "configController.saveConfig"
|
||||
},
|
||||
getServerConfig: {
|
||||
path: "server/getServerConfig",
|
||||
controller: "serverController.getServerConfig"
|
||||
controller: "configController.getServerConfig"
|
||||
},
|
||||
resetAllConfig: {
|
||||
path: "server/resetAllConfig",
|
||||
controller: "configController.resetAllConfig"
|
||||
},
|
||||
exportConfig: {
|
||||
path: "server/exportConfig",
|
||||
controller: "configController.exportConfig"
|
||||
}
|
||||
},
|
||||
LOG: {
|
||||
@ -97,6 +106,20 @@ export const ipcRouters: IpcRouters = {
|
||||
path: "proxy/getLocalPorts",
|
||||
controller: "proxyController.getLocalPorts"
|
||||
}
|
||||
},
|
||||
SYSTEM: {
|
||||
openUrl: {
|
||||
path: "system/openUrl",
|
||||
controller: "systemController.openUrl"
|
||||
},
|
||||
relaunchApp: {
|
||||
path: "system/relaunchApp",
|
||||
controller: "systemController.relaunchApp"
|
||||
},
|
||||
openAppData: {
|
||||
path: "system/openAppData",
|
||||
controller: "systemController.openAppData"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -124,40 +147,46 @@ class IpcRouterConfigurate {
|
||||
const serverDao = new ServerDao();
|
||||
const versionDao = new VersionDao();
|
||||
const proxyDao = new ProxyDao();
|
||||
const fileService = new FileService();
|
||||
const systemService = new SystemService();
|
||||
const serverService = new ServerService(serverDao, proxyDao);
|
||||
const gitHubService = new GitHubService();
|
||||
const versionService = new VersionService(
|
||||
versionDao,
|
||||
fileService,
|
||||
systemService,
|
||||
gitHubService
|
||||
);
|
||||
const logService = new LogService(fileService);
|
||||
const logService = new LogService(systemService);
|
||||
const frpcProcessService = new FrpcProcessService(
|
||||
serverService,
|
||||
versionDao
|
||||
);
|
||||
const proxyService = new ProxyService(proxyDao);
|
||||
const serverController = new ServerController(serverService, fileService);
|
||||
const configController = new ConfigController(
|
||||
serverService,
|
||||
systemService,
|
||||
frpcProcessService
|
||||
);
|
||||
const versionController = new VersionController(versionService, versionDao);
|
||||
const logController = new LogController(logService);
|
||||
const launchController = new LaunchController(frpcProcessService);
|
||||
const proxyController = new ProxyController(proxyService, proxyDao);
|
||||
const systemController = new SystemController(systemService);
|
||||
|
||||
this._beans.set("serverDao", serverDao);
|
||||
this._beans.set("versionDao", versionDao);
|
||||
this._beans.set("proxyDao", proxyDao);
|
||||
this._beans.set("fileService", fileService);
|
||||
this._beans.set("systemService", systemService);
|
||||
this._beans.set("serverService", serverService);
|
||||
this._beans.set("versionService", versionService);
|
||||
this._beans.set("logService", logService);
|
||||
this._beans.set("proxyService", proxyService);
|
||||
this._beans.set("frpcProcessService", frpcProcessService);
|
||||
this._beans.set("serverController", serverController);
|
||||
this._beans.set("configController", configController);
|
||||
this._beans.set("versionController", versionController);
|
||||
this._beans.set("logController", logController);
|
||||
this._beans.set("launchController", launchController);
|
||||
this._beans.set("proxyController", proxyController);
|
||||
this._beans.set("systemController", systemController);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -24,7 +24,10 @@ class BaseDao<T> {
|
||||
protected readonly db: Datastore;
|
||||
|
||||
constructor(dbName: string) {
|
||||
const dbFilename = path.join(PathUtils.getDataBaseStoragePath(), `${dbName}-v2.db`);
|
||||
const dbFilename = path.join(
|
||||
PathUtils.getDataBaseStoragePath(),
|
||||
`${dbName}-v2.db`
|
||||
);
|
||||
this.db = new Datastore({
|
||||
autoload: true,
|
||||
filename: dbFilename
|
||||
@ -118,6 +121,18 @@ class BaseDao<T> {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
truncate() {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
this.db.remove({}, { multi: true }, (err, n) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default BaseDao;
|
||||
|
@ -12,14 +12,9 @@ import { release } from "node:os";
|
||||
import node_path, { join } from "node:path";
|
||||
import { initGitHubApi } from "../api/github";
|
||||
import { initConfigApi } from "../api/config";
|
||||
import {
|
||||
initFrpcApi,
|
||||
startFrpWorkerProcess,
|
||||
stopFrpcProcess
|
||||
} from "../api/frpc";
|
||||
import { startFrpWorkerProcess, stopFrpcProcess } from "../api/frpc";
|
||||
import { initFileApi } from "../api/file";
|
||||
import { getConfig } from "../storage/config";
|
||||
import { initCommonApi } from "../api/common";
|
||||
import { initLog, logError, logInfo, LogModule } from "../utils/log";
|
||||
import { maskSensitiveData } from "../utils/desensitize";
|
||||
import IpcRouterConfigurate from "../core/IpcRouter";
|
||||
@ -202,8 +197,6 @@ app.whenReady().then(() => {
|
||||
initFileApi();
|
||||
logInfo(LogModule.APP, `File API initialized.`);
|
||||
|
||||
initCommonApi();
|
||||
logInfo(LogModule.APP, `Common API initialized.`);
|
||||
|
||||
// initUpdaterApi(win);
|
||||
logInfo(LogModule.APP, `Updater API initialization skipped.`);
|
||||
|
@ -30,12 +30,19 @@ class FrpcProcessService {
|
||||
}
|
||||
|
||||
async startFrpcProcess() {
|
||||
if (this.isRunning()) {
|
||||
return;
|
||||
}
|
||||
const config = await this._serverService.getServerConfig();
|
||||
if (!config) {
|
||||
throw new Error("请先进行配置")
|
||||
}
|
||||
const version = await this._versionDao.findByGithubReleaseId(
|
||||
config.frpcVersion
|
||||
);
|
||||
// todo genConfigfile.
|
||||
const configPath = await this._serverService.genTomlConfig();
|
||||
const configPath = PathUtils.getTomlConfigFilePath();
|
||||
await this._serverService.genTomlConfig(configPath);
|
||||
const command = `./${PathUtils.getFrpcFilename()} -c "${configPath}"`;
|
||||
this._frpcProcess = require("child_process").spawn(command, {
|
||||
cwd: version.localPath,
|
||||
@ -48,13 +55,10 @@ class FrpcProcessService {
|
||||
this._frpcProcess.stderr.on("data", data => {
|
||||
console.error(`stderr: ${data}`);
|
||||
});
|
||||
// this._frpcProcess.on("close",function(code){
|
||||
// console.log("out code:" + code)
|
||||
// })
|
||||
}
|
||||
|
||||
async stopFrpcProcess() {
|
||||
if (this._frpcProcess) {
|
||||
if (this._frpcProcess && this.isRunning()) {
|
||||
treeKill(this._frpcProcess.pid, (error: Error) => {
|
||||
if (error) {
|
||||
throw error;
|
||||
@ -63,7 +67,6 @@ class FrpcProcessService {
|
||||
// clearInterval(this._frpcProcessListener);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,18 +1,14 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { app } from "electron";
|
||||
import FileService from "./FileService";
|
||||
import { success } from "../utils/response";
|
||||
import PathUtils from "../utils/PathUtils";
|
||||
import SystemService from "./SystemService";
|
||||
|
||||
class LogService {
|
||||
private readonly _fileService: FileService;
|
||||
private readonly _logPath: string = path.join(
|
||||
app.getPath("userData"),
|
||||
"frpc.log"
|
||||
);
|
||||
private readonly _systemService: SystemService;
|
||||
private readonly _logPath: string = PathUtils.getFrpcLogFilePath();
|
||||
|
||||
constructor(fileService: FileService) {
|
||||
this._fileService = fileService;
|
||||
constructor(systemService: SystemService) {
|
||||
this._systemService = systemService;
|
||||
}
|
||||
|
||||
getFrpLogContent(): Promise<string> {
|
||||
@ -28,6 +24,11 @@ class LogService {
|
||||
}
|
||||
|
||||
watchFrpcLog(listenerParam: ListenerParam) {
|
||||
if (!fs.existsSync(this._logPath)) {
|
||||
setTimeout(() => this.watchFrpcLog(listenerParam), 1000);
|
||||
return;
|
||||
}
|
||||
console.log('watchFrpcLog succcess');
|
||||
fs.watch(this._logPath, (eventType, filename) => {
|
||||
if (eventType === "change") {
|
||||
console.log("change", eventType, listenerParam.channel);
|
||||
@ -45,7 +46,7 @@ class LogService {
|
||||
|
||||
openFrpcLogFile(): Promise<boolean> {
|
||||
return new Promise<boolean>((resolve, reject) => {
|
||||
this._fileService
|
||||
this._systemService
|
||||
.openLocalFile(this._logPath)
|
||||
.then(result => {
|
||||
resolve(result);
|
||||
|
@ -38,7 +38,10 @@ class ServerService extends BaseService<OpenSourceFrpcDesktopServer> {
|
||||
});
|
||||
}
|
||||
|
||||
async genTomlConfig() {
|
||||
async genTomlConfig(outputPath: string) {
|
||||
if (!outputPath) {
|
||||
return;
|
||||
}
|
||||
const server = await this.getServerConfig();
|
||||
const proxies = await this._proxyDao.findAll();
|
||||
const enabledProxies = proxies
|
||||
@ -51,13 +54,12 @@ class ServerService extends BaseService<OpenSourceFrpcDesktopServer> {
|
||||
const frpcConfig = { ...commonConfig };
|
||||
frpcConfig.log.to = PathUtils.getFrpcLogFilePath();
|
||||
const toml = TOML.stringify({ ...frpcConfig, proxies: enabledProxies });
|
||||
const tomlPath = PathUtils.getTomlConfigFilePath();
|
||||
|
||||
fs.writeFileSync(
|
||||
tomlPath, // 配置文件目录
|
||||
outputPath, // 配置文件目录
|
||||
toml, // 配置文件内容
|
||||
{ flag: "w" }
|
||||
);
|
||||
return tomlPath;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,23 @@
|
||||
import { dialog, shell } from "electron";
|
||||
import { app, dialog, shell } from "electron";
|
||||
import GlobalConstant from "../core/GlobalConstant";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import zlib from "zlib";
|
||||
import admZip from "adm-zip";
|
||||
import GlobalConstant from "../core/GlobalConstant";
|
||||
|
||||
|
||||
// import tar from "tar";
|
||||
const tar = require("tar");
|
||||
|
||||
class FileService {
|
||||
constructor() {}
|
||||
class SystemService {
|
||||
async openUrl(url: string) {
|
||||
if (url) {
|
||||
await shell.openExternal(url);
|
||||
}
|
||||
}
|
||||
|
||||
async relaunch() {
|
||||
await app.relaunch();
|
||||
app.quit();
|
||||
}
|
||||
|
||||
openLocalFile(filePath: string) {
|
||||
return new Promise<boolean>((resolve, reject) => {
|
||||
@ -100,17 +107,23 @@ class FileService {
|
||||
});
|
||||
}
|
||||
|
||||
selectLocalFile(name: string, path: any) {
|
||||
dialog.showOpenDialogSync({
|
||||
openFile(name: string, ext: any) {
|
||||
return dialog.showOpenDialogSync({
|
||||
properties: ["openFile"],
|
||||
filters: [
|
||||
{
|
||||
name: name,
|
||||
extensions: path
|
||||
extensions: ext
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async openDirectory() {
|
||||
return await dialog.showOpenDialog({
|
||||
properties: ["openDirectory"]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default FileService;
|
||||
export default SystemService;
|
@ -1,7 +1,6 @@
|
||||
import VersionDao from "../dao/VersionDao";
|
||||
import BaseService from "./BaseService";
|
||||
import GitHubService from "./GitHubService";
|
||||
import FileService from "./FileService";
|
||||
import frpReleasesJson from "../json/frp-releases.json";
|
||||
import { download } from "electron-dl";
|
||||
import { BrowserWindow, dialog } from "electron";
|
||||
@ -12,23 +11,24 @@ import SecureUtils from "../utils/SecureUtils";
|
||||
import PathUtils from "../utils/PathUtils";
|
||||
import FileUtils from "../utils/FileUtils";
|
||||
import frpChecksums from "../json/frp_all_sha256_checksums.json";
|
||||
import SystemService from "./SystemService";
|
||||
|
||||
class VersionService extends BaseService<FrpcVersion> {
|
||||
private readonly _versionDao: VersionDao;
|
||||
private readonly _fileService: FileService;
|
||||
private readonly _systemService: SystemService;
|
||||
private readonly _gitHubService: GitHubService;
|
||||
private readonly _currFrpArch: Array<string>;
|
||||
private _versions: Array<FrpcVersion> = [];
|
||||
|
||||
constructor(
|
||||
versionDao: VersionDao,
|
||||
fileService: FileService,
|
||||
systemService: SystemService,
|
||||
gitHubService: GitHubService
|
||||
) {
|
||||
super();
|
||||
this._versionDao = versionDao;
|
||||
this._gitHubService = gitHubService;
|
||||
this._fileService = fileService;
|
||||
this._systemService = systemService;
|
||||
const nodeVersion = `${process.platform}_${process.arch}`;
|
||||
this._currFrpArch = GlobalConstant.FRP_ARCH_VERSION_MAPPING[nodeVersion];
|
||||
}
|
||||
@ -207,13 +207,13 @@ class VersionService extends BaseService<FrpcVersion> {
|
||||
);
|
||||
const ext = path.extname(version.assetName);
|
||||
if (ext === GlobalConstant.ZIP_EXT) {
|
||||
this._fileService.decompressZipFile(compressedPath, versionFilePath);
|
||||
this._systemService.decompressZipFile(compressedPath, versionFilePath);
|
||||
// todo delete frps and other file.
|
||||
} else if (
|
||||
ext === GlobalConstant.GZ_EXT &&
|
||||
version.assetName.includes(GlobalConstant.TAR_GZ_EXT)
|
||||
) {
|
||||
this._fileService.decompressTarGzFile(
|
||||
this._systemService.decompressTarGzFile(
|
||||
compressedPath,
|
||||
versionFilePath,
|
||||
() => {
|
||||
|
@ -1,11 +1,12 @@
|
||||
<script lang="ts" setup>
|
||||
import {computed, defineComponent, onMounted, onUnmounted, ref} from "vue";
|
||||
import {ipcRenderer} from "electron";
|
||||
import {Icon} from "@iconify/vue";
|
||||
import { computed, defineComponent, onMounted, onUnmounted, ref } from "vue";
|
||||
import { ipcRenderer } from "electron";
|
||||
import { Icon } from "@iconify/vue";
|
||||
import Breadcrumb from "@/layout/compoenets/Breadcrumb.vue";
|
||||
import pkg from '../../../package.json';
|
||||
import {ElMessage, ElMessageBox} from "element-plus";
|
||||
|
||||
import pkg from "../../../package.json";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { send } from "@/utils/ipcUtils";
|
||||
import { ipcRouters } from "../../../electron/core/IpcRouter";
|
||||
|
||||
/**
|
||||
* 最后一个版本号
|
||||
@ -17,143 +18,161 @@ const isLastVersion = computed(() => {
|
||||
return true;
|
||||
}
|
||||
// tagName相对固定
|
||||
const tagName = latestVersionInfo.value['tag_name']
|
||||
console.log(tagName, latestVersionInfo.value, 'tagName')
|
||||
const tagName = latestVersionInfo.value["tag_name"];
|
||||
console.log(tagName, latestVersionInfo.value, "tagName");
|
||||
if (!tagName) {
|
||||
return true;
|
||||
}
|
||||
// 最后版本号
|
||||
const lastVersion = tagName.replace('v', '').toString();
|
||||
const lastVersion = tagName.replace("v", "").toString();
|
||||
const currVersion = pkg.version;
|
||||
console.log(lastVersion, currVersion, currVersion >= lastVersion, "isLast")
|
||||
console.log(lastVersion, currVersion, currVersion >= lastVersion, "isLast");
|
||||
// console.log()
|
||||
return currVersion >= lastVersion;
|
||||
// return false;
|
||||
})
|
||||
});
|
||||
/**
|
||||
* 打开github issues
|
||||
*/
|
||||
const handleOpenGitHubIssues = () => {
|
||||
ipcRenderer.send("common.openUrl", "https://github.com/luckjiawei/frpc-desktop/issues")
|
||||
}
|
||||
send(ipcRouters.SYSTEM.openUrl, {
|
||||
url: "https://github.com/luckjiawei/frpc-desktop/issues"
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 打开github主页
|
||||
*/
|
||||
const handleOpenGitHub = () => {
|
||||
ipcRenderer.send("common.openUrl", "https://github.com/luckjiawei/frpc-desktop")
|
||||
}
|
||||
send(ipcRouters.SYSTEM.openUrl, {
|
||||
url: "https://github.com/luckjiawei/frpc-desktop"
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 打开捐赠界面
|
||||
*/
|
||||
const handleOpenDonate = () => {
|
||||
ipcRenderer.send("common.openUrl", "https://jwinks.com/donate")
|
||||
}
|
||||
|
||||
send(ipcRouters.SYSTEM.openUrl, {
|
||||
url: "https://jwinks.com/donate"
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 打开文档
|
||||
*/
|
||||
const handleOpenDoc = () => {
|
||||
ipcRenderer.send("common.openUrl", "https://jwinks.com/p/frp")
|
||||
}
|
||||
|
||||
send(ipcRouters.SYSTEM.openUrl, {
|
||||
url: "https://jwinks.com/p/frp"
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取最后一个版本
|
||||
*/
|
||||
const handleGetLastVersion = () => {
|
||||
|
||||
ipcRenderer.send("github.getFrpcDesktopLastVersions")
|
||||
}
|
||||
ipcRenderer.send("github.getFrpcDesktopLastVersions");
|
||||
};
|
||||
|
||||
const handleOpenNewVersion = () => {
|
||||
ipcRenderer.send("common.openUrl", latestVersionInfo.value['html_url'])
|
||||
}
|
||||
ipcRenderer.send("common.openUrl", latestVersionInfo.value["html_url"]);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
ipcRenderer.on("github.getFrpcDesktopLastVersionsHook", (event, args) => {
|
||||
latestVersionInfo.value = args;
|
||||
console.log(latestVersionInfo.value, '1')
|
||||
console.log(latestVersionInfo.value, "1");
|
||||
if (!isLastVersion.value) {
|
||||
let content = latestVersionInfo.value.body
|
||||
content = content.replaceAll('\n', '<br/>')
|
||||
let content = latestVersionInfo.value.body;
|
||||
content = content.replaceAll("\n", "<br/>");
|
||||
ElMessageBox.alert(content, `🎉 发现新版本 ${args.name}`, {
|
||||
showCancelButton: true,
|
||||
cancelButtonText: "关闭",
|
||||
dangerouslyUseHTMLString: true,
|
||||
confirmButtonText: "去下载"
|
||||
}).then(() => {
|
||||
handleOpenNewVersion()
|
||||
})
|
||||
handleOpenNewVersion();
|
||||
});
|
||||
} else {
|
||||
ElMessage({
|
||||
message: "当前已是最新版本",
|
||||
type: "success"
|
||||
})
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
handleGetLastVersion();
|
||||
})
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
ipcRenderer.removeAllListeners("github.getFrpcDesktopLastVersionsHook");
|
||||
})
|
||||
});
|
||||
|
||||
defineComponent({
|
||||
name: "About"
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="main">
|
||||
<breadcrumb/>
|
||||
<breadcrumb />
|
||||
<div class="app-container-breadcrumb">
|
||||
<div
|
||||
class="w-full h-full bg-white p-4 rounded drop-shadow-lg overflow-y-auto flex justify-center items-center flex-col"
|
||||
class="w-full h-full bg-white p-4 rounded drop-shadow-lg overflow-y-auto flex justify-center items-center flex-col"
|
||||
>
|
||||
<img src="/logo/pack/1024x1024.png"
|
||||
class="w-[95px] h-[95px] mt-[-50px] animate__animated animate__flip" alt="Logo"/>
|
||||
<img
|
||||
src="/logo/pack/1024x1024.png"
|
||||
class="w-[95px] h-[95px] mt-[-50px] animate__animated animate__flip"
|
||||
alt="Logo"
|
||||
/>
|
||||
<div class="mt-[8px] text-2xl">Frpc Desktop</div>
|
||||
<div class="mt-[8px] text-neutral-400 flex items-center">
|
||||
<el-link
|
||||
:class="!isLastVersion? 'line-through': ''"
|
||||
class="ml-2 font-bold">v{{ pkg.version }}
|
||||
:class="!isLastVersion ? 'line-through' : ''"
|
||||
class="ml-2 font-bold"
|
||||
>v{{ pkg.version }}
|
||||
</el-link>
|
||||
<el-link v-if="!isLastVersion && latestVersionInfo"
|
||||
@click="handleOpenNewVersion"
|
||||
class="ml-2 text-[#67C23A] font-bold"
|
||||
type="success">v{{ latestVersionInfo.name }}
|
||||
<el-link
|
||||
v-if="!isLastVersion && latestVersionInfo"
|
||||
@click="handleOpenNewVersion"
|
||||
class="ml-2 text-[#67C23A] font-bold"
|
||||
type="success"
|
||||
>v{{ latestVersionInfo.name }}
|
||||
</el-link>
|
||||
<IconifyIconOffline class="ml-1.5 cursor-pointer check-update" icon="refresh-rounded"
|
||||
@click="handleGetLastVersion"/>
|
||||
<IconifyIconOffline
|
||||
class="ml-1.5 cursor-pointer check-update"
|
||||
icon="refresh-rounded"
|
||||
@click="handleGetLastVersion"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-[8px] text-sm text-center">
|
||||
<p>
|
||||
🎉 {{ pkg.description }}
|
||||
</p>
|
||||
<p>
|
||||
开机自启 / 可视化配置 / 免费开源
|
||||
</p>
|
||||
<p>🎉 {{ pkg.description }}</p>
|
||||
<p>开机自启 / 可视化配置 / 免费开源</p>
|
||||
</div>
|
||||
<div class="mt-[12px]">
|
||||
<el-button plain type="success" @click="handleOpenDoc">
|
||||
<IconifyIconOffline class="cursor-pointer mr-2" icon="description"/>
|
||||
<IconifyIconOffline
|
||||
class="cursor-pointer mr-2"
|
||||
icon="description"
|
||||
/>
|
||||
使用教程
|
||||
</el-button>
|
||||
<el-button plain type="success" @click="handleOpenDonate">
|
||||
<IconifyIconOffline class="cursor-pointer mr-2" icon="volunteer-activism-sharp"/>
|
||||
<IconifyIconOffline
|
||||
class="cursor-pointer mr-2"
|
||||
icon="volunteer-activism-sharp"
|
||||
/>
|
||||
捐赠名单
|
||||
</el-button>
|
||||
<el-button plain type="primary" @click="handleOpenGitHub">
|
||||
<Icon class="cursor-pointer mr-2" icon="logos:github-icon"/>
|
||||
<Icon class="cursor-pointer mr-2" icon="logos:github-icon" />
|
||||
仓库地址
|
||||
</el-button>
|
||||
<el-button type="danger" plain @click="handleOpenGitHubIssues">
|
||||
<IconifyIconOffline class="cursor-pointer mr-2" icon="question-mark"/>
|
||||
<IconifyIconOffline
|
||||
class="cursor-pointer mr-2"
|
||||
icon="question-mark"
|
||||
/>
|
||||
反馈问题
|
||||
</el-button>
|
||||
</div>
|
||||
@ -164,6 +183,6 @@ defineComponent({
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.check-update:hover {
|
||||
color: #5F3BB0;
|
||||
color: #5f3bb0;
|
||||
}
|
||||
</style>
|
||||
|
@ -9,6 +9,7 @@ import { Base64 } from "js-base64";
|
||||
import IconifyIconOffline from "@/components/IconifyIcon/src/iconifyIconOffline";
|
||||
import { on, removeRouterListeners, send } from "@/utils/ipcUtils";
|
||||
import { ipcRouters } from "../../../electron/core/IpcRouter";
|
||||
import confetti from "canvas-confetti/src/confetti.js";
|
||||
|
||||
defineComponent({
|
||||
name: "Config"
|
||||
@ -350,45 +351,40 @@ onMounted(() => {
|
||||
// ElMessageBox.alert(`配置路径:${configPath}`, `🎉 导出成功`);
|
||||
// }
|
||||
// });
|
||||
// ipcRenderer.on("Config.clearAll.hook", (event, args) => {
|
||||
// ElMessageBox.alert("重置成功 请重启软件", `提示`, {
|
||||
// closeOnClickModal: false,
|
||||
// showClose: false,
|
||||
// confirmButtonText: "立即重启"
|
||||
// }).then(() => {
|
||||
// ipcRenderer.send("common.relaunch");
|
||||
// });
|
||||
// });
|
||||
// ipcRenderer.on("Config.importConfig.hook", (event, args) => {
|
||||
// const { success, data } = args;
|
||||
// if (success) {
|
||||
// // 礼花
|
||||
// confetti({
|
||||
// zIndex: 12002,
|
||||
// particleCount: 200,
|
||||
// spread: 70,
|
||||
// origin: { y: 0.6 }
|
||||
// });
|
||||
// ElMessageBox.alert("🎉 恭喜你,导入成功 请重启软件", `提示`, {
|
||||
// closeOnClickModal: false,
|
||||
// showClose: false,
|
||||
// confirmButtonText: "立即重启"
|
||||
// }).then(() => {
|
||||
// ipcRenderer.send("common.relaunch");
|
||||
// });
|
||||
// } else {
|
||||
// ElMessageBox.alert(data, `提示`);
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// ipcRenderer.on("Config.openDataFolder.hook", (event, args) => {
|
||||
// if (args) {
|
||||
// ElMessage({
|
||||
// type: "success",
|
||||
// message: "打开数据目录成功"
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
|
||||
on(ipcRouters.SERVER.resetAllConfig, () => {
|
||||
ElMessageBox.alert("重置成功 请重启软件", `提示`, {
|
||||
closeOnClickModal: false,
|
||||
showClose: false,
|
||||
confirmButtonText: "立即重启"
|
||||
}).then(() => {
|
||||
send(ipcRouters.SYSTEM.relaunchApp);
|
||||
});
|
||||
});
|
||||
|
||||
on(ipcRouters.SERVER.exportConfig, () => {
|
||||
// 礼花
|
||||
confetti({
|
||||
zIndex: 12002,
|
||||
particleCount: 200,
|
||||
spread: 70,
|
||||
origin: { y: 0.6 }
|
||||
});
|
||||
ElMessageBox.alert("🎉 恭喜你,导入成功 请重启软件", `提示`, {
|
||||
closeOnClickModal: false,
|
||||
showClose: false,
|
||||
confirmButtonText: "立即重启"
|
||||
}).then(() => {
|
||||
send(ipcRouters.SYSTEM.relaunchApp);
|
||||
});
|
||||
});
|
||||
// ElMessageBox.alert(data, `提示`);
|
||||
on(ipcRouters.SYSTEM.openAppData, () => {
|
||||
ElMessage({
|
||||
type: "success",
|
||||
message: "打开数据目录成功"
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const handleSelectFile = (type: number, ext: string[]) => {
|
||||
@ -484,8 +480,9 @@ const handleShowExportDialog = () => {
|
||||
};
|
||||
|
||||
const handleExportConfig = useDebounceFn(() => {
|
||||
ipcRenderer.send("config.exportConfig", exportConfigType.value);
|
||||
visibles.exportConfig = false;
|
||||
send(ipcRouters.SERVER.exportConfig);
|
||||
// ipcRenderer.send("config.exportConfig", exportConfigType.value);
|
||||
// visibles.exportConfig = false;
|
||||
}, 300);
|
||||
|
||||
const handleImportConfig = () => {
|
||||
@ -498,7 +495,7 @@ const handleResetConfig = () => {
|
||||
cancelButtonText: "取消",
|
||||
confirmButtonText: "清空"
|
||||
}).then(() => {
|
||||
ipcRenderer.send("config.clearAll");
|
||||
send(ipcRouters.SERVER.resetAllConfig);
|
||||
});
|
||||
};
|
||||
|
||||
@ -506,18 +503,19 @@ const handleResetConfig = () => {
|
||||
* 打开数据目录
|
||||
*/
|
||||
const handleOpenDataFolder = useDebounceFn(() => {
|
||||
ipcRenderer.send("config.openDataFolder");
|
||||
}, 1000);
|
||||
send(ipcRouters.SYSTEM.openAppData);
|
||||
}, 300);
|
||||
|
||||
onUnmounted(() => {
|
||||
removeRouterListeners(ipcRouters.SERVER.saveConfig);
|
||||
removeRouterListeners(ipcRouters.VERSION.getDownloadedVersions);
|
||||
removeRouterListeners(ipcRouters.SERVER.getServerConfig);
|
||||
removeRouterListeners(ipcRouters.SERVER.saveConfig);
|
||||
removeRouterListeners(ipcRouters.SERVER.resetAllConfig);
|
||||
removeRouterListeners(ipcRouters.VERSION.getDownloadedVersions);
|
||||
// ipcRenderer.removeAllListeners("Config.exportConfig.hook");
|
||||
removeRouterListeners(ipcRouters.SERVER.exportConfig);
|
||||
// ipcRenderer.removeAllListeners("Config.clearAll.hook");
|
||||
// ipcRenderer.removeAllListeners("Config.openDataFolder.hook");
|
||||
removeRouterListeners(ipcRouters.SYSTEM.openAppData);
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
@ -532,7 +530,7 @@ onUnmounted(() => {
|
||||
<el-button plain type="primary" @click="handleImportConfig">
|
||||
<IconifyIconOffline icon="file-open-rounded" />
|
||||
</el-button>
|
||||
<el-button plain type="primary" @click="handleShowExportDialog">
|
||||
<el-button plain type="primary" @click="handleExportConfig">
|
||||
<IconifyIconOffline icon="file-save-rounded" />
|
||||
</el-button>
|
||||
<el-button type="primary" @click="handleSubmit">
|
||||
@ -1513,38 +1511,38 @@ onUnmounted(() => {
|
||||
</template>
|
||||
</el-dialog>
|
||||
<!-- 配置导出-->
|
||||
<el-dialog
|
||||
v-model="visibles.exportConfig"
|
||||
title="导出配置"
|
||||
width="500"
|
||||
top="5%"
|
||||
>
|
||||
<el-alert
|
||||
class="mb-4"
|
||||
:title="`导出文件名为 frpc-desktop.${exportConfigType} 重复导出则覆盖`"
|
||||
type="warning"
|
||||
:closable="false"
|
||||
/>
|
||||
<el-form>
|
||||
<el-form-item label="导出类型">
|
||||
<el-radio-group v-model="exportConfigType">
|
||||
<el-radio-button label="toml" value="toml" />
|
||||
<el-radio-button label="ini" value="ini" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button plain type="primary" @click="handleExportConfig">
|
||||
<IconifyIconOffline
|
||||
class="cursor-pointer mr-2"
|
||||
icon="downloadRounded"
|
||||
/>
|
||||
导 出
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<!-- <el-dialog-->
|
||||
<!-- v-model="visibles.exportConfig"-->
|
||||
<!-- title="导出配置"-->
|
||||
<!-- width="500"-->
|
||||
<!-- top="5%"-->
|
||||
<!-- >-->
|
||||
<!-- <el-alert-->
|
||||
<!-- class="mb-4"-->
|
||||
<!-- :title="`导出文件名为 frpc-desktop.${exportConfigType} 重复导出则覆盖`"-->
|
||||
<!-- type="warning"-->
|
||||
<!-- :closable="false"-->
|
||||
<!-- />-->
|
||||
<!-- <el-form>-->
|
||||
<!-- <el-form-item label="导出类型">-->
|
||||
<!-- <el-radio-group v-model="exportConfigType">-->
|
||||
<!-- <el-radio-button label="toml" value="toml" />-->
|
||||
<!-- <el-radio-button label="ini" value="ini" />-->
|
||||
<!-- </el-radio-group>-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- </el-form>-->
|
||||
<!-- <template #footer>-->
|
||||
<!-- <div class="dialog-footer">-->
|
||||
<!-- <el-button plain type="primary" @click="handleExportConfig">-->
|
||||
<!-- <IconifyIconOffline-->
|
||||
<!-- class="cursor-pointer mr-2"-->
|
||||
<!-- icon="downloadRounded"-->
|
||||
<!-- />-->
|
||||
<!-- 导 出-->
|
||||
<!-- </el-button>-->
|
||||
<!-- </div>-->
|
||||
<!-- </template>-->
|
||||
<!-- </el-dialog>-->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
1
types/core.d.ts
vendored
1
types/core.d.ts
vendored
@ -33,6 +33,7 @@ enum IpcRouterKeys {
|
||||
VERSION = "VERSION",
|
||||
LAUNCH = "LAUNCH",
|
||||
PROXY = "PROXY",
|
||||
SYSTEM = "SYSTEM",
|
||||
}
|
||||
|
||||
type IpcRouters = Record<
|
||||
|
Loading…
Reference in New Issue
Block a user