2016-11-26 17:57:08 +00:00
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
2020-05-07 13:10:53 +00:00
import { WSConnectionStatus } from '../services/api/api.service.js'
2020-07-12 21:06:45 +00:00
import { maybeShowChatNotification } from '../services/chat_utils/chat_utils.js'
2017-12-05 10:47:10 +00:00
import { Socket } from 'phoenix'
2016-11-26 17:57:08 +00:00
const api = {
state : {
2017-02-16 10:17:47 +00:00
backendInteractor : backendInteractorService ( ) ,
2017-12-05 10:47:10 +00:00
fetchers : { } ,
2017-12-07 16:20:44 +00:00
socket : null ,
2019-12-08 14:05:41 +00:00
mastoUserSocket : null ,
2020-05-07 13:10:53 +00:00
mastoUserSocketStatus : null ,
2018-06-07 01:24:31 +00:00
followRequests : [ ]
2016-11-26 17:57:08 +00:00
} ,
mutations : {
setBackendInteractor ( state , backendInteractor ) {
state . backendInteractor = backendInteractor
2017-02-16 10:17:47 +00:00
} ,
2019-04-04 16:06:53 +00:00
addFetcher ( state , { fetcherName , fetcher } ) {
2019-04-04 16:03:56 +00:00
state . fetchers [ fetcherName ] = fetcher
2017-02-16 10:17:47 +00:00
} ,
2019-12-08 14:05:41 +00:00
removeFetcher ( state , { fetcherName , fetcher } ) {
2020-09-04 08:19:53 +00:00
state . fetchers [ fetcherName ] . stop ( )
2019-04-04 16:03:56 +00:00
delete state . fetchers [ fetcherName ]
2017-12-05 10:47:10 +00:00
} ,
2019-01-29 15:16:25 +00:00
setWsToken ( state , token ) {
state . wsToken = token
} ,
2017-12-05 10:47:10 +00:00
setSocket ( state , socket ) {
state . socket = socket
2017-12-07 16:20:44 +00:00
} ,
2018-06-07 01:24:31 +00:00
setFollowRequests ( state , value ) {
state . followRequests = value
2020-05-07 13:10:53 +00:00
} ,
setMastoUserSocketStatus ( state , value ) {
state . mastoUserSocketStatus = value
2017-02-16 10:17:47 +00:00
}
} ,
actions : {
2019-12-10 19:30:27 +00:00
// Global MastoAPI socket control, in future should disable ALL sockets/(re)start relevant sockets
enableMastoSockets ( store ) {
const { state , dispatch } = store
if ( state . mastoUserSocket ) return
2019-12-26 12:12:35 +00:00
return dispatch ( 'startMastoUserSocket' )
2019-12-10 19:30:27 +00:00
} ,
disableMastoSockets ( store ) {
const { state , dispatch } = store
if ( ! state . mastoUserSocket ) return
2019-12-26 12:12:35 +00:00
return dispatch ( 'stopMastoUserSocket' )
2019-12-10 19:30:27 +00:00
} ,
2019-12-08 14:05:41 +00:00
// MastoAPI 'User' sockets
startMastoUserSocket ( store ) {
2019-12-26 12:12:35 +00:00
return new Promise ( ( resolve , reject ) => {
try {
2020-05-07 13:10:53 +00:00
const { state , commit , dispatch , rootState } = store
2019-12-26 12:35:46 +00:00
const timelineData = rootState . statuses . timelines . friends
2019-12-26 12:12:35 +00:00
state . mastoUserSocket = state . backendInteractor . startUserSocket ( { store } )
state . mastoUserSocket . addEventListener (
'message' ,
( { detail : message } ) => {
if ( ! message ) return // pings
if ( message . event === 'notification' ) {
dispatch ( 'addNewNotifications' , {
notifications : [ message . notification ] ,
older : false
} )
} else if ( message . event === 'update' ) {
dispatch ( 'addNewStatuses' , {
statuses : [ message . status ] ,
userId : false ,
2019-12-26 12:35:46 +00:00
showImmediately : timelineData . visibleStatuses . length === 0 ,
2019-12-26 12:12:35 +00:00
timeline : 'friends'
} )
2020-09-06 12:28:09 +00:00
} else if ( message . event === 'delete' ) {
dispatch ( 'deleteStatusById' , message . id )
2020-05-07 13:10:53 +00:00
} else if ( message . event === 'pleroma:chat_update' ) {
2020-10-29 10:33:06 +00:00
// The setTimeout wrapper is a temporary band-aid to avoid duplicates for the user's own messages when doing optimistic sending.
// The cause of the duplicates is the WS event arriving earlier than the HTTP response.
// This setTimeout wrapper can be removed once the commit `8e41baff` is in the stable Pleroma release.
// (`8e41baff` adds the idempotency key to the chat message entity, which PleromaFE uses when it's available, and it makes this artificial delay unnecessary).
setTimeout ( ( ) => {
dispatch ( 'addChatMessages' , {
chatId : message . chatUpdate . id ,
messages : [ message . chatUpdate . lastMessage ]
} )
dispatch ( 'updateChat' , { chat : message . chatUpdate } )
maybeShowChatNotification ( store , message . chatUpdate )
} , 100 )
2019-12-26 12:12:35 +00:00
}
}
)
2020-05-07 13:10:53 +00:00
state . mastoUserSocket . addEventListener ( 'open' , ( ) => {
commit ( 'setMastoUserSocketStatus' , WSConnectionStatus . JOINED )
} )
2019-12-26 12:12:35 +00:00
state . mastoUserSocket . addEventListener ( 'error' , ( { detail : error } ) => {
console . error ( 'Error in MastoAPI websocket:' , error )
2020-05-07 13:10:53 +00:00
commit ( 'setMastoUserSocketStatus' , WSConnectionStatus . ERROR )
dispatch ( 'clearOpenedChats' )
2019-12-26 12:12:35 +00:00
} )
state . mastoUserSocket . addEventListener ( 'close' , ( { detail : closeEvent } ) => {
const ignoreCodes = new Set ( [
1000 , // Normal (intended) closure
1001 // Going away
] )
const { code } = 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' )
2020-05-07 13:10:53 +00:00
dispatch ( 'startFetchingChats' )
2019-12-26 12:12:35 +00:00
dispatch ( 'restartMastoUserSocket' )
}
2020-05-07 13:10:53 +00:00
commit ( 'setMastoUserSocketStatus' , WSConnectionStatus . CLOSED )
dispatch ( 'clearOpenedChats' )
2019-12-26 12:12:35 +00:00
} )
resolve ( )
} catch ( e ) {
reject ( e )
2019-12-08 14:05:41 +00:00
}
2019-11-24 20:01:12 +00:00
} )
2019-11-24 16:50:28 +00:00
} ,
2019-12-08 14:05:41 +00:00
restartMastoUserSocket ( { dispatch } ) {
// This basically starts MastoAPI user socket and stops conventional
// fetchers when connection reestablished
2019-12-26 12:12:35 +00:00
return dispatch ( 'startMastoUserSocket' ) . then ( ( ) => {
2019-12-08 14:05:41 +00:00
dispatch ( 'stopFetchingTimeline' , { timeline : 'friends' } )
dispatch ( 'stopFetchingNotifications' )
2020-05-07 13:10:53 +00:00
dispatch ( 'stopFetchingChats' )
2019-12-08 14:05:41 +00:00
} )
} ,
2019-12-10 19:30:27 +00:00
stopMastoUserSocket ( { state , dispatch } ) {
dispatch ( 'startFetchingTimeline' , { timeline : 'friends' } )
dispatch ( 'startFetchingNotifications' )
2020-05-07 13:10:53 +00:00
dispatch ( 'startFetchingChats' )
2019-12-10 19:30:27 +00:00
state . mastoUserSocket . close ( )
} ,
2019-12-08 14:05:41 +00:00
// Timelines
startFetchingTimeline ( store , {
timeline = 'friends' ,
tag = false ,
userId = false
} ) {
2019-02-07 23:23:18 +00:00
if ( store . state . fetchers [ timeline ] ) return
2019-12-08 14:05:41 +00:00
const fetcher = store . state . backendInteractor . startFetchingTimeline ( {
timeline , store , userId , tag
} )
2019-04-04 16:03:56 +00:00
store . commit ( 'addFetcher' , { fetcherName : timeline , fetcher } )
2017-02-16 10:17:47 +00:00
} ,
2019-12-08 14:05:41 +00:00
stopFetchingTimeline ( store , timeline ) {
const fetcher = store . state . fetchers [ timeline ]
if ( ! fetcher ) return
store . commit ( 'removeFetcher' , { fetcherName : timeline , fetcher } )
} ,
2019-04-04 16:03:56 +00:00
2019-12-08 14:05:41 +00:00
// Notifications
startFetchingNotifications ( store ) {
if ( store . state . fetchers . notifications ) return
2019-04-04 16:03:56 +00:00
const fetcher = store . state . backendInteractor . startFetchingNotifications ( { store } )
store . commit ( 'addFetcher' , { fetcherName : 'notifications' , fetcher } )
} ,
2019-12-08 14:05:41 +00:00
stopFetchingNotifications ( store ) {
const fetcher = store . state . fetchers . notifications
if ( ! fetcher ) return
store . commit ( 'removeFetcher' , { fetcherName : 'notifications' , fetcher } )
} ,
2019-11-19 14:07:15 +00:00
2019-12-08 14:05:41 +00:00
// Follow requests
startFetchingFollowRequests ( store ) {
if ( store . state . fetchers [ 'followRequests' ] ) return
const fetcher = store . state . backendInteractor . startFetchingFollowRequests ( { store } )
2020-01-21 15:51:49 +00:00
2019-12-08 14:05:41 +00:00
store . commit ( 'addFetcher' , { fetcherName : 'followRequests' , fetcher } )
2019-11-19 14:07:15 +00:00
} ,
2019-12-08 14:05:41 +00:00
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 )
2017-12-05 10:47:10 +00:00
} ,
2019-12-08 14:05:41 +00:00
// Pleroma websocket
2019-01-29 15:16:25 +00:00
setWsToken ( store , token ) {
store . commit ( 'setWsToken' , token )
} ,
2019-08-17 08:18:42 +00:00
initializeSocket ( { dispatch , commit , state , rootState } ) {
2017-12-05 10:47:10 +00:00
// Set up websocket connection
2019-08-17 08:18:42 +00:00
const token = state . wsToken
if ( rootState . instance . chatAvailable && typeof token !== 'undefined' && state . socket === null ) {
2019-06-18 20:28:31 +00:00
const socket = new Socket ( '/socket' , { params : { token } } )
2017-12-07 16:20:44 +00:00
socket . connect ( )
2019-08-17 08:18:42 +00:00
commit ( 'setSocket' , socket )
dispatch ( 'initializeChat' , socket )
2017-12-07 16:20:44 +00:00
}
} ,
2019-08-17 08:18:42 +00:00
disconnectFromSocket ( { commit , state } ) {
state . socket && state . socket . disconnect ( )
commit ( 'setSocket' , null )
2016-11-26 17:57:08 +00:00
}
}
}
export default api