mirror of
https://github.com/MasterAcnolo/Freedom-Loader.git
synced 2026-11-13 15:09:20 +01:00
feat(bugReport): add service status check and update UI if sendReport server is down
This commit is contained in:
@@ -19,7 +19,7 @@ const config = require("../config");
|
|||||||
const { validateDownloadPath, getDefaultDownloadPath } = require("./pathValidator");
|
const { validateDownloadPath, getDefaultDownloadPath } = require("./pathValidator");
|
||||||
const { userThemesPath } = require("../server/helpers/path.helpers");
|
const { userThemesPath } = require("../server/helpers/path.helpers");
|
||||||
const { createSystemTray, destroyTray } = require("./tray");
|
const { createSystemTray, destroyTray } = require("./tray");
|
||||||
const { sendReport } = require("./sendReport");
|
const {sendReport, checkReportService, getReportServiceStatus} = require("./sendReport");
|
||||||
const { isUpdateAvailable, downloadUpdate, installUpdate } = require("./autoUpdater");
|
const { isUpdateAvailable, downloadUpdate, installUpdate } = require("./autoUpdater");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -210,6 +210,11 @@ function registerIpcHandlers(getMainWindow) {
|
|||||||
return await sendReport(params);
|
return await sendReport(params);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipcMain.handle("get-report-service-status", async () => {
|
||||||
|
await checkReportService();
|
||||||
|
return getReportServiceStatus();
|
||||||
|
});
|
||||||
|
|
||||||
ipcMain.handle("is-update-available", () => {
|
ipcMain.handle("is-update-available", () => {
|
||||||
return isUpdateAvailable();
|
return isUpdateAvailable();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,6 +2,58 @@ const fs = require("fs");
|
|||||||
const path = require("path");
|
const path = require("path");
|
||||||
const {logger, logDir} = require("../server/logger");
|
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) {
|
async function sendReport(params) {
|
||||||
try {
|
try {
|
||||||
const {title, description, includeLogs} = params;
|
const {title, description, includeLogs} = params;
|
||||||
@@ -35,13 +87,7 @@ async function sendReport(params) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const reportUrl = process.env.BUG_REPORT_URL;
|
const response = await fetch(REPORT_URL, {
|
||||||
|
|
||||||
if (!reportUrl) {
|
|
||||||
throw new Error("Bug report service is not configured. Missing BUG_REPORT_URL on backend.");
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await fetch(reportUrl, {
|
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: formData
|
body: formData
|
||||||
});
|
});
|
||||||
@@ -59,4 +105,4 @@ async function sendReport(params) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {sendReport};
|
module.exports = {sendReport, checkReportService, getReportServiceStatus};
|
||||||
4
main.js
4
main.js
@@ -77,6 +77,7 @@ const { createSplashWindow, closeSplashWindow, setSplashProgress } = require("./
|
|||||||
const { userThemesPath, initUserThemes, validateBinaries, defaultDownloadFolder } = require("./server/helpers/path.helpers");
|
const { userThemesPath, initUserThemes, validateBinaries, defaultDownloadFolder } = require("./server/helpers/path.helpers");
|
||||||
const {createSystemTray, destroyTray} = require("./app/tray");
|
const {createSystemTray, destroyTray} = require("./app/tray");
|
||||||
const { stopServer } = require("./server/server");
|
const { stopServer } = require("./server/server");
|
||||||
|
const {checkReportService} = require("./app/sendReport");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expose .env in process.env
|
* Expose .env in process.env
|
||||||
@@ -137,6 +138,9 @@ app.on("second-instance", () => {
|
|||||||
|
|
||||||
app.whenReady().then(async () => {
|
app.whenReady().then(async () => {
|
||||||
logSessionStart(logDir, defaultDownloadFolder);
|
logSessionStart(logDir, defaultDownloadFolder);
|
||||||
|
checkReportService().catch((err) => {
|
||||||
|
logger.warn(`Bug report service startup check failed: ${err.message}`);
|
||||||
|
});
|
||||||
|
|
||||||
createSplashWindow();
|
createSplashWindow();
|
||||||
|
|
||||||
|
|||||||
@@ -214,4 +214,9 @@ contextBridge.exposeInMainWorld("topbarAPI", {
|
|||||||
* @returns {Promise<any>}
|
* @returns {Promise<any>}
|
||||||
*/
|
*/
|
||||||
sendReport: (params) => ipcRenderer.invoke("send-report", params),
|
sendReport: (params) => ipcRenderer.invoke("send-report", params),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the startup health status of the bug report service.
|
||||||
|
*/
|
||||||
|
getReportServiceStatus: () => ipcRenderer.invoke("get-report-service-status"),
|
||||||
});
|
});
|
||||||
@@ -29,9 +29,13 @@ class BugReportModal {
|
|||||||
<option value="no" style="background:#2a2a2a !important; color:#ffffff !important;">No</option>
|
<option value="no" style="background:#2a2a2a !important; color:#ffffff !important;">No</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="bugReportServiceStatus" role="status" aria-live="polite" style="display:none !important; align-items:center !important; gap:8px !important; color:#aaaaaa !important; font-size:0.8rem !important;">
|
||||||
|
<span id="bugReportServiceStatusDot" style="width:8px !important; height:8px !important; border-radius:50% !important; background:#f59e0b !important; flex-shrink:0 !important;"></span>
|
||||||
|
<span id="bugReportServiceStatusText">Checking bug report service...</span>
|
||||||
|
</div>
|
||||||
<div style="display:flex !important; justify-content:flex-end !important; gap:8px !important; margin-top:8px !important;">
|
<div style="display:flex !important; justify-content:flex-end !important; gap:8px !important; margin-top:8px !important;">
|
||||||
<button type="button" id="bugCancelBtn" style="background:#333333 !important; border:none !important; color:#cccccc !important; padding:8px 14px !important; border-radius:6px !important; cursor:pointer !important;">Cancel</button>
|
<button type="button" id="bugCancelBtn" style="background:#333333 !important; border:none !important; color:#cccccc !important; padding:8px 14px !important; border-radius:6px !important; cursor:pointer !important;">Cancel</button>
|
||||||
<button type="submit" style="background:#4f46e5 !important; border:none !important; color:#ffffff !important; padding:8px 16px !important; border-radius:6px !important; cursor:pointer !important; font-weight:500 !important;">Send</button>
|
<button type="submit" id="bugSendBtn" disabled style="background:#4f46e5 !important; border:none !important; color:#ffffff !important; padding:8px 16px !important; border-radius:6px !important; cursor:not-allowed !important; opacity:0.5 !important; font-weight:500 !important;">Send</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -46,6 +50,7 @@ class BugReportModal {
|
|||||||
bindEvents() {
|
bindEvents() {
|
||||||
const titleInput = this.modal.querySelector("#bugTitle");
|
const titleInput = this.modal.querySelector("#bugTitle");
|
||||||
const descInput = this.modal.querySelector("#bugDescription");
|
const descInput = this.modal.querySelector("#bugDescription");
|
||||||
|
const sendButton = this.modal.querySelector("#bugSendBtn");
|
||||||
|
|
||||||
titleInput.addEventListener("input", () => {
|
titleInput.addEventListener("input", () => {
|
||||||
localStorage.setItem("draft_bug_title", titleInput.value);
|
localStorage.setItem("draft_bug_title", titleInput.value);
|
||||||
@@ -67,6 +72,10 @@ class BugReportModal {
|
|||||||
|
|
||||||
this.form.addEventListener("submit", async (e) => {
|
this.form.addEventListener("submit", async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
if (sendButton.disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
title: titleInput.value,
|
title: titleInput.value,
|
||||||
description: descInput.value,
|
description: descInput.value,
|
||||||
@@ -107,11 +116,46 @@ class BugReportModal {
|
|||||||
open() {
|
open() {
|
||||||
this.loadState();
|
this.loadState();
|
||||||
this.modal.style.display = "flex";
|
this.modal.style.display = "flex";
|
||||||
|
this.updateServiceStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
this.modal.style.display = "none";
|
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();
|
window.bugModal = new BugReportModal();
|
||||||
|
|||||||
Reference in New Issue
Block a user