diff --git a/aleksis/core/assets/components/app/App.vue b/aleksis/core/assets/components/app/App.vue index 797feda4dfbabc3f579849c452bb3aee623da5be..fddbb3378e79302b1b12fa1d7b92eb5c5951540a 100644 --- a/aleksis/core/assets/components/app/App.vue +++ b/aleksis/core/assets/components/app/App.vue @@ -349,9 +349,9 @@ import gqlWhoAmI from "./whoAmI.graphql"; import gqlMessages from "./messages.graphql"; import gqlSystemProperties from "./systemProperties.graphql"; import gqlSnackbarItems from "./snackbarItems.graphql"; -import gqlPing from "./ping.graphql"; import useRegisterSWMixin from "../../mixins/useRegisterSW"; +import offlineMixin from "../../mixins/offline"; import menusMixin from "../../mixins/menus"; export default { @@ -362,34 +362,9 @@ export default { systemProperties: null, messages: null, snackbarItems: null, - ping: null, }; }, - methods: { - toggleGlobalQueries(enable, pingPolling) { - console.debug("Toggling global queries: " + (enable ? "on" : "off")); - if (enable) { - this.$apollo.queries.whoAmI.startPolling(10000); - this.$apollo.queries.messages.startPolling(1000); - } else { - this.$apollo.queries.whoAmI.stopPolling(); - this.$apollo.queries.messages.stopPolling(); - } - if (pingPolling) { - console.debug("Starting ping polling."); - this.$apollo.queries.ping.observer.resetLastResults(); - this.ping = null; - this.$apollo.queries.ping.startPolling(1000); - } else { - this.$apollo.queries.ping.stopPolling(); - } - }, - - }, apollo: { - ping: { - query: gqlPing, - }, systemProperties: gqlSystemProperties, whoAmI: { query: gqlWhoAmI, @@ -428,32 +403,6 @@ export default { }, deep: true, }, - ping: function (ping) { - if (ping === "pong") { - console.debug("Pong was received. Resuming regular queries."); - this.toggleGlobalQueries(true, false); - this.$root.offline = false; - } - }, - "$root.offline": function (offline) { - if (navigator.onLine && !document.hidden) { - console.debug("Queries failed, but navigator is online."); - this.toggleGlobalQueries(false, true); - } - }, - }, - mounted() { - window.addEventListener("online", (e) => { console.debug("Navigator changed status to online."); if (!document.hidden) this.toggleGlobalQueries(false, true); }); - window.addEventListener("offline", (e) => { console.debug("Navigator changed status to offline."); this.toggleGlobalQueries(false, false); }); - document.addEventListener("visibilitychange", () => { - if (document.visibilityState === "hidden") { - console.debug("Visibility changed status to hidden."); - this.toggleGlobalQueries(false, false); - } else if (navigator.online) { - console.debug("Visibility changed status to visible. Navigator status is online."); - this.toggleGlobalQueries(false, true); - } - }); }, name: "App", components: { @@ -466,7 +415,7 @@ export default { Loading, SnackbarItem, }, - mixins: [useRegisterSWMixin, menusMixin], + mixins: [useRegisterSWMixin, offlineMixin, menusMixin], }; </script> diff --git a/aleksis/core/assets/mixins/offline.js b/aleksis/core/assets/mixins/offline.js new file mode 100644 index 0000000000000000000000000000000000000000..40b10b3b41ba1a8d15585e37ef7e05789a534db2 --- /dev/null +++ b/aleksis/core/assets/mixins/offline.js @@ -0,0 +1,87 @@ +import gqlPing from "../components/app/ping.graphql"; + +/** + * Mixin for handling of offline state / background queries. + * + * This handles three scenarios: + * - The navigator reports that it is in offline mode + * - The global offline flag was set due to network errors from queries + * - The navigator reports the page to be invisible + * + * The main goal is to save bandwidth, energy and server load in error + * conditions, or when the page is not in focus. This is achieved by a + * fallback strategy, where all background queries are stopped in offline + * state, and only a ping query is sent once the navigator reports itself + * as online and the app gets into focus. Once this ping query is successful, + * background activity is resumed. + */ +const offlineMixin = { + data() { + return { + ping: null, + }; + }, + mounted() { + window.addEventListener("online", (e) => { + console.debug("Navigator changed status to online."); + if (!document.hidden) this.toggleGlobalQueries(false, true); + }); + window.addEventListener("offline", (e) => { + console.debug("Navigator changed status to offline."); + this.toggleGlobalQueries(false, false); + }); + document.addEventListener("visibilitychange", () => { + if (document.visibilityState === "hidden") { + console.debug("Visibility changed status to hidden."); + this.toggleGlobalQueries(false, false); + } else if (navigator.online) { + console.debug( + "Visibility changed status to visible. Navigator status is online." + ); + this.toggleGlobalQueries(false, true); + } + }); + }, + methods: { + toggleGlobalQueries(enable, pingPolling) { + console.debug("Toggling global queries: " + (enable ? "on" : "off")); + if (enable) { + this.$apollo.queries.whoAmI.startPolling(10000); + this.$apollo.queries.messages.startPolling(1000); + } else { + this.$apollo.queries.whoAmI.stopPolling(); + this.$apollo.queries.messages.stopPolling(); + } + if (pingPolling) { + console.debug("Starting ping polling."); + this.$apollo.queries.ping.observer.resetLastResults(); + this.ping = null; + this.$apollo.queries.ping.startPolling(1000); + } else { + this.$apollo.queries.ping.stopPolling(); + } + }, + }, + apollo: { + ping: { + query: gqlPing, + }, + }, + watch: { + ping: function (ping) { + if (ping === "pong") { + console.debug("Pong was received. Resuming regular queries."); + this.toggleGlobalQueries(true, false); + this.$root.offline = false; + } + }, + "$root.offline": function (offline) { + if (navigator.onLine && !document.hidden) { + console.debug("Queries failed, but navigator is online."); + this.toggleGlobalQueries(false, true); + } + }, + }, +}; + +export default offlineMixin;