fix: socket connection

This commit is contained in:
Sergey Yarkov 2022-01-27 00:01:22 +03:00
parent 283fc683c8
commit e049ce7f71
10 changed files with 53 additions and 20 deletions

View File

@ -12,12 +12,17 @@ import { useRootStore } from '@educt/hooks/useRootStore';
*/ */
import PrivateRoute from '@educt/components/PrivateRoute'; import PrivateRoute from '@educt/components/PrivateRoute';
import PublicRoute from '@educt/components/PublicRoute'; import PublicRoute from '@educt/components/PublicRoute';
import { useSocketEvent } from './hooks/useSocketEvent';
const App = () => { const App = () => {
const { const {
uiStore: { history }, uiStore: { history },
} = useRootStore(); } = useRootStore();
useSocketEvent('connect', () => console.info('[WebSocket]: Connected.'));
useSocketEvent('disconnect', () => console.info('[WebSocket]: Disconnected.'));
useSocketEvent('connect_error', err => console.error(err));
return ( return (
<Router history={history}> <Router history={history}>
<Switch> <Switch>

View File

@ -1,4 +1,4 @@
import React, { Suspense } from 'react'; import React, { Suspense, useContext } from 'react';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import { Redirect } from 'react-router'; import { Redirect } from 'react-router';
import { useErrorHandler } from 'react-error-boundary'; import { useErrorHandler } from 'react-error-boundary';
@ -23,6 +23,11 @@ import NavDesktop from '@educt/components/Nav/Desktop';
import { useEffect } from 'react'; import { useEffect } from 'react';
import { useRootStore } from '@educt/hooks/useRootStore'; import { useRootStore } from '@educt/hooks/useRootStore';
/**
* Contexts
*/
import { SocketContext } from '@educt/contexts';
type LayoutPropsType = { roles: UserRoleEnum[] | undefined }; type LayoutPropsType = { roles: UserRoleEnum[] | undefined };
/** /**
@ -30,6 +35,7 @@ type LayoutPropsType = { roles: UserRoleEnum[] | undefined };
*/ */
const Layout: React.FC<LayoutPropsType> = ({ children, roles }) => { const Layout: React.FC<LayoutPropsType> = ({ children, roles }) => {
const { userStore } = useRootStore(); const { userStore } = useRootStore();
const { socket } = useContext(SocketContext);
const handleError = useErrorHandler(); const handleError = useErrorHandler();
/** /**
@ -39,6 +45,15 @@ const Layout: React.FC<LayoutPropsType> = ({ children, roles }) => {
userStore.loadCurrentUserData().catch(error => handleError(error)); userStore.loadCurrentUserData().catch(error => handleError(error));
}, [handleError, userStore]); }, [handleError, userStore]);
/**
* Connect to websocket server
*/
useEffect(() => {
if (!socket?.connected) {
socket?.connect();
}
}, [socket]);
return ( return (
<> <>
<Header /> <Header />

View File

@ -1,5 +1,7 @@
import { useToast } from '@chakra-ui/react'; import { useToast } from '@chakra-ui/react';
import { SocketContext } from '@educt/contexts';
import { IToken } from '@educt/interfaces'; import { IToken } from '@educt/interfaces';
import { useContext } from 'react';
import { useErrorHandler } from 'react-error-boundary'; import { useErrorHandler } from 'react-error-boundary';
import useAsync from '../../useAsync'; import useAsync from '../../useAsync';
import { useRootStore } from '../../useRootStore'; import { useRootStore } from '../../useRootStore';
@ -8,6 +10,7 @@ type LoginResultDataType = IToken;
const useLogin = () => { const useLogin = () => {
const { authStore } = useRootStore(); const { authStore } = useRootStore();
const { socket } = useContext(SocketContext);
const toast = useToast(); const toast = useToast();
const handleError = useErrorHandler(); const handleError = useErrorHandler();
@ -20,6 +23,7 @@ const useLogin = () => {
isClosable: true, isClosable: true,
status: 'success', status: 'success',
}); });
socket?.connect();
return result.data; return result.data;
} catch (error: any) { } catch (error: any) {
if (error.response) { if (error.response) {

View File

@ -3,11 +3,18 @@ import { useHistory } from 'react-router-dom';
import { useRootStore } from '../../useRootStore'; import { useRootStore } from '../../useRootStore';
import { useErrorHandler } from 'react-error-boundary'; import { useErrorHandler } from 'react-error-boundary';
import useAsync from '../../useAsync'; import useAsync from '../../useAsync';
import { useContext } from 'react';
/**
* Contexts
*/
import { SocketContext } from '@educt/contexts';
type LogoutResultDataType = Record<string, never>; type LogoutResultDataType = Record<string, never>;
const useLogout = () => { const useLogout = () => {
const { authStore } = useRootStore(); const { authStore } = useRootStore();
const { socket } = useContext(SocketContext);
const history = useHistory(); const history = useHistory();
const toast = useToast(); const toast = useToast();
const handleError = useErrorHandler(); const handleError = useErrorHandler();
@ -17,6 +24,7 @@ const useLogout = () => {
const result = await authStore.logout(); const result = await authStore.logout();
history.push('/auth'); history.push('/auth');
toast({ title: 'You are logged out.', isClosable: true, status: 'info' }); toast({ title: 'You are logged out.', isClosable: true, status: 'info' });
socket?.disconnect();
return result.data; return result.data;
} catch (error) { } catch (error) {
handleError(error); handleError(error);

View File

@ -5,12 +5,12 @@ export const useSocket = (url: string) => {
const [socket, setSocket] = useState<Socket | null>(null); const [socket, setSocket] = useState<Socket | null>(null);
useEffect(() => { useEffect(() => {
const socketClient = io(url, { autoConnect: true }); const socketClient = io(url, { autoConnect: false, withCredentials: true });
setSocket(socketClient); setSocket(socketClient);
return () => { return () => {
socket?.disconnect(); socket?.close();
}; };
}, []); }, []);

View File

@ -1,7 +1,7 @@
import { useContext, useEffect } from 'react'; import { useContext, useEffect } from 'react';
import { SocketContext } from '@educt/contexts'; import { SocketContext } from '@educt/contexts';
export const useSocketEvent = (event: string, callback: () => void) => { export const useSocketEvent = (event: string, callback: (...args: any) => void) => {
const { socket } = useContext(SocketContext); const { socket } = useContext(SocketContext);
useEffect(() => { useEffect(() => {

View File

@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'; import React, { useState } from 'react';
import { Flex, Box, Text, Link, SimpleGrid, Divider } from '@chakra-ui/react'; import { Flex, Box, Text, Link, SimpleGrid, Divider } from '@chakra-ui/react';
import { Link as ReactRouterLink } from 'react-router-dom'; import { Link as ReactRouterLink } from 'react-router-dom';
import { IPageProps } from '@educt/interfaces'; import { IPageProps } from '@educt/interfaces';
@ -22,6 +22,8 @@ import {
} from './components'; } from './components';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import { useFetchCourses, useFetchStat } from '@educt/hooks/queries'; import { useFetchCourses, useFetchStat } from '@educt/hooks/queries';
import { useSocketEvent } from '@educt/hooks/useSocketEvent';
import { useEffect } from 'react';
/** /**
* Main page * Main page
@ -34,18 +36,20 @@ const MainPage: React.FC<IPageProps> = () => {
const { data: stat } = useFetchStat(); const { data: stat } = useFetchStat();
const [online, setOnline] = useState<number>(0); const [online, setOnline] = useState<number>(0);
// useEffect(() => { /**
// const onUpdateOnline = users => { * Update online state on socket event
// console.log(users); */
// setOnline(users.length); useSocketEvent('user:online', online => setOnline(online));
// };
// socket.on('user:online', onUpdateOnline); useSocketEvent('user:connected', user => {
console.table(user);
});
// return () => { useEffect(() => {
// socket.off('user:online', onUpdateOnline); if (stat) {
// }; setOnline(stat.online);
// }, [setOnline, socket]); }
}, [stat?.online]);
if (me === null || courses === null || stat === null) return <LoadingPage />; if (me === null || courses === null || stat === null) return <LoadingPage />;

View File

@ -25,7 +25,7 @@ export const RootStoreProvider = ({ children }: { children: ReactNode }) => {
* Socket context provider * Socket context provider
*/ */
export const SocketContextProvider: React.FC = ({ children }) => { export const SocketContextProvider: React.FC = ({ children }) => {
const socket = useSocket(''); const socket = useSocket('ws://localhost:3333');
return <SocketContext.Provider value={{ socket }}>{children}</SocketContext.Provider>; return <SocketContext.Provider value={{ socket }}>{children}</SocketContext.Provider>;
}; };

View File

@ -43,6 +43,7 @@ export type LessonProgress = {
export type StatInfoType = { export type StatInfoType = {
courses_count: string; courses_count: string;
lessons_count: string; lessons_count: string;
online: number;
}; };
export type LessonVideoType = { export type LessonVideoType = {

View File

@ -33,10 +33,6 @@ export default defineConfig({
target: constants.BACKEND_URL, target: constants.BACKEND_URL,
changeOrigin: true, changeOrigin: true,
}, },
'/socket.io': {
target: constants.BACKEND_URL,
changeOrigin: true,
},
}, },
}, },
resolve: { resolve: {