From 1c0dd32732751e332db8340d313297eaf6999410 Mon Sep 17 00:00:00 2001 From: MasterAcnolo Date: Tue, 29 Sep 2026 21:30:20 +0200 Subject: [PATCH] feat(bugReport): add service status check and update UI if sendReport server is down --- app/ipcHandlers.js | 7 ++++- app/sendReport.js | 62 +++++++++++++++++++++++++++++++++----- main.js | 4 +++ preload.js | 5 +++ public/script/reportBug.js | 46 +++++++++++++++++++++++++++- 5 files changed, 114 insertions(+), 10 deletions(-) diff --git a/app/ipcHandlers.js b/app/ipcHandlers.js index 15dd06b..a82ed90 100644 --- a/app/ipcHandlers.js +++ b/app/ipcHandlers.js @@ -19,7 +19,7 @@ const config = require("../config"); const { validateDownloadPath, getDefaultDownloadPath } = require("./pathValidator"); const { userThemesPath } = require("../server/helpers/path.helpers"); const { createSystemTray, destroyTray } = require("./tray"); -const { sendReport } = require("./sendReport"); +const {sendReport, checkReportService, getReportServiceStatus} = require("./sendReport"); const { isUpdateAvailable, downloadUpdate, installUpdate } = require("./autoUpdater"); /** @@ -210,6 +210,11 @@ function registerIpcHandlers(getMainWindow) { return await sendReport(params); }); + ipcMain.handle("get-report-service-status", async () => { + await checkReportService(); + return getReportServiceStatus(); + }); + ipcMain.handle("is-update-available", () => { return isUpdateAvailable(); }); diff --git a/app/sendReport.js b/app/sendReport.js index 8ee05b5..e37266b 100644 --- a/app/sendReport.js +++ b/app/sendReport.js @@ -2,6 +2,58 @@ const fs = require("fs"); const path = require("path"); const {logger, logDir} = require("../server/logger"); +const REPORT_URL = "https://freedom-loader-report.acnolo.fr"; +const REPORT_SERVICE_TIMEOUT_MS = 5000; +let reportServiceStatus = { + status: "checking", + message: "Checking bug report service..." +}; +let reportServiceCheck = null; + +async function checkReportService() { + if (reportServiceCheck) { + return reportServiceCheck; + } + + reportServiceCheck = (async () => { + const controller = new AbortController(); + const timeout = setTimeout(() => controller.abort(), REPORT_SERVICE_TIMEOUT_MS); + + try { + const response = await fetch(REPORT_URL, { + method: "GET", + signal: controller.signal + }); + + if (response.status >= 500) { + throw new Error(`Server responded with status ${response.status}`); + } + + reportServiceStatus = { + status: "online", + message: "Bug report service is available." + }; + logger.info(`Bug report service is reachable (status ${response.status}).`); + } catch (err) { + reportServiceStatus = { + status: "offline", + message: "Bug report service is unavailable. Reports may fail to send." + }; + logger.warn(`Bug report service is unreachable: ${err.message}`); + } finally { + clearTimeout(timeout); + } + + return reportServiceStatus; + })(); + + return reportServiceCheck; +} + +function getReportServiceStatus() { + return reportServiceStatus; +} + async function sendReport(params) { try { const {title, description, includeLogs} = params; @@ -35,13 +87,7 @@ async function sendReport(params) { } } - const reportUrl = process.env.BUG_REPORT_URL; - - if (!reportUrl) { - throw new Error("Bug report service is not configured. Missing BUG_REPORT_URL on backend."); - } - - const response = await fetch(reportUrl, { + const response = await fetch(REPORT_URL, { method: "POST", body: formData }); @@ -59,4 +105,4 @@ async function sendReport(params) { } } -module.exports = {sendReport}; \ No newline at end of file +module.exports = {sendReport, checkReportService, getReportServiceStatus}; \ No newline at end of file diff --git a/main.js b/main.js index dd3b873..eac9fad 100644 --- a/main.js +++ b/main.js @@ -77,6 +77,7 @@ const { createSplashWindow, closeSplashWindow, setSplashProgress } = require("./ const { userThemesPath, initUserThemes, validateBinaries, defaultDownloadFolder } = require("./server/helpers/path.helpers"); const {createSystemTray, destroyTray} = require("./app/tray"); const { stopServer } = require("./server/server"); +const {checkReportService} = require("./app/sendReport"); /** * Expose .env in process.env @@ -137,6 +138,9 @@ app.on("second-instance", () => { app.whenReady().then(async () => { logSessionStart(logDir, defaultDownloadFolder); + checkReportService().catch((err) => { + logger.warn(`Bug report service startup check failed: ${err.message}`); + }); createSplashWindow(); diff --git a/preload.js b/preload.js index b05d6a6..c00d797 100644 --- a/preload.js +++ b/preload.js @@ -214,4 +214,9 @@ contextBridge.exposeInMainWorld("topbarAPI", { * @returns {Promise} */ sendReport: (params) => ipcRenderer.invoke("send-report", params), + + /** + * Returns the startup health status of the bug report service. + */ + getReportServiceStatus: () => ipcRenderer.invoke("get-report-service-status"), }); \ No newline at end of file diff --git a/public/script/reportBug.js b/public/script/reportBug.js index 69b428a..650174c 100644 --- a/public/script/reportBug.js +++ b/public/script/reportBug.js @@ -29,9 +29,13 @@ class BugReportModal { +
+ + Checking bug report service... +
- +
@@ -46,6 +50,7 @@ class BugReportModal { bindEvents() { const titleInput = this.modal.querySelector("#bugTitle"); const descInput = this.modal.querySelector("#bugDescription"); + const sendButton = this.modal.querySelector("#bugSendBtn"); titleInput.addEventListener("input", () => { localStorage.setItem("draft_bug_title", titleInput.value); @@ -67,6 +72,10 @@ class BugReportModal { this.form.addEventListener("submit", async (e) => { e.preventDefault(); + if (sendButton.disabled) { + return; + } + const data = { title: titleInput.value, description: descInput.value, @@ -107,11 +116,46 @@ class BugReportModal { open() { this.loadState(); this.modal.style.display = "flex"; + this.updateServiceStatus(); } close() { this.modal.style.display = "none"; } + + async updateServiceStatus() { + const statusText = this.modal.querySelector("#bugReportServiceStatusText"); + const statusDot = this.modal.querySelector("#bugReportServiceStatusDot"); + const sendButton = this.modal.querySelector("#bugSendBtn"); + + sendButton.disabled = true; + sendButton.style.setProperty("cursor", "not-allowed", "important"); + sendButton.style.setProperty("opacity", "0.5", "important"); + + try { + const serviceStatus = await window.topbarAPI.getReportServiceStatus(); + const serviceAvailable = serviceStatus.status === "online"; + const statusVisible = !serviceAvailable; + statusText.textContent = serviceStatus.message; + statusDot.style.background = "#ef4444"; + statusText.style.color = "#fca5a5"; + this.modal.querySelector("#bugReportServiceStatus").style.setProperty( + "display", + statusVisible ? "flex" : "none", + "important" + ); + sendButton.disabled = !serviceAvailable; + sendButton.style.setProperty("cursor", serviceAvailable ? "pointer" : "not-allowed", "important"); + sendButton.style.setProperty("opacity", serviceAvailable ? "1" : "0.5", "important"); + } catch (err) { + statusText.textContent = "Unable to check bug report service."; + statusDot.style.background = "#ef4444"; + statusText.style.color = "#fca5a5"; + this.modal.querySelector("#bugReportServiceStatus").style.setProperty("display", "flex", "important"); + sendButton.disabled = true; + window.electronAPI.logError("Failed to retrieve bug report service status:", err.message); + } + } } window.bugModal = new BugReportModal();