зеркало из https://github.com/nextcloud/spreed.git
Merge pull request #2360 from nextcloud/bugfix/vuejs/stop-long-polling-requests-when-changing-conversations
Stop long polling requests when changing conversations.
This commit is contained in:
Коммит
5c2c7b1738
|
@ -954,30 +954,23 @@
|
|||
}
|
||||
},
|
||||
"@nextcloud/axios": {
|
||||
"version": "0.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/axios/-/axios-0.4.2.tgz",
|
||||
"integrity": "sha512-HrViGxCX0qTE5uCQyMWD0BM5x0cj9VGLXN708zWsehgkTUnwt7qEnyrbuaGSOkdqlbQbf36+bRMxQI23a2mlIg==",
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/axios/-/axios-0.5.0.tgz",
|
||||
"integrity": "sha512-cnf/bgyOpiUty50VMfmtWYNvq0n2G4YJpNldUcY/LJrB5ENyuiv7vJbOl9R40pb6NztWkmDyTK8Ycl1VlzcYrA==",
|
||||
"requires": {
|
||||
"@babel/cli": "^7.6.2",
|
||||
"@babel/core": "^7.6.2",
|
||||
"@babel/preset-env": "^7.6.2",
|
||||
"@babel/preset-typescript": "^7.6.0",
|
||||
"@nextcloud/auth": "^0.3.1",
|
||||
"@nextcloud/event-bus": "^0.2.0",
|
||||
"axios": "^0.19.0",
|
||||
"browserslist-config-nextcloud": "0.0.1",
|
||||
"core-js": "^3.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"browserslist-config-nextcloud": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/browserslist-config-nextcloud/-/browserslist-config-nextcloud-0.0.1.tgz",
|
||||
"integrity": "sha512-BUpPPPfE42jL2puSqfnsoOMoz6g+jqznoaoZmig4Kx1ULApBmM6iH+/7V1yblQz2PsOp39HET1byAB3h3h+kew=="
|
||||
},
|
||||
"core-js": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.4.tgz",
|
||||
"integrity": "sha512-BtibooaAmSOptGLRccsuX/dqgPtXwNgqcvYA6kOTTMzonRxZ+pJS4e+6mvVutESfXMeTnK8m3M+aBu3bkJbR+w=="
|
||||
"version": "3.3.5",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.3.5.tgz",
|
||||
"integrity": "sha512-0J3K+Par/ZydhKg8pEiTcK/9d65/nqJOzY62uMkjeBmt05fDOt/khUVjDdh8TpeIuGQDy1yLDDCjiWN/8pFIuw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -6568,7 +6561,6 @@
|
|||
"resolved": "https://registry.npmjs.org/nextcloud-vue-collections/-/nextcloud-vue-collections-0.6.0.tgz",
|
||||
"integrity": "sha512-P91zLvjFtYikfS2Nz5FNgGpZAzdDACzlHhaG8yjPTFxZI9nv0a8tzHTMYdDzUc3cgxriJ5N4ENBtrWKWWnrR5g==",
|
||||
"requires": {
|
||||
"@nextcloud/axios": "^0.4.2",
|
||||
"@nextcloud/router": "^0.1.0",
|
||||
"lodash": "^4.17.11",
|
||||
"nextcloud-vue": "^0.12.1",
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@nextcloud/auth": "^0.3.1",
|
||||
"@nextcloud/axios": "^0.5.0",
|
||||
"crypto-js": "^3.1.9-1",
|
||||
"debounce": "^1.2.0",
|
||||
"nextcloud-auth": "0.0.3",
|
||||
"nextcloud-axios": "^0.2.1",
|
||||
"nextcloud-initial-state": "0.0.3",
|
||||
"nextcloud-router": "0.0.9",
|
||||
"nextcloud-vue": "^0.12.7",
|
||||
|
|
|
@ -116,9 +116,16 @@ export default {
|
|||
* This runs whenever the new route is a conversation.
|
||||
*/
|
||||
if (to.name === 'conversation') {
|
||||
// Page title
|
||||
const NEXT_CONVERSATION_NAME = this.getConversationName(to.params.token)
|
||||
this.setPageTitle(NEXT_CONVERSATION_NAME)
|
||||
}
|
||||
/**
|
||||
* Fires a global event that tells the whole app that the route has changed. The event
|
||||
* carries the from and to objects as payload
|
||||
*/
|
||||
EventBus.$emit('routeChange', { from, to })
|
||||
|
||||
next()
|
||||
})
|
||||
},
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
:display-name="item.displayName" />
|
||||
<div v-if="showFavorite"
|
||||
class="favorite-mark">
|
||||
<span class="icon icon-favorite"></span>
|
||||
<span class="icon icon-favorite" />
|
||||
<span class="hidden-visually">{{ t('spreed', 'Favorite') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -47,7 +47,8 @@ the Vue virtual scroll list component, whose docs you can find [here.](https://g
|
|||
<script>
|
||||
import virtualList from 'vue-virtual-scroll-list'
|
||||
import MessagesGroup from './MessagesGroup/MessagesGroup'
|
||||
import { fetchMessages, lookForNewMessges } from '../../services/messagesService'
|
||||
import { fetchMessages, cancelableLookForNewMessages } from '../../services/messagesService'
|
||||
import { EventBus } from '../../services/EventBus'
|
||||
|
||||
export default {
|
||||
name: 'MessagesList',
|
||||
|
@ -73,6 +74,12 @@ export default {
|
|||
* bottom.
|
||||
*/
|
||||
isInitiated: false,
|
||||
/**
|
||||
* Stores the cancel function returned by `cancelableLookForNewMessages`,
|
||||
* which allows to cancel the previous long polling request for new
|
||||
* messages before making another one.
|
||||
*/
|
||||
cancelRequest: null,
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -115,19 +122,20 @@ export default {
|
|||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
token: function() {
|
||||
this.onTokenChange()
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetches the messages when the MessageList is mounted for the
|
||||
* first time. The router mounts this component only if the token
|
||||
* is passed in so there's no need to check the token prop.
|
||||
* Fetches the messages when the MessageList created. The router mounts this
|
||||
* component only if the token is passed in so there's no need to check the
|
||||
* token prop.
|
||||
*/
|
||||
beforeMount() {
|
||||
this.onTokenChange()
|
||||
created() {
|
||||
this.onRouteChange()
|
||||
/**
|
||||
* Add a listener for routeChange event emitted by the App.vue component.
|
||||
* Call the onRouteChange method function whenever the route changes.
|
||||
*/
|
||||
EventBus.$on('routeChange', () => {
|
||||
this.onRouteChange()
|
||||
})
|
||||
},
|
||||
|
||||
beforeUpdate() {
|
||||
|
@ -165,27 +173,37 @@ export default {
|
|||
},
|
||||
|
||||
/**
|
||||
* Fetches the messages of a conversation given the
|
||||
* conversation token.
|
||||
* Fetches the messages of a conversation given the conversation token. Triggers
|
||||
* a long-polling request for new messages.
|
||||
*/
|
||||
async onTokenChange() {
|
||||
async onRouteChange() {
|
||||
this.isInitiated = false
|
||||
const messages = await fetchMessages(this.token)
|
||||
// Process each messages and adds it to the store
|
||||
messages.data.ocs.data.forEach(message => {
|
||||
this.$store.dispatch('processMessage', message)
|
||||
})
|
||||
// After loading the old messages to the store, we start looking for new mwssages.
|
||||
this.getNewMessages()
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a long polling request for a new message.
|
||||
*/
|
||||
async getNewMessages() {
|
||||
const lastKnownMessageId = this.messagesList[this.messagesList.length - 1].id
|
||||
const messages = await lookForNewMessges(this.token, lastKnownMessageId)
|
||||
// If there are no new messages, the variable messages will be undefined.
|
||||
/**
|
||||
* If there's already one pending long polling request from a previous call
|
||||
* of this method, we call the `cancelRequest` function to clear it and reset
|
||||
* the cancelRequest to null in the component's data.
|
||||
*/
|
||||
if (typeof this.cancelRequest === 'function') {
|
||||
this.cancelRequest('canceled')
|
||||
this.cancelRequest = null
|
||||
}
|
||||
// Get a new request function and cancel function pair
|
||||
const { lookForNewMessages, cancel } = cancelableLookForNewMessages()
|
||||
// store the cancel function in the data
|
||||
this.cancelRequest = cancel
|
||||
const lastKnownMessageId = this.getLastKnownMessageId()
|
||||
const messages = await lookForNewMessages(this.token, lastKnownMessageId)
|
||||
if (messages !== undefined) {
|
||||
// Process each messages and adds it to the store
|
||||
messages.data.ocs.data.forEach(message => {
|
||||
|
@ -194,12 +212,11 @@ export default {
|
|||
this.scrollToBottom()
|
||||
}
|
||||
/**
|
||||
* This method recursively call itself after a response, so we're always
|
||||
* looking for new messages.
|
||||
* If there are no new messages, the variable messages will be undefined, so the
|
||||
* previous code block will be skipped and this method recursively calls itself.
|
||||
*/
|
||||
this.getNewMessages()
|
||||
},
|
||||
|
||||
/**
|
||||
* Dispatches the deleteMessages action.
|
||||
* @param {object} event The deleteMessage event emitted by the Message component.
|
||||
|
@ -216,6 +233,17 @@ export default {
|
|||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* gets the last known message id.
|
||||
* @returns {string} The last known message id.
|
||||
*/
|
||||
getLastKnownMessageId() {
|
||||
if (this.messagesList[this.messagesList.length - 1]) {
|
||||
return this.messagesList[this.messagesList.length - 1].id
|
||||
}
|
||||
return '0'
|
||||
},
|
||||
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
<ConversationIcon
|
||||
slot="icon"
|
||||
:item="item"
|
||||
:hideFavorite="false" />
|
||||
:hide-favorite="false" />
|
||||
<template slot="subtitle">
|
||||
{{ simpleLastChatMessage }}
|
||||
</template>
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import axios from 'nextcloud-axios'
|
||||
import axios from '@nextcloud/axios'
|
||||
import { generateOcsUrl } from 'nextcloud-router'
|
||||
import { CONVERSATION } from '../constants'
|
||||
|
||||
|
|
|
@ -20,9 +20,11 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import axios from 'nextcloud-axios'
|
||||
import axios from '@nextcloud/axios'
|
||||
import { generateOcsUrl } from 'nextcloud-router'
|
||||
|
||||
const CANCEL_TOKEN = axios.CancelToken
|
||||
|
||||
/**
|
||||
* Fetches messages that belong to a particular conversation
|
||||
* specified with its token.
|
||||
|
@ -39,18 +41,44 @@ const fetchMessages = async function(token) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Fetches newly created messages that belong to a particular conversation
|
||||
* specified with its token.
|
||||
*
|
||||
* @param {string} token The conversation token;
|
||||
* @param {int} lastKnownMessageId The id of the last message in the store.
|
||||
* Creates a cancelable axios 'request object'. We need this in order to cancel
|
||||
* long polling requests for new messages of previous conversatios when
|
||||
* switching to a new one.
|
||||
* @returns {object} An object that contains 2 functions:
|
||||
* - `lookForNewMessages` : the api call async function with the injected cancel
|
||||
* token;
|
||||
* - `cancel` : the function that allows to cancel that particular a call;
|
||||
*/
|
||||
const lookForNewMessges = async function(token, lastKnownMessageId) {
|
||||
try {
|
||||
const response = await axios.get(generateOcsUrl('apps/spreed/api/v1/chat', 2) + token + '?lookIntoFuture=1' + '&includeLastKnown=0' + `&lastKnownMessageId=${lastKnownMessageId}`)
|
||||
return response
|
||||
} catch (error) {
|
||||
console.debug('Error while looking for new message: ', error)
|
||||
const cancelableLookForNewMessages = function() {
|
||||
/**
|
||||
* cancelToken= the token that gets injected into the axios method and links it
|
||||
* to the cancel function;
|
||||
* cancel= function that allows to delete the api call;
|
||||
*/
|
||||
const { token: cancelToken, cancel } = CANCEL_TOKEN.source()
|
||||
/**
|
||||
* Fetches newly created messages that belong to a particular conversation
|
||||
* specified with its token.
|
||||
*
|
||||
* @param {string} token The conversation token;
|
||||
* @param {int} lastKnownMessageId The id of the last message in the store.
|
||||
*/
|
||||
const lookForNewMessages = async(token, lastKnownMessageId) => {
|
||||
try {
|
||||
const response = await axios.get(generateOcsUrl('apps/spreed/api/v1/chat', 2) + token + '?lookIntoFuture=1' + '&includeLastKnown=0' + `&lastKnownMessageId=${lastKnownMessageId}`, { cancelToken })
|
||||
return response
|
||||
} catch (exception) {
|
||||
if (axios.isCancel(exception)) {
|
||||
console.debug(exception.message)
|
||||
return exception.message
|
||||
} else {
|
||||
console.debug('Error while looking for new message: ', exception)
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
lookForNewMessages,
|
||||
cancel,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,6 +101,6 @@ const postNewMessage = async function({ token, message, parent }) {
|
|||
|
||||
export {
|
||||
fetchMessages,
|
||||
lookForNewMessges,
|
||||
cancelableLookForNewMessages,
|
||||
postNewMessage,
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import axios from 'nextcloud-axios'
|
||||
import axios from '@nextcloud/axios'
|
||||
import { generateOcsUrl } from 'nextcloud-router'
|
||||
|
||||
/**
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'nextcloud-axios'
|
||||
import axios from '@nextcloud/axios'
|
||||
import debounce from 'debounce'
|
||||
import { Multiselect } from 'nextcloud-vue'
|
||||
import { generateOcsUrl } from 'nextcloud-router/dist/index'
|
||||
|
|
|
@ -105,7 +105,7 @@
|
|||
/* global OC */
|
||||
import { Modal } from 'nextcloud-vue/dist/Components/Modal'
|
||||
import { Avatar } from 'nextcloud-vue/dist/Components/Avatar'
|
||||
import axios from 'nextcloud-axios'
|
||||
import axios from '@nextcloud/axios'
|
||||
|
||||
export default {
|
||||
name: 'RoomSelector',
|
||||
|
|
Загрузка…
Ссылка в новой задаче