Skip to content

Commit c346cb9

Browse files
committed
main a single socket instance across the app
1 parent 7071307 commit c346cb9

File tree

4 files changed

+109
-153
lines changed

4 files changed

+109
-153
lines changed

app/src/components/left/RoomsContainer.tsx

Lines changed: 52 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import List from '@mui/material/List';
55
import ListItem from '@mui/material/ListItem';
66
import ListItemText from '@mui/material/ListItemText';
77
import Button from '@mui/material/Button';
8-
import React, { useEffect } from 'react';
8+
import React from 'react';
99
import { RootState } from '../../redux/store';
1010
import TextField from '@mui/material/TextField';
1111
import {
@@ -19,18 +19,17 @@ import {
1919
setUserList
2020
} from '../../redux/reducers/slice/roomSlice';
2121
import { codePreviewCooperative } from '../../redux/reducers/slice/codePreviewSlice';
22-
import config from '../../../../config';
2322
import { cooperativeStyle } from '../../redux/reducers/slice/styleSlice';
2423
// websocket front end starts here
25-
import { io } from 'socket.io-client';
2624
import store from '../../redux/store';
2725
//pasted from navbarbuttons
28-
import debounce from '../../../../node_modules/lodash/debounce.js';
26+
import {
27+
initializeSocket,
28+
getSocket,
29+
disconnectSocket
30+
} from '../../helperFunctions/socket';
2931

30-
// // for websockets
31-
// // Part - join room and room code functionality
32-
let socket;
33-
const { API_BASE_URL } = config;
32+
//Websocket
3433

3534
const RoomsContainer = () => {
3635
const dispatch = useDispatch();
@@ -43,131 +42,70 @@ const RoomsContainer = () => {
4342
);
4443

4544
function initSocketConnection(roomCode: string) {
46-
if (socket) socket.disconnect(); //edge case check if socket connection existed
47-
//establishing client and server connection
48-
socket = io(API_BASE_URL, {
49-
transports: ['websocket']
50-
});
51-
52-
//connecting user to server
53-
socket.on('connect', () => {
54-
socket.emit('joining', userName, roomCode);
55-
console.log(`${userName} Joined room ${roomCode}`);
56-
});
57-
58-
//If you are the host: send current state to server when a new user joins
59-
socket.on('requesting state from host', (callback) => {
60-
const newState = store.getState(); //pull the current state
61-
callback(newState); //send it to backend server
62-
});
63-
64-
//If you are the new user: receive the state from the host
65-
socket.on('server emitting state from host', (state, callback) => {
66-
//dispatching new state to change user current state
67-
console.log('state recieved by new join:', state);
68-
store.dispatch(allCooperativeState(state.appState));
69-
store.dispatch(codePreviewCooperative(state.codePreviewCooperative));
70-
store.dispatch(cooperativeStyle(state.styleSlice));
71-
callback({ status: 'confirmed' });
72-
});
73-
74-
// update user list when there's a change: new join or leave the room
75-
socket.on('updateUserList', (newUserList: object) => {
76-
dispatch(setUserList(Object.values(newUserList)));
77-
});
78-
79-
// // receive the new state from the server and dispatch action creators to update state
80-
// socket.on('new state from back', (event) => {
81-
// const currentStore = JSON.parse(JSON.stringify(store.getState()));
82-
// const newState = JSON.parse(event);
83-
84-
// const areStatesEqual = (stateA, stateB) =>
85-
// JSON.stringify(stateA) === JSON.stringify(stateB);
86-
87-
// //checking if current state are equal to the state being sent from server
88-
// if (!areStatesEqual(currentStore, newState)) {
89-
// if (!areStatesEqual(currentStore.appState, newState.appState)) {
90-
// store.dispatch(allCooperativeState(newState.appState));
91-
// } else if (
92-
// !areStatesEqual(
93-
// currentStore.codePreviewSlice,
94-
// newState.codePreviewCooperative
95-
// )
96-
// ) {
97-
// store.dispatch(
98-
// codePreviewCooperative(newState.codePreviewCooperative)
99-
// );
100-
// } else if (
101-
// !areStatesEqual(currentStore.styleSlice, newState.styleSlice)
102-
// ) {
103-
// store.dispatch(cooperativeStyle(newState.styleSlice));
104-
// }
105-
// }
45+
// if (socket) socket.disconnect(); //edge case: disconnect previous socket connection
46+
// // establishing client and server connection
47+
// socket = io(API_BASE_URL, {
48+
// transports: ['websocket']
10649
// });
107-
}
10850

109-
// let previousState = store.getState();
110-
// // sending info to backend whenever the redux store changes
111-
// //handling state changes and send to server
51+
initializeSocket();
52+
const socket = getSocket();
53+
// only create a new connection if not already connected
54+
if (socket) {
55+
//run everytime when a client connects to server
56+
socket.on('connect', () => {
57+
socket.emit('joining', userName, roomCode);
58+
console.log(`${userName} Joined room ${roomCode} from RoomsConatiner`);
59+
});
11260

113-
// const findStateDiff = (prevState, newState) => {
114-
// const changes = {};
115-
// for (let key in newState) {
116-
// if (JSON.stringify(newState[key]) !== JSON.stringify(prevState[key])) {
117-
// changes[key] = newState[key];
118-
// }
119-
// }
120-
// return changes;
121-
// };
61+
//If you are the host: send current state to server when a new user joins
62+
socket.on('requesting state from host', (callback) => {
63+
const newState = store.getState(); //pull the current state
64+
callback(newState); //send it to backend server
65+
});
12266

123-
// const handleStoreChange = debounce(() => {
124-
// const newState = store.getState();
125-
// const roomCode = newState.roomSlice.roomCode;
126-
// const changes = findStateDiff(previousState, newState);
67+
//If you are the new user: receive the state from the host
68+
socket.on('server emitting state from host', (state, callback) => {
69+
//dispatching new state to change user current state
70+
console.log('state recieved by new join:', state);
71+
store.dispatch(allCooperativeState(state.appState));
72+
store.dispatch(codePreviewCooperative(state.codePreviewCooperative));
73+
store.dispatch(cooperativeStyle(state.styleSlice));
74+
callback({ status: 'confirmed' });
75+
});
12776

128-
// if (Object.keys(changes).length > 0) {
129-
// // Send the current state to the server
130-
// console.log('newState:', newState);
131-
// console.log('changes:', changes);
132-
// socket.emit('new state from front', JSON.stringify(changes), roomCode);
133-
// //re-assgin previousState to be the newState
134-
// previousState = newState;
135-
// }
136-
// }, 100);
77+
// update user list when there's a change: new join or leave the room
78+
socket.on('updateUserList', (newUserList) => {
79+
dispatch(setUserList(newUserList));
80+
});
13781

138-
// //listening to changes from store by users, whenever the store's state changes, invoke handleStoreChange function
139-
// store.subscribe(() => {
140-
// if (socket) {
141-
// handleStoreChange();
142-
// }
143-
// });
82+
socket.on('child data from server', (childData: object) => {
83+
console.log('child data received by users', childData);
84+
store.dispatch(addChild(childData));
85+
});
86+
}
87+
}
14488

14589
function handleUserEnteredRoom(roomCode) {
14690
initSocketConnection(roomCode);
14791
}
14892

149-
//-----------------------
150-
151-
if (socket) {
152-
socket.on('child data from back', (childData: string) => {
153-
console.log('child data received by users', JSON.parse(childData));
154-
store.dispatch(addChild(JSON.parse(childData)));
155-
});
156-
}
157-
158-
//-----------------------
159-
16093
//joining room function
16194
function joinRoom() {
162-
if (userList.length !== 0) dispatch(setUserList([])); //edge case check if userList not empty.
163-
handleUserEnteredRoom(roomCode); // Call handleUserEnteredRoom when joining a room
164-
dispatch(setRoomCode(roomCode));
95+
//edge case: if userList is not empty, reset it to empty array
96+
if (userList.length !== 0) dispatch(setUserList([]));
97+
handleUserEnteredRoom(roomCode);
98+
99+
dispatch(setRoomCode(roomCode)); //?
165100
dispatch(setUserJoined(true)); //setting joined room to true for rendering leave room button
166101
}
167102

168103
function leaveRoom() {
104+
let socket = getSocket();
169105
if (socket) {
170106
socket.disconnect(); //disconnecting socket from server
107+
socket = null;
108+
console.log('user leaves the room');
171109
}
172110
//reset all state values
173111
dispatch(setRoomCode(''));

app/src/components/main/Canvas.tsx

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,15 @@ import { ItemTypes } from '../../constants/ItemTypes';
1313
import { RootState } from '../../redux/store';
1414
import { combineStyles } from '../../helperFunctions/combineStyles';
1515
import renderChildren from '../../helperFunctions/renderChildren';
16-
import socket from '../../helperFunctions/socket';
16+
import { emitEvent } from '../../helperFunctions/socket';
1717

1818
function Canvas(props: {}): JSX.Element {
1919
const state = useSelector((store: RootState) => store.appState);
2020
const contextParam = useSelector((store: RootState) => store.contextSlice);
2121

2222
const roomCode = useSelector((store: RootState) => store.roomSlice.roomCode);
2323
// console.log('roomCode:', roomCode);
24+
// console.log('canavs is rendered');
2425

2526
// find the current component based on the canvasFocus component ID in the state
2627
const currentComponent: Component = state.components.find(
@@ -82,25 +83,16 @@ function Canvas(props: {}): JSX.Element {
8283
})
8384
);
8485

85-
// //emit the socket event
86+
//emit the socket event
8687
if (roomCode) {
87-
socket.emit(
88-
'addChildAction',
89-
JSON.stringify({
90-
type: item.instanceType,
91-
typeId: item.instanceTypeId,
92-
childId: null,
93-
contextParam: contextParam
94-
}),
95-
roomCode
96-
);
97-
98-
console.log('payload:', {
88+
emitEvent('addChildAction', roomCode, {
9989
type: item.instanceType,
10090
typeId: item.instanceTypeId,
10191
childId: null,
10292
contextParam: contextParam
10393
});
94+
95+
console.log('emit addChildAction event is triggered in canvas');
10496
}
10597
} else if (item.newInstance && item.instanceType === 'Component') {
10698
let hasDiffParent = false;

app/src/helperFunctions/socket.ts

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,41 @@
11
import { io } from 'socket.io-client';
22
import config from '../../../config';
33

4-
const { API_BASE_URL } = config;
4+
//DON'T connect client in this file, instead export a function that creates a new socket connection
5+
// const { API_BASE_URL } = config;
6+
// let socket;
7+
// //disconnect previous socket connection
8+
// if (socket) socket.disconnect();
9+
// // Initialize the socket connection
510

6-
// Initialize the socket connection
7-
const socket = io(API_BASE_URL, {
8-
transports: ['websocket']
9-
});
11+
// socket = io(API_BASE_URL, {
12+
// transports: ['websocket']
13+
// });
14+
// export default socket;
1015

11-
export default socket;
16+
let socket = null;
17+
18+
export const initializeSocket = () => {
19+
if (socket) socket.disconnect();
20+
if (!socket) {
21+
socket = io(config.API_BASE_URL, { transports: ['websocket'] });
22+
console.log('A user connected');
23+
}
24+
};
25+
26+
export const getSocket = () => {
27+
return socket;
28+
};
29+
30+
export const disconnectSocket = () => {
31+
if (socket) {
32+
socket.disconnect();
33+
socket = null;
34+
}
35+
};
36+
37+
export const emitEvent = (event, roomCode, data) => {
38+
if (socket) {
39+
socket.emit(event, roomCode, data);
40+
}
41+
};

server/server.ts

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ const io = new Server(httpServer, {
9999
const roomLists = {}; //key: roomCode, value: Obj{ socketid: username }
100100
//server listening to new connections
101101
io.on('connection', (client) => {
102+
console.log('A user connected with socket ID:', client.id);
102103
//when user Joined a room
103104
client.on('joining', async (userName: string, roomCode: string) => {
104105
//adding async
@@ -107,20 +108,20 @@ io.on('connection', (client) => {
107108
if (!roomLists[roomCode]) {
108109
roomLists[roomCode] = {};
109110
}
110-
//roomLists = { 1: {1223: 'Rose', 2257: 'Jack'}, 3: {3345: 'Dan'} }
111+
//roomLists = { happyRoom: { bHhFDmzPGam: 'Rose', mqri45c94E3: 'Jack' }, someRoom: { o5VeWAAAD: 'Dan'} }
111112
roomLists[roomCode][client.id] = userName; // adding user into the room list with id: userName on server side
112-
const userList = Object.keys(roomLists[roomCode]);
113+
const userList = Object.keys(roomLists[roomCode]); //[ bHhFDmzPGam, mqri45c94E3 ] order is not perserved?
113114
const hostID = userList[0];
114115
const newClientID = userList[userList.length - 1];
116+
console.log('hostID:', hostID);
117+
console.log('newClientID:', newClientID);
115118

116119
//server ask host for the current state
117120
const hostState = await io //once the request is sent back save to host state
118121
.timeout(5000)
119122
.to(hostID)
120123
.emitWithAck('requesting state from host'); //sending request
121124

122-
// console.log('hostState:', hostState);
123-
124125
//share host's state with the latest user
125126
const newClientResponse = await io //send the requested host state to the new client awaiting for the host state to come back before doing other task
126127
.timeout(5000)
@@ -130,7 +131,12 @@ io.on('connection', (client) => {
130131
//client response is confirmed
131132
if (newClientResponse[0].status === 'confirmed') {
132133
client.join(roomCode); //client joining a room
133-
io.to(roomCode).emit('updateUserList', roomLists[roomCode]); //send the message to all clients in room but the sender
134+
console.log('a user joined the room');
135+
//send the message to all clients in room but the sender
136+
io.to(roomCode).emit(
137+
'updateUserList',
138+
Object.values(roomLists[roomCode])
139+
);
134140
}
135141
} catch (error) {
136142
//if joining event is having an error and time out
@@ -141,15 +147,6 @@ io.on('connection', (client) => {
141147
}
142148
});
143149

144-
// //server monitors incoming data from users for any new state changes
145-
// client.on('new state from front', (redux_store, room: string) => {
146-
// // console.log('new state from front:', JSON.parse(redux_store));
147-
// if (room) {
148-
// //server send the state from the user to everyone in the room
149-
// client.to(room).emit('new state from back', redux_store);
150-
// }
151-
// });
152-
153150
//disconnecting functionality
154151
client.on('disconnecting', () => {
155152
// the client.rooms Set contains at least the socket ID
@@ -165,12 +162,11 @@ io.on('connection', (client) => {
165162
});
166163

167164
//--------------------------------
168-
client.on('addChildAction', (childData: string, room: string) => {
169-
// console.log('addChildAction:', JSON.parse(childData));
170-
if (room) {
165+
client.on('addChildAction', (roomCode: string, childData: object) => {
166+
// console.log('child data received on server:', childData);
167+
if (roomCode) {
171168
//server send the data to everyone in the room
172-
console.log('child data received in server');
173-
client.to(room).emit('child data from back', childData);
169+
client.to(roomCode).emit('child data from server', childData);
174170
}
175171
});
176172
});

0 commit comments

Comments
 (0)