From 0b4824975a7e4954dbabfdbe4ec97c1269e2a06c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E5=98=89=E4=BC=9F?= <8473136@qq.com> Date: Sun, 22 Dec 2024 22:04:52 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20=E5=A2=9E=E5=8A=A0=E6=89=93?= =?UTF-8?q?=E5=BC=80=E6=95=B0=E6=8D=AE=E7=9B=AE=E5=BD=95=E6=8C=89=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- electron/api/config.ts | 493 +++++++++--------- src/components/IconifyIcon/src/offlineIcon.ts | 2 + src/views/config/index.vue | 20 + src/views/logger/index.vue | 3 + 4 files changed, 275 insertions(+), 243 deletions(-) diff --git a/electron/api/config.ts b/electron/api/config.ts index 22a1db9..8937fff 100644 --- a/electron/api/config.ts +++ b/electron/api/config.ts @@ -1,261 +1,268 @@ -import { app, dialog, ipcMain } from "electron"; -import { clearConfig, getConfig, saveConfig } from "../storage/config"; -import { clearVersion, listVersion } from "../storage/version"; -import { - generateConfig, - genIniConfig, - genTomlConfig, - stopFrpcProcess -} from "./frpc"; -import { exec } from "child_process"; -import { clearProxy, insertProxy, listProxy } from "../storage/proxy"; +import {app, dialog, ipcMain, shell} from "electron"; +import {clearConfig, getConfig, saveConfig} from "../storage/config"; +import {clearVersion, listVersion} from "../storage/version"; +import {genIniConfig, genTomlConfig, stopFrpcProcess} from "./frpc"; +import {clearProxy, insertProxy, listProxy} from "../storage/proxy"; import path from "path"; import fs from "fs"; const log = require("electron-log"); const toml = require("@iarna/toml"); -const { v4: uuidv4 } = require("uuid"); +const {v4: uuidv4} = require("uuid"); export const initConfigApi = win => { - ipcMain.on("config.saveConfig", async (event, args) => { - saveConfig(args, (err, numberOfUpdated, upsert) => { - if (!err) { - const start = args.systemSelfStart || false; - log.info("开启自启状态", start); - app.setLoginItemSettings({ - openAtLogin: start, //win - 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); + ipcMain.on("config.saveConfig", async (event, args) => { + saveConfig(args, (err, numberOfUpdated, upsert) => { + if (!err) { + const start = args.systemSelfStart || false; + log.info("开启自启状态", start); + app.setLoginItemSettings({ + openAtLogin: start, //win + openAsHidden: start //macOs + }); } - 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 - } + event.reply("Config.saveConfig.hook", { + err: err, + numberOfUpdated: numberOfUpdated, + upsert: upsert }); - } }); - } }); - }); - 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 + 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( + 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) => { - const result = await dialog.showOpenDialog(win, { - properties: ["openFile"], - filters: [ - { name: "FrpcConfig Files", extensions: ["toml", "ini"] } // 允许选择的文件类型 - ] + ipcMain.on("config.importConfig", async (event, args) => { + const result = await dialog.showOpenDialog(win, { + properties: ["openFile"], + filters: [ + {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) => { - stopFrpcProcess(() => { - clearConfig(); - clearProxy(); - clearVersion(); - event.reply("Config.clearAll.hook", {}); + ipcMain.on("config.clearAll", async (event, args) => { + stopFrpcProcess(() => { + clearConfig(); + clearProxy(); + clearVersion(); + 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); + } + }); }); - }); }; diff --git a/src/components/IconifyIcon/src/offlineIcon.ts b/src/components/IconifyIcon/src/offlineIcon.ts index d656bc5..16d159a 100644 --- a/src/components/IconifyIcon/src/offlineIcon.ts +++ b/src/components/IconifyIcon/src/offlineIcon.ts @@ -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 volunteerActivismSharp from "@iconify-icons/material-symbols/volunteer-activism-sharp"; import description from "@iconify-icons/material-symbols/description"; +import folderRounded from "@iconify-icons/material-symbols/folder-rounded"; addIcon("cloud", Cloud); addIcon("rocket-launch-rounded", RocketLaunchRounded); @@ -68,4 +69,5 @@ addIcon("file-open-rounded", fileOpenRounded); addIcon("attach-money-rounded", attachMoneyRounded); addIcon("volunteer-activism-sharp", volunteerActivismSharp); addIcon("description", description); +addIcon("folder-rounded", folderRounded); diff --git a/src/views/config/index.vue b/src/views/config/index.vue index b91bf97..a80836d 100644 --- a/src/views/config/index.vue +++ b/src/views/config/index.vue @@ -257,6 +257,15 @@ onMounted(() => { ElMessageBox.alert(data, `提示`); } }); + + ipcRenderer.on("Config.openDataFolder.hook", (event, args) => { + if (args) { + ElMessage({ + type: "success", + message: "打开数据目录成功" + }); + } + }); }); const handleSelectFile = (type: number, ext: string[]) => { @@ -371,17 +380,28 @@ const handleResetConfig = () => { }); }; +/** + * 打开数据目录 + */ +const handleOpenDataFolder = useDebounceFn(() => { + ipcRenderer.send("config.openDataFolder"); +}, 1000); + onUnmounted(() => { ipcRenderer.removeAllListeners("Config.getConfig.hook"); ipcRenderer.removeAllListeners("Config.saveConfig.hook"); ipcRenderer.removeAllListeners("Config.versions.hook"); ipcRenderer.removeAllListeners("Config.exportConfig.hook"); ipcRenderer.removeAllListeners("Config.clearAll.hook"); + ipcRenderer.removeAllListeners("Config.openDataFolder.hook"); });