diff --git a/src/components/MessagesList/MessagesList.vue b/src/components/MessagesList/MessagesList.vue index c81c407edd2..74a3138d9e4 100644 --- a/src/components/MessagesList/MessagesList.vue +++ b/src/components/MessagesList/MessagesList.vue @@ -129,6 +129,8 @@ export default { loadingOldMessages: false, destroying: false, + + expirationInterval: null, } }, @@ -247,8 +249,16 @@ export default { this.$store.dispatch('cancelLookForNewMessages', { requestId: oldValue }) } this.handleStartGettingMessagesPreconditions() + + // Remove expired messages when joining a room + this.removeExpiredMessagesFromStore() }, }, + + token(newToken, oldToken) { + // Expire older messages when navigating to another conversation + this.$store.dispatch('easeMessageList', { token: oldToken }) + }, }, mounted() { @@ -261,6 +271,13 @@ export default { subscribe('networkOffline', this.handleNetworkOffline) subscribe('networkOnline', this.handleNetworkOnline) window.addEventListener('focus', this.onWindowFocus) + + /** + * Every 30 seconds we remove expired messages from the store + */ + this.expirationInterval = window.setInterval(() => { + this.removeExpiredMessagesFromStore() + }, 30000) }, beforeDestroy() { @@ -275,9 +292,20 @@ export default { unsubscribe('networkOffline', this.handleNetworkOffline) unsubscribe('networkOnline', this.handleNetworkOnline) + + if (this.expirationInterval) { + clearInterval(this.expirationInterval) + this.expirationInterval = null + } }, methods: { + removeExpiredMessagesFromStore() { + this.$store.dispatch('removeExpiredMessages', { + token: this.token, + }) + }, + /** * Compare two messages to decide if they should be grouped * diff --git a/src/store/messagesStore.js b/src/store/messagesStore.js index b19b0054501..d6b64ead3ec 100644 --- a/src/store/messagesStore.js +++ b/src/store/messagesStore.js @@ -382,6 +382,43 @@ const mutations = { } } }, + + removeExpiredMessages(state, { token }) { + if (!state.messages[token]) { + return + } + + const timestamp = (new Date()) / 1000 + const messageIds = Object.keys(state.messages[token]) + messageIds.forEach((messageId) => { + if (state.messages[token][messageId].expirationTimestamp + && timestamp > state.messages[token][messageId].expirationTimestamp) { + Vue.delete(state.messages[token], messageId) + } + }) + }, + + easeMessageList(state, { token }) { + if (!state.messages[token]) { + return + } + + const messageIds = Object.keys(state.messages[token]) + if (messageIds.length < 300) { + return + } + + const messagesToRemove = messageIds.sort().reverse().slice(199) + const newFirstKnown = messagesToRemove.shift() + + messagesToRemove.forEach((messageId) => { + Vue.delete(state.messages[token], messageId) + }) + + if (state.firstKnown[token] && messagesToRemove.includes(state.firstKnown[token])) { + Vue.set(state.firstKnown, token, newFirstKnown) + } + }, } const actions = { @@ -1079,6 +1116,14 @@ const actions = { showError(t('spreed', 'Failed to remove reaction')) } }, + + async removeExpiredMessages(context, { token }) { + context.commit('removeExpiredMessages', { token }) + }, + + async easeMessageList(context, { token }) { + context.commit('easeMessageList', { token }) + }, } export default { state, mutations, getters, actions }