diff --git a/aleksis/core/assets/app/apollo.js b/aleksis/core/assets/app/apollo.js index 35b1b231dfd1756464bb83a38d843e43d1872fcf..7236b9d3f692807aafa4ffc420a22543290099ee 100644 --- a/aleksis/core/assets/app/apollo.js +++ b/aleksis/core/assets/app/apollo.js @@ -4,7 +4,6 @@ import { ApolloClient, HttpLink, from } from "@/apollo-boost"; -import { onError } from "@/apollo-link-error"; import { RetryLink } from "@/apollo-link-retry"; import { persistCache, LocalStorageWrapper } from "@/apollo3-cache-persist"; import { InMemoryCache } from "@/apollo-cache-inmemory"; @@ -97,15 +96,6 @@ function getGraphqlURL() { const links = [ // Automatically retry failed queries new RetryLink(), - // Add custom error handlers - onError(({ graphQLErrors, networkError }) => { - // Add a snackbar on all errors returned by the GraphQL endpoint - if (graphQLErrors) addErrorSnackbarItem("graphql.snackbar_error_message"); - // Set app offline globally on network errors - // This will cause the offline logic to kick in, starting a ping check or - // similar recovery strategies depending on the app/navigator state - if (networkError) app.offline = true; - }), // Finally, the HTTP link to the real backend (Django) new HttpLink({ uri: getGraphqlURL(), @@ -122,6 +112,30 @@ const apolloClient = new ApolloClient({ const apolloOpts = { defaultClient: apolloClient, + defaultOptions: { + $query: { + skip: (vm, queryKey) => { + // We only want to run this query when background activity is on and we are not reported offline + return !vm.$root.backgroundActive || vm.$root.offline; + }, + error: ({ graphQLErrors, networkError }, vm, key, type, options) => { + if (graphQLErrors) { + // Add a snackbar on all errors returned by the GraphQL endpoint + console.error("A GraphQL query failed on the server"); + addErrorSnackbarItem("graphql.snackbar_error_message"); + } + if (networkError) { + // Set app offline globally on network errors + // This will cause the offline logic to kick in, starting a ping check or + // similar recovery strategies depending on the app/navigator state + console.error( + "Network error during GraphQL query, setting offline state" + ); + vm.$root.offline = true; + } + }, + }, + }, }; export default apolloOpts; diff --git a/aleksis/core/assets/components/app/ping.graphql b/aleksis/core/assets/components/app/ping.graphql index 1a13edeb72aa88284dd3a0ea64f8c3f4d5732c08..cc2f908e4bb80794c5a3c6c1bda2ecf98f31c087 100644 --- a/aleksis/core/assets/components/app/ping.graphql +++ b/aleksis/core/assets/components/app/ping.graphql @@ -1,3 +1,3 @@ -{ - ping +query Pinf($payload: String) { + ping(payload: $payload) } diff --git a/aleksis/core/assets/index.js b/aleksis/core/assets/index.js index 459978ed1d533e73ea5b03bf8f8ef700cefcfeb7..ac9c36e45184410a2ee7347a13b1c770c6f8211b 100644 --- a/aleksis/core/assets/index.js +++ b/aleksis/core/assets/index.js @@ -46,6 +46,7 @@ const app = new Vue({ showCacheAlert: false, contentLoading: false, offline: false, + backgroundActive: true, }), router, i18n, diff --git a/aleksis/core/assets/mixins/offline.js b/aleksis/core/assets/mixins/offline.js index 7bdd551a33a1361120a41b448cd7aa640935e40d..02a34644e15a84293d13a5c597f090e8d83d7e08 100644 --- a/aleksis/core/assets/mixins/offline.js +++ b/aleksis/core/assets/mixins/offline.js @@ -23,63 +23,48 @@ const offlineMixin = { }, mounted() { window.addEventListener("online", (e) => { - console.debug("Navigator changed status to online."); - if (!document.hidden) this.toggleGlobalQueries(false, true); + console.info("Navigator changed status to online."); + this.checkOfflineState(); }); window.addEventListener("offline", (e) => { - console.debug("Navigator changed status to offline."); - this.toggleGlobalQueries(false, false); + console.info("Navigator changed status to offline."); + this.checkOfflineState(); }); 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); - } + console.info("Visibility changed status to", document.visibilityState); + this.checkOfflineState(); }); }, 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); + checkOfflineState() { + if (navigator.onLine && document.visibilityState === "visible") { + console.info("Resuming background activity"); + this.$root.backgroundActive = true; } else { - this.$apollo.queries.ping.stopPolling(); + console.info("Pausing background activity"); + this.$root.backgroundActive = false; } }, }, apollo: { ping: { query: gqlPing, + variables: () => { + return { + payload: Date.now().toString(), + }; + }, + pollInterval: 1000, + skip: (component, query) => { + // We only want to run this query when background activity is on and we are reported offline + return !(component.$root.backgroundActive && component.$root.offline); + }, }, }, 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); - } + ping(payload) { + console.info("Pong received, clearing offline state"); + this.$root.offline = false; }, }, }; diff --git a/aleksis/core/schema/__init__.py b/aleksis/core/schema/__init__.py index a4ed8158083184e0451e1b8d03dab25bc581d0ef..a94f88d48274f3c70ad0b60fb2c7644fbad06a0e 100644 --- a/aleksis/core/schema/__init__.py +++ b/aleksis/core/schema/__init__.py @@ -27,7 +27,7 @@ from .user import UserType class Query(graphene.ObjectType): - ping = graphene.String(default_value="pong") + ping = graphene.String(payload=graphene.String()) notifications = graphene.List(NotificationType) @@ -53,6 +53,9 @@ class Query(graphene.ObjectType): custom_menu_by_name = graphene.Field(CustomMenuType, name=graphene.String()) + def resolve_ping(root, info, payload) -> str: + return payload + def resolve_notifications(root, info, **kwargs): return Notification.objects.filter( Q(