diff options
author | René Gieling <github@dartcafe.de> | 2022-09-18 00:51:00 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-18 00:51:00 +0300 |
commit | ff80649e795c8386ffdfb7f9a7fddb42fa9738ed (patch) | |
tree | c7013121cb65c7f992d24024b076fce630c931c6 /src | |
parent | 7027be751a2edfaaa3a97d918d5df8b625841db1 (diff) | |
parent | b879f8f3b59739979a1408b2f50fd96a3c53a57c (diff) |
Merge pull request #2591 from nextcloud/ref/optimize-watch
change watchPolls
Diffstat (limited to 'src')
-rw-r--r-- | src/js/Exceptions/Exceptions.js | 11 | ||||
-rw-r--r-- | src/js/mixins/watchPolls.js | 96 |
2 files changed, 70 insertions, 37 deletions
diff --git a/src/js/Exceptions/Exceptions.js b/src/js/Exceptions/Exceptions.js index e7f2a356..4e5ae135 100644 --- a/src/js/Exceptions/Exceptions.js +++ b/src/js/Exceptions/Exceptions.js @@ -38,4 +38,13 @@ class NotReady extends Error { } -export { Exception, NotReady } +class InvalidJSON extends Error { + + constructor(message) { + super(message) + this.name = 'InvalidJSON' + } + +} + +export { Exception, InvalidJSON, NotReady } diff --git a/src/js/mixins/watchPolls.js b/src/js/mixins/watchPolls.js index aadfcbfb..b88a7cd5 100644 --- a/src/js/mixins/watchPolls.js +++ b/src/js/mixins/watchPolls.js @@ -25,6 +25,7 @@ import axios from '@nextcloud/axios' import { generateUrl } from '@nextcloud/router' import { getCurrentUser } from '@nextcloud/auth' import { mapState } from 'vuex' +import { InvalidJSON } from '../Exceptions/Exceptions.js' const defaultSleepTimeout = 30 @@ -53,53 +54,47 @@ export const watchPolls = { methods: { async watchPolls() { - if (this.cancelToken) { - // there is already a cancelToken, so just cancel the previous session and exit - this.cancelWatch() + // quit if polling for updates is disabled + if (this.updateType === 'noPolling') { return } - if (this.updateType === 'noPolling') { - console.debug('[polls]', 'Polling for updates is disabled') + if (this.cancelToken) { + // there is already a cancelToken, so just cancel the previous session and exit + this.cancelWatch() return } - console.debug('[polls]', 'Watch for updates') this.cancelToken = axios.CancelToken.source() while (this.retryCounter < this.maxTries) { // reset sleep timer to default this.sleepTimeout = defaultSleepTimeout + this.gotValidResponse = false await this.$store.dispatch('appSettings/get') + if (this.updateType === 'noPolling') { + console.debug('[polls]', 'Polling for updates is disabled. Cancel watch.') + this.cancelWatch() + return + } + try { - const response = await this.fetchUpdates() - - // check, if we got a valid json response - if (response.headers['content-type'].includes('application/json')) { - this.gotValidResponse = true - console.debug('[polls]', `Update detected (${this.updateType})`, response.data.updates) - this.loadTables(response.data.updates) - this.retryCounter = 0 // reset retryCounter after we got a valid response - } else { - console.debug('[polls]', `No JSON response recieved, got "${response.headers['content-type']}"`) - this.gotValidResponse = false + // Avoid requests, if the tab/window is not visible + if (!document.hidden) { + console.debug('[polls]', 'Watch for updates') + await this.handleResponse(await this.fetchUpdates()) } - } catch (e) { if (axios.isCancel(e)) { this.handleCanceledRequest() - } else if (e.response?.status === 304) { - this.handleNotModifiedResponse() } else { - this.gotValidResponse = false - await this.handleConnectionError(e) + this.handleConnectionError(e) } } - if (this.updateType === 'periodicPolling' || !this.gotValidResponse) { - console.debug('[polls]', `Sleep for ${this.sleepTimeout} seconds`) - await this.sleep(this.sleepTimeout) + if (this.updateType !== 'longPolling' || !this.gotValidResponse || document.hidden) { + await this.sleep() } } @@ -115,8 +110,17 @@ export const watchPolls = { this.cancelToken.cancel() }, - sleep(timeout) { - return new Promise((resolve) => setTimeout(resolve, timeout * 1000)) + sleep() { + let reason = `Connection error, Attempt: ${this.retryCounter}/${this.maxTries})` + + if (this.gotValidResponse) { + reason = this.updateType + } else if (document.hidden) { + reason = 'app is in background' + } + + console.debug('[polls]', `Sleep for ${this.sleepTimeout} seconds (reason: ${reason})`) + return new Promise((resolve) => setTimeout(resolve, this.sleepTimeout * 1000)) }, async fetchUpdates() { @@ -125,6 +129,7 @@ export const watchPolls = { } else { this.endPoint = `apps/polls/poll/${this.$route.params.id ?? 0}/watch` } + return await axios.get(generateUrl(this.endPoint), { params: { offset: this.lastUpdated }, cancelToken: this.cancelToken.token, @@ -132,28 +137,47 @@ export const watchPolls = { }) }, + handleResponse(response) { + if (response.headers['content-type'].includes('application/json')) { + this.gotValidResponse = true + console.debug('[polls]', `Update detected (${this.updateType})`, response.data.updates) + this.loadTables(response.data.updates) + this.retryCounter = 0 // reset retryCounter after we got a valid response + return + } + + // console.debug('[polls]', `No JSON response recieved, got "${response.headers['content-type']}"`) + this.gotValidResponse = false + throw new InvalidJSON(`No JSON response recieved, got "${response.headers['content-type']}"`) + }, + handleCanceledRequest() { console.debug('[polls]', 'Fetch canceled') this.cancelToken = axios.CancelToken.source() }, - handleNotModifiedResponse() { - console.debug('[polls]', `No updates (using ${this.updateType})`) - this.retryCounter = 0 // reset retryCounter, after we get a 304 - }, - async handleConnectionError(e) { + if (e.response?.status === 304) { + console.debug('[polls]', `No updates (using ${this.updateType})`) + this.gotValidResponse = true + this.retryCounter = 0 // reset retryCounter, after we get a 304 + return + } + this.retryCounter += 1 if (e?.response?.status === 503) { // Server possibly in maintenance mode this.sleepTimeout = e.response.headers['retry-after'] ?? this.sleepTimeout console.debug('[polls]', `Service not avaiable - retry after ${this.sleepTimeout} seconds`) - } else if (e.response) { - console.error('[polls]', 'Unhandled error while watching polls updates', e) - } else { - console.debug('[polls]', e.message ?? `No response - request aborted - failed request ${this.retryCounter}/${this.maxTries}`) + return } + if (e.response) { + console.error('[polls]', e) + return + } + + console.debug('[polls]', e.message ?? `No response - request aborted - failed request ${this.retryCounter}/${this.maxTries}`) }, async loadTables(tables) { |