Browse Source

limit fetch requests for messages evenly

Signed-off-by: Maksim Sukharev <antreesy.web@gmail.com>
pull/9897/head
Maksim Sukharev 2 years ago
parent
commit
ad58c729ec
No known key found for this signature in database GPG Key ID: 6349D071889BD1D5
  1. 12
      src/components/MessagesList/MessagesList.vue
  2. 16
      src/services/messagesService.js
  3. 26
      src/services/messagesService.spec.js
  4. 19
      src/store/messagesStore.js
  5. 164
      src/store/messagesStore.spec.js

12
src/components/MessagesList/MessagesList.vue

@ -590,21 +590,20 @@ export default {
},
async getMessageContext(messageId) {
// Make the request
this.loadingOldMessages = true
try {
this.loadingOldMessages = true
await this.$store.dispatch('getMessageContext', {
token: this.token,
messageId,
minimumVisible: CHAT.MINIMUM_VISIBLE,
})
this.loadingOldMessages = false
} catch (exception) {
if (Axios.isCancel(exception)) {
console.debug('The request has been canceled', exception)
}
this.loadingOldMessages = false
}
this.loadingOldMessages = false
},
/**
@ -614,8 +613,8 @@ export default {
*/
async getOldMessages(includeLastKnown) {
// Make the request
this.loadingOldMessages = true
try {
this.loadingOldMessages = true
await this.$store.dispatch('fetchMessages', {
token: this.token,
lastKnownMessageId: this.$store.getters.getFirstKnownMessageId(this.token),
@ -623,13 +622,12 @@ export default {
minimumVisible: CHAT.MINIMUM_VISIBLE,
})
this.loadingOldMessages = false
} catch (exception) {
if (Axios.isCancel(exception)) {
console.debug('The request has been canceled', exception)
}
this.loadingOldMessages = false
}
this.loadingOldMessages = false
},
/**

16
src/services/messagesService.js

@ -34,16 +34,16 @@ import { generateOcsUrl } from '@nextcloud/router'
* @param {string} data.token the conversation token;
* @param {string} data.lastKnownMessageId last known message id;
* @param {boolean} data.includeLastKnown whether to include the last known message in the response;
* @param {number} data.limit Number of messages to load (default: 100)
* @param {number} [data.limit=100] Number of messages to load
* @param {object} options options;
*/
const fetchMessages = async function({ token, lastKnownMessageId, includeLastKnown, limit }, options) {
const fetchMessages = async function({ token, lastKnownMessageId, includeLastKnown, limit = 100 }, options) {
return axios.get(generateOcsUrl('apps/spreed/api/v1/chat/{token}', { token }), Object.assign(options, {
params: {
setReadMarker: 0,
lookIntoFuture: 0,
lastKnownMessageId,
limit: limit || 100,
limit,
includeLastKnown: includeLastKnown ? 1 : 0,
},
}))
@ -56,14 +56,16 @@ const fetchMessages = async function({ token, lastKnownMessageId, includeLastKno
* @param {object} data the wrapping object;
* @param {number} data.lastKnownMessageId The id of the last message in the store.
* @param {string} data.token The conversation token;
* @param {number} [data.limit=100] Number of messages to load
* @param {object} options options
*/
const lookForNewMessages = async ({ token, lastKnownMessageId }, options) => {
const lookForNewMessages = async ({ token, lastKnownMessageId, limit = 100 }, options) => {
return axios.get(generateOcsUrl('apps/spreed/api/v1/chat/{token}', { token }), Object.assign(options, {
params: {
setReadMarker: 0,
lookIntoFuture: 1,
lastKnownMessageId,
limit,
includeLastKnown: 0,
},
}))
@ -77,13 +79,13 @@ const lookForNewMessages = async ({ token, lastKnownMessageId }, options) => {
* @param {object} data the wrapping object;
* @param {string} data.token the conversation token;
* @param {number} data.messageId last known message id;
* @param {number} data.limit Number of messages to load (default: 50)
* @param {number} [data.limit=50] Number of messages to load
* @param {object} options options;
*/
const getMessageContext = async function({ token, messageId, limit }, options) {
const getMessageContext = async function({ token, messageId, limit = 50 }, options) {
return axios.get(generateOcsUrl('apps/spreed/api/v1/chat/{token}/{messageId}/context', { token, messageId }), Object.assign(options, {
params: {
limit: limit || 50,
limit,
},
}))
}

26
src/services/messagesService.spec.js

@ -1,8 +1,10 @@
import axios from '@nextcloud/axios'
import { generateOcsUrl } from '@nextcloud/router'
import { CHAT } from '../constants.js'
import {
fetchMessages,
getMessageContext,
lookForNewMessages,
postNewMessage,
deleteMessage,
@ -39,7 +41,7 @@ describe('messagesService', () => {
setReadMarker: 0,
lookIntoFuture: 0,
lastKnownMessageId: 1234,
limit: 100,
limit: CHAT.FETCH_LIMIT,
includeLastKnown: 0,
},
}
@ -63,13 +65,32 @@ describe('messagesService', () => {
setReadMarker: 0,
lookIntoFuture: 0,
lastKnownMessageId: 1234,
limit: 100,
limit: CHAT.FETCH_LIMIT,
includeLastKnown: 1,
},
}
)
})
test('getMessageContext calls the chat API endpoint within specific messageId', () => {
getMessageContext({
token: 'XXTOKENXX',
messageId: 1234,
}, {
dummyOption: true,
})
expect(axios.get).toHaveBeenCalledWith(
generateOcsUrl('apps/spreed/api/v1/chat/XXTOKENXX/1234/context'),
{
dummyOption: true,
params: {
limit: CHAT.FETCH_LIMIT / 2,
},
}
)
})
test('lookForNewMessages calls the chat API endpoint excluding last known', () => {
lookForNewMessages({
token: 'XXTOKENXX',
@ -86,6 +107,7 @@ describe('messagesService', () => {
setReadMarker: 0,
lookIntoFuture: 1,
lastKnownMessageId: 1234,
limit: CHAT.FETCH_LIMIT,
includeLastKnown: 0,
},
}

19
src/store/messagesStore.js

@ -868,10 +868,11 @@ const actions = {
const response = await request({
token,
messageId,
limit: CHAT.FETCH_LIMIT,
limit: CHAT.FETCH_LIMIT / 2,
}, requestOptions)
let newestKnownMessageId = 0
let oldestKnownMessageId = messageId
let newestKnownMessageId = messageId
if ('x-chat-last-common-read' in response.headers) {
const lastCommonReadMessage = parseInt(response.headers['x-chat-last-common-read'], 10)
@ -889,6 +890,7 @@ const actions = {
}
context.dispatch('processMessage', message)
newestKnownMessageId = Math.max(newestKnownMessageId, message.id)
oldestKnownMessageId = Math.min(oldestKnownMessageId, message.id)
if (message.id <= messageId
&& message.systemMessage !== 'reaction'
@ -900,15 +902,14 @@ const actions = {
}
})
if ('x-chat-last-given' in response.headers) {
if (!context.getters.getFirstKnownMessageId(token) || oldestKnownMessageId < context.getters.getFirstKnownMessageId(token)) {
context.dispatch('setFirstKnownMessageId', {
token,
id: parseInt(response.headers['x-chat-last-given'], 10),
id: oldestKnownMessageId,
})
}
if (newestKnownMessageId
&& !context.getters.getLastKnownMessageId(token)) {
if (!context.getters.getLastKnownMessageId(token) || newestKnownMessageId > context.getters.getLastKnownMessageId(token)) {
context.dispatch('setLastKnownMessageId', {
token,
id: newestKnownMessageId,
@ -983,7 +984,11 @@ const actions = {
// Assign the new cancel function to our data value
context.commit('setCancelLookForNewMessages', { cancelFunction: cancel, requestId })
const response = await request({ token, lastKnownMessageId }, requestOptions)
const response = await request({
token,
lastKnownMessageId,
limit: CHAT.FETCH_LIMIT,
}, requestOptions)
context.commit('setCancelLookForNewMessages', { requestId })
if ('x-chat-last-common-read' in response.headers) {

164
src/store/messagesStore.spec.js

@ -6,12 +6,13 @@ import Vuex from 'vuex'
import { showError } from '@nextcloud/dialogs'
import {
ATTENDEE,
ATTENDEE, CHAT,
} from '../constants.js'
import {
deleteMessage,
updateLastReadMessage,
fetchMessages,
getMessageContext,
lookForNewMessages,
postNewMessage,
} from '../services/messagesService.js'
@ -22,6 +23,7 @@ jest.mock('../services/messagesService', () => ({
deleteMessage: jest.fn(),
updateLastReadMessage: jest.fn(),
fetchMessages: jest.fn(),
getMessageContext: jest.fn(),
lookForNewMessages: jest.fn(),
postNewMessage: jest.fn(),
}))
@ -770,7 +772,7 @@ describe('messagesStore', () => {
token: TOKEN,
lastKnownMessageId: 100,
includeLastKnown: true,
limit: 100,
limit: CHAT.FETCH_LIMIT,
}, {
dummyOption: true,
})
@ -823,7 +825,7 @@ describe('messagesStore', () => {
token: TOKEN,
lastKnownMessageId: 100,
includeLastKnown: false,
limit: 100,
limit: CHAT.FETCH_LIMIT,
}, {
dummyOption: true,
})
@ -872,6 +874,161 @@ describe('messagesStore', () => {
})
})
describe('get message context', () => {
let updateLastCommonReadMessageAction
let setGuestNameIfEmptyAction
let cancelFunctionMock
beforeEach(() => {
testStoreConfig = cloneDeep(messagesStore)
updateLastCommonReadMessageAction = jest.fn()
setGuestNameIfEmptyAction = jest.fn()
testStoreConfig.actions.updateLastCommonReadMessage = updateLastCommonReadMessageAction
testStoreConfig.actions.setGuestNameIfEmpty = setGuestNameIfEmptyAction
cancelFunctionMock = jest.fn()
CancelableRequest.mockImplementation((request) => {
return {
request,
cancel: cancelFunctionMock,
}
})
store = new Vuex.Store(testStoreConfig)
})
test('get context around specified message id', async () => {
const messages = [{
id: 1,
token: TOKEN,
actorType: ATTENDEE.ACTOR_TYPE.USERS,
}, {
id: 2,
token: TOKEN,
actorType: ATTENDEE.ACTOR_TYPE.GUESTS,
}]
const response = {
headers: {
'x-chat-last-common-read': '1',
'x-chat-last-given': '2',
},
data: {
ocs: {
data: messages,
},
},
}
getMessageContext.mockResolvedValueOnce(response)
await store.dispatch('getMessageContext', {
token: TOKEN,
messageId: 1,
requestOptions: {
dummyOption: true,
},
minimumVisible: 0,
})
expect(getMessageContext).toHaveBeenCalledWith({
token: TOKEN,
messageId: 1,
limit: CHAT.FETCH_LIMIT / 2,
}, {
dummyOption: true,
})
expect(updateLastCommonReadMessageAction)
.toHaveBeenCalledWith(expect.anything(), { token: TOKEN, lastCommonReadMessage: 1 })
expect(setGuestNameIfEmptyAction).toHaveBeenCalledWith(expect.anything(), messages[1])
expect(store.getters.messagesList(TOKEN)).toStrictEqual(messages)
expect(store.getters.getFirstKnownMessageId(TOKEN)).toBe(1)
expect(store.getters.getLastKnownMessageId(TOKEN)).toBe(2)
})
test('fetch additional messages around context', async () => {
const messagesContext = [{
id: 3,
token: TOKEN,
actorType: ATTENDEE.ACTOR_TYPE.USERS,
}, {
id: 4,
token: TOKEN,
actorType: ATTENDEE.ACTOR_TYPE.GUESTS,
}]
const messagesFetch = [{
id: 1,
token: TOKEN,
actorType: ATTENDEE.ACTOR_TYPE.USERS,
}, {
id: 2,
token: TOKEN,
actorType: ATTENDEE.ACTOR_TYPE.GUESTS,
}]
const responseContext = {
headers: {
'x-chat-last-common-read': '2',
'x-chat-last-given': '4',
},
data: {
ocs: {
data: messagesContext,
},
},
}
const responseFetch = {
headers: {
'x-chat-last-common-read': '2',
'x-chat-last-given': '1',
},
data: {
ocs: {
data: messagesFetch,
},
},
}
getMessageContext.mockResolvedValueOnce(responseContext)
fetchMessages.mockResolvedValueOnce(responseFetch)
await store.dispatch('getMessageContext', {
token: TOKEN,
messageId: 3,
requestOptions: {
dummyOption: true,
},
minimumVisible: 2,
})
expect(getMessageContext).toHaveBeenCalledWith({
token: TOKEN,
messageId: 3,
limit: CHAT.FETCH_LIMIT / 2,
}, {
dummyOption: true,
})
expect(fetchMessages).toHaveBeenCalledWith({
token: TOKEN,
lastKnownMessageId: 3,
includeLastKnown: false,
limit: CHAT.FETCH_LIMIT,
}, undefined)
expect(updateLastCommonReadMessageAction).toHaveBeenCalledTimes(2)
expect(updateLastCommonReadMessageAction).toHaveBeenNthCalledWith(1, expect.anything(), { token: TOKEN, lastCommonReadMessage: 2 })
expect(updateLastCommonReadMessageAction).toHaveBeenNthCalledWith(2, expect.anything(), { token: TOKEN, lastCommonReadMessage: 2 })
expect(setGuestNameIfEmptyAction).toHaveBeenCalledWith(expect.anything(), messagesContext[1])
expect(store.getters.messagesList(TOKEN)).toStrictEqual([...messagesFetch, ...messagesContext])
expect(store.getters.getFirstKnownMessageId(TOKEN)).toBe(1)
expect(store.getters.getLastKnownMessageId(TOKEN)).toBe(4)
})
})
describe('look for new messages', () => {
let updateLastCommonReadMessageAction
let updateConversationLastMessageAction
@ -957,6 +1114,7 @@ describe('messagesStore', () => {
expect(lookForNewMessages).toHaveBeenCalledWith({
token: TOKEN,
lastKnownMessageId: 100,
limit: CHAT.FETCH_LIMIT,
}, {
dummyOption: true,
})

Loading…
Cancel
Save