Created
November 17, 2020 13:32
-
-
Save diego3g/b11d7c9f63100af250b8748d7fc902d5 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Ws from '@adonisjs/websocket-client'; | |
import { toast } from 'react-toastify'; | |
import { eventChannel } from 'redux-saga'; | |
import { all, takeLatest, call, take, put, select } from 'redux-saga/effects'; | |
import { history } from '../../../services'; | |
import { | |
subscribeUserRequest, | |
subscribeChatRequest, | |
subscribeChatSuccess, | |
closeOpenedChatConnections, | |
chatConnectionLost, | |
reconnect, | |
subscribeUserSuccess, | |
connectionLost, | |
} from './actions'; | |
import { | |
newMessageReceived, | |
getChatDataRequest, | |
messageUpdatedSuccess, | |
} from '../chat/actions'; | |
import { signOutRequest } from '../auth/actions'; | |
import { saveUserData } from '../user/actions'; | |
import { notificationNew } from '../notification/actions'; | |
import { connectionNew } from '../connection/actions'; | |
function connect(ws) { | |
return eventChannel((emitter) => { | |
ws.connect(); | |
ws.on('open', () => { | |
return emitter(reconnect()); | |
}); | |
ws.on('close', (connection) => { | |
if (connection._connectionState !== 'terminated') { | |
return emitter(connectionLost()); | |
} | |
}); | |
return () => { | |
ws.close(); | |
}; | |
}); | |
} | |
function* reconnectSocket() { | |
const connectionStatus = yield select( | |
(state) => state.websocket.connectionStatus, | |
); | |
if (connectionStatus === 'lost') { | |
const profileId = yield select((state) => state.user.data.id); | |
if (profileId) { | |
yield put(subscribeUserRequest(profileId)); | |
} | |
} | |
} | |
function* closeChannels(ws, channel) { | |
const id = yield select((state) => state.user.data.id); | |
const userChannel = ws.getSubscription(`user:${id}`); | |
if (userChannel) { | |
userChannel.close(); | |
} | |
const notificationChannel = ws.getSubscription(`notifications:${id}`); | |
if (notificationChannel) { | |
notificationChannel.close(); | |
} | |
const connectionsChannel = ws.getSubscription(`connections:${id}`); | |
if (connectionsChannel) { | |
connectionsChannel.close(); | |
} | |
const chatChannel = yield select((state) => state.websocket.chat); | |
if (chatChannel) { | |
chatChannel.close(); | |
} | |
channel.close(); | |
} | |
function subscribeUser({ ws, id }) { | |
return eventChannel((emitter) => { | |
const channel = | |
ws.getSubscription(`user:${id}`) || ws.subscribe(`user:${id}`); | |
channel.on('ready', () => { | |
return emitter(subscribeUserSuccess()); | |
}); | |
channel.on('logout', ({ forced } = { forced: false }) => { | |
if (!forced) { | |
toast.error('Login realizado em outro navegador'); | |
} | |
return emitter(signOutRequest()); | |
}); | |
channel.on('discordUpdateUser', (data) => { | |
return emitter(saveUserData(data)); | |
}); | |
return () => { | |
channel.close(); | |
}; | |
}); | |
} | |
function subscribeNotification({ ws, id }) { | |
return eventChannel((emitter) => { | |
const channel = | |
ws.getSubscription(`notifications:${id}`) || | |
ws.subscribe(`notifications:${id}`); | |
channel.on('new', (data) => { | |
return emitter(notificationNew(data)); | |
}); | |
return () => { | |
channel.close(); | |
}; | |
}); | |
} | |
function subscribeConnection({ ws, id }) { | |
return eventChannel((emitter) => { | |
const channel = | |
ws.getSubscription(`connections:${id}`) || | |
ws.subscribe(`connections:${id}`); | |
channel.on('new', (data) => { | |
return emitter(connectionNew(data)); | |
}); | |
return () => { | |
channel.close(); | |
}; | |
}); | |
} | |
function* watchNotificationSubscription(ws, { payload: { id } }) { | |
const channel = yield call(subscribeNotification, { ws, id }); | |
while (true) { | |
const action = yield take(channel); | |
yield put(action); | |
} | |
} | |
function* watchConnectionSubscription(ws, { payload: { id } }) { | |
const channel = yield call(subscribeConnection, { ws, id }); | |
while (true) { | |
const action = yield take(channel); | |
yield put(action); | |
} | |
} | |
function* watchUserSubscription(ws, { payload: { id } }) { | |
const channel = yield call(subscribeUser, { ws, id }); | |
while (true) { | |
const action = yield take(channel); | |
yield put(action); | |
} | |
} | |
function subscribeChat(ws, id, type, userId) { | |
return eventChannel((emitter) => { | |
ws.on('open', () => { | |
emitter({ type: 'RECONNECT' }); | |
}); | |
const chat = | |
ws.getSubscription(`${type}:${id}`) || ws.subscribe(`${type}:${id}`); | |
chat.on( | |
'message', | |
(message) => | |
(message.user.user_id !== userId || message.type === 'topic') && | |
emitter({ type: 'MESSAGE', payload: message }), | |
); | |
chat.on( | |
'reaction', | |
(message) => | |
(message.reactedBy !== userId || message.type === 'topic') && | |
emitter({ type: 'REACTION', payload: message }), | |
); | |
chat.on('answer', (message) => { | |
return ( | |
(message.answeredBy !== userId || message.type === 'topic') && | |
emitter({ type: 'ANSWER', payload: message }) | |
); | |
}); | |
chat.on('close', () => emitter({ type: 'CLOSE' })); | |
chat.on('error', (error) => error.message); | |
return () => { | |
chat.close(); | |
}; | |
}); | |
} | |
function* chatReconnect(id, type) { | |
const connectionStatus = yield select( | |
(state) => state.websocket.connectionStatus, | |
); | |
if (connectionStatus !== 'lost') return; | |
yield put(getChatDataRequest()); | |
yield put(subscribeChatRequest(id, type)); | |
} | |
function* chatSubscribeRequest(ws, { payload }) { | |
try { | |
const signed = yield select((state) => state.auth.signed); | |
const profileId = yield select((state) => state.user.data.id); | |
yield put(closeOpenedChatConnections()); | |
if (!signed) return; | |
const { id, type } = payload; | |
const chat = subscribeChat(ws, id, type, profileId); | |
yield put(subscribeChatSuccess(chat)); | |
try { | |
while (true) { | |
const action = yield take(chat); | |
switch (action.type) { | |
case 'MESSAGE': | |
yield put(newMessageReceived(action.payload)); | |
break; | |
case 'REACTION': | |
yield put(messageUpdatedSuccess(action.payload)); | |
break; | |
case 'ANSWER': | |
yield put(messageUpdatedSuccess(action.payload)); | |
break; | |
case 'CLOSE': | |
yield put(chatConnectionLost()); | |
break; | |
case 'RECONNECT': | |
yield call(chatReconnect, id, type); | |
break; | |
default: | |
break; | |
} | |
} | |
} catch (err) { | |
chat.close(); | |
} | |
} catch (err) { | |
history.push('/dashboard'); | |
} | |
} | |
function* closeChatConnections() { | |
try { | |
const chat = yield select((state) => state.websocket.chat); | |
yield call(chat.close); | |
} catch (err) { | |
toast.error('Houve um erro ao encerrar a conversa anterior.'); | |
} | |
} | |
function* initWebsocket() { | |
const protocol = process.env.NODE_ENV === 'development' ? 'ws' : 'wss'; | |
const ws = Ws(`${protocol}://${process.env.REACT_APP_WS_URL}`, { | |
reconnectionAttempts: 15, | |
}); | |
const token = localStorage.getItem('@Skylab:token'); | |
if (token) { | |
ws.withApiToken(token); | |
} | |
const channel = yield call(connect, ws); | |
yield all([ | |
takeLatest(subscribeUserRequest().type, watchUserSubscription, ws), | |
takeLatest(subscribeUserRequest().type, watchNotificationSubscription, ws), | |
takeLatest(subscribeUserRequest().type, watchConnectionSubscription, ws), | |
takeLatest(reconnect().type, reconnectSocket), | |
takeLatest(subscribeChatRequest().type, chatSubscribeRequest, ws), | |
takeLatest(closeOpenedChatConnections().type, closeChatConnections), | |
takeLatest(signOutRequest().type, closeChannels, ws, channel), | |
]); | |
while (true) { | |
const action = yield take(channel); | |
yield put(action); | |
} | |
} | |
export default all([takeLatest(saveUserData().type, initWebsocket)]); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment