🏗️ lower electron version

This commit is contained in:
刘嘉伟 2025-02-18 17:52:09 +08:00
parent 183a86d10b
commit 3ef92a8af9
20 changed files with 453 additions and 93 deletions

View File

@ -1,53 +0,0 @@
import { app, ipcMain, shell } from "electron";
import { logInfo, logError, LogModule } from "../utils/log";
const fs = require("fs");
const path = require("path");
export const initLoggerApi = () => {
const logPath = path.join(app.getPath("userData"), "frpc.log");
const readLogger = (callback: (content: string) => void) => {
fs.readFile(logPath, "utf-8", (error, data) => {
if (!error) {
logInfo(LogModule.APP, "Log file read successfully.");
callback(data);
} else {
logError(LogModule.APP, `Error reading log file: ${error.message}`);
}
});
};
ipcMain.on("logger.getLog", async (event, args) => {
logInfo(LogModule.APP, "Received request to get log.");
readLogger(content => {
event.reply("Logger.getLog.hook", content);
logInfo(LogModule.APP, "Log data sent to client.");
});
});
ipcMain.on("logger.update", (event, args) => {
logInfo(LogModule.APP, "Watching log file for changes.");
fs.watch(logPath, (eventType, filename) => {
if (eventType === "change") {
logInfo(LogModule.APP, "Log file changed, reading new content.");
readLogger(content => {
event.reply("Logger.update.hook", content);
logInfo(LogModule.APP, "Updated log data sent to client.");
});
}
});
});
ipcMain.on("logger.openLog", (event, args) => {
logInfo(LogModule.APP, "Attempting to open log file.");
shell.openPath(logPath).then((errorMessage) => {
if (errorMessage) {
logError(LogModule.APP, `Failed to open Logger: ${errorMessage}`);
event.reply("Logger.openLog.hook", false);
} else {
logInfo(LogModule.APP, "Logger opened successfully.");
event.reply("Logger.openLog.hook", true);
}
});
});
};

View File

@ -0,0 +1,21 @@
class BaseController {
// success<T>(data: any, message?: string) {
// const resp: ApiResponse<T> = {
// success: true,
// data: data,
// message: message || "successful."
// };
// return resp;
// }
//
// fail(message?: string) {
// const resp: ApiResponse<any> = {
// success: false,
// data: null,
// message: message || "internal error."
// };
// return resp;
// }
}
export default BaseController;

View File

@ -0,0 +1,5 @@
import BaseController from "./BaseController";
class LaunchController extends BaseController {
}

View File

@ -0,0 +1,39 @@
import BaseController from "./BaseController";
import LogService from "../service/LogService";
import { fail, success } from "../utils/response";
class LogController extends BaseController {
private readonly _logService: LogService;
constructor(logService: LogService) {
super();
this._logService = logService;
console.log("logService2", this._logService);
}
getFrpLogContent(req: ControllerRequest) {
console.log("logService3", this._logService);
this._logService.getFrpLogContent().then(data => {
req.event.reply(req.reply, success(data));
});
}
// watchFrpcLogContent(req: ControllerRequest) {
// this._logService.watchFrpcLog().then(data => {
// console.log('reply watch', data);
// req.event.reply(req.reply, this.success(data));
// });
// }
openFrpcLogFile(req: ControllerRequest) {
this._logService.openFrpcLogFile().then(data => {
if (data) {
success(null);
} else {
fail();
}
});
}
}
export default LogController;

View File

@ -0,0 +1,7 @@
import BaseController from "./BaseController";
class ProxyController extends BaseController {
constructor() {
super();
}
}

View File

@ -0,0 +1,18 @@
import BaseController from "./BaseController";
import ServerService from "../service/ServerService";
import IpcMainEvent = Electron.IpcMainEvent;
class ServerController extends BaseController {
serverService: ServerService;
constructor(serverService: ServerService) {
super();
this.serverService = serverService;
}
saveConfig(event: IpcMainEvent, ...args: any[]) {
console.log("test", args);
}
}
export default ServerController;

View File

