You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
210 lines
6.3 KiB
210 lines
6.3 KiB
/* 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<ServerStatus>({ |
|
key: 'serverStatusState', |
|
default: makeEmptyServerStatus(), |
|
}); |
|
|
|
// The config that comes from the API. |
|
export const clientConfigStateAtom = atom({ |
|
key: 'clientConfigState', |
|
default: makeEmptyClientConfig(), |
|
}); |
|
|
|
export const appStateAtom = atom<AppState>({ |
|
key: 'appStateAtom', |
|
default: AppState.Loading, |
|
}); |
|
|
|
export const chatStateAtom = atom<ChatState>({ |
|
key: 'chatStateAtom', |
|
default: ChatState.Offline, |
|
}); |
|
|
|
export const videoStateAtom = atom<VideoState>({ |
|
key: 'videoStateAtom', |
|
default: VideoState.Unavailable, |
|
}); |
|
|
|
export const chatVisibilityAtom = atom<ChatVisibilityState>({ |
|
key: 'chatVisibility', |
|
default: ChatVisibilityState.Visible, |
|
}); |
|
|
|
export const chatDisplayNameAtom = atom<string>({ |
|
key: 'chatDisplayName', |
|
default: null, |
|
}); |
|
|
|
export const accessTokenAtom = atom<string>({ |
|
key: 'accessTokenAtom', |
|
default: null, |
|
}); |
|
|
|
export const chatMessagesAtom = atom<ChatMessage[]>({ |
|
key: 'chatMessages', |
|
default: [] as ChatMessage[], |
|
}); |
|
|
|
export const websocketServiceAtom = atom<WebsocketService>({ |
|
key: 'websocketServiceAtom', |
|
default: null, |
|
}); |
|
|
|
export function ClientConfigStore() { |
|
const setClientConfig = useSetRecoilState<ClientConfig>(clientConfigStateAtom); |
|
const setServerStatus = useSetRecoilState<ServerStatus>(serverStatusState); |
|
const setChatVisibility = useSetRecoilState<ChatVisibilityState>(chatVisibilityAtom); |
|
const setChatState = useSetRecoilState<ChatState>(chatStateAtom); |
|
const [chatMessages, setChatMessages] = useRecoilState<ChatMessage[]>(chatMessagesAtom); |
|
const setChatDisplayName = useSetRecoilState<string>(chatDisplayNameAtom); |
|
const [appState, setAppState] = useRecoilState<AppState>(appStateAtom); |
|
const [accessToken, setAccessToken] = useRecoilState<string>(accessTokenAtom); |
|
const setWebsocketService = useSetRecoilState<WebsocketService>(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; |
|
}
|
|
|