Skip to content

Commit

Permalink
fix: Adjustments to startup routine to set room key and get room status
Browse files Browse the repository at this point in the history
  • Loading branch information
ndorin committed May 17, 2024
1 parent 1a57523 commit e66cfdc
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 125 deletions.
8 changes: 4 additions & 4 deletions src/lib/store/runtimeConfig/runtimeConfig.slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,17 @@ const initialState: RuntimeConfigState = {
pluginVersion: '',
disconnectionMessage: '',
token: '',
currentRoomKey: '',
roomData: {
clientId: '',
defaultRoomKey: '',
currentRoomKey: '',
roomKey: '',
systemUuid: '',
roomUuid: '',
userAppUrl: '',
config: undefined,
userCode: '',
qrUrl: '',
},

};


Expand Down Expand Up @@ -52,7 +51,7 @@ const runtimeConfigSlice = createSlice({
// clear out any existing room/device data
store.dispatch(roomsActions.clearRooms());
store.dispatch(devicesActions.clearDevices());
state.roomData.currentRoomKey = action.payload;
state.currentRoomKey = action.payload;
},
setUserCode(state, action: PayloadAction<UserCode>) {
state.roomData.userCode = action.payload.userCode;
Expand All @@ -71,6 +70,7 @@ export interface RuntimeConfigState {
disconnectionMessage: string;
token: string;
roomData: RoomData;
currentRoomKey: string;
}

export interface UserCode {
Expand Down
2 changes: 1 addition & 1 deletion src/lib/store/runtimeConfig/runtimeSelectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ import { useAppSelector } from '../hooks';

export const useWsIsConnected = () => useAppSelector((state) => state.runtimeConfig.websocket.isConnected);

export const useRoomKey = () => useAppSelector((state) => state.runtimeConfig.roomData.currentRoomKey);
export const useRoomKey = () => useAppSelector((state) => state.runtimeConfig.currentRoomKey);

export const useClientId = () => useAppSelector((state) => state.runtimeConfig.roomData.clientId);
3 changes: 1 addition & 2 deletions src/lib/types/classes/room-data.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
export interface RoomData {
clientId: string | number;
defaultRoomKey: string;
currentRoomKey: string;
roomKey: string;
systemUuid: string;
roomUuid: string;
userAppUrl: string;
Expand Down
253 changes: 135 additions & 118 deletions src/lib/utils/WebsocketProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ const WebsocketProvider = ({ children }: { children: ReactNode }) => {
* callback: the function to call when the event is received that takes the message as an argument
* if additional data is required beyond the eventType
*/
const eventHandlers = useRef<Record<string, Record<string, (data: Message) => void>>>({});
const eventHandlers = useRef<
Record<string, Record<string, (data: Message) => void>>
>({});

/* FUNCTIONS *******************************************************/

Expand All @@ -63,8 +65,8 @@ const WebsocketProvider = ({ children }: { children: ReactNode }) => {
.catch((err) => {
console.log(err);

if(err.repsonse && err.response.status === 498) {
console.error('Invalid token. Unable to join room');
if (err.repsonse && err.response.status === 498) {
console.error("Invalid token. Unable to join room");
}
});
},
Expand All @@ -76,6 +78,7 @@ const WebsocketProvider = ({ children }: { children: ReactNode }) => {
*/
const sendMessage = useCallback(
(type: string, content: unknown) => {

if (clientRef.current && isConnected) {
clientRef.current.send(JSON.stringify({ type, clientId, content }));
}
Expand All @@ -85,13 +88,15 @@ const WebsocketProvider = ({ children }: { children: ReactNode }) => {

/**
* Helper function to send a simple message with a boolean, number, or string value
* @param type
* @param value
* @param type
* @param value
*/
const sendSimpleMessage =
(type: string, value: boolean | number | string ) => {
sendMessage(type, { value });
};
const sendSimpleMessage = (
type: string,
value: boolean | number | string
) => {
sendMessage(type, { value });
};

const addEventHandler = useCallback(
(eventType: string, key: string, callback: (data: Message) => void) => {
Expand All @@ -101,26 +106,21 @@ const WebsocketProvider = ({ children }: { children: ReactNode }) => {

eventHandlers.current[eventType][key] = callback;

console.log('event handler added', eventType, key);
console.log("event handler added", eventType, key);
},
[]
);

const removeEventHandler = useCallback(
(eventType: string, key: string) => {
if (eventHandlers.current[eventType]) {
delete eventHandlers.current[eventType][key];

console.log('event handler removed', eventType, key);
}
},
[]
);
const removeEventHandler = useCallback((eventType: string, key: string) => {
if (eventHandlers.current[eventType]) {
delete eventHandlers.current[eventType][key];

console.log("event handler removed", eventType, key);
}
}, []);

//* EFFECTS *********************************************************/
useEffect(() => {

// Get the join token from the url params or from session storage and sets it as a local state variable
const qp = new URLSearchParams(window.location.search);

Expand Down Expand Up @@ -149,126 +149,143 @@ const WebsocketProvider = ({ children }: { children: ReactNode }) => {
* Connect to the websocket and get the room data when the apiPath changes
*/
useEffect(() => {
if (!appConfig.apiPath || waitingToReconnect || !token) return;

getRoomData(appConfig.apiPath);

if (!clientRef.current) {
const wsPath = appConfig.apiPath.replace("http", "ws");
const url = `${wsPath}/ui/join/${token}`;

const newWs = new WebSocket(url);
async function joinWebsocket() {
if (!appConfig.apiPath || waitingToReconnect || !token) return;

clientRef.current = newWs;

newWs.onopen = () => {
console.log("connected");
store.dispatch(runtimeConfigActions.setWebsocketIsConnected(true));
};

newWs.onerror = (err) => {
console.log(err);
};
await getRoomData(appConfig.apiPath);

newWs.onclose = () => {
console.log("disconnected");
if (clientRef.current) {
console.log("WebSocket closed by server.");
} else {
console.log("WebSocket closed by client.");
return;
}
if (!clientRef.current) {
const wsPath = appConfig.apiPath.replace("http", "ws");
const url = `${wsPath}/ui/join/${token}`;

if (waitingToReconnect) {
return;
}
const newWs = new WebSocket(url);

store.dispatch(runtimeConfigActions.setWebsocketIsConnected(false));
clientRef.current = newWs;

setWaitingToReconnect(true);
newWs.onopen = () => {
console.log("connected");
store.dispatch(runtimeConfigActions.setWebsocketIsConnected(true));
};

setTimeout(() => setWaitingToReconnect(undefined), 5000);
};
newWs.onerror = (err) => {
console.log(err);
};

newWs.onclose = () => {
console.log("disconnected");
if (clientRef.current) {
console.log("WebSocket closed by server.");
} else {
console.log("WebSocket closed by client.");
return;
}

newWs.onmessage = (e) => {
try {
const message: Message = JSON.parse(e.data);
console.log(message);

if (message.type.startsWith("/system/")) {
switch (message.type) {
case "/system/roomKey":
store.dispatch(
runtimeConfigActions.setCurrentRoomKey(
message.content as string
)
);
break;
case "/system/userCodeChanged":
store.dispatch(
runtimeConfigActions.setUserCode(message.content as UserCode)
);
break;
case "/system/roomCombinationChanged":
window.location.reload();
break;
default:
console.log("unhandled system message", message);
break;
}
} else if (message.type.startsWith("/event/")) {
console.log('event message received', message);
// const eventType = (message.content as EventContent).eventType;
// if (!eventType) return;
const handlers = eventHandlers.current[message.type];

if(!handlers) {
console.log('no handlers found for event type', message.type);
}
if (waitingToReconnect) {
return;
}

if (handlers) {
Object.values(handlers).forEach((handler) => {
try {
handler(message)
}
catch (err) {
console.error(err);
}
});
store.dispatch(runtimeConfigActions.setWebsocketIsConnected(false));
store.dispatch(devicesActions.clearDevices());
store.dispatch(roomsActions.clearRooms());

setWaitingToReconnect(true);

setTimeout(() => setWaitingToReconnect(undefined), 5000);
};

newWs.onmessage = (e) => {
try {
const message: Message = JSON.parse(e.data);
console.log(message);

if (message.type.startsWith("/system/")) {
switch (message.type) {
case "/system/roomKey":
store.dispatch(
runtimeConfigActions.setCurrentRoomKey(
message.content as string
)
);
break;
case "/system/userCodeChanged":
store.dispatch(
runtimeConfigActions.setUserCode(
message.content as UserCode
)
);
break;
case "/system/roomCombinationChanged":
// TODO: Revisit if this is the right way to handle combination scenario changes
window.location.reload();
break;
default:
console.log("unhandled system message", message);
break;
}
} else if (message.type.startsWith("/event/")) {
console.log("event message received", message);
// const eventType = (message.content as EventContent).eventType;
// if (!eventType) return;
const handlers = eventHandlers.current[message.type];

if (!handlers) {
console.log("no handlers found for event type", message.type);
}

if (handlers) {
Object.values(handlers).forEach((handler) => {
try {
handler(message);
} catch (err) {
console.error(err);
}
});
}
} else if (message.type.startsWith("/room/")) {
store.dispatch(roomsActions.setRoomState(message));
} else if (message.type.startsWith("/device/")) {
store.dispatch(devicesActions.setDeviceState(message));
}
} else if (message.type.startsWith("/room/")) {
store.dispatch(roomsActions.setRoomState(message));
} else if (message.type.startsWith("/device/")) {
store.dispatch(devicesActions.setDeviceState(message));
} catch (err) {
console.log(err);
}
} catch (err) {
console.log(err);
};
}
// Cleanup first websocket in dev mode due to double render cycle
return () => {
if (clientRef.current) {
clientRef.current.close();
}

clientRef.current = null;
};
}
// Cleanup first websocket in dev mode due to double render cycle
return () => {
if (clientRef.current) {
clientRef.current.close();
}

clientRef.current = null;
};
joinWebsocket();
}, [appConfig.apiPath, getRoomData, token, waitingToReconnect]);

/**
* Send a status message to the server to get the current state of the room when the roomKey changes
* */
useEffect(() => {
if (roomKey) {
console.log("requesting status from room: ", roomKey);
sendMessage(`/room/${roomKey}/status`, null);
}
}, [roomKey, sendMessage]);
if (!roomKey || !isConnected) return;
console.log("clientId: ", clientId);
if (!clientId) return;

console.log("requesting status from room: ", roomKey);
sendMessage(`/room/${roomKey}/status`, null);
}, [roomKey, clientId, isConnected, sendMessage]);

//* RENDER **********************************************************/
return (
<WebsocketContext.Provider value={{ sendMessage, sendSimpleMessage, addEventHandler, removeEventHandler }}>
<WebsocketContext.Provider
value={{
sendMessage,
sendSimpleMessage,
addEventHandler,
removeEventHandler,
}}
>
{isConnected ? children : <DisconnectedMessage />}
</WebsocketContext.Provider>
);
Expand Down

0 comments on commit e66cfdc

Please sign in to comment.