-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathMuseEventHandler.js
93 lines (88 loc) · 4.72 KB
/
MuseEventHandler.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import { useContext, useEffect } from "react";
import {useRecoilCallback, useRecoilState} from "recoil";
import { SocketContext } from "./socket";
import PlaybackMetadataHandler from "../MuseDataHandlers/PlaybackMetadataHandler";
import PlaybackStateHandler from "../MuseDataHandlers/PlaybackStateHandler";
import VolumeHandler from "../MuseDataHandlers/VolumeHandler";
import playbackMetadataAtom from "../Recoil/playbackMetadataAtom";
import playbackStateAtom from "../Recoil/playbackStateAtom";
import volumeAtom from "../Recoil/volumeAtom";
import selectedGroupAtom from "../Recoil/selectedGroupAtom";
import SelectedGroupHandler from "../MuseDataHandlers/SelectedGroupHandler";
import playerVolumeAtomFamily from "../Recoil/playerVolumeAtomFamily";
import groupsInfoAtom from "../Recoil/groupsInfoAtom";
import GroupsInfoHandler from "../MuseDataHandlers/GroupsInfoHandler";
/**
* Functional component that listens for Sonos API events sent via WebSocket connection from the server
* Updates the state of Recoil atoms depending on the type of event received
*/
export default function MuseEventHandler() {
// Uses WebSocket context defined in socket.js and connects to WebSocket initiated in Server/main.mjs
const socket = useContext(SocketContext);
const [playbackMetadataResponse, setPlaybackMetadataResponse] = useRecoilState(playbackMetadataAtom);
const [playbackStateResponse, setPlaybackStateResponse] = useRecoilState(playbackStateAtom);
const [volumeResponse, setVolumeResponse] = useRecoilState(volumeAtom);
const [selectedGroupResponse, setSelectedGroupResponse] = useRecoilState(selectedGroupAtom);
const [groupsInfoResponse, setGroupsInfoResponse] = useRecoilState(groupsInfoAtom);
// useRecoilCallback was used to fetch the state of Recoil atoms without having MuseEventHandler subscribed to their states
const selectedGroupSnapshot = useRecoilCallback(({snapshot}) => () => {
let loadable = snapshot.getLoadable(selectedGroupAtom);
return loadable.valueMaybe();
}, []);
const setPlayerVolumeResponse = useRecoilCallback(({set}) => (playerId, val) => {
set(playerVolumeAtomFamily(playerId), val);
}, []);
const groupsInfoSnapshot = useRecoilCallback(({snapshot}) => () => {
let loadable = snapshot.getLoadable(groupsInfoAtom);
return loadable.valueMaybe();
}, []);
// Sets up a callback function to handle incoming messages
useEffect(() => {
if (socket !== undefined) {
// Receive the events from server via WebSocket connection
socket.on("message from server", (requestData) => {
// An event has been received from the server and will be processed based on the type of event
if (requestData.headers !== undefined) {
// Filters events to ensure only group events targeting the current group are acted on
if (requestData.headers["x-sonos-target-value"] === selectedGroupSnapshot().groupId) {
if (getMethodType(requestData) === "playbackStatus") {
const res = PlaybackStateHandler(requestData.data);
setPlaybackStateResponse(res);
} else if (getMethodType(requestData) === "groupVolume") {
const res = VolumeHandler(requestData.data);
setVolumeResponse(res);
} else if (getMethodType(requestData) === "metadataStatus") {
const res = PlaybackMetadataHandler(requestData.data);
setPlaybackMetadataResponse(res);
} else if (getMethodType(requestData) === "groupCoordinatorChanged") {
const res = SelectedGroupHandler(requestData.data);
res.groupId = selectedGroupSnapshot().groupId;
setSelectedGroupResponse(res);
}
} else if (getMethodType(requestData) === "playerVolume") {
// Uses message's target to determine which player's volume to update
const res = VolumeHandler(requestData.data);
setPlayerVolumeResponse(requestData.headers["x-sonos-target-value"], res);
} else if (getMethodType(requestData) === "groups" && requestData.headers["x-sonos-target-value"] === groupsInfoSnapshot().householdId) {
// Filters events to ensure that only events targeting the current household are acted on
const res = GroupsInfoHandler(requestData.data);
res.householdId = groupsInfoSnapshot().householdId;
setGroupsInfoResponse(res);
}
}
});
}
}, []);
}
/**
* Retrieves message type from Sonos API message
* @param request {JSON} Message received by client via WebSocket connection
* @return {string} Sonos API message type
*/
function getMethodType(request) {
try {
return request.headers["x-sonos-type"];
} catch (e) {
console.error("Error in fetching method type...", e);
}
}