diff --git a/src/main.js b/src/main.js index 21793faa..a4129db8 100644 --- a/src/main.js +++ b/src/main.js @@ -20,6 +20,7 @@ import EditMonitor from "./pages/EditMonitor.vue"; import Settings from "./pages/Settings.vue"; import Setup from "./pages/Setup.vue"; import List from "./pages/List.vue"; +import StatusPage from "./pages/StatusPage.vue"; import { appName } from "./util.ts"; @@ -94,6 +95,10 @@ const routes = [ path: "/setup", component: Setup, }, + { + path: "/status-page", + component: StatusPage, + }, ] const router = createRouter({ diff --git a/src/mixins/socket.js b/src/mixins/socket.js index 9771db0d..5ffdf752 100644 --- a/src/mixins/socket.js +++ b/src/mixins/socket.js @@ -4,6 +4,10 @@ const toast = useToast() let socket; +const noSocketIOPage = [ + "/status-page", +]; + export default { data() { @@ -14,6 +18,8 @@ export default { firstConnect: true, connected: false, connectCount: 0, + initedSocketIO: false, + }, remember: (localStorage.remember !== "0"), allowLoginDialog: false, // Allowed to show login dialog, but "loggedIn" have to be true too. This exists because prevent the login dialog show 0.1s in first before the socket server auth-ed. @@ -31,162 +37,177 @@ export default { created() { window.addEventListener("resize", this.onResize); - - let protocol = (location.protocol === "https:") ? "wss://" : "ws://"; - - let wsHost; - const env = process.env.NODE_ENV || "production"; - if (env === "development" || localStorage.dev === "dev") { - wsHost = protocol + location.hostname + ":3001"; - } else { - wsHost = protocol + location.host; - } - - socket = io(wsHost, { - transports: ["websocket"], - }); - - socket.on("info", (info) => { - this.info = info; - }); - - socket.on("setup", (monitorID, data) => { - this.$router.push("/setup") - }); - - socket.on("autoLogin", (monitorID, data) => { - this.loggedIn = true; - this.storage().token = "autoLogin"; - this.allowLoginDialog = false; - }); - - socket.on("monitorList", (data) => { - // Add Helper function - Object.entries(data).forEach(([monitorID, monitor]) => { - monitor.getUrl = () => { - try { - return new URL(monitor.url); - } catch (_) { - return null; - } - }; - }); - this.monitorList = data; - }); - - socket.on("notificationList", (data) => { - this.notificationList = data; - }); - - socket.on("heartbeat", (data) => { - if (! (data.monitorID in this.heartbeatList)) { - this.heartbeatList[data.monitorID] = []; - } - - this.heartbeatList[data.monitorID].push(data) - - // Add to important list if it is important - // Also toast - if (data.important) { - - if (data.status === 0) { - toast.error(`[${this.monitorList[data.monitorID].name}] [DOWN] ${data.msg}`, { - timeout: false, - }); - } else if (data.status === 1) { - toast.success(`[${this.monitorList[data.monitorID].name}] [Up] ${data.msg}`, { - timeout: 20000, - }); - } else { - toast(`[${this.monitorList[data.monitorID].name}] ${data.msg}`); - } - - if (! (data.monitorID in this.importantHeartbeatList)) { - this.importantHeartbeatList[data.monitorID] = []; - } - - this.importantHeartbeatList[data.monitorID].unshift(data) - } - }); - - socket.on("heartbeatList", (monitorID, data, overwrite = false) => { - if (! (monitorID in this.heartbeatList) || overwrite) { - this.heartbeatList[monitorID] = data; - } else { - this.heartbeatList[monitorID] = data.concat(this.heartbeatList[monitorID]) - } - }); - - socket.on("avgPing", (monitorID, data) => { - this.avgPingList[monitorID] = data - }); - - socket.on("uptime", (monitorID, type, data) => { - this.uptimeList[`${monitorID}_${type}`] = data - }); - - socket.on("certInfo", (monitorID, data) => { - this.certInfoList[monitorID] = JSON.parse(data) - }); - - socket.on("importantHeartbeatList", (monitorID, data, overwrite) => { - if (! (monitorID in this.importantHeartbeatList) || overwrite) { - this.importantHeartbeatList[monitorID] = data; - } else { - this.importantHeartbeatList[monitorID] = data.concat(this.importantHeartbeatList[monitorID]) - } - }); - - socket.on("connect_error", (err) => { - console.error(`Failed to connect to the backend. Socket.io connect_error: ${err.message}`); - this.connectionErrorMsg = `Cannot connect to the socket server. [${err}] Reconnecting...`; - this.socket.connected = false; - this.socket.firstConnect = false; - }); - - socket.on("disconnect", () => { - console.log("disconnect") - this.connectionErrorMsg = "Lost connection to the socket server. Reconnecting..."; - this.socket.connected = false; - }); - - socket.on("connect", () => { - console.log("connect") - this.socket.connectCount++; - this.socket.connected = true; - - // Reset Heartbeat list if it is re-connect - if (this.socket.connectCount >= 2) { - this.clearData() - } - - let token = this.storage().token; - - if (token) { - if (token !== "autoLogin") { - this.loginByToken(token) - } else { - - // Timeout if it is not actually auto login - setTimeout(() => { - if (! this.loggedIn) { - this.allowLoginDialog = true; - this.$root.storage().removeItem("token"); - } - }, 5000); - - } - } else { - this.allowLoginDialog = true; - } - - this.socket.firstConnect = false; - }); - + this.initSocketIO(); }, methods: { + initSocketIO(bypass = false) { + // No need to re-init + if (this.socket.initedSocketIO) { + return; + } + + // No need to connect to the socket.io for status page + if (! bypass && noSocketIOPage.includes(location.pathname)) { + return; + } + + this.socket.initedSocketIO = true; + + let protocol = (location.protocol === "https:") ? "wss://" : "ws://"; + + let wsHost; + const env = process.env.NODE_ENV || "production"; + if (env === "development" || localStorage.dev === "dev") { + wsHost = protocol + location.hostname + ":3001"; + } else { + wsHost = protocol + location.host; + } + + socket = io(wsHost, { + transports: ["websocket"], + }); + + socket.on("info", (info) => { + this.info = info; + }); + + socket.on("setup", (monitorID, data) => { + this.$router.push("/setup") + }); + + socket.on("autoLogin", (monitorID, data) => { + this.loggedIn = true; + this.storage().token = "autoLogin"; + this.allowLoginDialog = false; + }); + + socket.on("monitorList", (data) => { + // Add Helper function + Object.entries(data).forEach(([monitorID, monitor]) => { + monitor.getUrl = () => { + try { + return new URL(monitor.url); + } catch (_) { + return null; + } + }; + }); + this.monitorList = data; + }); + + socket.on("notificationList", (data) => { + this.notificationList = data; + }); + + socket.on("heartbeat", (data) => { + if (! (data.monitorID in this.heartbeatList)) { + this.heartbeatList[data.monitorID] = []; + } + + this.heartbeatList[data.monitorID].push(data) + + // Add to important list if it is important + // Also toast + if (data.important) { + + if (data.status === 0) { + toast.error(`[${this.monitorList[data.monitorID].name}] [DOWN] ${data.msg}`, { + timeout: false, + }); + } else if (data.status === 1) { + toast.success(`[${this.monitorList[data.monitorID].name}] [Up] ${data.msg}`, { + timeout: 20000, + }); + } else { + toast(`[${this.monitorList[data.monitorID].name}] ${data.msg}`); + } + + if (! (data.monitorID in this.importantHeartbeatList)) { + this.importantHeartbeatList[data.monitorID] = []; + } + + this.importantHeartbeatList[data.monitorID].unshift(data) + } + }); + + socket.on("heartbeatList", (monitorID, data, overwrite = false) => { + if (! (monitorID in this.heartbeatList) || overwrite) { + this.heartbeatList[monitorID] = data; + } else { + this.heartbeatList[monitorID] = data.concat(this.heartbeatList[monitorID]) + } + }); + + socket.on("avgPing", (monitorID, data) => { + this.avgPingList[monitorID] = data + }); + + socket.on("uptime", (monitorID, type, data) => { + this.uptimeList[`${monitorID}_${type}`] = data + }); + + socket.on("certInfo", (monitorID, data) => { + this.certInfoList[monitorID] = JSON.parse(data) + }); + + socket.on("importantHeartbeatList", (monitorID, data, overwrite) => { + if (! (monitorID in this.importantHeartbeatList) || overwrite) { + this.importantHeartbeatList[monitorID] = data; + } else { + this.importantHeartbeatList[monitorID] = data.concat(this.importantHeartbeatList[monitorID]) + } + }); + + socket.on("connect_error", (err) => { + console.error(`Failed to connect to the backend. Socket.io connect_error: ${err.message}`); + this.connectionErrorMsg = `Cannot connect to the socket server. [${err}] Reconnecting...`; + this.socket.connected = false; + this.socket.firstConnect = false; + }); + + socket.on("disconnect", () => { + console.log("disconnect") + this.connectionErrorMsg = "Lost connection to the socket server. Reconnecting..."; + this.socket.connected = false; + }); + + socket.on("connect", () => { + console.log("connect") + this.socket.connectCount++; + this.socket.connected = true; + + // Reset Heartbeat list if it is re-connect + if (this.socket.connectCount >= 2) { + this.clearData() + } + + let token = this.storage().token; + + if (token) { + if (token !== "autoLogin") { + this.loginByToken(token) + } else { + + // Timeout if it is not actually auto login + setTimeout(() => { + if (! this.loggedIn) { + this.allowLoginDialog = true; + this.$root.storage().removeItem("token"); + } + }, 5000); + + } + } else { + this.allowLoginDialog = true; + } + + this.socket.firstConnect = false; + }); + + }, + storage() { return (this.remember) ? localStorage : sessionStorage; }, @@ -336,6 +357,14 @@ export default { localStorage.remember = (this.remember) ? "1" : "0" }, + // Reconnect the socket io, if status-page to dashboard + "$route.fullPath"(newValue, oldValue) { + if (noSocketIOPage.includes(newValue)) { + return; + } + this.initSocketIO(); + }, + }, } diff --git a/src/pages/StatusPage.vue b/src/pages/StatusPage.vue new file mode 100644 index 00000000..7cb493ad --- /dev/null +++ b/src/pages/StatusPage.vue @@ -0,0 +1,36 @@ + + +