diff --git a/client/components/Windows/SignIn.vue b/client/components/Windows/SignIn.vue
index e69dd572..92736aae 100644
--- a/client/components/Windows/SignIn.vue
+++ b/client/components/Windows/SignIn.vue
@@ -85,7 +85,7 @@ export default {
storage.set("user", values.user);
- socket.emit("auth", values);
+ socket.emit("auth:perform", values);
},
getStoredUser() {
return storage.get("user");
diff --git a/client/index.html.tpl b/client/index.html.tpl
index bbd144fa..d3b9477a 100644
--- a/client/index.html.tpl
+++ b/client/index.html.tpl
@@ -53,13 +53,13 @@
This is taking longer than it should, there might be connectivity issues.
-
+
diff --git a/client/js/loading-error-handlers.js b/client/js/loading-error-handlers.js
index d6c118c6..922175fb 100644
--- a/client/js/loading-error-handlers.js
+++ b/client/js/loading-error-handlers.js
@@ -1,4 +1,4 @@
-/* eslint strict: 0, no-var: 0 */
+/* eslint strict: 0 */
"use strict";
/*
@@ -9,71 +9,66 @@
*/
(function() {
- var msg = document.getElementById("loading-page-message");
+ const msg = document.getElementById("loading-page-message");
+ msg.textContent = "Loading the app…";
- if (msg) {
- msg.textContent = "Loading the app…";
+ document
+ .getElementById("loading-reload")
+ .addEventListener("click", () => location.reload(true));
- document.getElementById("loading-reload").addEventListener("click", function() {
- location.reload(true);
- });
- }
-
- var displayReload = function displayReload() {
- var loadingReload = document.getElementById("loading-reload");
+ const displayReload = () => {
+ const loadingReload = document.getElementById("loading-reload");
if (loadingReload) {
loadingReload.style.visibility = "visible";
}
};
- var loadingSlowTimeout = setTimeout(function() {
- var loadingSlow = document.getElementById("loading-slow");
-
- // The parent element, #loading, is being removed when the app is loaded.
- // Since the timer is not cancelled, `loadingSlow` can be not found after
- // 5s. Wrap everything in this block to make sure nothing happens if the
- // element does not exist (i.e. page has loaded).
- if (loadingSlow) {
- loadingSlow.style.visibility = "visible";
- displayReload();
- }
+ const loadingSlowTimeout = setTimeout(() => {
+ const loadingSlow = document.getElementById("loading-slow");
+ loadingSlow.style.visibility = "visible";
+ displayReload();
}, 5000);
- window.g_LoungeErrorHandler = function LoungeErrorHandler(e) {
- var message = document.getElementById("loading-page-message");
- message.textContent =
- "An error has occurred that prevented the client from loading correctly.";
+ const errorHandler = (e) => {
+ msg.textContent = "An error has occurred that prevented the client from loading correctly.";
- var summary = document.createElement("summary");
+ const summary = document.createElement("summary");
summary.textContent = "More details";
- var data = document.createElement("pre");
+ const data = document.createElement("pre");
data.textContent = e.message; // e is an ErrorEvent
- var info = document.createElement("p");
+ const info = document.createElement("p");
info.textContent = "Open the developer tools of your browser for more information.";
- var details = document.createElement("details");
+ const details = document.createElement("details");
details.appendChild(summary);
details.appendChild(data);
details.appendChild(info);
- message.parentNode.insertBefore(details, message.nextSibling);
+ msg.parentNode.insertBefore(details, msg.nextSibling);
window.clearTimeout(loadingSlowTimeout);
displayReload();
};
- window.addEventListener("error", window.g_LoungeErrorHandler);
+ window.addEventListener("error", errorHandler);
+
+ window.g_TheLoungeRemoveLoading = () => {
+ delete window.g_TheLoungeRemoveLoading;
+ window.clearTimeout(loadingSlowTimeout);
+ window.removeEventListener("error", errorHandler);
+ document.getElementById("loading").remove();
+ };
// Trigger early service worker registration
if ("serviceWorker" in navigator) {
navigator.serviceWorker.register("service-worker.js");
// Handler for messages coming from the service worker
- var messageHandler = function ServiceWorkerMessageHandler(event) {
+ const messageHandler = (event) => {
if (event.data.type === "fetch-error") {
- window.g_LoungeErrorHandler({
+ errorHandler({
message: `Service worker failed to fetch an url: ${event.data.message}`,
});
diff --git a/client/js/router.js b/client/js/router.js
index 202cab6c..64fe147d 100644
--- a/client/js/router.js
+++ b/client/js/router.js
@@ -25,7 +25,7 @@ const router = new VueRouter({
});
router.afterEach((to) => {
- if (router.app.initialized) {
+ if (store.state.appLoaded) {
router.app.closeSidebarIfNeeded();
}
diff --git a/client/js/socket-events/auth.js b/client/js/socket-events/auth.js
index a2836494..296a8f97 100644
--- a/client/js/socket-events/auth.js
+++ b/client/js/socket-events/auth.js
@@ -5,76 +5,89 @@ const socket = require("../socket");
const storage = require("../localStorage");
const {getActiveWindowComponent} = require("../vue");
const store = require("../store").default;
-let lastServerHash = -1;
+let lastServerHash = null;
-socket.on("auth", function(data) {
+socket.on("auth:success", function() {
+ store.commit("currentUserVisibleError", "Loading messages…");
+ $("#loading-page-message").text(store.state.currentUserVisibleError);
+});
+
+socket.on("auth:failed", function() {
+ storage.remove("token");
+
+ if (store.state.appLoaded) {
+ return reloadPage("Authentication failed, reloading…");
+ }
+
+ // TODO: This will most likely fail getActiveWindowComponent
+ showSignIn();
+
+ // TODO: getActiveWindowComponent is the SignIn component, find a better way to set this
+ getActiveWindowComponent().errorShown = true;
+ getActiveWindowComponent().inFlight = false;
+});
+
+socket.on("auth:start", function(serverHash) {
// If we reconnected and serverHash differs, that means the server restarted
// And we will reload the page to grab the latest version
- if (lastServerHash > -1 && data.serverHash > -1 && data.serverHash !== lastServerHash) {
- socket.disconnect();
- store.commit("isConnected", false);
- store.commit("currentUserVisibleError", "Server restarted, reloading…");
- location.reload(true);
- return;
+ if (lastServerHash && serverHash !== lastServerHash) {
+ return reloadPage("Server restarted, reloading…");
}
- if (data.serverHash > -1) {
- lastServerHash = data.serverHash;
- } else {
- getActiveWindowComponent().inFlight = false;
- }
+ lastServerHash = serverHash;
- let token;
const user = storage.get("user");
+ const token = storage.get("token");
+ const doFastAuth = user && token;
- if (!data.success) {
- if (store.state.activeWindow !== "SignIn") {
- socket.disconnect();
- store.commit("isConnected", false);
- store.commit("currentUserVisibleError", "Authentication failed, reloading…");
- location.reload();
- return;
- }
+ // If we reconnect and no longer have a stored token, reload the page
+ if (store.state.appLoaded && !doFastAuth) {
+ return reloadPage("Authentication failed, reloading…");
+ }
- storage.remove("token");
+ // If we have user and token stored, perform auth without showing sign-in first
+ if (doFastAuth) {
+ store.commit("currentUserVisibleError", "Authorizing…");
+ $("#loading-page-message").text(store.state.currentUserVisibleError);
- getActiveWindowComponent().errorShown = true;
- } else if (user) {
- token = storage.get("token");
+ let lastMessage = -1;
- if (token) {
- store.commit("currentUserVisibleError", "Authorizing…");
- $("#loading-page-message").text(store.state.currentUserVisibleError);
+ for (const network of store.state.networks) {
+ for (const chan of network.channels) {
+ if (chan.messages.length > 0) {
+ const id = chan.messages[chan.messages.length - 1].id;
- let lastMessage = -1;
-
- for (const network of store.state.networks) {
- for (const chan of network.channels) {
- if (chan.messages.length > 0) {
- const id = chan.messages[chan.messages.length - 1].id;
-
- if (lastMessage < id) {
- lastMessage = id;
- }
+ if (lastMessage < id) {
+ lastMessage = id;
}
}
}
-
- const openChannel =
- (store.state.activeChannel && store.state.activeChannel.channel.id) || null;
-
- socket.emit("auth", {user, token, lastMessage, openChannel});
}
+
+ const openChannel =
+ (store.state.activeChannel && store.state.activeChannel.channel.id) || null;
+
+ socket.emit("auth:perform", {user, token, lastMessage, openChannel});
+ } else {
+ showSignIn();
+ }
+});
+
+function showSignIn() {
+ // TODO: this flashes grey background because it takes a little time for vue to mount signin
+ if (window.g_TheLoungeRemoveLoading) {
+ window.g_TheLoungeRemoveLoading();
}
- if (token) {
- return;
- }
-
- $("#loading").remove();
$("#footer")
.find(".sign-in")
.trigger("click", {
pushState: false,
});
-});
+}
+
+function reloadPage(message) {
+ socket.disconnect();
+ store.commit("currentUserVisibleError", message);
+ location.reload(true);
+}
diff --git a/client/js/socket-events/init.js b/client/js/socket-events/init.js
index 2fc1e4f4..d979db05 100644
--- a/client/js/socket-events/init.js
+++ b/client/js/socket-events/init.js
@@ -10,17 +10,14 @@ const router = require("../router");
const store = require("../store").default;
socket.on("init", function(data) {
- store.commit("currentUserVisibleError", "Rendering…");
-
- $("#loading-page-message").text(store.state.currentUserVisibleError);
-
store.commit("networks", mergeNetworkData(data.networks));
store.commit("isConnected", true);
store.commit("currentUserVisibleError", null);
- if (!vueApp.initialized) {
+ if (!store.state.appLoaded) {
router.initialize();
- vueApp.onSocketInit();
+
+ store.commit("appLoaded");
if (data.token) {
storage.set("token", data.token);
@@ -43,12 +40,10 @@ socket.on("init", function(data) {
vueApp.setUserlist(isUserlistOpen === "true");
- $(document.body).removeClass("signed-out");
- $("#loading").remove();
+ document.body.classList.remove("signed-out");
- if (window.g_LoungeErrorHandler) {
- window.removeEventListener("error", window.g_LoungeErrorHandler);
- window.g_LoungeErrorHandler = null;
+ if (window.g_TheLoungeRemoveLoading) {
+ window.g_TheLoungeRemoveLoading();
}
if (!vueApp.$route.name || vueApp.$route.name === "SignIn") {
diff --git a/client/js/socket.js b/client/js/socket.js
index 8f47c78b..1295ef80 100644
--- a/client/js/socket.js
+++ b/client/js/socket.js
@@ -38,21 +38,18 @@ socket.on("connect", function() {
$("#loading-page-message").text(store.state.currentUserVisibleError);
});
-socket.on("authorized", function() {
- store.commit("currentUserVisibleError", "Loading messages…");
- $("#loading-page-message").text(store.state.currentUserVisibleError);
-});
-
function handleDisconnect(data) {
const message = data.message || data;
store.commit("isConnected", false);
+
store.commit("currentUserVisibleError", `Waiting to reconnect… (${message})`);
$("#loading-page-message").text(store.state.currentUserVisibleError);
// If the server shuts down, socket.io skips reconnection
// and we have to manually call connect to start the process
- if (socket.io.skipReconnect) {
+ // However, do not reconnect if TL client manually closed the connection
+ if (socket.io.skipReconnect && message !== "io client disconnect") {
requestIdleCallback(() => socket.connect(), 2000);
}
}
diff --git a/client/js/store.js b/client/js/store.js
index a9f22645..b1161b2e 100644
--- a/client/js/store.js
+++ b/client/js/store.js
@@ -11,6 +11,7 @@ const store = new Vuex.Store({
settings,
},
state: {
+ appLoaded: false,
activeChannel: null,
currentUserVisibleError: null,
desktopNotificationState: "unsupported",
@@ -31,6 +32,9 @@ const store = new Vuex.Store({
versionDataExpired: false,
},
mutations: {
+ appLoaded(state) {
+ state.appLoaded = true;
+ },
activeChannel(state, channel) {
state.activeChannel = channel;
},
diff --git a/client/js/vue.js b/client/js/vue.js
index 2f456a9e..9484e86a 100644
--- a/client/js/vue.js
+++ b/client/js/vue.js
@@ -15,9 +15,6 @@ const appName = document.title;
const vueApp = new Vue({
el: "#viewport",
- data: {
- initialized: false,
- },
router,
mounted() {
if (navigator.platform.match(/(Mac|iPhone|iPod|iPad)/i)) {
@@ -43,10 +40,6 @@ const vueApp = new Vue({
}, 1);
},
methods: {
- onSocketInit() {
- this.initialized = true;
- this.$store.commit("isConnected", true);
- },
setSidebar(state) {
this.$store.commit("sidebarOpen", state);
diff --git a/src/server.js b/src/server.js
index f698f456..a49f7741 100644
--- a/src/server.js
+++ b/src/server.js
@@ -174,11 +174,8 @@ module.exports = function(options = {}) {
if (Helper.config.public) {
performAuthentication.call(socket, {});
} else {
- socket.emit("auth", {
- serverHash: serverHash,
- success: true,
- });
- socket.on("auth", performAuthentication);
+ socket.on("auth:perform", performAuthentication);
+ socket.emit("auth:start", serverHash);
}
});
@@ -337,7 +334,8 @@ function indexRequest(req, res) {
}
function initializeClient(socket, client, token, lastMessage, openChannel) {
- socket.emit("authorized");
+ socket.off("auth:perform", performAuthentication);
+ socket.emit("auth:success");
client.clientAttach(socket.id, token);
@@ -789,7 +787,7 @@ function performAuthentication(data) {
);
}
- socket.emit("auth", {success: false});
+ socket.emit("auth:failed");
return;
}
diff --git a/test/server.js b/test/server.js
index 48798c05..095d21e4 100644
--- a/test/server.js
+++ b/test/server.js
@@ -72,7 +72,7 @@ describe("Server", function() {
});
it("should emit authorized message", (done) => {
- client.on("authorized", done);
+ client.on("auth:success", done);
});
it("should create network", (done) => {