@ -0,0 +1,75 @@
import ServerController from "../controller/ServerController";
import ServerDao from "../dao/ServerDao";
import ServerService from "../service/ServerService";
import LogService from "../service/LogService";
import { BrowserWindow, ipcMain } from "electron";
import LogController from "../controller/LogController";
import FileService from "../service/FileService";
type IpcRouter = {
path: string;
reply: string;
controller: any;
instance: any;
};
class IpcRouterConfigurate {
ipcRouters: Array<IpcRouter>;
private readonly _win: BrowserWindow;
constructor(win: BrowserWindow) {
this._win = win;
const serverDao = new ServerDao();
const fileService = new FileService();
const serverService = new ServerService(serverDao);
const logService = new LogService(fileService);
const serverController = new ServerController(serverService);
const logController = new LogController(logService);
logService.watchFrpcLog(win);
this.ipcRouters = [
{
path: "server/test",
reply: "server/test.hook",
controller: serverController.saveConfig,
instance: serverController
},
{
path: "log/getFrpLogContent",
reply: "log/getFrpLogContent.hook",
controller: logController.getFrpLogContent,
instance: logController
},
// {
// path: "log/watchFrpcLogContent",
// reply: "log/watchFrpcLogContent.hook",
// controller: logController.watchFrpcLogContent,
// instance: logController
// },
{
path: "log/openFrpcLogFile",
reply: "log/openFrpcLogFile.hook",
controller: logController.openFrpcLogFile,
instance: logController
}
];
}
init() {
this.ipcRouters.forEach(router => {
ipcMain.on(router.path, (event, args) => {
const req: ControllerRequest = {
win: this._win,
reply: router.reply,
event: event,
args: args
};
router.controller.call(router.instance, req);
});
});
console.log("ipcRouter init success.");
}
}
export default IpcRouterConfigurate;

48
electron/dao/BaseDao.ts Normal file
View File

@ -0,0 +1,48 @@
import Datastore from "nedb";
import path from "path";
import { app } from "electron";
interface BaseDaoInterface<T> {
db: Datastore;
insert(t: T): Promise<T>;
updateById(t: T): T;
deleteById(id: string): void;
findAll(): T[];
}
class BaseDao<T> implements BaseDaoInterface<T> {
db: Datastore;
constructor(dbName: string) {
const dbFilename = path.join(app.getPath("userData"), `${dbName}-v2.db`);
this.db = new Datastore({
autoload: true,
filename: dbFilename
});
// todo log
}
async insert(t: T): Promise<T> {
return new Promise<T>((resolve, reject) => {
resolve(t);
});
}
updateById(t: T): T {
return null;
}
deleteById(id: string): void {
return null;
}
findAll(): T[] {
return null;
}
}
export default BaseDao;

View File

@ -0,0 +1,9 @@
import BaseDao from "./BaseDao";
class ServerDao extends BaseDao<FrpcDesktopServer> {
constructor() {
super("config");
}
}
export default ServerDao

View File

@ -1,11 +0,0 @@
/// <reference types="vite-plugin-electron/electron-env" />
declare namespace NodeJS {
interface ProcessEnv {
VSCODE_DEBUG?: 'true'
DIST_ELECTRON: string
DIST: string
/** /dist/ or /public/ */
VITE_PUBLIC: string
}
}

View File

