Prechádzať zdrojové kódy

feat(WS): when a modal is closed, socket listeners are now removed

Signed-off-by: Jonathan <theflametrooper@gmail.com>
Jonathan 3 rokov pred
rodič
commit
8a1602b9d7

+ 5 - 6
backend/logic/actions/hooks/ownerRequired.js

@@ -24,9 +24,7 @@ export default destination =>
 						},
 						this
 					)
-						.then(session => {
-							next(null, session);
-						})
+						.then(session => next(null, session))
 						.catch(next);
 				},
 				(session, next) => {
@@ -36,10 +34,11 @@ export default destination =>
 				(user, next) => {
 					if (!user) return next("Login required.");
 					if (user.role === "admin") return next(true);
+
+					if (!stationId) return next("Please provide a stationId.");
+
 					return StationsModule.runJob("GET_STATION", { stationId }, this)
-						.then(station => {
-							next(null, station);
-						})
+						.then(station => next(null, station))
 						.catch(next);
 				},
 				(station, next) => {

+ 70 - 44
frontend/src/components/modals/EditPlaylist.vue

@@ -442,56 +442,82 @@ export default {
 			} else new Toast(res.message);
 		});
 
-		this.socket.on("event:playlist.addSong", res => {
-			if (this.playlist._id === res.data.playlistId)
-				this.playlist.songs.push(res.data.song);
-		});
-
-		this.socket.on("event:playlist.removeSong", res => {
-			if (this.playlist._id === res.data.playlistId) {
-				// remove song from array of playlists
-				this.playlist.songs.forEach((song, index) => {
-					if (song.youtubeId === res.data.youtubeId)
-						this.playlist.songs.splice(index, 1);
-				});
-
-				// if this song is in search results, mark it available to add to the playlist again
-				this.search.songs.results.forEach((searchItem, index) => {
-					if (res.data.youtubeId === searchItem.id) {
-						this.search.songs.results[index].isAddedToQueue = false;
-					}
-				});
+		this.socket.on(
+			"event:playlist.addSong",
+			res => {
+				if (this.playlist._id === res.data.playlistId)
+					this.playlist.songs.push(res.data.song);
+			},
+			{
+				modal: "editPlaylist"
 			}
-		});
+		);
 
-		this.socket.on("event:playlist.updateDisplayName", res => {
-			if (this.playlist._id === res.data.playlistId)
-				this.playlist.displayName = res.data.displayName;
-		});
-
-		this.socket.on("event:playlist.repositionSongs", res => {
-			if (this.playlist._id === res.data.playlistId) {
-				// for each song that has a new position
-				res.data.songsBeingChanged.forEach(changedSong => {
+		this.socket.on(
+			"event:playlist.removeSong",
+			res => {
+				if (this.playlist._id === res.data.playlistId) {
+					// remove song from array of playlists
 					this.playlist.songs.forEach((song, index) => {
-						// find song locally
-						if (song.youtubeId === changedSong.youtubeId) {
-							// change song position attribute
-							this.playlist.songs[index].position =
-								changedSong.position;
-
-							// reposition in array if needed
-							if (index !== changedSong.position - 1)
-								this.playlist.songs.splice(
-									changedSong.position - 1,
-									0,
-									this.playlist.songs.splice(index, 1)[0]
-								);
+						if (song.youtubeId === res.data.youtubeId)
+							this.playlist.songs.splice(index, 1);
+					});
+
+					// if this song is in search results, mark it available to add to the playlist again
+					this.search.songs.results.forEach((searchItem, index) => {
+						if (res.data.youtubeId === searchItem.id) {
+							this.search.songs.results[
+								index
+							].isAddedToQueue = false;
 						}
 					});
-				});
+				}
+			},
+			{
+				modal: "editPlaylist"
 			}
-		});
+		);
+
+		this.socket.on(
+			"event:playlist.updateDisplayName",
+			res => {
+				if (this.playlist._id === res.data.playlistId)
+					this.playlist.displayName = res.data.displayName;
+			},
+			{
+				modal: "editPlaylist"
+			}
+		);
+
+		this.socket.on(
+			"event:playlist.repositionSongs",
+			res => {
+				if (this.playlist._id === res.data.playlistId) {
+					// for each song that has a new position
+					res.data.songsBeingChanged.forEach(changedSong => {
+						this.playlist.songs.forEach((song, index) => {
+							// find song locally
+							if (song.youtubeId === changedSong.youtubeId) {
+								// change song position attribute
+								this.playlist.songs[index].position =
+									changedSong.position;
+
+								// reposition in array if needed
+								if (index !== changedSong.position - 1)
+									this.playlist.songs.splice(
+										changedSong.position - 1,
+										0,
+										this.playlist.songs.splice(index, 1)[0]
+									);
+							}
+						});
+					});
+				}
+			},
+			{
+				modal: "editPlaylist"
+			}
+		);
 	},
 	methods: {
 		importPlaylist() {

+ 1 - 0
frontend/src/components/modals/ManageStation/Tabs/Playlists.vue

@@ -357,6 +357,7 @@ export default {
 		}),
 		...mapState("modals/manageStation", {
 			originalStation: state => state.originalStation,
+			station: state => state.station,
 			includedPlaylists: state => state.includedPlaylists,
 			excludedPlaylists: state => state.excludedPlaylists,
 			songsList: state => state.songsList

+ 185 - 86
frontend/src/components/modals/ManageStation/index.vue

@@ -251,9 +251,8 @@ export default {
 					"stations.getStationIncludedPlaylistsById",
 					this.stationId,
 					res => {
-						if (res.status === "success") {
+						if (res.status === "success")
 							this.setIncludedPlaylists(res.data.playlists);
-						}
 					}
 				);
 
@@ -261,9 +260,8 @@ export default {
 					"stations.getStationExcludedPlaylistsById",
 					this.stationId,
 					res => {
-						if (res.status === "success") {
+						if (res.status === "success")
 							this.setExcludedPlaylists(res.data.playlists);
-						}
 					}
 				);
 
@@ -271,9 +269,8 @@ export default {
 					"stations.getQueue",
 					this.stationId,
 					res => {
-						if (res.status === "success") {
+						if (res.status === "success")
 							this.updateSongsList(res.data.queue);
-						}
 					}
 				);
 
@@ -282,94 +279,196 @@ export default {
 					`manage-station.${this.stationId}`
 				);
 
-				this.socket.on("event:station.updateName", res => {
-					this.station.name = res.data.name;
-				});
-
-				this.socket.on("event:station.updateDisplayName", res => {
-					this.station.displayName = res.data.displayName;
-				});
-
-				this.socket.on("event:station.updateDescription", res => {
-					this.station.description = res.data.description;
-				});
-
-				this.socket.on("event:partyMode.updated", res => {
-					if (this.station.type === "community")
-						this.station.partyMode = res.data.partyMode;
-				});
-
-				this.socket.on("event:playMode.updated", res => {
-					this.station.playMode = res.data.playMode;
-				});
-
-				this.socket.on("event:station.themeUpdated", res => {
-					const { theme } = res.data;
-					this.station.theme = theme;
-				});
-
-				this.socket.on("event:station.updatePrivacy", res => {
-					this.station.privacy = res.data.privacy;
-				});
-
-				this.socket.on("event:queueLockToggled", res => {
-					this.station.locked = res.data.locked;
-				});
-
-				this.socket.on("event:station.includedPlaylist", res => {
-					const { playlist } = res.data;
-					this.includedPlaylists.push(playlist);
-				});
-
-				this.socket.on("event:station.excludedPlaylist", res => {
-					const { playlist } = res.data;
-					this.excludedPlaylists.push(playlist);
-				});
-
-				this.socket.on("event:station.removedIncludedPlaylist", res => {
-					const { playlistId } = res.data;
-					const playlistIndex = this.includedPlaylists
-						.map(playlist => playlist._id)
-						.indexOf(playlistId);
-					if (playlistIndex >= 0)
-						this.includedPlaylists.splice(playlistIndex, 1);
-				});
-
-				this.socket.on("event:station.removedExcludedPlaylist", res => {
-					const { playlistId } = res.data;
-					const playlistIndex = this.excludedPlaylists
-						.map(playlist => playlist._id)
-						.indexOf(playlistId);
-					if (playlistIndex >= 0)
-						this.excludedPlaylists.splice(playlistIndex, 1);
-				});
+				this.socket.on(
+					"event:station.updateName",
+					res => {
+						this.station.name = res.data.name;
+					},
+					{
+						modal: "manageStation"
+					}
+				);
+
+				this.socket.on(
+					"event:station.updateDisplayName",
+					res => {
+						this.station.displayName = res.data.displayName;
+					},
+					{
+						modal: "manageStation"
+					}
+				);
+
+				this.socket.on(
+					"event:station.updateDescription",
+					res => {
+						this.station.description = res.data.description;
+					},
+					{
+						modal: "manageStation"
+					}
+				);
+
+				this.socket.on(
+					"event:partyMode.updated",
+					res => {
+						if (this.station.type === "community")
+							this.station.partyMode = res.data.partyMode;
+					},
+					{
+						modal: "manageStation"
+					}
+				);
+
+				this.socket.on(
+					"event:playMode.updated",
+					res => {
+						this.station.playMode = res.data.playMode;
+					},
+					{
+						modal: "manageStation"
+					}
+				);
+
+				this.socket.on(
+					"event:station.themeUpdated",
+					res => {
+						const { theme } = res.data;
+						this.station.theme = theme;
+					},
+					{
+						modal: "manageStation"
+					}
+				);
+
+				this.socket.on(
+					"event:station.updatePrivacy",
+					res => {
+						this.station.privacy = res.data.privacy;
+					},
+					{
+						modal: "manageStation"
+					}
+				);
+
+				this.socket.on(
+					"event:queueLockToggled",
+					res => {
+						this.station.locked = res.data.locked;
+					},
+					{
+						modal: "manageStation"
+					}
+				);
+
+				this.socket.on(
+					"event:station.includedPlaylist",
+					res => {
+						const { playlist } = res.data;
+						this.includedPlaylists.push(playlist);
+					},
+					{
+						modal: "manageStation"
+					}
+				);
+
+				this.socket.on(
+					"event:station.excludedPlaylist",
+					res => {
+						const { playlist } = res.data;
+						this.excludedPlaylists.push(playlist);
+					},
+					{
+						modal: "manageStation"
+					}
+				);
+
+				this.socket.on(
+					"event:station.removedIncludedPlaylist",
+					res => {
+						const { playlistId } = res.data;
+						const playlistIndex = this.includedPlaylists
+							.map(playlist => playlist._id)
+							.indexOf(playlistId);
+						if (playlistIndex >= 0)
+							this.includedPlaylists.splice(playlistIndex, 1);
+					},
+					{
+						modal: "manageStation"
+					}
+				);
+
+				this.socket.on(
+					"event:station.removedExcludedPlaylist",
+					res => {
+						const { playlistId } = res.data;
+						const playlistIndex = this.excludedPlaylists
+							.map(playlist => playlist._id)
+							.indexOf(playlistId);
+						if (playlistIndex >= 0)
+							this.excludedPlaylists.splice(playlistIndex, 1);
+					},
+					{
+						modal: "manageStation"
+					}
+				);
 			} else {
 				new Toast(`Station with that ID not found`);
 				this.closeModal("manageStation");
 			}
 		});
 
-		this.socket.on("event:queue.update", res => {
-			this.updateSongsList(res.data.queue);
-		});
-
-		this.socket.on("event:queue.repositionSong", res => {
-			this.repositionSongInList(res.data.song);
-		});
-
-		this.socket.on("event:stations.pause", () => {
-			this.updateStationPaused(true);
-		});
-
-		this.socket.on("event:stations.resume", () => {
-			this.updateStationPaused(false);
-		});
+		this.socket.on(
+			"event:queue.update",
+			res => {
+				this.updateSongsList(res.data.queue);
+			},
+			{
+				modal: "manageStation"
+			}
+		);
+
+		this.socket.on(
+			"event:queue.repositionSong",
+			res => {
+				this.repositionSongInList(res.data.song);
+			},
+			{
+				modal: "manageStation"
+			}
+		);
+
+		this.socket.on(
+			"event:stations.pause",
+			() => {
+				this.updateStationPaused(true);
+			},
+			{
+				modal: "manageStation"
+			}
+		);
+
+		this.socket.on(
+			"event:stations.resume",
+			() => {
+				this.updateStationPaused(false);
+			},
+			{
+				modal: "manageStation"
+			}
+		);
 
-		this.socket.on("event:songs.next", res => {
-			const { currentSong } = res.data;
+		this.socket.on(
+			"event:songs.next",
+			res => {
+				const { currentSong } = res.data;
 
-			this.updateCurrentSong(currentSong || {});
-		});
+				this.updateCurrentSong(currentSong || {});
+			},
+			{
+				modal: "manageStation"
+			}
+		);
 	},
 	beforeDestroy() {
 		this.repositionSongInList([]);

+ 4 - 0
frontend/src/store/modules/modalVisibility.js

@@ -1,4 +1,5 @@
 /* eslint no-param-reassign: 0 */
+import ws from "@/ws";
 
 const state = {
 	modals: {
@@ -49,6 +50,9 @@ const mutations = {
 		state.currentlyActive.unshift(modal);
 	},
 	closeCurrentModal(state) {
+		// remove any websocket listeners for the modal
+		ws.removeModalListeners(state.currentlyActive[0]);
+
 		state.modals[state.currentlyActive[0]] = false;
 		state.currentlyActive.shift();
 	}

+ 15 - 3
frontend/src/ws.js

@@ -45,6 +45,17 @@ export default {
 				delete CB_REFS[id];
 		}),
 
+	removeModalListeners(modal) {
+		Object.keys(this.socket.dispatcher.listeners).forEach(type =>
+			this.socket.dispatcher.listeners[type].forEach(
+				(listener, index) => {
+					if (listener.options && listener.options.modal === modal)
+						this.socket.dispatcher.listeners[type].splice(index, 1);
+				}
+			)
+		);
+	},
+
 	init(url) {
 		// ensures correct context of socket object when dispatching (because socket object is recreated on reconnection)
 		const waitForConnectionToDispatch = (...args) =>
@@ -63,20 +74,21 @@ export default {
 				const stack = this.listeners[type];
 
 				// push the callback
-				stack.push({ cb, ...options });
+				stack.push({ cb, options });
 
 				const replaceableIndexes = [];
 
 				// check for any replaceable callbacks
 				stack.forEach((element, index) => {
-					if (element.replaceable) replaceableIndexes.push(index);
+					if (element.options && element.options.replaceable)
+						replaceableIndexes.push(index);
 				});
 
 				// should always be 1 replaceable callback remaining
 				replaceableIndexes.pop();
 
 				// delete the other replaceable callbacks
-				replaceableIndexes.forEach(index => delete stack[index]);
+				replaceableIndexes.forEach(index => stack.splice(index, 1));
 			}
 
 			// eslint-disable-next-line consistent-return