增加打开数据目录按钮

This commit is contained in:
刘嘉伟 2024-12-22 22:04:52 +08:00
parent 32555d45b1
commit 0b4824975a
4 changed files with 275 additions and 243 deletions

View File

@ -1,261 +1,268 @@
import { app, dialog, ipcMain } from "electron"; import {app, dialog, ipcMain, shell} from "electron";
import { clearConfig, getConfig, saveConfig } from "../storage/config"; import {clearConfig, getConfig, saveConfig} from "../storage/config";
import { clearVersion, listVersion } from "../storage/version"; import {clearVersion, listVersion} from "../storage/version";
import { import {genIniConfig, genTomlConfig, stopFrpcProcess} from "./frpc";
generateConfig, import {clearProxy, insertProxy, listProxy} from "../storage/proxy";
genIniConfig,
genTomlConfig,
stopFrpcProcess
} from "./frpc";
import { exec } from "child_process";
import { clearProxy, insertProxy, listProxy } from "../storage/proxy";
import path from "path"; import path from "path";
import fs from "fs"; import fs from "fs";
const log = require("electron-log"); const log = require("electron-log");
const toml = require("@iarna/toml"); const toml = require("@iarna/toml");
const { v4: uuidv4 } = require("uuid"); const {v4: uuidv4} = require("uuid");
export const initConfigApi = win => { export const initConfigApi = win => {
ipcMain.on("config.saveConfig", async (event, args) => { ipcMain.on("config.saveConfig", async (event, args) => {
saveConfig(args, (err, numberOfUpdated, upsert) => { saveConfig(args, (err, numberOfUpdated, upsert) => {
if (!err) { if (!err) {
const start = args.systemSelfStart || false; const start = args.systemSelfStart || false;
log.info("开启自启状态", start); log.info("开启自启状态", start);
app.setLoginItemSettings({ app.setLoginItemSettings({
openAtLogin: start, //win openAtLogin: start, //win
openAsHidden: start //macOs openAsHidden: start //macOs
}); });
}
event.reply("Config.saveConfig.hook", {
err: err,
numberOfUpdated: numberOfUpdated,
upsert: upsert
});
});
});
ipcMain.on("config.getConfig", async (event, args) => {
getConfig((err, doc) => {
event.reply("Config.getConfig.hook", {
err: err,
data: doc
});
});
});
ipcMain.on("config.versions", event => {
listVersion((err, doc) => {
event.reply("Config.versions.hook", {
err: err,
data: doc
});
});
});
ipcMain.on("config.hasConfig", event => {
getConfig((err, doc) => {
event.reply("Config.getConfig.hook", {
err: err,
data: doc
});
});
});
ipcMain.on("config.exportConfig", async (event, args) => {
const result = await dialog.showOpenDialog({
properties: ["openDirectory"]
});
const outputDirectory = result.filePaths[0];
if (!outputDirectory) {
// 取消了
return;
}
log.info(`导出目录 ${outputDirectory} 类型:${args}`);
getConfig((err1, config) => {
if (!err1 && config) {
listProxy((err2, proxys) => {
if (!err2) {
let configContent = "";
if (args === "ini") {
configContent = genIniConfig(config, proxys);
} else if (args === "toml") {
configContent = genTomlConfig(config, proxys);
} }
const configPath = path.join( event.reply("Config.saveConfig.hook", {
outputDirectory, err: err,
`frpc-desktop.${args}` numberOfUpdated: numberOfUpdated,
); upsert: upsert
fs.writeFile(
configPath, // 配置文件目录
configContent, // 配置文件内容
{ flag: "w" },
err => {
if (!err) {
// callback(filename);
event.reply("config.exportConfig.hook", {
data: "导出错误",
err: err
});
}
}
);
event.reply("Config.exportConfig.hook", {
data: {
configPath: configPath
}
}); });
}
}); });
}
}); });
});
const parseTomlConfig = (tomlPath: string) => { ipcMain.on("config.getConfig", async (event, args) => {
const importConfigPath = tomlPath; getConfig((err, doc) => {
const tomlData = fs.readFileSync(importConfigPath, "utf-8"); event.reply("Config.getConfig.hook", {
log.info(`读取到配置内容 ${tomlData}`); err: err,
const sourceConfig = toml.parse(tomlData); data: doc
// log.info(`解析结果 ${sourceConfig}`); });
// console.log(sourceConfig, "frpcConfig"); });
// 解析config });
const targetConfig: FrpConfig = {
currentVersion: null, ipcMain.on("config.versions", event => {
serverAddr: sourceConfig.serverAddr || "", listVersion((err, doc) => {
serverPort: sourceConfig.serverPort || "", event.reply("Config.versions.hook", {
authMethod: sourceConfig?.user err: err,
? "multiuser" data: doc
: sourceConfig?.auth?.method || "", });
authToken: sourceConfig?.auth?.token || "", });
transportHeartbeatInterval: });
sourceConfig?.transport?.heartbeatInterval || 30,
transportHeartbeatTimeout: ipcMain.on("config.hasConfig", event => {
sourceConfig?.transport?.heartbeatTimeout || 90, getConfig((err, doc) => {
tlsConfigEnable: sourceConfig?.transport?.tls?.enable || false, event.reply("Config.getConfig.hook", {
tlsConfigCertFile: sourceConfig?.transport?.tls?.certFile || "", err: err,
tlsConfigKeyFile: sourceConfig?.transport?.tls?.keyFile || "", data: doc
tlsConfigServerName: sourceConfig?.transport?.tls?.serverName || "", });
tlsConfigTrustedCaFile: sourceConfig?.transport?.tls?.trustedCaFile || "", });
logLevel: sourceConfig?.log?.level || "info", });
logMaxDays: sourceConfig?.log?.maxDays || 3,
proxyConfigProxyUrl: sourceConfig?.transport?.proxyURL || "", ipcMain.on("config.exportConfig", async (event, args) => {
proxyConfigEnable: Boolean(sourceConfig?.transport?.proxyURL) || false, const result = await dialog.showOpenDialog({
user: sourceConfig?.user || "", properties: ["openDirectory"]
metaToken: sourceConfig?.metadatas?.token || "", });
systemSelfStart: false, const outputDirectory = result.filePaths[0];
systemStartupConnect: false, if (!outputDirectory) {
systemSilentStartup: false, // 取消了
webEnable: true, return;
webPort: sourceConfig?.webServer?.port || 57400 }
log.info(`导出目录 ${outputDirectory} 类型:${args}`);
getConfig((err1, config) => {
if (!err1 && config) {
listProxy((err2, proxys) => {
if (!err2) {
let configContent = "";
if (args === "ini") {
configContent = genIniConfig(config, proxys);
} else if (args === "toml") {
configContent = genTomlConfig(config, proxys);
}
const configPath = path.join(
outputDirectory,
`frpc-desktop.${args}`
);
fs.writeFile(
configPath, // 配置文件目录
configContent, // 配置文件内容
{flag: "w"},
err => {
if (!err) {
// callback(filename);
event.reply("config.exportConfig.hook", {
data: "导出错误",
err: err
});
}
}
);
event.reply("Config.exportConfig.hook", {
data: {
configPath: configPath
}
});
}
});
}
});
});
const parseTomlConfig = (tomlPath: string) => {
const importConfigPath = tomlPath;
const tomlData = fs.readFileSync(importConfigPath, "utf-8");
log.info(`读取到配置内容 ${tomlData}`);
const sourceConfig = toml.parse(tomlData);
// log.info(`解析结果 ${sourceConfig}`);
// console.log(sourceConfig, "frpcConfig");
// 解析config
const targetConfig: FrpConfig = {
currentVersion: null,
serverAddr: sourceConfig.serverAddr || "",
serverPort: sourceConfig.serverPort || "",
authMethod: sourceConfig?.user
? "multiuser"
: sourceConfig?.auth?.method || "",
authToken: sourceConfig?.auth?.token || "",
transportHeartbeatInterval:
sourceConfig?.transport?.heartbeatInterval || 30,
transportHeartbeatTimeout:
sourceConfig?.transport?.heartbeatTimeout || 90,
tlsConfigEnable: sourceConfig?.transport?.tls?.enable || false,
tlsConfigCertFile: sourceConfig?.transport?.tls?.certFile || "",
tlsConfigKeyFile: sourceConfig?.transport?.tls?.keyFile || "",
tlsConfigServerName: sourceConfig?.transport?.tls?.serverName || "",
tlsConfigTrustedCaFile: sourceConfig?.transport?.tls?.trustedCaFile || "",
logLevel: sourceConfig?.log?.level || "info",
logMaxDays: sourceConfig?.log?.maxDays || 3,
proxyConfigProxyUrl: sourceConfig?.transport?.proxyURL || "",
proxyConfigEnable: Boolean(sourceConfig?.transport?.proxyURL) || false,
user: sourceConfig?.user || "",
metaToken: sourceConfig?.metadatas?.token || "",
systemSelfStart: false,
systemStartupConnect: false,
systemSilentStartup: false,
webEnable: true,
webPort: sourceConfig?.webServer?.port || 57400
};
let frpcProxys = [];
// 解析proxy
if (sourceConfig?.proxies && sourceConfig.proxies.length > 0) {
const frpcProxys1 = sourceConfig.proxies.map(m => {
const rm: Proxy = {
_id: uuidv4(),
name: m?.name,
type: m?.type,
localIp: m?.localIP || "",
localPort: m?.localPort || null,
remotePort: m?.remotePort || null,
customDomains: m?.customDomains || [],
subdomain: m.subdomain || "",
basicAuth: m.basicAuth || false,
httpUser: m.httpUser || "",
httpPassword: m.httpPassword || "",
// 以下为stcp参数
stcpModel: "visited",
serverName: "",
secretKey: m?.secretKey || "",
bindAddr: "",
bindPort: null,
status: m?.status || true,
fallbackTo: m?.fallbackTo,
fallbackTimeoutMs: m?.fallbackTimeoutMs || 500
};
return rm;
});
frpcProxys = [...frpcProxys, ...frpcProxys1];
}
// 解析stcp的访问者
if (sourceConfig?.visitors && sourceConfig.visitors.length > 0) {
const frpcProxys2 = sourceConfig.visitors.map(m => {
const rm: Proxy = {
_id: uuidv4(),
name: m?.name,
type: m?.type,
localIp: "",
localPort: null,
remotePort: null,
customDomains: [],
subdomain: m.subdomain || "",
basicAuth: m.basicAuth || false,
httpUser: m.httpUser || "",
httpPassword: m.httpPassword || "",
// 以下为stcp参数
stcpModel: "visitors",
serverName: m?.serverName,
secretKey: m?.secretKey || "",
bindAddr: m?.bindAddr,
bindPort: m?.bindPort,
status: m?.status || true,
fallbackTo: m?.fallbackTo,
fallbackTimeoutMs: m?.fallbackTimeoutMs || 500
};
return rm;
});
frpcProxys = [...frpcProxys, ...frpcProxys2];
}
if (targetConfig) {
clearConfig(() => {
saveConfig(targetConfig);
});
}
if (frpcProxys && frpcProxys.length > 0) {
clearProxy(() => {
frpcProxys.forEach(f => {
insertProxy(f, err => {
console.log("插入", f, err);
});
});
});
}
}; };
let frpcProxys = [];
// 解析proxy
if (sourceConfig?.proxies && sourceConfig.proxies.length > 0) {
const frpcProxys1 = sourceConfig.proxies.map(m => {
const rm: Proxy = {
_id: uuidv4(),
name: m?.name,
type: m?.type,
localIp: m?.localIP || "",
localPort: m?.localPort || null,
remotePort: m?.remotePort || null,
customDomains: m?.customDomains || [],
subdomain: m.subdomain || "",
basicAuth: m.basicAuth || false,
httpUser: m.httpUser || "",
httpPassword: m.httpPassword || "",
// 以下为stcp参数
stcpModel: "visited",
serverName: "",
secretKey: m?.secretKey || "",
bindAddr: "",
bindPort: null,
status: m?.status || true,
fallbackTo: m?.fallbackTo,
fallbackTimeoutMs: m?.fallbackTimeoutMs || 500
};
return rm;
});
frpcProxys = [...frpcProxys, ...frpcProxys1];
}
// 解析stcp的访问者
if (sourceConfig?.visitors && sourceConfig.visitors.length > 0) {
const frpcProxys2 = sourceConfig.visitors.map(m => {
const rm: Proxy = {
_id: uuidv4(),
name: m?.name,
type: m?.type,
localIp: "",
localPort: null,
remotePort: null,
customDomains: [],
subdomain: m.subdomain || "",
basicAuth: m.basicAuth || false,
httpUser: m.httpUser || "",
httpPassword: m.httpPassword || "",
// 以下为stcp参数
stcpModel: "visitors",
serverName: m?.serverName,
secretKey: m?.secretKey || "",
bindAddr: m?.bindAddr,
bindPort: m?.bindPort,
status: m?.status || true,
fallbackTo: m?.fallbackTo,
fallbackTimeoutMs: m?.fallbackTimeoutMs || 500
};
return rm;
});
frpcProxys = [...frpcProxys, ...frpcProxys2];
}
if (targetConfig) {
clearConfig(() => {
saveConfig(targetConfig);
});
}
if (frpcProxys && frpcProxys.length > 0) {
clearProxy(() => {
frpcProxys.forEach(f => {
insertProxy(f, err => {
console.log("插入", f, err);
});
});
});
}
};
ipcMain.on("config.importConfig", async (event, args) => { ipcMain.on("config.importConfig", async (event, args) => {
const result = await dialog.showOpenDialog(win, { const result = await dialog.showOpenDialog(win, {
properties: ["openFile"], properties: ["openFile"],
filters: [ filters: [
{ name: "FrpcConfig Files", extensions: ["toml", "ini"] } // 允许选择的文件类型 {name: "FrpcConfig Files", extensions: ["toml", "ini"]} // 允许选择的文件类型
] ]
});
if (result.canceled) {
return;
} else {
const filePath = result.filePaths[0];
const fileExtension = path.extname(filePath); // 获取文件后缀名
log.info(`导入文件 ${filePath} ${fileExtension}`);
if (fileExtension === ".toml") {
parseTomlConfig(filePath);
event.reply("Config.importConfig.hook", {
success: true
});
} else {
event.reply("Config.importConfig.hook", {
success: false,
data: `导入失败,暂不支持 ${fileExtension} 格式文件`
});
}
}
}); });
if (result.canceled) {
return;
} else {
const filePath = result.filePaths[0];
const fileExtension = path.extname(filePath); // 获取文件后缀名
log.info(`导入文件 ${filePath} ${fileExtension}`);
if (fileExtension === ".toml") {
parseTomlConfig(filePath);
event.reply("Config.importConfig.hook", {
success: true
});
} else {
event.reply("Config.importConfig.hook", {
success: false,
data: `导入失败,暂不支持 ${fileExtension} 格式文件`
});
}
}
});
ipcMain.on("config.clearAll", async (event, args) => { ipcMain.on("config.clearAll", async (event, args) => {
stopFrpcProcess(() => { stopFrpcProcess(() => {
clearConfig(); clearConfig();
clearProxy(); clearProxy();
clearVersion(); clearVersion();
event.reply("Config.clearAll.hook", {}); event.reply("Config.clearAll.hook", {});
});
});
ipcMain.on("config.openDataFolder", async (event, args) => {
const userDataPath = app.getPath("userData");
shell.openPath(userDataPath).then((errorMessage) => {
if (errorMessage) {
console.error('Failed to open Logger:', errorMessage);
event.reply("Config.openDataFolder.hook", false);
} else {
console.log('Logger opened successfully');
event.reply("Config.openDataFolder.hook", true);
}
});
}); });
});
}; };

View File

@ -34,6 +34,7 @@ import fileOpenRounded from "@iconify-icons/material-symbols/file-open-rounded";
import attachMoneyRounded from "@iconify-icons/material-symbols/attach-money-rounded"; import attachMoneyRounded from "@iconify-icons/material-symbols/attach-money-rounded";
import volunteerActivismSharp from "@iconify-icons/material-symbols/volunteer-activism-sharp"; import volunteerActivismSharp from "@iconify-icons/material-symbols/volunteer-activism-sharp";
import description from "@iconify-icons/material-symbols/description"; import description from "@iconify-icons/material-symbols/description";
import folderRounded from "@iconify-icons/material-symbols/folder-rounded";
addIcon("cloud", Cloud); addIcon("cloud", Cloud);
addIcon("rocket-launch-rounded", RocketLaunchRounded); addIcon("rocket-launch-rounded", RocketLaunchRounded);
@ -68,4 +69,5 @@ addIcon("file-open-rounded", fileOpenRounded);
addIcon("attach-money-rounded", attachMoneyRounded); addIcon("attach-money-rounded", attachMoneyRounded);
addIcon("volunteer-activism-sharp", volunteerActivismSharp); addIcon("volunteer-activism-sharp", volunteerActivismSharp);
addIcon("description", description); addIcon("description", description);
addIcon("folder-rounded", folderRounded);

View File

@ -257,6 +257,15 @@ onMounted(() => {
ElMessageBox.alert(data, `提示`); ElMessageBox.alert(data, `提示`);
} }
}); });
ipcRenderer.on("Config.openDataFolder.hook", (event, args) => {
if (args) {
ElMessage({
type: "success",
message: "打开数据目录成功"
});
}
});
}); });
const handleSelectFile = (type: number, ext: string[]) => { const handleSelectFile = (type: number, ext: string[]) => {
@ -371,17 +380,28 @@ const handleResetConfig = () => {
}); });
}; };
/**
* 打开数据目录
*/
const handleOpenDataFolder = useDebounceFn(() => {
ipcRenderer.send("config.openDataFolder");
}, 1000);
onUnmounted(() => { onUnmounted(() => {
ipcRenderer.removeAllListeners("Config.getConfig.hook"); ipcRenderer.removeAllListeners("Config.getConfig.hook");
ipcRenderer.removeAllListeners("Config.saveConfig.hook"); ipcRenderer.removeAllListeners("Config.saveConfig.hook");
ipcRenderer.removeAllListeners("Config.versions.hook"); ipcRenderer.removeAllListeners("Config.versions.hook");
ipcRenderer.removeAllListeners("Config.exportConfig.hook"); ipcRenderer.removeAllListeners("Config.exportConfig.hook");
ipcRenderer.removeAllListeners("Config.clearAll.hook"); ipcRenderer.removeAllListeners("Config.clearAll.hook");
ipcRenderer.removeAllListeners("Config.openDataFolder.hook");
}); });
</script> </script>
<template> <template>
<div class="main"> <div class="main">
<breadcrumb> <breadcrumb>
<el-button plain type="primary" @click="handleOpenDataFolder">
<IconifyIconOffline icon="folder-rounded" />
</el-button>
<el-button plain type="primary" @click="handleResetConfig"> <el-button plain type="primary" @click="handleResetConfig">
<IconifyIconOffline icon="deviceReset" /> <IconifyIconOffline icon="deviceReset" />
</el-button> </el-button>

View File

@ -37,6 +37,7 @@ const refreshStatus = ref(false);
const logLoading = ref(true); const logLoading = ref(true);
onMounted(() => { onMounted(() => {
console.log('logger mounted')
ipcRenderer.send("logger.getLog"); ipcRenderer.send("logger.getLog");
ipcRenderer.on("Logger.getLog.hook", (event, args) => { ipcRenderer.on("Logger.getLog.hook", (event, args) => {
// console.log("", args, args.indexOf("\n")); // console.log("", args, args.indexOf("\n"));
@ -89,7 +90,9 @@ const refreshLog = useDebounceFn(() => {
}, 300); }, 300);
onUnmounted(() => { onUnmounted(() => {
console.log('logger unmounted')
ipcRenderer.removeAllListeners("Logger.getLog.hook"); ipcRenderer.removeAllListeners("Logger.getLog.hook");
ipcRenderer.removeAllListeners("Logger.openLog.hook");
}); });
</script> </script>
<template> <template>