Updated streaming and improved error-handling, some more refactoring to api

This commit is contained in:
Henry Jameson 2019-12-08 16:05:41 +02:00
parent 172ebaf4e6
commit ff95d865d2
7 changed files with 84 additions and 40 deletions

View File

@ -10,7 +10,7 @@ const PublicAndExternalTimeline = {
this.$store.dispatch('startFetchingTimeline', { timeline: 'publicAndExternal' })
},
destroyed () {
this.$store.dispatch('stopFetching', 'publicAndExternal')
this.$store.dispatch('stopFetchingTimeline', 'publicAndExternal')
}
}

View File

@ -10,7 +10,7 @@ const PublicTimeline = {
this.$store.dispatch('startFetchingTimeline', { timeline: 'public' })
},
destroyed () {
this.$store.dispatch('stopFetching', 'public')
this.$store.dispatch('stopFetchingTimeline', 'public')
}
}

View File

@ -19,7 +19,7 @@ const TagTimeline = {
}
},
destroyed () {
this.$store.dispatch('stopFetching', 'tag')
this.$store.dispatch('stopFetchingTimeline', 'tag')
}
}

View File

@ -112,9 +112,9 @@ const UserProfile = {
}
},
stopFetching () {
this.$store.dispatch('stopFetching', 'user')
this.$store.dispatch('stopFetching', 'favorites')
this.$store.dispatch('stopFetching', 'media')
this.$store.dispatch('stopFetchingTimeline', 'user')
this.$store.dispatch('stopFetchingTimeline', 'favorites')
this.$store.dispatch('stopFetchingTimeline', 'media')
},
switchUser (userNameOrId) {
this.stopFetching()

View File

@ -6,7 +6,7 @@ const api = {
backendInteractor: backendInteractorService(),
fetchers: {},
socket: null,
mastoSocket: null,
mastoUserSocket: null,
followRequests: []
},
mutations: {
@ -16,7 +16,8 @@ const api = {
addFetcher (state, { fetcherName, fetcher }) {
state.fetchers[fetcherName] = fetcher
},
removeFetcher (state, { fetcherName }) {
removeFetcher (state, { fetcherName, fetcher }) {
window.clearInterval(fetcher)
delete state.fetchers[fetcherName]
},
setWsToken (state, token) {
@ -30,13 +31,14 @@ const api = {
}
},
actions: {
startMastoSocket (store) {
// MastoAPI 'User' sockets
startMastoUserSocket (store) {
const { state, dispatch } = store
state.mastoSocket = state.backendInteractor
state.mastoUserSocket = state.backendInteractor
.startUserSocket({
store,
onMessage: (message) => {
if (!message) return
if (!message) return // pings
if (message.event === 'notification') {
dispatch('addNewNotifications', {
notifications: [message.notification],
@ -52,41 +54,86 @@ const api = {
}
}
})
state.mastoSocket.addEventListener('error', error => {
console.error('Error with MastoAPI websocket:', error)
dispatch('startFetchingTimeline', { timeline: 'friends' })
dispatch('startFetchingNotifications')
state.mastoUserSocket.addEventListener('error', error => {
console.error('Error in MastoAPI websocket:', error)
})
state.mastoUserSocket.addEventListener('close', closeEvent => {
const ignoreCodes = new Set([
1000, // Normal (intended) closure
1001 // Going away
])
const { code } = closeEvent
console.debug('Socket closure event:', closeEvent)
if (ignoreCodes.has(code)) {
console.debug(`Not restarting socket becasue of closure code ${code} is in ignore list`)
} else {
console.warn(`MastoAPI websocket disconnected, restarting. CloseEvent code: ${code}`)
dispatch('startFetchingTimeline', { timeline: 'friends' })
dispatch('startFetchingNotifications')
dispatch('restartMastoUserSocket')
}
})
},
startFetchingTimeline (store, { timeline = 'friends', tag = false, userId = false }) {
// Don't start fetching if we already are.
restartMastoUserSocket ({ dispatch }) {
// This basically starts MastoAPI user socket and stops conventional
// fetchers when connection reestablished
dispatch('startMastoUserSocket').then(() => {
dispatch('stopFetchingTimeline', { timeline: 'friends' })
dispatch('stopFetchingNotifications')
})
},
// Timelines
startFetchingTimeline (store, {
timeline = 'friends',
tag = false,
userId = false
}) {
if (store.state.fetchers[timeline]) return
const fetcher = store.state.backendInteractor.startFetchingTimeline({ timeline, store, userId, tag })
const fetcher = store.state.backendInteractor.startFetchingTimeline({
timeline, store, userId, tag
})
store.commit('addFetcher', { fetcherName: timeline, fetcher })
},
startFetchingNotifications (store) {
// Don't start fetching if we already are.
if (store.state.fetchers['notifications']) return
stopFetchingTimeline (store, timeline) {
const fetcher = store.state.fetchers[timeline]
if (!fetcher) return
store.commit('removeFetcher', { fetcherName: timeline, fetcher })
},
// Notifications
startFetchingNotifications (store) {
if (store.state.fetchers.notifications) return
const fetcher = store.state.backendInteractor.startFetchingNotifications({ store })
store.commit('addFetcher', { fetcherName: 'notifications', fetcher })
},
stopFetchingNotifications (store) {
const fetcher = store.state.fetchers.notifications
if (!fetcher) return
store.commit('removeFetcher', { fetcherName: 'notifications', fetcher })
},
fetchAndUpdateNotifications (store) {
store.state.backendInteractor.fetchAndUpdateNotifications({ store })
},
startFetchingFollowRequest (store) {
// Don't start fetching if we already are.
if (store.state.fetchers['followRequest']) return
const fetcher = store.state.backendInteractor.startFetchingFollowRequest({ store })
store.commit('addFetcher', { fetcherName: 'followRequest', fetcher })
// Follow requests
startFetchingFollowRequests (store) {
if (store.state.fetchers['followRequests']) return
const fetcher = store.state.backendInteractor.startFetchingFollowRequests({ store })
store.commit('addFetcher', { fetcherName: 'followRequests', fetcher })
},
stopFetching (store, fetcherName) {
const fetcher = store.state.fetchers[fetcherName]
window.clearInterval(fetcher)
store.commit('removeFetcher', { fetcherName })
stopFetchingFollowRequests (store) {
const fetcher = store.state.fetchers.followRequests
if (!fetcher) return
store.commit('removeFetcher', { fetcherName: 'followRequests', fetcher })
},
removeFollowRequest (store, request) {
let requests = store.state.followRequests.filter((it) => it !== request)
store.commit('setFollowRequests', requests)
},
// Pleroma websocket
setWsToken (store, token) {
store.commit('setWsToken', token)
},
@ -104,10 +151,6 @@ const api = {
disconnectFromSocket ({ commit, state }) {
state.socket && state.socket.disconnect()
commit('setSocket', null)
},
removeFollowRequest (store, request) {
let requests = store.state.followRequests.filter((it) => it !== request)
store.commit('setFollowRequests', requests)
}
}
}

View File

@ -431,10 +431,10 @@ const users = {
store.commit('clearCurrentUser')
store.dispatch('disconnectFromSocket')
store.commit('clearToken')
store.dispatch('stopFetching', 'friends')
store.dispatch('stopFetchingTimeline', 'friends')
store.commit('setBackendInteractor', backendInteractorService(store.getters.getToken()))
store.dispatch('stopFetching', 'notifications')
store.dispatch('stopFetching', 'followRequest')
store.dispatch('stopFetchingNotifications')
store.dispatch('stopFetchingFollowRequests')
store.commit('clearNotifications')
store.commit('resetStatuses')
})
@ -469,7 +469,7 @@ const users = {
store.dispatch('initializeSocket')
}
store.dispatch('startMastoSocket').catch((error) => {
store.dispatch('startMastoUserSocket').catch((error) => {
console.error('Failed initializing MastoAPI Streaming socket', error)
// Start getting fresh posts.
store.dispatch('startFetchingTimeline', { timeline: 'friends' })

View File

@ -24,10 +24,11 @@ const backendInteractorService = credentials => ({
const serv = store.rootState.instance.server.replace('http', 'ws')
const url = serv + getMastodonSocketURI({ credentials, stream: 'user' })
const socket = new WebSocket(url)
console.log(socket)
console.debug('Socket created:', socket)
if (socket) {
socket.addEventListener('open', (wsEvent) => console.debug('MastoAPI User WebSocket connection established'))
socket.addEventListener('message', (wsEvent) => onMessage(handleMastoWS(wsEvent)))
socket.addEventListener('error', (error) => console.error('WebSocket Error:', error))
socket.addEventListener('error', (error) => console.error('MastoApi User WebSocket Error:', error))
return socket
} else {
throw new Error('failed to connect to socket')