/* eslint-disable no-case-declarations */ import { useEffect } from 'react'; import { atom, useRecoilState, useSetRecoilState } from 'recoil'; import { makeEmptyClientConfig, ClientConfig } from '../../interfaces/client-config.model'; import ClientConfigService from '../../services/client-config-service'; import ChatService from '../../services/chat-service'; import WebsocketService from '../../services/websocket-service'; import { ChatMessage } from '../../interfaces/chat-message.model'; import { ServerStatus, makeEmptyServerStatus } from '../../interfaces/server-status.model'; import { AppState, ChatState, VideoState, ChatVisibilityState, getChatState, getChatVisibilityState, } from '../../interfaces/application-state'; import { ConnectedClientInfoEvent, MessageType, ChatEvent, SocketEvent, } from '../../interfaces/socket-events'; import handleConnectedClientInfoMessage from './eventhandlers/connectedclientinfo'; import handleChatMessage from './eventhandlers/handleChatMessage'; import ServerStatusService from '../../services/status-service'; // Server status is what gets updated such as viewer count, durations, // stream title, online/offline state, etc. export const serverStatusState = atom({ key: 'serverStatusState', default: makeEmptyServerStatus(), }); // The config that comes from the API. export const clientConfigStateAtom = atom({ key: 'clientConfigState', default: makeEmptyClientConfig(), }); export const appStateAtom = atom({ key: 'appStateAtom', default: AppState.Loading, }); export const chatStateAtom = atom({ key: 'chatStateAtom', default: ChatState.Offline, }); export const videoStateAtom = atom({ key: 'videoStateAtom', default: VideoState.Unavailable, }); export const chatVisibilityAtom = atom({ key: 'chatVisibility', default: ChatVisibilityState.Visible, }); export const chatDisplayNameAtom = atom({ key: 'chatDisplayName', default: null, }); export const accessTokenAtom = atom({ key: 'accessTokenAtom', default: null, }); export const chatMessagesAtom = atom({ key: 'chatMessages', default: [] as ChatMessage[], }); export const websocketServiceAtom = atom({ key: 'websocketServiceAtom', default: null, }); export function ClientConfigStore() { const setClientConfig = useSetRecoilState(clientConfigStateAtom); const setServerStatus = useSetRecoilState(serverStatusState); const setChatVisibility = useSetRecoilState(chatVisibilityAtom); const setChatState = useSetRecoilState(chatStateAtom); const [chatMessages, setChatMessages] = useRecoilState(chatMessagesAtom); const setChatDisplayName = useSetRecoilState(chatDisplayNameAtom); const [appState, setAppState] = useRecoilState(appStateAtom); const [accessToken, setAccessToken] = useRecoilState(accessTokenAtom); const setWebsocketService = useSetRecoilState(websocketServiceAtom); let ws: WebsocketService; const updateClientConfig = async () => { try { const config = await ClientConfigService.getConfig(); setClientConfig(config); } catch (error) { console.error(`ClientConfigService -> getConfig() ERROR: \n${error}`); } }; const updateServerStatus = async () => { try { const status = await ServerStatusService.getStatus(); setServerStatus(status); if (status.online) { setAppState(AppState.Online); } else { setAppState(AppState.Offline); } return status; } catch (error) { console.error(`serverStatusState -> getStatus() ERROR: \n${error}`); return null; } }; const handleUserRegistration = async (optionalDisplayName?: string) => { try { setAppState(AppState.Registering); const response = await ChatService.registerUser(optionalDisplayName); console.log(`ChatService -> registerUser() response: \n${response}`); const { accessToken: newAccessToken, displayName: newDisplayName } = response; if (!newAccessToken) { return; } console.log('setting access token', newAccessToken); setAccessToken(newAccessToken); // setLocalStorage('accessToken', newAccessToken); setChatDisplayName(newDisplayName); } catch (e) { console.error(`ChatService -> registerUser() ERROR: \n${e}`); } }; const handleMessage = (message: SocketEvent) => { switch (message.type) { case MessageType.CONNECTED_USER_INFO: handleConnectedClientInfoMessage(message as ConnectedClientInfoEvent); break; case MessageType.CHAT: handleChatMessage(message as ChatEvent, chatMessages, setChatMessages); break; default: console.error('Unknown socket message type: ', message.type); } }; const getChatHistory = async () => { try { const messages = await ChatService.getChatHistory(accessToken); const updatedChatMessages = [...messages, ...chatMessages]; setChatMessages(updatedChatMessages); } catch (error) { console.error(`ChatService -> getChatHistory() ERROR: \n${error}`); } }; const startChat = async () => { setChatState(ChatState.Loading); try { ws = new WebsocketService(accessToken, '/ws'); ws.handleMessage = handleMessage; setWebsocketService(ws); } catch (error) { console.error(`ChatService -> startChat() ERROR: \n${error}`); } }; useEffect(() => { updateClientConfig(); handleUserRegistration(); }, []); useEffect(() => { setInterval(() => { updateServerStatus(); }, 5000); updateServerStatus(); }, []); useEffect(() => { if (!accessToken) { return; } getChatHistory(); startChat(); }, [accessToken]); useEffect(() => { const updatedChatState = getChatState(appState); console.log('updatedChatState', updatedChatState); setChatState(updatedChatState); const updatedChatVisibility = getChatVisibilityState(appState); console.log( 'app state: ', AppState[appState], 'chat state:', ChatState[updatedChatState], 'chat visibility:', ChatVisibilityState[updatedChatVisibility], ); setChatVisibility(updatedChatVisibility); }, [appState]); return null; }