@ -18,13 +18,13 @@ import {
startFrpWorkerProcess,
stopFrpcProcess
} from "../api/frpc";
import { initLoggerApi } from "../api/logger";
import { initFileApi } from "../api/file";
import { getConfig } from "../storage/config";
import { initCommonApi } from "../api/common";
import { initLocalApi } from "../api/local";
import { initLog, logError, logInfo, LogModule } from "../utils/log";
import { maskSensitiveData } from "../utils/desensitize";
import IpcRouterConfigurate from "../core/IpcRouter";
process.env.DIST_ELECTRON = join(__dirname, "..");
process.env.DIST = join(process.env.DIST_ELECTRON, "../dist");
@ -192,6 +192,8 @@ app.whenReady().then(() => {
startFrpWorkerProcess(config);
}
}
const ipcRouterConfig = new IpcRouterConfigurate(win);
ipcRouterConfig.init();
// Initialize APIs
try {
initGitHubApi(win);
@ -206,8 +208,7 @@ app.whenReady().then(() => {
initFrpcApi();
logInfo(LogModule.APP, `FRPC API initialized.`);
initLoggerApi();
logInfo(LogModule.APP, `Logger API initialized.`);
// logInfo(LogModule.APP, `Logger API initialized.`);
initFileApi();
logInfo(LogModule.APP, `File API initialized.`);

View File

@ -0,0 +1,15 @@
import BaseDao from "../dao/BaseDao";
interface BaseServiceInterface<T> {
dao: BaseDao<T>;
}
class BaseService<T> implements BaseServiceInterface<T> {
dao: BaseDao<T>;
constructor(dao: BaseDao<T>) {
this.dao = dao;
}
}
export default BaseService;

View File

@ -0,0 +1,24 @@
import { shell } from "electron";
class FileService {
constructor() {}
openFile(filePath: string) {
return new Promise<boolean>((resolve, reject) => {
shell
.openPath(filePath)
.then(errorMessage => {
if (errorMessage) {
resolve(false);
} else {
resolve(true);
}
})
.catch(err => {
reject(err);
});
});
}
}
export default FileService;

View File

@ -0,0 +1,59 @@
import fs from "fs";
import path from "path";
import { app, BrowserWindow } from "electron";
import FileService from "./FileService";
import { success } from "../utils/response";
class LogService {
private readonly _fileService: FileService;
private readonly _logPath: string = path.join(
app.getPath("userData"),
"frpc.log"
);
constructor(fileService: FileService) {
this._fileService = fileService;
}
getFrpLogContent(): Promise<string> {
return new Promise((resolve, reject) => {
fs.readFile(this._logPath, "utf-8", (error, data) => {
if (!error) {
resolve(data);
} else {
reject(error);
}
});
});
}
watchFrpcLog(win: BrowserWindow) {
fs.watch(this._logPath, (eventType, filename) => {
if (eventType === "change") {
win.webContents.send(
"log/watchFrpcLogContent.hook",
success(true)
)
} else {
}
});
// return new Promise<boolean>((resolve, reject) => {
//
// });
}
openFrpcLogFile(): Promise<boolean> {
return new Promise<boolean>((resolve, reject) => {
this._fileService
.openFile(this._logPath)
.then(result => {
resolve(result);
})
.catch(err => {
reject(err);
});
});
}
}
export default LogService;

View File

@ -0,0 +1,12 @@
import BaseService from "./BaseService";
import ServerDao from "../dao/ServerDao";
class ServerService extends BaseService<FrpcDesktopServer> {
constructor(serverDao: ServerDao) {
super(serverDao);
}
saveServerConfig(frpcServer: FrpcDesktopServer) {}
}
export default ServerService;

View File

@ -0,0 +1,17 @@
export function success<T>(data: any, message?: string) {
const resp: ApiResponse<T> = {
success: true,
data: data,
message: message || "successful."
};
return resp;
}
export function fail(message?: string) {
const resp: ApiResponse<any> = {
success: false,
data: null,
message: message || "internal error."
};
return resp;
}

View File

@ -1,9 +1,9 @@
<script lang="ts" setup>
import { createVNode, defineComponent, onMounted, onUnmounted, ref } from "vue";
import { defineComponent, onMounted, onUnmounted, ref } from "vue";
import Breadcrumb from "@/layout/compoenets/Breadcrumb.vue";
import { ipcRenderer } from "electron";
import IconifyIconOffline from "@/components/IconifyIcon/src/iconifyIconOffline";
import { useDebounce, useDebounceFn } from "@vueuse/core";
import { useDebounceFn } from "@vueuse/core";
import { ElMessage } from "element-plus";
defineComponent({
@ -12,7 +12,7 @@ defineComponent({
const loggerContent = ref('<div class="text-white">暂无日志</div>');
const handleLog2Html = (logContent: string) => {
const formatLogContent = (logContent: string) => {
const logs = logContent
.split("\n")
.filter(f => f)
@ -31,20 +31,16 @@ const handleLog2Html = (logContent: string) => {
});
return logs.reverse().join("");
};
const refreshStatus = ref(false);
const logLoading = ref(true);
// const isWatch = ref(false);
onMounted(() => {
console.log('logger mounted')
ipcRenderer.send("logger.getLog");
ipcRenderer.on("Logger.getLog.hook", (event, args) => {
// console.log("", args, args.indexOf("\n"));
// const logs = args.split("\n");
// console.log(logs, "2");
if (args) {
loggerContent.value = handleLog2Html(args);
ipcRenderer.send("log/getFrpLogContent");
ipcRenderer.on("log/getFrpLogContent.hook", (event, args) => {
const { success, data } = args;
if (success) {
loggerContent.value = formatLogContent(data);
}
logLoading.value = false;
if (refreshStatus.value) {
@ -54,18 +50,36 @@ onMounted(() => {
message: "刷新成功"
});
} else {
ipcRenderer.send("logger.update");
// if (!isWatch.value) {
// // ipcRenderer.send("log/watchFrpcLogContent");
// isWatch.value = true;
// }
}
});
ipcRenderer.on("Logger.update.hook", (event, args) => {
console.log("logger update hook", 1);
if (args) {
loggerContent.value = handleLog2Html(args);
ipcRenderer.on("log/watchFrpcLogContent.hook", (event, args) => {
console.log(event,'eevent');
console.log("watchFrpcLogContent", args);
const { success, data } = args;
if (success && data) {
ipcRenderer.send("log/getFrpLogContent");
}
// if (args) {
// loggerContent.value = formatLogContent(args);
// }
});
ipcRenderer.on("Logger.openLog.hook", (event, args) => {
if (args) {
// ipcRenderer.on("log/watchFrpcLogContent.hook", (event, args) => {
// console.log("watchFrpcLogContent", args);
// const { success, data } = args;
// if (success && data) {
// ipcRenderer.send("log/getFrpLogContent");
// }
// // if (args) {
// // loggerContent.value = formatLogContent(args);
// // }
// });
ipcRenderer.on("log/openFrpcLogFile.hook", (event, args) => {
const { success } = args;
if (success) {
ElMessage({
type: "success",
message: "打开日志成功"
@ -75,7 +89,7 @@ onMounted(() => {
});
const openLocalLog = useDebounceFn(() => {
ipcRenderer.send("logger.openLog");
ipcRenderer.send("log/openFrpcLogFile");
}, 1000);
const refreshLog = useDebounceFn(() => {
@ -86,13 +100,12 @@ const refreshLog = useDebounceFn(() => {
// });
refreshStatus.value = true;
logLoading.value = true;
ipcRenderer.send("logger.getLog");
ipcRenderer.send("log/getFrpLogContent");
}, 300);
onUnmounted(() => {
console.log('logger unmounted')
ipcRenderer.removeAllListeners("Logger.getLog.hook");
ipcRenderer.removeAllListeners("Logger.openLog.hook");
ipcRenderer.removeAllListeners("log/getFrpLogContent.hook");
ipcRenderer.removeAllListeners("log/openFrpcLogFile.hook");
});
</script>
<template>

12
types/core.d.ts vendored Normal file
View File

@ -0,0 +1,12 @@
interface ApiResponse<T> {
success: boolean;
data: T;
message: string;
}
interface ControllerRequest {
win: BrowserWindow;
reply: string;
event: Electron.IpcMainEvent;
args: any[];
}

46
types/frp.d.ts vendored Normal file
View File

@ -0,0 +1,46 @@
type LogConfig = {
to: string;
level: string;
maxDays: number;
disablePrintColor: boolean;
};
type AuthConfig = {
method: string;
token: string;
};
type WebServerConfig = {
addr: string;
port: number;
user: string;
password: string;
pprofEnable: boolean;
};
type TransportConfig = {
poolCount: number;
protocol: string;
connectServerLocalIP: string;
};
interface FrpcCommonConfig {
user: string;
serverAddr: string;
serverPort: number;
loginFailExit: boolean;
log: LogConfig;
auth: AuthConfig;
webServer: WebServerConfig;
transport: TransportConfig;
udpPacketSize: number;
// metadatas: MetadataConfig;
}
interface FrpcProxyConfig {
name: string;
type: string;
localIP: string;
localPort: number;
remotePort: number;
}

3
types/frpc-desktop.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
type FrpcDesktopProxy = FrpcProxyConfig & {};
type FrpcDesktopServer = FrpcCommonConfig & {};