From efd68fb4532daf9bd392eb819fb59333b9e108dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E5=98=89=E4=BC=9F?= <8473136@qq.com> Date: Tue, 25 Feb 2025 23:01:57 +0800 Subject: [PATCH] :building_construction: refactor error handling in controllers to utilize BusinessError and enhance response structure --- electron/controller/ConfigController.ts | 55 ++++++++++++++++++------ electron/controller/LaunchController.ts | 3 +- electron/controller/LogController.ts | 6 +-- electron/controller/ProxyController.ts | 12 +++--- electron/controller/SystemController.ts | 11 ++--- electron/controller/VersionController.ts | 8 ++-- electron/core/BusinessError.ts | 28 ++++++++++++ electron/service/FrpcProcessService.ts | 4 +- electron/service/ServerService.ts | 4 +- electron/utils/ResponseUtils.ts | 27 ++++++++++-- src/utils/ipcUtils.ts | 24 ++++++++--- src/views/config/index.vue | 31 +++++++------ src/views/home/index.vue | 39 ++++++++++++----- types/core.d.ts | 2 +- 14 files changed, 183 insertions(+), 71 deletions(-) create mode 100644 electron/core/BusinessError.ts diff --git a/electron/controller/ConfigController.ts b/electron/controller/ConfigController.ts index 3b32236..c46d14b 100644 --- a/electron/controller/ConfigController.ts +++ b/electron/controller/ConfigController.ts @@ -6,8 +6,9 @@ import FrpcProcessService from "../service/FrpcProcessService"; import SystemService from "../service/SystemService"; import moment from "moment"; import ResponseUtils from "../utils/ResponseUtils"; -import { dialog } from "electron"; +import { BrowserWindow, dialog } from "electron"; import Logger from "../core/Logger"; +import BeanFactory from "../core/BeanFactory"; class ConfigController extends BaseController { private readonly _serverService: ServerService; @@ -33,7 +34,7 @@ class ConfigController extends BaseController { }) .catch((err: Error) => { Logger.error("ConfigController.saveConfig", err); - req.event.reply(req.channel, ResponseUtils.fail(err.message)); + req.event.reply(req.channel, ResponseUtils.fail(err)); }); } @@ -45,7 +46,7 @@ class ConfigController extends BaseController { }) .catch((err: Error) => { Logger.error("ConfigController.getServerConfig", err); - req.event.reply(req.channel, ResponseUtils.fail(err.message)); + req.event.reply(req.channel, ResponseUtils.fail(err)); }); } @@ -57,7 +58,7 @@ class ConfigController extends BaseController { }) .catch((err: Error) => { Logger.error("ConfigController.openAppData", err); - req.event.reply(req.channel, ResponseUtils.fail(err.message)); + req.event.reply(req.channel, ResponseUtils.fail(err)); }); } @@ -91,7 +92,7 @@ class ConfigController extends BaseController { }) .catch((err: Error) => { Logger.error("ConfigController.resetAllConfig", err); - req.event.reply(req.channel, ResponseUtils.fail(err.message)); + req.event.reply(req.channel, ResponseUtils.fail(err)); }); } @@ -126,20 +127,48 @@ class ConfigController extends BaseController { }) .catch((err: Error) => { Logger.error("ConfigController.exportConfig", err); - req.event.reply(req.channel, ResponseUtils.fail(err.message)); + req.event.reply(req.channel, ResponseUtils.fail(err)); }); } importTomlConfig(req: ControllerParam) { - this._serverService - .importTomlConfig() - .then(() => { - req.event.reply(req.channel, ResponseUtils.success()); + const win: BrowserWindow = BeanFactory.getBean("win"); + dialog + .showOpenDialog(win, { + properties: ["openFile"], + filters: [{ name: "Frpc Toml ConfigFile", extensions: ["toml"] }] }) - .catch((err: Error) => { - Logger.error("ConfigController.importTomlConfig", err); - req.event.reply(req.channel, ResponseUtils.fail(err.message)); + .then(result => { + if (result.canceled) { + req.event.reply( + req.channel, + ResponseUtils.success({ + canceled: true, + path: "" + }) + ); + } else { + req.event.reply( + req.channel, + ResponseUtils.success({ + canceled: false, + path: "" + }) + ); + } }); + // if (result.canceled) { + // } else { + // } + // this._serverService + // .importTomlConfig() + // .then(() => { + // req.event.reply(req.channel, ResponseUtils.success()); + // }) + // .catch((err: Error) => { + // Logger.error("ConfigController.importTomlConfig", err); + // req.event.reply(req.channel, ResponseUtils.fail(err)); + // }); } } diff --git a/electron/controller/LaunchController.ts b/electron/controller/LaunchController.ts index f85a1ed..5499daa 100644 --- a/electron/controller/LaunchController.ts +++ b/electron/controller/LaunchController.ts @@ -19,7 +19,7 @@ class LaunchController extends BaseController { }) .catch((err: Error) => { Logger.error("LaunchController.launch", err); - req.event.reply(req.channel, ResponseUtils.fail(err.message)); + req.event.reply(req.channel, ResponseUtils.fail(err)); }); } @@ -31,6 +31,7 @@ class LaunchController extends BaseController { }) .catch(err => { Logger.error("LaunchController.terminate", err); + req.event.reply(req.channel, ResponseUtils.fail(err)); }); } diff --git a/electron/controller/LogController.ts b/electron/controller/LogController.ts index 63bbe16..a9294cc 100644 --- a/electron/controller/LogController.ts +++ b/electron/controller/LogController.ts @@ -19,7 +19,7 @@ class LogController extends BaseController { }) .catch((err: Error) => { Logger.error("LogController.getFrpLogContent", err); - req.event.reply(req.channel, ResponseUtils.fail(err.message)); + req.event.reply(req.channel, ResponseUtils.fail(err)); }); } @@ -37,12 +37,12 @@ class LogController extends BaseController { if (data) { ResponseUtils.success(); } else { - ResponseUtils.fail(); + // ResponseUtils.fail(); } }) .catch((err: Error) => { Logger.error("LogController.openFrpcLogFile", err); - req.event.reply(req.channel, ResponseUtils.fail(err.message)); + req.event.reply(req.channel, ResponseUtils.fail(err)); }); } } diff --git a/electron/controller/ProxyController.ts b/electron/controller/ProxyController.ts index 2bd0c61..bf5fa0f 100644 --- a/electron/controller/ProxyController.ts +++ b/electron/controller/ProxyController.ts @@ -22,7 +22,7 @@ class ProxyController extends BaseController { }) .catch((err: Error) => { Logger.error("ProxyController.createProxy", err); - req.event.reply(req.channel, ResponseUtils.fail(err.message)); + req.event.reply(req.channel, ResponseUtils.fail(err)); }); } @@ -34,7 +34,7 @@ class ProxyController extends BaseController { }) .catch((err: Error) => { Logger.error("ProxyController.modifyProxy", err); - req.event.reply(req.channel, ResponseUtils.fail(err.message)); + req.event.reply(req.channel, ResponseUtils.fail(err)); }); } @@ -46,7 +46,7 @@ class ProxyController extends BaseController { }) .catch((err: Error) => { Logger.error("ProxyController.getAllProxies", err); - req.event.reply(req.channel, ResponseUtils.fail(err.message)); + req.event.reply(req.channel, ResponseUtils.fail(err)); }); } @@ -58,7 +58,7 @@ class ProxyController extends BaseController { }) .catch((err: Error) => { Logger.error("ProxyController.deleteProxy", err); - req.event.reply(req.channel, ResponseUtils.fail(err.message)); + req.event.reply(req.channel, ResponseUtils.fail(err)); }); } @@ -70,7 +70,7 @@ class ProxyController extends BaseController { }) .catch((err: Error) => { Logger.error("ProxyController.modifyProxyStatus", err); - req.event.reply(req.channel, ResponseUtils.fail(err.message)); + req.event.reply(req.channel, ResponseUtils.fail(err)); }); } @@ -82,7 +82,7 @@ class ProxyController extends BaseController { }) .catch((err: Error) => { Logger.error("ProxyController.getLocalPorts", err); - req.event.reply(req.channel, ResponseUtils.fail(err.message)); + req.event.reply(req.channel, ResponseUtils.fail(err)); }); } } diff --git a/electron/controller/SystemController.ts b/electron/controller/SystemController.ts index 501eca4..62c2e23 100644 --- a/electron/controller/SystemController.ts +++ b/electron/controller/SystemController.ts @@ -20,7 +20,7 @@ class SystemController { }) .catch((err: Error) => { Logger.error("SystemController.openUrl", err); - req.event.reply(req.channel, ResponseUtils.fail(err.message)); + req.event.reply(req.channel, ResponseUtils.fail(err)); }); } @@ -32,7 +32,7 @@ class SystemController { }) .catch((err: Error) => { Logger.error("SystemController.relaunchApp", err); - req.event.reply(req.channel, ResponseUtils.fail(err.message)); + req.event.reply(req.channel, ResponseUtils.fail(err)); }); } @@ -44,14 +44,15 @@ class SystemController { }) .catch((err: Error) => { Logger.error("SystemController.openAppData", err); - req.event.reply(req.channel, ResponseUtils.fail(err.message)); + req.event.reply(req.channel, ResponseUtils.fail(err)); }); } selectLocalFile(req: ControllerParam) { const { name, extensions } = req.args; if (!extensions || extensions.length === 0) { - req.event.reply(req.channel, ResponseUtils.fail("可选择扩展名不能为空")); + return; + // req.event.reply(req.channel, ResponseUtils.fail("可选择扩展名不能为空")); } const win: BrowserWindow = BeanFactory.getBean("win"); dialog @@ -75,7 +76,7 @@ class SystemController { }) .catch((err: Error) => { Logger.error("SystemController.selectLocalFile", err); - req.event.reply(req.channel, ResponseUtils.fail(err.message)); + req.event.reply(req.channel, ResponseUtils.fail(err)); }); } } diff --git a/electron/controller/VersionController.ts b/electron/controller/VersionController.ts index 5bc4367..4932d27 100644 --- a/electron/controller/VersionController.ts +++ b/electron/controller/VersionController.ts @@ -36,7 +36,7 @@ class VersionController extends BaseController { }) .catch((err: Error) => { Logger.error("VersionController.getDownloadedVersions", err); - req.event.reply(req.channel, ResponseUtils.fail(err.message)); + req.event.reply(req.channel, ResponseUtils.fail(err)); }); } @@ -64,7 +64,7 @@ class VersionController extends BaseController { }) .catch((err: Error) => { Logger.error("VersionController.downloadFrpVersion", err); - req.event.reply(req.channel, ResponseUtils.fail(err.message)); + req.event.reply(req.channel, ResponseUtils.fail(err)); }); } @@ -76,7 +76,7 @@ class VersionController extends BaseController { }) .catch((err: Error) => { Logger.error("VersionController.deleteDownloadedVersion", err); - req.event.reply(req.channel, ResponseUtils.fail(err.message)); + req.event.reply(req.channel, ResponseUtils.fail(err)); }); } @@ -88,7 +88,7 @@ class VersionController extends BaseController { }) .catch((err: Error) => { Logger.error("VersionController.importLocalFrpcVersion", err); - req.event.reply(req.channel, ResponseUtils.fail(err.message)); + req.event.reply(req.channel, ResponseUtils.fail(err)); }); } } diff --git a/electron/core/BusinessError.ts b/electron/core/BusinessError.ts new file mode 100644 index 0000000..44f05b1 --- /dev/null +++ b/electron/core/BusinessError.ts @@ -0,0 +1,28 @@ + +enum ResponseCode { + SUCCESS = "A1000:successful.", + INTERNAL_ERROR = "B1000:internal error.", + NOT_CONFIG = "B1001:未配置" +} + +class BusinessError extends Error { + private readonly _bizCode: string; + // constructor(bizCode: string, message: string) { + // super(message); + // this.bizCode = bizCode; + // this.name = "BusinessError"; + // } + + constructor(bizErrorEnum: ResponseCode) { + const [bizCode, message] = bizErrorEnum.split(":"); + super(message); + this._bizCode = bizCode; + this.name = "BusinessError"; + } + + get bizCode(): string { + return this._bizCode; + } +} + +export { BusinessError, ResponseCode }; diff --git a/electron/service/FrpcProcessService.ts b/electron/service/FrpcProcessService.ts index 619fd16..49f5dc8 100644 --- a/electron/service/FrpcProcessService.ts +++ b/electron/service/FrpcProcessService.ts @@ -6,7 +6,7 @@ import { app, BrowserWindow, Notification } from "electron"; import treeKill from "tree-kill"; import BeanFactory from "../core/BeanFactory"; import ResponseUtils from "../utils/ResponseUtils"; -import Logger from "../core/Logger"; +import { BusinessError, ResponseCode } from "../core/BusinessError"; class FrpcProcessService { private readonly _serverService: ServerService; @@ -37,7 +37,7 @@ class FrpcProcessService { } const config = await this._serverService.getServerConfig(); if (!config) { - throw new Error("请先进行配置"); + throw new BusinessError(ResponseCode.NOT_CONFIG); } const version = await this._versionDao.findByGithubReleaseId( config.frpcVersion diff --git a/electron/service/ServerService.ts b/electron/service/ServerService.ts index 0502ace..5867db7 100644 --- a/electron/service/ServerService.ts +++ b/electron/service/ServerService.ts @@ -83,13 +83,13 @@ class ServerService extends BaseService { ] }); if (result.canceled) { + + }else { const filePath = result.filePaths[0]; const fileExtension = path.extname(filePath); if (fileExtension === GlobalConstant.TOML_EXT) { const tomlData = fs.readFileSync(filePath, "utf-8"); const sourceConfig = TOML.parse(tomlData); - console.log('1'); - // todo Persistent } else { throw new Error(`导入失败,暂不支持 ${fileExtension} 格式文件`); } diff --git a/electron/utils/ResponseUtils.ts b/electron/utils/ResponseUtils.ts index db3c70c..0d61a7d 100644 --- a/electron/utils/ResponseUtils.ts +++ b/electron/utils/ResponseUtils.ts @@ -1,16 +1,35 @@ +import { BusinessError, ResponseCode } from "../core/BusinessError"; + class ResponseUtils { public static success(data?: any, message?: string) { + const [bizCode, message2] = ResponseCode.SUCCESS.split(":"); const resp: ApiResponse = { - success: true, + bizCode: bizCode, data: data, - message: message || "successful." + message: message || message2 }; return resp; } - public static fail(message?: string) { + // public static fail(bizCode?: string, message?: string) { + // const resp: ApiResponse = { + // success: false, + // bizCode: bizCode, + // data: null, + // message: message || "internal error." + // }; + // return resp; + // } + + public static fail(err: Error) { + let bizCode = ""; + let message = ""; + if (err instanceof BusinessError) { + bizCode = (err as BusinessError).bizCode; + message = (err as BusinessError).message; + } const resp: ApiResponse = { - success: false, + bizCode: bizCode, data: null, message: message || "internal error." }; diff --git a/src/utils/ipcUtils.ts b/src/utils/ipcUtils.ts index 6864861..55f83d2 100644 --- a/src/utils/ipcUtils.ts +++ b/src/utils/ipcUtils.ts @@ -1,4 +1,5 @@ import { ipcRenderer } from "electron"; +import { ElMessage } from "element-plus"; export const send = (router: IpcRouter, params?: any) => { ipcRenderer.send(router.path, params); @@ -21,12 +22,25 @@ export const send = (router: IpcRouter, params?: any) => { // }); // }; -export const on = (router: IpcRouter, listerHandler: (data: any) => void) => { +export const on = ( + router: IpcRouter, + listerHandler: (data: any) => void, + errHandler?: (bizCode: string, message: string) => void +) => { ipcRenderer.on(`${router.path}:hook`, (event, args: ApiResponse) => { - const { success, data, message } = args; - if (success) { + const { bizCode, data, message } = args; + if (bizCode === "A1000") { listerHandler(data); } else { + if (errHandler) { + errHandler(bizCode, message); + } else { + // ElMessageBox.alert(message,"出错了"); + ElMessage({ + message: message, + type: "error" + }); + } // reject(new Error(message)); } }); @@ -38,8 +52,8 @@ export const onListener = ( ) => { // return new Promise((resolve, reject) => { ipcRenderer.on(`${listener.channel}`, (event, args: ApiResponse) => { - const { success, data, message } = args; - if (success) { + const { bizCode, data, message } = args; + if (bizCode === "A1000") { listerHandler(data); } }); diff --git a/src/views/config/index.vue b/src/views/config/index.vue index 797f529..543818d 100644 --- a/src/views/config/index.vue +++ b/src/views/config/index.vue @@ -380,20 +380,23 @@ onMounted(() => { }); on(ipcRouters.SERVER.importTomlConfig, data => { - // 礼花 - confetti({ - zIndex: 12002, - particleCount: 200, - spread: 70, - origin: { y: 0.6 } - }); - ElMessageBox.alert("🎉 恭喜你,导入成功 请重启软件", `提示`, { - closeOnClickModal: false, - showClose: false, - confirmButtonText: "立即重启" - }).then(() => { - send(ipcRouters.SYSTEM.relaunchApp); - }); + const { canceled, path } = data; + if (!canceled) { + // 礼花 + confetti({ + zIndex: 12002, + particleCount: 200, + spread: 70, + origin: { y: 0.6 } + }); + ElMessageBox.alert("🎉 恭喜你,导入成功 请重启软件", `提示`, { + closeOnClickModal: false, + showClose: false, + confirmButtonText: "立即重启" + }).then(() => { + send(ipcRouters.SYSTEM.relaunchApp); + }); + } }); on(ipcRouters.SERVER.exportConfig, data => { diff --git a/src/views/home/index.vue b/src/views/home/index.vue index 59a3c8b..a66d422 100644 --- a/src/views/home/index.vue +++ b/src/views/home/index.vue @@ -2,9 +2,11 @@ import { defineComponent, onMounted, onUnmounted, ref } from "vue"; import Breadcrumb from "@/layout/compoenets/Breadcrumb.vue"; import { useDebounceFn } from "@vueuse/core"; -import { on, onListener, removeRouterListeners2, send } from "@/utils/ipcUtils"; -import { ipcRouters, listeners } from "../../../electron/core/IpcRouter"; +import { on, removeRouterListeners, send } from "@/utils/ipcUtils"; +import { ipcRouters } from "../../../electron/core/IpcRouter"; import { useFrpcProcessStore } from "@/store/frpcProcess"; +import { ElMessageBox } from "element-plus"; +import router from "@/router"; defineComponent({ name: "Home" @@ -12,7 +14,6 @@ defineComponent({ const frpcProcessStore = useFrpcProcessStore(); - // const running = ref(false); const loading = ref(false); @@ -34,14 +35,28 @@ const handleButtonClick = useDebounceFn(() => { }, 300); onMounted(() => { - - - - on(ipcRouters.LAUNCH.launch, () => { - // send(ipcRouters.LAUNCH.getStatus); - frpcProcessStore.refreshRunning(); - loading.value = false; - }); + on( + ipcRouters.LAUNCH.launch, + () => { + // send(ipcRouters.LAUNCH.getStatus); + frpcProcessStore.refreshRunning(); + loading.value = false; + }, + (bizCode: string, message: string) => { + if (bizCode === "B1001") { + ElMessageBox.alert("请先前往设置页面,修改配置后再启动", "提示", { + showCancelButton: true, + cancelButtonText: "取消", + confirmButtonText: "去设置" + }).then(() => { + router.replace({ + name: "Config" + }); + }); + } + loading.value = false; + } + ); on(ipcRouters.LAUNCH.terminate, () => { // send(ipcRouters.LAUNCH.getStatus); @@ -66,6 +81,8 @@ onMounted(() => { onUnmounted(() => { // ipcRenderer.removeAllListeners("Home.frpc.start.error.hook"); // removeRouterListeners2(listeners.watchFrpcProcess); + removeRouterListeners(ipcRouters.LAUNCH.launch); + removeRouterListeners(ipcRouters.LAUNCH.terminate); }); diff --git a/types/core.d.ts b/types/core.d.ts index b99d7d8..bd9d672 100644 --- a/types/core.d.ts +++ b/types/core.d.ts @@ -1,5 +1,5 @@ interface ApiResponse { - success: boolean; + bizCode: string; data: T; message: string; }