🔊 Improve the log

This commit is contained in:
刘嘉伟 2025-01-08 12:01:00 +08:00
parent 19fde43f8b
commit aad6fd78d5
8 changed files with 520 additions and 182 deletions

View File

@ -5,6 +5,7 @@ import { genIniConfig, genTomlConfig, stopFrpcProcess } from "./frpc";
import { clearProxy, insertProxy, listProxy } from "../storage/proxy";
import path from "path";
import fs from "fs";
import { logDebug, logError, logInfo, LogModule, logWarn } from "../utils/log";
const log = require("electron-log");
const toml = require("@iarna/toml");
@ -12,14 +13,18 @@ const { v4: uuidv4 } = require("uuid");
export const initConfigApi = win => {
ipcMain.on("config.saveConfig", async (event, args) => {
logInfo(LogModule.APP, "Attempting to save configuration.");
saveConfig(args, (err, numberOfUpdated, upsert) => {
if (!err) {
const start = args.systemSelfStart || false;
log.info("开启自启状态", start);
logDebug(LogModule.APP, "Startup status set to: " + start);
app.setLoginItemSettings({
openAtLogin: start, //win
openAsHidden: start //macOs
});
logInfo(LogModule.APP, "Configuration saved successfully.");
} else {
logError(LogModule.APP, `Error saving configuration: ${err}`);
}
event.reply("Config.saveConfig.hook", {
err: err,
@ -30,7 +35,11 @@ export const initConfigApi = win => {
});
ipcMain.on("config.getConfig", async (event, args) => {
logInfo(LogModule.APP, "Requesting configuration.");
getConfig((err, doc) => {
if (err) {
logError(LogModule.APP, `Error retrieving configuration: ${err}`);
}
event.reply("Config.getConfig.hook", {
err: err,
data: doc
@ -39,7 +48,11 @@ export const initConfigApi = win => {
});
ipcMain.on("config.versions", event => {
logInfo(LogModule.APP, "Requesting version information.");
listVersion((err, doc) => {
if (err) {
logError(LogModule.APP, `Error retrieving version information: ${err}`);
}
event.reply("Config.versions.hook", {
err: err,
data: doc
@ -48,7 +61,11 @@ export const initConfigApi = win => {
});
ipcMain.on("config.hasConfig", event => {
logInfo(LogModule.APP, "Checking if configuration exists.");
getConfig((err, doc) => {
if (err) {
logError(LogModule.APP, `Error checking configuration: ${err}`);
}
event.reply("Config.getConfig.hook", {
err: err,
data: doc
@ -57,15 +74,18 @@ export const initConfigApi = win => {
});
ipcMain.on("config.exportConfig", async (event, args) => {
logInfo(LogModule.APP, "Attempting to export configuration.");
const result = await dialog.showOpenDialog({
properties: ["openDirectory"]
});
const outputDirectory = result.filePaths[0];
if (!outputDirectory) {
// 取消了
logWarn(LogModule.APP, "Export canceled by user.");
return;
}
log.info(`导出目录 ${outputDirectory} 类型:${args}`);
log.info(
`Exporting configuration to directory ${outputDirectory} with type: ${args}`
);
getConfig((err1, config) => {
if (!err1 && config) {
listProxy((err2, proxys) => {
@ -85,33 +105,44 @@ export const initConfigApi = win => {
configContent, // 配置文件内容
{ flag: "w" },
err => {
if (!err) {
// callback(filename);
if (err) {
logError(
LogModule.APP,
`Error writing configuration file: ${err}`
);
event.reply("config.exportConfig.hook", {
data: "导出错误",
err: err
});
} else {
logInfo(
LogModule.APP,
"Configuration exported successfully."
);
event.reply("Config.exportConfig.hook", {
data: {
configPath: configPath
}
});
}
}
);
event.reply("Config.exportConfig.hook", {
data: {
configPath: configPath
}
});
} else {
logError(LogModule.APP, `Error listing proxies: ${err2}`);
}
});
} else {
logError(LogModule.APP, `Error retrieving configuration: ${err1}`);
}
});
});
const parseTomlConfig = (tomlPath: string) => {
logInfo(LogModule.APP, `Parsing TOML configuration from ${tomlPath}`);
const importConfigPath = tomlPath;
const tomlData = fs.readFileSync(importConfigPath, "utf-8");
log.info(`读取到配置内容 ${tomlData}`);
logInfo(LogModule.APP, "Configuration content read successfully.");
const sourceConfig = toml.parse(tomlData);
// log.info(`解析结果 ${sourceConfig}`);
// console.log(sourceConfig, "frpcConfig");
// 解析config
const targetConfig: FrpConfig = {
currentVersion: null,
@ -180,6 +211,7 @@ export const initConfigApi = win => {
return rm;
});
frpcProxys = [...frpcProxys, ...frpcProxys1];
logInfo(LogModule.APP, "Parsed proxies from configuration.");
}
// 解析stcp的访问者
if (sourceConfig?.visitors && sourceConfig.visitors.length > 0) {
@ -209,17 +241,24 @@ export const initConfigApi = win => {
return rm;
});
frpcProxys = [...frpcProxys, ...frpcProxys2];
logInfo(LogModule.APP, "Parsed visitors from configuration.");
}
if (targetConfig) {
clearConfig(() => {
logInfo(LogModule.APP, "Clearing existing configuration.");
saveConfig(targetConfig);
logInfo(LogModule.APP, "New configuration saved.");
});
}
if (frpcProxys && frpcProxys.length > 0) {
clearProxy(() => {
frpcProxys.forEach(f => {
insertProxy(f, err => {
console.log("插入", f, err);
if (err) {
logError(LogModule.APP, `Error inserting proxy: ${err}`);
} else {
logInfo(LogModule.APP, `Inserted proxy: ${JSON.stringify(f)}`);
}
});
});
});
@ -227,6 +266,7 @@ export const initConfigApi = win => {
};
ipcMain.on("config.importConfig", async (event, args) => {
logInfo(LogModule.APP, "Attempting to import configuration.");
const result = await dialog.showOpenDialog(win, {
properties: ["openFile"],
filters: [
@ -234,17 +274,22 @@ export const initConfigApi = win => {
]
});
if (result.canceled) {
logWarn(LogModule.APP, "Import canceled by user.");
return;
} else {
const filePath = result.filePaths[0];
const fileExtension = path.extname(filePath); // 获取文件后缀名
log.info(`导入文件 ${filePath} ${fileExtension}`);
log.info(`Importing file ${filePath} with extension ${fileExtension}`);
if (fileExtension === ".toml") {
parseTomlConfig(filePath);
event.reply("Config.importConfig.hook", {
success: true
});
} else {
logError(
LogModule.APP,
`Import failed, unsupported file format: ${fileExtension}`
);
event.reply("Config.importConfig.hook", {
success: false,
data: `导入失败,暂不支持 ${fileExtension} 格式文件`
@ -254,22 +299,25 @@ export const initConfigApi = win => {
});
ipcMain.on("config.clearAll", async (event, args) => {
logInfo(LogModule.APP, "Clearing all configurations.");
stopFrpcProcess(() => {
clearConfig();
clearProxy();
clearVersion();
event.reply("Config.clearAll.hook", {});
logInfo(LogModule.APP, "All configurations cleared.");
});
});
ipcMain.on("config.openDataFolder", async (event, args) => {
const userDataPath = app.getPath("userData");
logInfo(LogModule.APP, "Attempting to open data folder.");
shell.openPath(userDataPath).then(errorMessage => {
if (errorMessage) {
console.error("Failed to open Logger:", errorMessage);
logError(LogModule.APP, `Failed to open data folder: ${errorMessage}`);
event.reply("Config.openDataFolder.hook", false);
} else {
console.log("Logger opened successfully");
logInfo(LogModule.APP, "Data folder opened successfully.");
event.reply("Config.openDataFolder.hook", true);
}
});

View File

@ -3,11 +3,12 @@ import { getConfig } from "../storage/config";
import { listProxy } from "../storage/proxy";
import { getVersionById } from "../storage/version";
import treeKill from "tree-kill";
import { logInfo, logError, LogModule, logDebug, logWarn } from "../utils/log";
const fs = require("fs");
const path = require("path");
const { exec, spawn } = require("child_process");
const log = require("electron-log");
export let frpcProcess = null;
const runningCmd = {
commandPath: null,
@ -15,11 +16,6 @@ const runningCmd = {
};
let frpcStatusListener = null;
/**
*
* @param versionId ID
* @param callback
*/
const getFrpcVersionWorkerPath = (
versionId: number,
callback: (workerPath: string) => void
@ -56,10 +52,10 @@ export const genTomlConfig = (config: FrpConfig, proxys: Proxy[]) => {
"\\\\"
);
let toml = `${
rangePort
? `{{- range $_, $v := parseNumberRangePair "${m.localPort}" "${m.remotePort}" }}`
: ""
}
rangePort
? `{{- range $_, $v := parseNumberRangePair "${m.localPort}" "${m.remotePort}" }}`
: ""
}
[[${
(m.type === "stcp" || m.type === "xtcp" || m.type === "sudp") &&
m.stcpModel === "visitors"
@ -200,9 +196,9 @@ ${
: ""
}
${
config.tlsConfigEnable && config.tlsConfigKeyFile
? `transport.tls.keyFile = "${config.tlsConfigKeyFile}"`
: ""
config.tlsConfigEnable && config.tlsConfigKeyFile
? `transport.tls.keyFile = "${config.tlsConfigKeyFile}"`
: ""
}
${
config.tlsConfigEnable && config.tlsConfigTrustedCaFile
@ -408,39 +404,65 @@ export const generateConfig = (
callback: (configPath: string) => void
) => {
listProxy((err3, proxys) => {
if (!err3) {
const { currentVersion } = config;
let filename = null;
let configContent = "";
const filtered = proxys
.map(m => {
if (m.status == null || m.status == undefined) {
m.status = true;
}
return m;
})
.filter(f => f.status);
if (currentVersion < 124395282) {
// 版本小于v0.52.0
filename = "frp.ini";
configContent = genIniConfig(config, filtered);
} else {
filename = "frp.toml";
configContent = genTomlConfig(config, filtered);
}
const configPath = path.join(app.getPath("userData"), filename);
log.info(`生成配置成功 配置路径:${configPath}`);
fs.writeFile(
configPath, // 配置文件目录
configContent, // 配置文件内容
{ flag: "w" },
err => {
if (!err) {
callback(filename);
}
if (err3) {
logError(LogModule.FRP_CLIENT, `Failed to list proxies: ${err3.message}`);
return;
}
const { currentVersion } = config;
let filename = null;
let configContent = "";
const filtered = proxys
.map(m => {
if (m.status == null || m.status == undefined) {
m.status = true;
}
return m;
})
.filter(f => f.status);
if (currentVersion < 124395282) {
// 版本小于v0.52.0
filename = "frp.ini";
configContent = genIniConfig(config, filtered);
logInfo(
LogModule.FRP_CLIENT,
`Using INI format for configuration: ${filename}`
);
} else {
filename = "frp.toml";
configContent = genTomlConfig(config, filtered);
logInfo(
LogModule.FRP_CLIENT,
`Using TOML format for configuration: ${filename}`
);
}
const configPath = path.join(app.getPath("userData"), filename);
logInfo(
LogModule.FRP_CLIENT,
`Writing configuration to file: ${configPath}`
);
fs.writeFile(
configPath, // 配置文件目录
configContent, // 配置文件内容
{ flag: "w" },
err => {
if (err) {
logError(
LogModule.FRP_CLIENT,
`Failed to write configuration file: ${err.message}`
);
} else {
logInfo(
LogModule.FRP_CLIENT,
`Configuration file written successfully: ${filename}`
);
callback(filename);
}
}
);
});
};
@ -451,7 +473,13 @@ export const generateConfig = (
* @param configPath
*/
const startFrpcProcess = (commandPath: string, configPath: string) => {
log.info(`启动frpc 目录:${app.getPath("userData")} 命令:${commandPath}`);
logInfo(
LogModule.FRP_CLIENT,
`Starting frpc process. Directory: ${app.getPath(
"userData"
)}, Command: ${commandPath}`
);
const command = `${commandPath} -c ${configPath}`;
frpcProcess = spawn(command, {
cwd: app.getPath("userData"),
@ -459,21 +487,31 @@ const startFrpcProcess = (commandPath: string, configPath: string) => {
});
runningCmd.commandPath = commandPath;
runningCmd.configPath = configPath;
frpcProcess.stdout.on("data", data => {
log.debug(`启动输出:${data}`);
logDebug(LogModule.FRP_CLIENT, `Frpc process output: ${data}`);
});
frpcProcess.stdout.on("error", data => {
log.error(`启动错误:${data}`);
logError(LogModule.FRP_CLIENT, `Frpc process error: ${data}`);
stopFrpcProcess(() => {});
});
frpcStatusListener = setInterval(() => {
const status = frpcProcessStatus();
log.debug(`监听frpc子进程状态${status} ${frpcStatusListener}`);
logDebug(
LogModule.FRP_CLIENT,
`Monitoring frpc process status: ${status}, Listener ID: ${frpcStatusListener}`
);
if (!status) {
new Notification({
title: "Frpc Desktop",
body: "连接已断开,请前往日志查看原因"
body: "Connection lost, please check the logs for details."
}).show();
logError(
LogModule.FRP_CLIENT,
"Frpc process status check failed. Connection lost."
);
clearInterval(frpcStatusListener);
}
}, 3000);
@ -484,20 +522,58 @@ const startFrpcProcess = (commandPath: string, configPath: string) => {
*/
export const reloadFrpcProcess = () => {
if (frpcProcess && !frpcProcess.killed) {
logDebug(
LogModule.FRP_CLIENT,
"Attempting to reload frpc process configuration."
);
getConfig((err1, config) => {
if (!err1) {
if (config) {
generateConfig(config, configPath => {
const command = `${runningCmd.commandPath} reload -c ${configPath}`;
log.info(`重载配置:${command}`);
exec(command, {
cwd: app.getPath("userData"),
shell: true
});
logInfo(
LogModule.FRP_CLIENT,
`Reloading configuration: ${command}`
);
exec(
command,
{
cwd: app.getPath("userData"),
shell: true
},
(error, stdout, stderr) => {
if (error) {
logError(
LogModule.FRP_CLIENT,
`Error reloading configuration: ${error.message}`
);
return;
}
logDebug(
LogModule.FRP_CLIENT,
`Configuration reload output: ${stdout}`
);
if (stderr) {
logWarn(
LogModule.FRP_CLIENT,
`Configuration reload warnings: ${stderr}`
);
}
}
);
});
} else {
logWarn(LogModule.FRP_CLIENT, "No configuration found to reload.");
}
} else {
logError(LogModule.FRP_CLIENT, `Error getting configuration: ${err1}`);
}
});
} else {
logWarn(
LogModule.FRP_CLIENT,
"frpc process is not running or has been killed."
);
}
};
@ -508,16 +584,27 @@ export const stopFrpcProcess = (callback?: () => void) => {
if (frpcProcess) {
treeKill(frpcProcess.pid, (error: Error) => {
if (error) {
log.error(`关闭frpc子进程失败 pid${frpcProcess.pid} error${error}`);
logError(
LogModule.FRP_CLIENT,
`Failed to stop frpc process with pid: ${frpcProcess.pid}. Error: ${error.message}`
);
callback();
} else {
log.info(`关闭frpc子进程成功`);
logInfo(
LogModule.FRP_CLIENT,
`Successfully stopped frpc process with pid: ${frpcProcess.pid}.`
);
frpcProcess = null;
clearInterval(frpcStatusListener);
callback();
}
});
} else {
logWarn(
LogModule.FRP_CLIENT,
"Attempted to stop frpc process, but no process is running."
);
logWarn(LogModule.FRP_CLIENT, "No frpc process to stop.");
callback();
}
};
@ -527,14 +614,23 @@ export const stopFrpcProcess = (callback?: () => void) => {
*/
export const frpcProcessStatus = () => {
if (!frpcProcess) {
logWarn(LogModule.FRP_CLIENT, "frpc process is not running.");
return false;
}
try {
// 发送信号给进程,如果进程存在,会正常返回
process.kill(frpcProcess.pid, 0);
logDebug(
LogModule.FRP_CLIENT,
`frpc process is running with pid: ${frpcProcess.pid}`
);
return true;
} catch (error) {
// 进程不存在,抛出异常
logError(
LogModule.FRP_CLIENT,
`frpc process not found. Error: ${error.message}`
);
return false;
}
};
@ -544,29 +640,47 @@ export const frpcProcessStatus = () => {
* @param config
*/
export const startFrpWorkerProcess = async (config: FrpConfig) => {
logInfo(LogModule.FRP_CLIENT, "Starting frpc worker process...");
getFrpcVersionWorkerPath(config.currentVersion, (frpcVersionPath: string) => {
if (frpcVersionPath) {
logInfo(
LogModule.FRP_CLIENT,
`Found frpc version path: ${frpcVersionPath}`
);
generateConfig(config, configPath => {
const platform = process.platform;
if (platform === "win32") {
logInfo(LogModule.FRP_CLIENT, "Starting frpc on Windows.");
startFrpcProcess(path.join(frpcVersionPath, "frpc.exe"), configPath);
} else {
logInfo(
LogModule.FRP_CLIENT,
"Starting frpc on non-Windows platform."
);
startFrpcProcess(path.join(frpcVersionPath, "frpc"), configPath);
}
});
} else {
logError(LogModule.FRP_CLIENT, "frpc version path not found.");
}
});
};
export const initFrpcApi = () => {
ipcMain.handle("frpc.running", async (event, args) => {
logDebug(LogModule.FRP_CLIENT, "Checking if frpc process is running...");
return frpcProcessStatus();
});
ipcMain.on("frpc.start", async (event, args) => {
logInfo(LogModule.FRP_CLIENT, "Received request to start frpc process.");
getConfig((err1, config) => {
if (!err1) {
if (!config) {
logWarn(
LogModule.FRP_CLIENT,
"Configuration not found. Prompting user to set configuration."
);
event.reply(
"Home.frpc.start.error.hook",
"请先前往设置页面,修改配置后再启动"
@ -574,6 +688,10 @@ export const initFrpcApi = () => {
return;
}
if (!config.currentVersion) {
logWarn(
LogModule.FRP_CLIENT,
"Current version not set in configuration. Prompting user."
);
event.reply(
"Home.frpc.start.error.hook",
"请先前往设置页面,修改配置后再启动"
@ -581,13 +699,18 @@ export const initFrpcApi = () => {
return;
}
startFrpWorkerProcess(config);
} else {
logError(LogModule.FRP_CLIENT, `Error getting configuration: ${err1}`);
}
});
});
ipcMain.on("frpc.stop", () => {
logInfo(LogModule.FRP_CLIENT, "Received request to stop frpc process.");
if (frpcProcess && !frpcProcess.killed) {
stopFrpcProcess(() => {});
} else {
logWarn(LogModule.FRP_CLIENT, "No frpc process to stop.");
}
});
};

View File

@ -12,6 +12,7 @@ const { download } = require("electron-dl");
const AdmZip = require("adm-zip");
const log = require("electron-log");
import frpReleasesJson from "../json/frp-releases.json";
import { logInfo, logError, LogModule, logDebug, logWarn } from "../utils/log";
const versionRelation = {
win32_x64: ["window", "amd64"],
@ -31,23 +32,45 @@ const frpArch = versionRelation[currArch];
const unTarGZ = (tarGzPath: string, targetPath: string) => {
const tar = require("tar");
const unzip = zlib.createGunzip();
log.debug(`开始解压tar.gz${tarGzPath} 目标目录:${targetPath}`);
logInfo(
LogModule.APP,
`Starting to extract tar.gz: ${tarGzPath} to ${targetPath}`
);
const readStream = fs.createReadStream(tarGzPath);
if (!fs.existsSync(unzip)) {
fs.mkdirSync(targetPath, { recursive: true });
logInfo(LogModule.APP, `Created target directory: ${targetPath}`);
}
readStream.pipe(unzip).pipe(
tar.extract({
cwd: targetPath,
filter: filePath => path.basename(filePath) === "frpc"
readStream.on("error", err => {
logError(LogModule.APP, `Error reading tar.gz file: ${err.message}`);
});
readStream
.pipe(unzip)
.on("error", err => {
logError(LogModule.APP, `Error during gunzip: ${err.message}`);
})
);
const frpcPath = path.join("frp", path.basename(tarGzPath, ".tar.gz"));
log.debug(`解压完成 解压后目录:${frpcPath}`);
return frpcPath;
// .on("finish", () => {
// console.log("解压完成!");
// });
.pipe(
tar
.extract({
cwd: targetPath,
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}`
);
});
return path.join("frp", path.basename(tarGzPath, ".tar.gz"));
};
const unZip = (zipPath: string, targetPath: string) => {
@ -55,28 +78,37 @@ const unZip = (zipPath: string, targetPath: string) => {
fs.mkdirSync(path.join(targetPath, path.basename(zipPath, ".zip")), {
recursive: true
});
logInfo(LogModule.APP, `Created target directory: ${targetPath}`);
logInfo(
LogModule.APP,
`Created directory for zip extraction: ${path.basename(zipPath, ".zip")}`
);
}
log.debug(`开始解压zip${zipPath} 目标目录:${targetPath}`);
/**
* unzipper解压
*/
// fs.createReadStream(zipPath)
// .pipe(unzipper.Extract({ path: targetPath }))
// // 只解压frpc.exe
// // .pipe(unzipper.ParseOne('frpc'))
// // .pipe(fs.createWriteStream(path.join(targetPath, path.basename(zipPath, ".zip"), "frpc.exe")))
// .on('finish', () => {
// console.log('File extracted successfully.');
// })
// .on('error', (err) => {
// console.error('Error extracting file:', err);
// });
logDebug(
LogModule.APP,
`Starting to unzip: ${zipPath} to target directory: ${targetPath}`
);
logInfo(LogModule.APP, `Starting to extract zip file: ${zipPath}`);
const zip = new AdmZip(zipPath);
zip.extractAllTo(targetPath, true); // 第二个参数为 true表示覆盖已存在的文件
const frpcPath = path.join("frp", path.basename(zipPath, ".zip"));
log.debug(`解压完成 解压后目录:${frpcPath}`);
return frpcPath;
try {
zip.extractAllTo(targetPath, true); // 第二个参数为 true表示覆盖已存在的文件
const frpcPath = path.join("frp", path.basename(zipPath, ".zip"));
logInfo(
LogModule.APP,
`Extraction completed. Extracted directory: ${frpcPath}`
);
logDebug(
LogModule.APP,
`Unzip completed. Extracted directory: ${frpcPath}`
);
return frpcPath;
} catch (error) {
logError(LogModule.APP, `Error extracting zip file: ${error.message}`);
}
return null;
};
export const initGitHubApi = () => {
@ -84,40 +116,68 @@ export const initGitHubApi = () => {
let versions: FrpVersion[] = [];
const getVersion = versionId => {
return versions.find(f => f.id === versionId);
logDebug(
LogModule.GITHUB,
`Attempting to get version with ID: ${versionId}`
);
const version = versions.find(f => f.id === versionId);
if (version) {
logInfo(LogModule.GITHUB, `Version found: ${JSON.stringify(version)}`);
} else {
logWarn(LogModule.GITHUB, `No version found for ID: ${versionId}`);
}
return version;
};
const getAdaptiveAsset = versionId => {
const { assets } = getVersion(versionId);
if (!assets || assets.length === 0) {
logWarn(LogModule.GITHUB, `No assets found for version ID: ${versionId}`);
return null;
}
const asset = assets.find(f => {
// const a = versionRelation[currArch]
const a = frpArch;
if (a) {
const flag = a.every(item => f.name.includes(item));
if (flag) {
logInfo(
LogModule.GITHUB,
`Found matching asset: ${f.name} for version ID: ${versionId}`
);
}
return flag;
}
logWarn(
LogModule.GITHUB,
`No architecture match found for asset: ${f.name}`
);
return false;
});
// if (asset) {
// log.info(`找到对应版本 ${asset.name}`);
// }
if (!asset) {
logError(
LogModule.GITHUB,
`No adaptive asset found for version ID: ${versionId}`
);
}
return asset;
};
/**
*
* @param bytes
* @param decimals
* Format byte information
* @param bytes Bytes
* @param decimals Decimal places
* @returns
*/
const formatBytes = (bytes: number, decimals: number = 2): string => {
if (bytes === 0) return "0 Bytes";
const k = 1024; // 1 KB = 1024 Bytes
const dm = decimals < 0 ? 0 : decimals; // 确保小数位数不小于 0
const dm = decimals < 0 ? 0 : decimals; // Ensure decimal places are not less than 0
const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
const i = Math.floor(Math.log(bytes) / Math.log(k)); // 计算单位索引
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i]; // 返回格式化的字符串
const i = Math.floor(Math.log(bytes) / Math.log(k)); // Calculate unit index
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i]; // Return formatted string
};
/**
@ -127,8 +187,15 @@ export const initGitHubApi = () => {
*/
const handleApiResponse = (githubReleaseJsonStr: string) => {
const downloadPath = path.join(app.getPath("userData"), "download");
logInfo(LogModule.GITHUB, "Parsing GitHub release JSON response.");
versions = JSON.parse(githubReleaseJsonStr);
if (versions) {
logInfo(
LogModule.GITHUB,
"Successfully parsed versions from GitHub response."
);
const returnVersionsData = versions
.filter(f => getAdaptiveAsset(f.id))
.map(m => {
@ -143,12 +210,25 @@ export const initGitHubApi = () => {
m.download_completed = fs.existsSync(absPath);
m.download_count = download_count;
m.size = formatBytes(asset.size);
logInfo(
LogModule.GITHUB,
`Asset found: ${asset.name}, download count: ${download_count}`
);
} else {
logWarn(LogModule.GITHUB, `No asset found for version ID: ${m.id}`);
}
return m;
});
// log.debug(`获取到frp版本${JSON.stringify(returnVersionsData)}`)
logDebug(
LogModule.GITHUB,
`Retrieved FRP versions: ${JSON.stringify(returnVersionsData)}`
);
return returnVersionsData;
} else {
logError(
LogModule.GITHUB,
"Failed to parse versions: No versions found in response."
);
return [];
}
};
@ -172,7 +252,7 @@ export const initGitHubApi = () => {
*/
ipcMain.on("github.getFrpVersions", async (event, mirror: string) => {
const mirrorUrl = conventMirrorUrl(mirror);
log.info("request mirror Url", mirrorUrl);
log.info("Requesting mirror URL: ", mirrorUrl);
const request = net.request({
method: "get",
url: `${mirrorUrl}/repos/fatedier/frp/releases?page=1&per_page=1000`
@ -180,7 +260,7 @@ export const initGitHubApi = () => {
let githubReleaseJsonStr = null;
request.on("response", response => {
log.info("request mirror Status Code", response.statusCode);
log.info("Received response with status code: ", response.statusCode);
let responseData: Buffer = Buffer.alloc(0);
response.on("data", (data: Buffer) => {
responseData = Buffer.concat([responseData, data]);
@ -188,8 +268,16 @@ export const initGitHubApi = () => {
response.on("end", () => {
if (response.statusCode === 200) {
githubReleaseJsonStr = responseData.toString();
logInfo(
LogModule.GITHUB,
"Successfully retrieved GitHub release data."
);
} else {
log.info("use local json", response.statusCode);
logWarn(
LogModule.GITHUB,
"Failed to retrieve data, using local JSON instead. Status code: " +
response.statusCode
);
githubReleaseJsonStr = JSON.stringify(frpReleasesJson);
}
const versions = handleApiResponse(githubReleaseJsonStr);
@ -198,7 +286,10 @@ export const initGitHubApi = () => {
});
request.on("error", error => {
log.info("error use local json", error);
logError(
LogModule.GITHUB,
"Error occurred while requesting GitHub releases: " + error
);
githubReleaseJsonStr = JSON.stringify(frpReleasesJson);
const versions = handleApiResponse(githubReleaseJsonStr);
event.reply("Download.frpVersionHook", versions);
@ -221,7 +312,11 @@ export const initGitHubApi = () => {
url = "https://mirror.ghproxy.com/" + url;
}
log.info(`开始下载frp url${url} asset${asset.name}`);
logDebug(
LogModule.GITHUB,
`Starting download for versionId: ${versionId}, mirror: ${mirror}, download URL: ${url}`
);
// 数据目录
await download(BrowserWindow.getFocusedWindow(), url, {
filename: `${asset.name}`,
@ -231,29 +326,54 @@ export const initGitHubApi = () => {
id: versionId,
progress: progress
});
logDebug(
LogModule.GITHUB,
`Download progress for versionId: ${versionId} is ${progress}%`
);
},
onCompleted: () => {
log.info(`frp下载完成 url${url} asset${asset.name}`);
logInfo(
LogModule.GITHUB,
`Download completed for versionId: ${versionId}, asset: ${asset.name}`
);
const targetPath = path.resolve(
path.join(app.getPath("userData"), "frp")
);
const ext = path.extname(asset.name);
let frpcVersionPath = "";
if (ext === ".zip") {
frpcVersionPath = unZip(
path.join(
path.join(app.getPath("userData"), "download"),
`${asset.name}`
),
targetPath
);
} else if (ext === ".gz" && asset.name.includes(".tar.gz")) {
frpcVersionPath = unTarGZ(
path.join(
path.join(app.getPath("userData"), "download"),
`${asset.name}`
),
targetPath
try {
if (ext === ".zip") {
frpcVersionPath = unZip(
path.join(
path.join(app.getPath("userData"), "download"),
`${asset.name}`
),
targetPath
);
logInfo(
LogModule.GITHUB,
`Unzipped file to path: ${frpcVersionPath}`
);
} else if (ext === ".gz" && asset.name.includes(".tar.gz")) {
frpcVersionPath = unTarGZ(
path.join(
path.join(app.getPath("userData"), "download"),
`${asset.name}`
),
targetPath
);
logInfo(
LogModule.GITHUB,
`Untarred file to path: ${frpcVersionPath}`
);
}
} catch (error) {
logError(
LogModule.GITHUB,
`Error during extraction: ${error.message}`
);
}
@ -264,7 +384,13 @@ export const initGitHubApi = () => {
event.reply("Config.versions.hook", { err, data: doc });
event.reply("Download.frpVersionDownloadOnCompleted", versionId);
version.download_completed = true;
logInfo(
LogModule.GITHUB,
`Version ${versionId} has been inserted successfully.`
);
});
} else {
logError(LogModule.GITHUB, `Error inserting version: ${err}`);
}
});
}
@ -276,17 +402,34 @@ export const initGitHubApi = () => {
*/
ipcMain.on("github.deleteVersion", async (event, args) => {
const { absPath, id } = args;
logDebug(
LogModule.GITHUB,
`Attempting to delete version with ID: ${id} and path: ${absPath}`
);
if (fs.existsSync(absPath)) {
deleteVersionById(id, () => {
fs.unlinkSync(absPath);
logInfo(
LogModule.GITHUB,
`Successfully deleted version with ID: ${id}`
);
});
} else {
logWarn(
LogModule.GITHUB,
`Version with ID: ${id} not found at path: ${absPath}`
);
}
listVersion((err, doc) => {
event.reply("Config.versions.hook", { err, data: doc });
event.reply("Download.deleteVersion.hook", {
err: null,
data: "删除成功"
});
if (err) {
logError(LogModule.GITHUB, `Error listing versions: ${err}`);
} else {
event.reply("Config.versions.hook", { err, data: doc });
event.reply("Download.deleteVersion.hook", {
err: null,
data: "删除成功"
});
}
});
});
@ -294,6 +437,7 @@ export const initGitHubApi = () => {
*
*/
ipcMain.on("github.getFrpcDesktopLastVersions", async event => {
logInfo(LogModule.GITHUB, "Requesting the latest version from GitHub.");
const request = net.request({
method: "get",
url: "https://api.github.com/repos/luckjiawei/frpc-desktop/releases/latest"
@ -304,26 +448,24 @@ export const initGitHubApi = () => {
responseData = Buffer.concat([responseData, data]);
});
response.on("end", () => {
versions = JSON.parse(responseData.toString());
// const borderContent: Electron.WebContents =
// BrowserWindow.getFocusedWindow().webContents;
// const downloadPath = path.join(app.getPath("userData"), "download");
// log.info(`开始获取frp版本 当前架构:${currArch} 对应frp架构${frpArch}`)
// const returnVersionsData = versions
// .filter(f => getAdaptiveAsset(f.id))
// .map(m => {
// const asset = getAdaptiveAsset(m.id);
// if (asset) {
// const absPath = `${downloadPath}/${asset.name}`;
// m.absPath = absPath;
// m.download_completed = fs.existsSync(absPath);
// }
// return m;
// });
// log.debug(`获取到frp版本${JSON.stringify(returnVersionsData)}`)
event.reply("github.getFrpcDesktopLastVersionsHook", versions);
try {
versions = JSON.parse(responseData.toString());
logInfo(
LogModule.GITHUB,
"Successfully retrieved the latest version."
);
event.reply("github.getFrpcDesktopLastVersionsHook", versions);
} catch (error) {
logError(
LogModule.GITHUB,
`Error parsing response data: ${error.message}`
);
}
});
});
request.on("error", error => {
logError(LogModule.GITHUB, `Request error: ${error.message}`);
});
request.end();
});
};

View File

@ -1,5 +1,5 @@
import {ipcMain} from "electron";
import log from "electron-log";
import { logDebug, logError, logInfo, LogModule, logWarn } from "electron/utils/log";
const {exec, spawn} = require("child_process");
@ -15,19 +15,19 @@ export const initLocalApi = () => {
: 'netstat -an | grep LISTEN';
ipcMain.on("local.getLocalPorts", async (event, args) => {
log.info("开始获取本地端口")
logInfo(LogModule.APP, "Starting to retrieve local ports");
// 执行命令
exec(command, (error, stdout, stderr) => {
if (error) {
log.error(`getLocalPorts - error ${error.message}`)
logError(LogModule.APP, `getLocalPorts - error: ${error.message}`);
return;
}
if (stderr) {
log.error(`getLocalPorts - stderr ${stderr}`)
logWarn(LogModule.APP, `getLocalPorts - stderr: ${stderr}`);
return;
}
log.debug(`sc ${stdout}`)
logDebug(LogModule.APP, `Command output: ${stdout}`);
let ports = [];
if (stdout) {
if (process.platform === 'win32') {
@ -72,7 +72,6 @@ export const initLocalApi = () => {
}
return singe;
})
// .filter(f => f.indexOf('TCP') > 0 || f.indexOf('UDP') > 0)
} else if (process.platform === 'linux') {
ports = stdout.split('\n')

View File

@ -8,10 +8,16 @@ import {
updateProxyStatus
} from "../storage/proxy";
import { reloadFrpcProcess } from "./frpc";
import { logError, logInfo, LogModule, logWarn } from "../utils/log";
export const initProxyApi = () => {
ipcMain.on("proxy.getProxys", async (event, args) => {
logInfo(LogModule.APP, "Requesting to get proxies.");
listProxy((err, documents) => {
if (err) {
logError(LogModule.APP, `Error retrieving proxies: ${err.message}`);
} else {
logInfo(LogModule.APP, "Proxies retrieved successfully.");
}
event.reply("Proxy.getProxys.hook", {
err: err,
data: documents
@ -21,8 +27,12 @@ export const initProxyApi = () => {
ipcMain.on("proxy.insertProxy", async (event, args) => {
delete args["_id"];
logInfo(LogModule.APP, "Inserting a new proxy.");
insertProxy(args, (err, documents) => {
if (!err) {
if (err) {
logError(LogModule.APP, `Error inserting proxy: ${err.message}`);
} else {
logInfo(LogModule.APP, "Proxy inserted successfully.");
reloadFrpcProcess();
}
event.reply("Proxy.insertProxy.hook", {
@ -33,8 +43,12 @@ export const initProxyApi = () => {
});
ipcMain.on("proxy.deleteProxyById", async (event, args) => {
logInfo(LogModule.APP, `Deleting proxy with ID: ${args._id}`);
deleteProxyById(args, (err, documents) => {
if (!err) {
if (err) {
logError(LogModule.APP, `Error deleting proxy: ${err.message}`);
} else {
logInfo(LogModule.APP, "Proxy deleted successfully.");
reloadFrpcProcess();
}
event.reply("Proxy.deleteProxyById.hook", {
@ -45,7 +59,13 @@ export const initProxyApi = () => {
});
ipcMain.on("proxy.getProxyById", async (event, args) => {
logInfo(LogModule.APP, `Requesting proxy with ID: ${args._id}`);
getProxyById(args, (err, documents) => {
if (err) {
logError(LogModule.APP, `Error retrieving proxy: ${err.message}`);
} else {
logInfo(LogModule.APP, "Proxy retrieved successfully.");
}
event.reply("Proxy.getProxyById.hook", {
err: err,
data: documents
@ -54,9 +74,16 @@ export const initProxyApi = () => {
});
ipcMain.on("proxy.updateProxy", async (event, args) => {
if (!args._id) return;
if (!args._id) {
logWarn(LogModule.APP, "No proxy ID provided for update.");
return;
}
logInfo(LogModule.APP, `Updating proxy with ID: ${args._id}`);
updateProxyById(args, (err, documents) => {
if (!err) {
if (err) {
logError(LogModule.APP, `Error updating proxy: ${err.message}`);
} else {
logInfo(LogModule.APP, "Proxy updated successfully.");
reloadFrpcProcess();
}
event.reply("Proxy.updateProxy.hook", {
@ -67,10 +94,16 @@ export const initProxyApi = () => {
});
ipcMain.on("proxy.updateProxyStatus", async (event, args) => {
console.log("更新状态", args);
if (!args._id) return;
logInfo(LogModule.APP, `Updating status for proxy ID: ${args._id}`);
if (!args._id) {
logWarn(LogModule.APP, "No proxy ID provided for status update.");
return;
}
updateProxyStatus(args._id, args.status, (err, documents) => {
if (!err) {
if (err) {
logError(LogModule.APP, `Error updating proxy status: ${err.message}`);
} else {
logInfo(LogModule.APP, "Proxy status updated successfully.");
reloadFrpcProcess();
}
event.reply("Proxy.updateProxyStatus.hook", {

View File

@ -2,7 +2,6 @@ import {app, dialog, autoUpdater, BrowserWindow} from "electron";
const log = require('electron-log');
export const initUpdaterApi = (win: BrowserWindow) => {
//更新测试打开
Object.defineProperty(app, 'isPackaged', {
@ -56,10 +55,7 @@ export const initUpdaterApi = (win: BrowserWindow) => {
})
autoUpdater.on('update-downloaded', () => {
console.log('update-downloaded')
dialog.showMessageBox({
type: 'info',
title: '应用更新',

View File

@ -2,9 +2,7 @@ export const maskSensitiveData = (
obj: Record<string, any>,
keysToMask: string[]
) => {
console.log("obj", obj);
const maskedObj = JSON.parse(JSON.stringify(obj));
console.log("masked", maskedObj);
keysToMask.forEach(key => {
if (maskedObj.hasOwnProperty(key)) {
maskedObj[key] = "***";

View File

@ -3,10 +3,9 @@ import log from "electron-log";
export enum LogModule {
APP = "app",
FRP_CLIENT = "frpc client",
PROXY = "proxy",
DOWNLOAD = "download",
SETTING = "setting",
LOGGER = "logger"
LOGGER = "logger",
GITHUB = "github",
STORAGE = "",
}
// 设置日志级别