diff --git a/src/components/chat_view/chat_view.js b/src/components/chat_view/chat_view.js index ab655cc39..44eaf57cf 100644 --- a/src/components/chat_view/chat_view.js +++ b/src/components/chat_view/chat_view.js @@ -268,14 +268,17 @@ const Chat = { }, attachSocket() { const et = new EventTarget() - const socket = { et } + const socket = { + name: 'chatview', + et, + } et.addEventListener('update', this.onStreamMessage) et.addEventListener('open', this.onStreamConnect) et.addEventListener('close', this.onStreamDisconnect) - useStreamingStore().addSubscriber(socket) this.socket = socket + useStreamingStore().addSubscriber(this.socket) }, detachSocket() { const { et } = this.socket diff --git a/src/stores/chats.js b/src/stores/chats.js index 9da01c76b..66e483b18 100644 --- a/src/stores/chats.js +++ b/src/stores/chats.js @@ -37,7 +37,10 @@ export const useChatsStore = defineStore('chats', { actions: { attachSocket() { const et = new EventTarget() - const socket = { et } + const socket = { + name: 'chats', + et, + } et.addEventListener('pleroma:chat_update', this.updateChat) diff --git a/src/stores/interface.js b/src/stores/interface.js index 5dd4fa8df..e87a0ecd9 100644 --- a/src/stores/interface.js +++ b/src/stores/interface.js @@ -96,7 +96,10 @@ export const useInterfaceStore = defineStore('interface', { actions: { attachSocket() { const et = new EventTarget() - const socket = { et } + const socket = { + name: 'interface', + et, + } et.addEventListener('open', this.onStreamConnect) et.addEventListener('close', this.onStreamDisconnect) diff --git a/src/stores/notifications.js b/src/stores/notifications.js index eb9257602..3405fb352 100644 --- a/src/stores/notifications.js +++ b/src/stores/notifications.js @@ -31,7 +31,9 @@ export const defaultState = () => ({ statusIdStore: new Set(), socket: null, streaming: false, + fetching: true, fetcher: null, + paused: false, }) export const useNotificationsStore = defineStore('notifications', { @@ -40,14 +42,29 @@ export const useNotificationsStore = defineStore('notifications', { // Init attachSocket() { const et = new EventTarget() - const socket = { et } + const socket = { + name: 'notifications', + et, + } et.addEventListener('notification', this.addNewNotifications) et.addEventListener('open', this.onStreamConnect) et.addEventListener('close', this.onStreamDisconnect) - useStreamingStore().addSubscriber(socket) this.socket = socket + useStreamingStore().addSubscriber(this.socket) + }, + pause() { + this.paused = true + if (this.fetcher && this.fetching) { + this.stopFetching('Notifications paused') + } + }, + resume() { + this.paused = false + if (this.fetcher && this.fetching) { + this.startFetching('Notifications resumed') + } }, activate() { this.attachSocket() @@ -62,7 +79,7 @@ export const useNotificationsStore = defineStore('notifications', { this.startFetching('Notifications activated') }, deactivate() { - if (!this.streaming) { + if (this.fetching) { this.stopFetching('Notifications deactivated') } @@ -77,6 +94,7 @@ export const useNotificationsStore = defineStore('notifications', { Object.keys(blankState).forEach((k) => { this[k] = blankState[k] }) + console.log('[Notifications] Deactivated', this.fetcher) }, // Poll & Push @@ -91,20 +109,30 @@ export const useNotificationsStore = defineStore('notifications', { this.startFetching('Socket disconnected') }, startFetching(reason) { + if (this.paused) { + console.debug( + '[Notificatiosn] NOT Starting notifications fetcher because it is paused', + 'Original Reason:', + reason, + ) + return + } console.debug( - '[Notifications] Starting fetching notifications', + '[Notifications] Starting notifications fetcher', 'Reason:', reason, ) this.fetcher.startFetching() + this.fetching = true }, stopFetching(reason) { + this.fetcher.stopFetching() + this.fetching = false console.debug( - '[Notifications] Stopped fetching notifications', + '[Notifications] Stopped notifications fetcher', 'Reason:', reason, ) - this.fetcher.stopFetching() }, // Updates diff --git a/src/stores/statuses.js b/src/stores/statuses.js index 0bcbc29f6..337cb399d 100644 --- a/src/stores/statuses.js +++ b/src/stores/statuses.js @@ -49,6 +49,7 @@ export const useStatusesStore = defineStore('statuses', { data.forEach((id) => this.setDeleted(id)) const socket = { + name: 'statuses', et, handlers: { handleUpdate, diff --git a/src/stores/timelines.js b/src/stores/timelines.js index a6fdcc64f..190396f48 100644 --- a/src/stores/timelines.js +++ b/src/stores/timelines.js @@ -16,9 +16,11 @@ const emptyTl = (name, argument = null) => { maxId: '', minId: '', streaming: false, + fetching: false, reloadNeeded: false, fetcher: null, socket: null, + paused: false, } const property = ARGUMENT_MAP[name] @@ -114,6 +116,7 @@ export const useTimelinesStore = defineStore('timelines', { et.addEventListener('update', messageHandler) timeline.socket = { + name: 'timelines', stream: { name: streamName, argument, @@ -132,7 +135,7 @@ export const useTimelinesStore = defineStore('timelines', { deactivate(timelineName, persistent) { const timeline = this[timelineName] if (timeline.persistent && !persistent) return - if (!timeline.streaming) { + if (timeline.fetching) { this.stopFetchingTimeline(timelineName, 'Timeline deactivation') } @@ -176,6 +179,48 @@ export const useTimelinesStore = defineStore('timelines', { }) }, + // Pause + pause(name) { + const timeline = this[name] + timeline.paused = true + console.debug( + '[Timelines] Pausing timeline', + name, + ) + if (timeline.fetcher && timeline.fetching) { + timeline.fetcher.stopFetching() + } + }, + resume(name) { + const timeline = this[name] + timeline.paused = false + console.debug( + '[Timelines] Resuming timeline', + name, + ) + if (timeline.fetcher && timeline.fetching) { + timeline.fetcher.startFetching() + } + }, + pauseAll() { + TIMELINES.forEach((name) => { + try { + this.pause(name) + } catch (e) { + console.error(`[Timelines] Failed to pause timeline ${name}:`, e) + } + }) + }, + resumeAll() { + TIMELINES.forEach((name) => { + try { + this.resume(name) + } catch (e) { + console.error(`[Timelines] Failed to pause timeline ${name}:`, e) + } + }) + }, + // Update stuff addStatusesToTimeline( timelineName, @@ -246,15 +291,28 @@ export const useTimelinesStore = defineStore('timelines', { this.startFetchingTimeline(timeline, argument, 'Socket disconnected') }, startFetchingTimeline(timelineName, argument, reason) { + const timeline = this[timelineName] + console.log('[Timelines]', toValue(timeline)) + if (timeline.paused) { + console.debug( + '[Timelines] NOT Starting timeline fetcher because it is paused', + timelineName, + argument, + 'Original Reason:', + reason, + ) + return + } + console.debug( - '[Timelines] Starting fetching timeline', + '[Timelines] Starting timeline fetcher', timelineName, argument, 'Reason:', reason, ) - const timeline = this[timelineName] timeline.fetcher.startFetching() + timeline.fetching = true }, stopFetchingTimeline(timelineName, reason) { const timeline = this[timelineName] @@ -274,6 +332,7 @@ export const useTimelinesStore = defineStore('timelines', { 'Reason:', reason, ) + timeline.fetching = false } }, diff --git a/src/stores/users.js b/src/stores/users.js index 10d9222c9..60ed893a5 100644 --- a/src/stores/users.js +++ b/src/stores/users.js @@ -2,6 +2,8 @@ import Cookies from 'js-cookie' import { last } from 'lodash' import { defineStore } from 'pinia' +import { WSConnectionStatus } from 'src/api/websocket.js' + import { useAnnouncementsStore } from 'src/stores/announcements.js' import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders.js' import { useChatsStore } from 'src/stores/chats.js' @@ -708,6 +710,16 @@ export const useUsersStore = defineStore('users', { const store = window.vuex const oauth = useOAuthStore() + // Pause fetching + useNotificationsStore().pause() + useTimelinesStore().pauseAll() + + // Pause-less stores + useAnnouncementsStore().stopFetching() + useListsStore().stopFetching() + useBookmarkFoldersStore().stopFetching() + store?.dispatch('stopFetchingFollowRequests') + // NOTE: No need to verify the app still exists, because if it doesn't, // the token will be invalid too return oauth @@ -722,6 +734,8 @@ export const useUsersStore = defineStore('users', { return revokeToken(params) }) .then(() => { + oauth.clearToken() + this.currentUser = null this.lastLoginName = null @@ -729,21 +743,45 @@ export const useUsersStore = defineStore('users', { this.usersByName = new Map() this.usersByURL = new Map() this.relationships = new Map() + useNotificationsStore().deactivate() - useAnnouncementsStore().stopFetching() - useListsStore().stopFetching() - useBookmarkFoldersStore().stopFetching() - store?.dispatch('stopFetchingFollowRequests') useTimelinesStore().deactivateAll() + + // Full reset on logout success useStatusesStore().resetStatuses() - if (useMergedConfigStore().mergedConfig.useStreamingApi) { + useTimelinesStore().deactivateAll() + useChatsStore().resetChats() + + // Socket is most likely already closed by server + if ( + useMergedConfigStore().mergedConfig.useStreamingApi + && useStreamingStore().state !== WSConnectionStatus.CLOSED + ) { useStreamingStore().stopSocket() } - useChatsStore().resetChats() - oauth.clearToken() + Cookies.remove('__Host-pleroma_key', { path: '/' }) useInterfaceStore().onLogout() }) + .catch((e) => { + useInterfaceStore().pushGlobalNotice({ + messageKey: 'user.logout_failure', + messageArgs: { + error: e, + }, + level: 'error', + }) + console.error('Logout error!', e) + + useAnnouncementsStore().startFetching() + useListsStore().startFetching() + useBookmarkFoldersStore().startFetching() + store?.dispatch('startFetchingFollowRequests') + }) + .finally(() => { + useNotificationsStore().resume() + useTimelinesStore().resumeAll() + }) }, }, persist: {