Browse Source

feat(socket.io -> WS): sockets can join/leave rooms that can be emitted to

Signed-off-by: Jonathan <theflametrooper@gmail.com>
Jonathan 4 years ago
parent
commit
2fa13a2419

+ 4 - 4
backend/logic/actions/activities.js

@@ -12,8 +12,8 @@ const UtilsModule = moduleManager.modules.utils;
 CacheModule.runJob("SUB", {
 	channel: "activity.removeAllForUser",
 	cb: userId => {
-		IOModule.runJob("SOCKETS_FROM_USER", { userId }, this).then(res =>
-			res.sockets.forEach(socket => socket.emit("event:activity.removeAllForUser"))
+		IOModule.runJob("SOCKETS_FROM_USER", { userId }, this).then(sockets =>
+			sockets.forEach(socket => socket.emit("event:activity.removeAllForUser"))
 		);
 
 		IOModule.runJob("EMIT_TO_ROOM", {
@@ -26,8 +26,8 @@ CacheModule.runJob("SUB", {
 CacheModule.runJob("SUB", {
 	channel: "activity.hide",
 	cb: res => {
-		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(response =>
-			response.sockets.forEach(socket => socket.emit("event:activity.hide", res.activityId))
+		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(sockets =>
+			sockets.forEach(socket => socket.emit("event:activity.hide", res.activityId))
 		);
 
 		IOModule.runJob("EMIT_TO_ROOM", {

+ 14 - 16
backend/logic/actions/playlists.js

@@ -16,10 +16,8 @@ const ActivitiesModule = moduleManager.modules.activities;
 CacheModule.runJob("SUB", {
 	channel: "playlist.create",
 	cb: playlist => {
-		IOModule.runJob("SOCKETS_FROM_USER", { userId: playlist.createdBy }, this).then(response => {
-			response.sockets.forEach(socket => {
-				socket.emit("event:playlist.create", playlist);
-			});
+		IOModule.runJob("SOCKETS_FROM_USER", { userId: playlist.createdBy }, this).then(sockets => {
+			sockets.forEach(socket => socket.emit("event:playlist.create", playlist));
 		});
 
 		if (playlist.privacy === "public")
@@ -33,8 +31,8 @@ CacheModule.runJob("SUB", {
 CacheModule.runJob("SUB", {
 	channel: "playlist.delete",
 	cb: res => {
-		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(response => {
-			response.sockets.forEach(socket => {
+		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(sockets => {
+			sockets.forEach(socket => {
 				socket.emit("event:playlist.delete", res.playlistId);
 			});
 		});
@@ -49,8 +47,8 @@ CacheModule.runJob("SUB", {
 CacheModule.runJob("SUB", {
 	channel: "playlist.repositionSongs",
 	cb: res => {
-		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(response =>
-			response.sockets.forEach(socket =>
+		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(sockets =>
+			sockets.forEach(socket =>
 				socket.emit("event:playlist.repositionSongs", {
 					playlistId: res.playlistId,
 					songsBeingChanged: res.songsBeingChanged
@@ -63,8 +61,8 @@ CacheModule.runJob("SUB", {
 CacheModule.runJob("SUB", {
 	channel: "playlist.addSong",
 	cb: res => {
-		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(response => {
-			response.sockets.forEach(socket => {
+		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(sockets => {
+			sockets.forEach(socket => {
 				socket.emit("event:playlist.addSong", {
 					playlistId: res.playlistId,
 					song: res.song
@@ -89,8 +87,8 @@ CacheModule.runJob("SUB", {
 CacheModule.runJob("SUB", {
 	channel: "playlist.removeSong",
 	cb: res => {
-		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(response => {
-			response.sockets.forEach(socket => {
+		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(sockets => {
+			sockets.forEach(socket => {
 				socket.emit("event:playlist.removeSong", {
 					playlistId: res.playlistId,
 					songId: res.songId
@@ -115,8 +113,8 @@ CacheModule.runJob("SUB", {
 CacheModule.runJob("SUB", {
 	channel: "playlist.updateDisplayName",
 	cb: res => {
-		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(response => {
-			response.sockets.forEach(socket => {
+		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(sockets => {
+			sockets.forEach(socket => {
 				socket.emit("event:playlist.updateDisplayName", {
 					playlistId: res.playlistId,
 					displayName: res.displayName
@@ -141,8 +139,8 @@ CacheModule.runJob("SUB", {
 CacheModule.runJob("SUB", {
 	channel: "playlist.updatePrivacy",
 	cb: res => {
-		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(response => {
-			response.sockets.forEach(socket => {
+		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(sockets => {
+			sockets.forEach(socket => {
 				socket.emit("event:playlist.updatePrivacy", {
 					playlist: res.playlist
 				});

+ 8 - 8
backend/logic/actions/songs.js

@@ -62,8 +62,8 @@ CacheModule.runJob("SUB", {
 				}
 			]
 		});
-		IOModule.runJob("SOCKETS_FROM_USER", { userId: data.userId }).then(response => {
-			response.sockets.forEach(socket => {
+		IOModule.runJob("SOCKETS_FROM_USER", { userId: data.userId }).then(sockets => {
+			sockets.forEach(socket => {
 				socket.emit("event:song.newRatings", {
 					songId: data.songId,
 					liked: true,
@@ -88,8 +88,8 @@ CacheModule.runJob("SUB", {
 				}
 			]
 		});
-		IOModule.runJob("SOCKETS_FROM_USER", { userId: data.userId }).then(response => {
-			response.sockets.forEach(socket => {
+		IOModule.runJob("SOCKETS_FROM_USER", { userId: data.userId }).then(sockets => {
+			sockets.forEach(socket => {
 				socket.emit("event:song.newRatings", {
 					songId: data.songId,
 					liked: false,
@@ -114,8 +114,8 @@ CacheModule.runJob("SUB", {
 				}
 			]
 		});
-		IOModule.runJob("SOCKETS_FROM_USER", { userId: data.userId }).then(response => {
-			response.sockets.forEach(socket => {
+		IOModule.runJob("SOCKETS_FROM_USER", { userId: data.userId }).then(sockets => {
+			sockets.forEach(socket => {
 				socket.emit("event:song.newRatings", {
 					songId: data.songId,
 					liked: false,
@@ -140,8 +140,8 @@ CacheModule.runJob("SUB", {
 				}
 			]
 		});
-		IOModule.runJob("SOCKETS_FROM_USER", { userId: data.userId }).then(response => {
-			response.sockets.forEach(socket => {
+		IOModule.runJob("SOCKETS_FROM_USER", { userId: data.userId }).then(sockets => {
+			sockets.forEach(socket => {
 				socket.emit("event:song.newRatings", {
 					songId: data.songId,
 					liked: false,

+ 10 - 12
backend/logic/actions/stations.js

@@ -400,16 +400,17 @@ export default {
 	 * @param {Function} cb - callback
 	 */
 	index(session, cb) {
+		console.log("called");
+
 		async.waterfall(
 			[
 				next => {
-					CacheModule.runJob("HGETALL", { table: "stations" }, this).then(stations => {
-						next(null, stations);
-					});
+					CacheModule.runJob("HGETALL", { table: "stations" }, this).then(stations => next(null, stations));
 				},
 
 				(items, next) => {
 					const filteredStations = [];
+
 					async.each(
 						items,
 						(station, nextStation) => {
@@ -418,14 +419,10 @@ export default {
 									callback => {
 										// only relevant if user logged in
 										if (session.userId) {
-											return StationsModule.runJob(
-												"HAS_USER_FAVORITED_STATION",
-												{
-													userId: session.userId,
-													stationId: station._id
-												},
-												this
-											)
+											return StationsModule.runJob("HAS_USER_FAVORITED_STATION", {
+												userId: session.userId,
+												stationId: station._id
+											})
 												.then(isStationFavorited => {
 													station.isFavorited = isStationFavorited;
 													return callback();
@@ -456,7 +453,6 @@ export default {
 									station.userCount = StationsModule.usersPerStationCount[station._id] || 0;
 
 									if (exists) filteredStations.push(station);
-
 									return nextStation();
 								}
 							);
@@ -471,7 +467,9 @@ export default {
 					this.log("ERROR", "STATIONS_INDEX", `Indexing stations failed. "${err}"`);
 					return cb({ status: "failure", message: err });
 				}
+
 				this.log("SUCCESS", "STATIONS_INDEX", `Indexing stations successful.`, false);
+
 				return cb({ status: "success", stations });
 			}
 		);

+ 22 - 22
backend/logic/actions/users.js

@@ -21,8 +21,8 @@ const PlaylistsModule = moduleManager.modules.playlists;
 CacheModule.runJob("SUB", {
 	channel: "user.updatePreferences",
 	cb: res => {
-		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(response => {
-			response.sockets.forEach(socket => {
+		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(sockets => {
+			sockets.forEach(socket => {
 				socket.emit("keep.event:user.preferences.changed", res.preferences);
 			});
 		});
@@ -32,8 +32,8 @@ CacheModule.runJob("SUB", {
 CacheModule.runJob("SUB", {
 	channel: "user.updateOrderOfPlaylists",
 	cb: res => {
-		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(response => {
-			response.sockets.forEach(socket => {
+		IOModule.runJob("SOCKETS_FROM_USER", { userId: res.userId }, this).then(sockets => {
+			sockets.forEach(socket => {
 				socket.emit("event:user.orderOfPlaylists.changed", res.orderOfPlaylists);
 			});
 		});
@@ -48,8 +48,8 @@ CacheModule.runJob("SUB", {
 CacheModule.runJob("SUB", {
 	channel: "user.updateUsername",
 	cb: user => {
-		IOModule.runJob("SOCKETS_FROM_USER", { userId: user._id }).then(response => {
-			response.sockets.forEach(socket => {
+		IOModule.runJob("SOCKETS_FROM_USER", { userId: user._id }).then(sockets => {
+			sockets.forEach(socket => {
 				socket.emit("event:user.username.changed", user.username);
 			});
 		});
@@ -59,8 +59,8 @@ CacheModule.runJob("SUB", {
 CacheModule.runJob("SUB", {
 	channel: "user.removeSessions",
 	cb: userId => {
-		IOModule.runJob("SOCKETS_FROM_USER_WITHOUT_CACHE", { userId }).then(response => {
-			response.sockets.forEach(socket => {
+		IOModule.runJob("SOCKETS_FROM_USER_WITHOUT_CACHE", { userId }).then(sockets => {
+			sockets.forEach(socket => {
 				socket.emit("keep.event:user.session.removed");
 			});
 		});
@@ -70,8 +70,8 @@ CacheModule.runJob("SUB", {
 CacheModule.runJob("SUB", {
 	channel: "user.linkPassword",
 	cb: userId => {
-		IOModule.runJob("SOCKETS_FROM_USER", { userId }).then(response => {
-			response.sockets.forEach(socket => {
+		IOModule.runJob("SOCKETS_FROM_USER", { userId }).then(sockets => {
+			sockets.forEach(socket => {
 				socket.emit("event:user.linkPassword");
 			});
 		});
@@ -81,8 +81,8 @@ CacheModule.runJob("SUB", {
 CacheModule.runJob("SUB", {
 	channel: "user.unlinkPassword",
 	cb: userId => {
-		IOModule.runJob("SOCKETS_FROM_USER", { userId }).then(response => {
-			response.sockets.forEach(socket => {
+		IOModule.runJob("SOCKETS_FROM_USER", { userId }).then(sockets => {
+			sockets.forEach(socket => {
 				socket.emit("event:user.unlinkPassword");
 			});
 		});
@@ -92,8 +92,8 @@ CacheModule.runJob("SUB", {
 CacheModule.runJob("SUB", {
 	channel: "user.linkGithub",
 	cb: userId => {
-		IOModule.runJob("SOCKETS_FROM_USER", { userId }).then(response => {
-			response.sockets.forEach(socket => {
+		IOModule.runJob("SOCKETS_FROM_USER", { userId }).then(sockets => {
+			sockets.forEach(socket => {
 				socket.emit("event:user.linkGithub");
 			});
 		});
@@ -103,8 +103,8 @@ CacheModule.runJob("SUB", {
 CacheModule.runJob("SUB", {
 	channel: "user.unlinkGithub",
 	cb: userId => {
-		IOModule.runJob("SOCKETS_FROM_USER", { userId }).then(response => {
-			response.sockets.forEach(socket => {
+		IOModule.runJob("SOCKETS_FROM_USER", { userId }).then(sockets => {
+			sockets.forEach(socket => {
 				socket.emit("event:user.unlinkGithub");
 			});
 		});
@@ -114,8 +114,8 @@ CacheModule.runJob("SUB", {
 CacheModule.runJob("SUB", {
 	channel: "user.ban",
 	cb: data => {
-		IOModule.runJob("SOCKETS_FROM_USER", { userId: data.userId }).then(response => {
-			response.sockets.forEach(socket => {
+		IOModule.runJob("SOCKETS_FROM_USER", { userId: data.userId }).then(sockets => {
+			sockets.forEach(socket => {
 				socket.emit("keep.event:banned", data.punishment);
 				socket.disconnect(true);
 			});
@@ -126,8 +126,8 @@ CacheModule.runJob("SUB", {
 CacheModule.runJob("SUB", {
 	channel: "user.favoritedStation",
 	cb: data => {
-		IOModule.runJob("SOCKETS_FROM_USER", { userId: data.userId }).then(response => {
-			response.sockets.forEach(socket => {
+		IOModule.runJob("SOCKETS_FROM_USER", { userId: data.userId }).then(sockets => {
+			sockets.forEach(socket => {
 				socket.emit("event:user.favoritedStation", data.stationId);
 			});
 		});
@@ -137,8 +137,8 @@ CacheModule.runJob("SUB", {
 CacheModule.runJob("SUB", {
 	channel: "user.unfavoritedStation",
 	cb: data => {
-		IOModule.runJob("SOCKETS_FROM_USER", { userId: data.userId }).then(response => {
-			response.sockets.forEach(socket => {
+		IOModule.runJob("SOCKETS_FROM_USER", { userId: data.userId }).then(sockets => {
+			sockets.forEach(socket => {
 				socket.emit("event:user.unfavoritedStation", data.stationId);
 			});
 		});

+ 6 - 6
backend/logic/activities.js

@@ -73,8 +73,8 @@ class _ActivitiesModule extends CoreClass {
 
 					(activity, next) => {
 						IOModule.runJob("SOCKETS_FROM_USER", { userId: activity.userId }, this)
-							.then(res => {
-								res.sockets.forEach(socket => socket.emit("event:activity.create", activity));
+							.then(sockets => {
+								sockets.forEach(socket => socket.emit("event:activity.create", activity));
 								next(null, activity);
 							})
 							.catch(next);
@@ -226,8 +226,8 @@ class _ActivitiesModule extends CoreClass {
 							activityModel.updateOne({ _id: activity._id }, { $set: { hidden: true } }).catch(next);
 
 							IOModule.runJob("SOCKETS_FROM_USER", { userId: payload.userId }, this)
-								.then(res =>
-									res.sockets.forEach(socket => socket.emit("event:activity.hide", activity._id))
+								.then(sockets =>
+									sockets.forEach(socket => socket.emit("event:activity.hide", activity._id))
 								)
 								.catch(next);
 
@@ -331,8 +331,8 @@ class _ActivitiesModule extends CoreClass {
 							activityModel.updateOne({ _id: activity._id }, { $set: { hidden: true } }).catch(next);
 
 							IOModule.runJob("SOCKETS_FROM_USER", { userId: payload.userId }, this)
-								.then(res =>
-									res.sockets.forEach(socket => socket.emit("event:activity.hide", activity._id))
+								.then(sockets =>
+									sockets.forEach(socket => socket.emit("event:activity.hide", activity._id))
 								)
 								.catch(next);
 

+ 125 - 229
backend/logic/io.js

@@ -51,17 +51,13 @@ class _IOModule extends CoreClass {
 
 		// this._io.origins(config.get("cors.origin"));
 
-		// this._io = socketio(server);
-
 		this._io = new WebSocket.Server({ server, path: "/ws" });
 
+		this.rooms = {};
+
 		return new Promise(resolve => {
 			this.setStage(3);
 
-			// this._io.use(async (socket, cb) => {
-			// 	IOModule.runJob("HANDLE_IO_USE", { socket, cb });
-			// });
-
 			this.setStage(4);
 
 			this._io.on("connection", async (socket, req) => {
@@ -73,7 +69,6 @@ class _IOModule extends CoreClass {
 				socket.actions.setMaxListeners(0);
 				socket.listen = (target, cb) => socket.actions.addListener(target, args => cb(args));
 
-				socket.dispatch("test2", { color: "red" }, 9);
 				IOModule.runJob("HANDLE_IO_USE", { socket, req }).then(socket =>
 					IOModule.runJob("HANDLE_IO_CONNECTION", { socket })
 				);
@@ -97,18 +92,20 @@ class _IOModule extends CoreClass {
 	}
 
 	/**
-	 * Returns whether there is a socket for a session id or not
+	 * Obtains socket object for a specified socket id
 	 *
 	 * @param {object} payload - object containing the payload
-	 * @param {string} payload.sessionId - user session id
+	 * @param {string} payload.socketId - the id of the socket
 	 * @returns {Promise} - returns promise (reject, resolve)
 	 */
-	async SOCKET_FROM_SESSION(payload) {
-		// socketId
+	async SOCKET_FROM_SOCKET_ID(payload) {
 		return new Promise((resolve, reject) => {
-			const ns = IOModule._io.of("/");
-			if (ns) {
-				return resolve(ns.connected[payload.socketId]);
+			const { clients } = IOModule._io;
+
+			if (clients) {
+				return clients.forEach(socket => {
+					if (socket.session.socketId === payload.socketId) resolve(socket);
+				});
 			}
 
 			return reject();
@@ -124,20 +121,18 @@ class _IOModule extends CoreClass {
 	 */
 	async SOCKETS_FROM_SESSION_ID(payload) {
 		return new Promise(resolve => {
-			const ns = IOModule._io.of("/");
+			const { clients } = IOModule._io;
 			const sockets = [];
 
-			if (ns) {
+			if (clients) {
 				return async.each(
-					Object.keys(ns.connected),
+					Object.keys(clients),
 					(id, next) => {
-						const { session } = ns.connected[id];
+						const { session } = clients[id];
 						if (session.sessionId === payload.sessionId) sockets.push(session.sessionId);
 						next();
 					},
-					() => {
-						resolve({ sockets });
-					}
+					() => resolve(sockets)
 				);
 			}
 
@@ -154,33 +149,37 @@ class _IOModule extends CoreClass {
 	 */
 	async SOCKETS_FROM_USER(payload) {
 		return new Promise((resolve, reject) => {
-			const ns = IOModule._io.of("/");
 			const sockets = [];
 
-			if (ns) {
-				return async.eachLimit(
-					Object.keys(ns.connected),
-					1,
-					(id, next) => {
-						const { session } = ns.connected[id];
-
-						if (session.sessionId) {
-							CacheModule.runJob("HGET", { table: "sessions", key: session.sessionId }, this)
-								.then(session => {
-									if (session && session.userId === payload.userId) sockets.push(ns.connected[id]);
-									next();
-								})
-								.catch(err => next(err));
-						} else next();
-					},
-					err => {
-						if (err) return reject(err);
-						return resolve({ sockets });
+			return async.eachLimit(
+				Object.keys(IOModule._io.clients),
+				1,
+				(id, next) => {
+					const { session } = IOModule._io.clients[id];
+
+					console.log(1, session);
+
+					if (session.sessionId) {
+						return CacheModule.runJob("HGET", { table: "sessions", key: session.sessionId }, this)
+							.then(session => {
+								console.log(2, session, payload.userId);
+
+								if (session && session.userId === payload.userId)
+									sockets.push(IOModule._io.clients[id]);
+								next();
+							})
+							.catch(err => next(err));
 					}
-				);
-			}
 
-			return resolve();
+					return next();
+				},
+				err => {
+					console.log("SOCKETS_FROM_USER", sockets, err);
+
+					if (err) return reject(err);
+					return resolve(sockets);
+				}
+			);
 		});
 	}
 
@@ -193,35 +192,24 @@ class _IOModule extends CoreClass {
 	 */
 	async SOCKETS_FROM_IP(payload) {
 		return new Promise(resolve => {
-			const ns = IOModule._io.of("/");
+			const { clients } = IOModule._io;
+
 			const sockets = [];
-			if (ns) {
-				return async.each(
-					Object.keys(ns.connected),
-					(id, next) => {
-						const { session } = ns.connected[id];
-
-						CacheModule.runJob(
-							"HGET",
-							{
-								table: "sessions",
-								key: session.sessionId
-							},
-							this
-						)
-							.then(session => {
-								if (session && ns.connected[id].ip === payload.ip) sockets.push(ns.connected[id]);
-								next();
-							})
-							.catch(() => next());
-					},
-					() => {
-						resolve(sockets);
-					}
-				);
-			}
 
-			return resolve();
+			return async.each(
+				Object.keys(clients),
+				(id, next) => {
+					const { session } = clients[id];
+
+					CacheModule.runJob("HGET", { table: "sessions", key: session.sessionId }, this)
+						.then(session => {
+							if (session && clients[id].ip === payload.ip) sockets.push(clients[id]);
+							next();
+						})
+						.catch(() => next());
+				},
+				() => resolve(sockets)
+			);
 		});
 	}
 
@@ -234,20 +222,18 @@ class _IOModule extends CoreClass {
 	 */
 	async SOCKETS_FROM_USER_WITHOUT_CACHE(payload) {
 		return new Promise(resolve => {
-			const ns = IOModule._io.of("/");
+			const { clients } = IOModule._io;
 			const sockets = [];
 
-			if (ns) {
+			if (clients) {
 				return async.each(
-					Object.keys(ns.connected),
+					Object.keys(clients),
 					(id, next) => {
-						const { session } = ns.connected[id];
-						if (session.userId === payload.userId) sockets.push(ns.connected[id]);
+						const { session } = clients[id];
+						if (session.userId === payload.userId) sockets.push(clients[id]);
 						next();
 					},
-					() => {
-						resolve({ sockets });
-					}
+					() => resolve(sockets)
 				);
 			}
 
@@ -263,20 +249,10 @@ class _IOModule extends CoreClass {
 	 * @returns {Promise} - returns promise (reject, resolve)
 	 */
 	async SOCKET_LEAVE_ROOMS(payload) {
-		const socket = await IOModule.runJob(
-			"SOCKET_FROM_SESSION",
-			{
-				socketId: payload.socketId
-			},
-			this
-		);
-
 		return new Promise(resolve => {
-			const { rooms } = socket;
-
-			Object.keys(rooms).forEach(roomKey => {
-				const room = rooms[roomKey];
-				socket.leave(room);
+			// filter out rooms that the user is in
+			Object.keys(IOModule.rooms).forEach(room => {
+				IOModule.rooms[room] = IOModule.rooms[room].filter(participant => participant !== payload.socketId);
 			});
 
 			return resolve();
@@ -284,7 +260,7 @@ class _IOModule extends CoreClass {
 	}
 
 	/**
-	 * Allows a socket to join a specified room
+	 * Allows a socket to join a specified room (this will remove them from any rooms they are currently in)
 	 *
 	 * @param {object} payload - object that contains the payload
 	 * @param {string} payload.socketId - the id of the socket which should join the room
@@ -292,22 +268,51 @@ class _IOModule extends CoreClass {
 	 * @returns {Promise} - returns promise (reject, resolve)
 	 */
 	async SOCKET_JOIN_ROOM(payload) {
-		const socket = await IOModule.runJob(
-			"SOCKET_FROM_SESSION",
-			{
-				socketId: payload.socketId
-			},
-			this
-		);
+		const { room, socketId } = payload;
+
+		console.log("JOIN_ROOM", payload.room);
+
+		// leave all other rooms
+		await IOModule.runJob("SOCKET_LEAVE_ROOMS", { socketId }, this);
 
 		return new Promise(resolve => {
-			const { rooms } = socket;
-			Object.keys(rooms).forEach(roomKey => {
-				const room = rooms[roomKey];
-				socket.leave(room);
-			});
+			// create room if it doesn't exist, and add socketId to array
+			if (IOModule.rooms[room]) IOModule.rooms[room].push(socketId);
+			else IOModule.rooms[room] = [socketId];
 
-			socket.join(payload.room);
+			return resolve();
+		});
+	}
+
+	/**
+	 * Emits arguments to any sockets that are in a specified a room
+	 *
+	 * @param {object} payload - object that contains the payload
+	 * @param {string} payload.room - the name of the room to emit arguments
+	 * @param {object} payload.args - any arguments to be emitted to the sockets in the specific room
+	 * @returns {Promise} - returns promise (reject, resolve)
+	 */
+	async EMIT_TO_ROOM(payload) {
+		console.log("EMIT_TO_ROOM", payload.room);
+
+		return new Promise(resolve => {
+			// IOModule._io.clients.forEach(socket => {
+			// 	console.log(1234);
+			// 	console.log(socket, socket.rooms);
+
+			// 	if (socket.rooms[payload.room]) {
+			// 		console.log(payload.args);
+			// 		socket.dispatch(...payload.args);
+			// 	}
+			// });
+
+			console.log(IOModule.rooms, payload.room);
+
+			if (IOModule.rooms[payload.room])
+				return IOModule.rooms[payload.room].forEach(async socketId => {
+					const socket = await IOModule.runJob("SOCKET_FROM_SOCKET_ID", { socketId }, this);
+					socket.dispatch(...payload.args);
+				});
 
 			return resolve();
 		});
@@ -317,13 +322,7 @@ class _IOModule extends CoreClass {
 	// eslint-disable-next-line require-jsdoc
 	async SOCKET_JOIN_SONG_ROOM(payload) {
 		// socketId, room
-		const socket = await IOModule.runJob(
-			"SOCKET_FROM_SESSION",
-			{
-				socketId: payload.socketId
-			},
-			this
-		);
+		const socket = await IOModule.runJob("SOCKET_FROM_SOCKET_ID", { socketId: payload.socketId }, this);
 
 		return new Promise(resolve => {
 			const { rooms } = socket;
@@ -376,28 +375,6 @@ class _IOModule extends CoreClass {
 		});
 	}
 
-	/**
-	 * Emits arguments to any sockets that are in a specified a room
-	 *
-	 * @param {object} payload - object that contains the payload
-	 * @param {string} payload.room - the name of the room to emit arguments
-	 * @param {object} payload.args - any arguments to be emitted to the sockets in the specific room
-	 * @returns {Promise} - returns promise (reject, resolve)
-	 */
-	async EMIT_TO_ROOM(payload) {
-		return new Promise(resolve =>
-			// const { sockets } = IOModule._io.sockets;
-			// Object.keys(sockets).forEach(socketKey => {
-			// 	const socket = sockets[socketKey];
-			// 	if (socket.rooms[payload.room]) {
-			// 		socket.dispatch(...payload.args);
-			// 	}
-			// });
-
-			resolve()
-		);
-	}
-
 	/**
 	 * Gets any sockets connected to a room
 	 *
@@ -407,14 +384,8 @@ class _IOModule extends CoreClass {
 	 */
 	async GET_ROOM_SOCKETS(payload) {
 		return new Promise(resolve => {
-			const { sockets } = IOModule._io.sockets;
-			const roomSockets = [];
-			Object.keys(sockets).forEach(socketKey => {
-				const socket = sockets[socketKey];
-				if (socket.rooms[payload.room]) roomSockets.push(socket);
-			});
-
-			return resolve(roomSockets);
+			if (IOModule.rooms[payload.room]) return resolve(IOModule.rooms[payload.room]);
+			return resolve([]);
 		});
 	}
 
@@ -504,8 +475,6 @@ class _IOModule extends CoreClass {
 					if (!socket.session) socket.session = { socketId: req.headers["sec-websocket-key"] };
 					else socket.session.socketId = req.headers["sec-websocket-key"];
 
-					console.log("session", socket.session);
-
 					// cb();
 					resolve(socket);
 				}
@@ -539,16 +508,18 @@ class _IOModule extends CoreClass {
 
 				socket.dispatch("keep.event:banned", socket.banishment.ban);
 
-				return socket.disconnect(true);
+				return socket.disconnect(true); // need to fix
 			}
 
 			IOModule.log("INFO", "IO_CONNECTION", `User connected. IP: ${socket.ip}.${sessionInfo}`);
 
 			// catch when the socket has been disconnected
-			socket.onclose = () => {
+			socket.on("close", async () => {
 				if (socket.session.sessionId) sessionInfo = ` UserID: ${socket.session.userId}.`;
 				IOModule.log("INFO", "IO_DISCONNECTION", `User disconnected. IP: ${socket.ip}.${sessionInfo}`);
-			};
+
+				await IOModule.runJob("SOCKET_LEAVE_ROOMS", { socketId: socket.session.socketId });
+			});
 
 			// socket.use((data, next) => {
 			// 	if (data.length === 0) return next(new Error("Not enough arguments specified."));
@@ -573,7 +544,7 @@ class _IOModule extends CoreClass {
 			// });
 
 			// catch errors on the socket (internal to socket.io)
-			socket.onerror = console.error;
+			socket.onerror = console.error; // need to update
 
 			if (socket.session.sessionId) {
 				CacheModule.runJob("HGET", {
@@ -625,86 +596,9 @@ class _IOModule extends CoreClass {
 					};
 
 					// listen for this action to be called
-					socket.listen(name, async args => {
-						IOModule.runJob("RUN_ACTION", { socket, namespace, action, args });
-
-						console.log(name, args);
-
-						/* let cb = args[args.length - 1];
-
-						if (typeof cb !== "function")
-							cb = () => {
-								IOModule.log("INFO", "IO_MODULE", `There was no callback provided for ${name}.`);
-							};
-						else args.pop();
-
-						if (this.getStatus() !== "READY") {
-							IOModule.log(
-								"INFO",
-								"IO_REJECTED_ACTION",
-								`A user tried to execute an action, but the IO module is currently not ready. Action: ${namespace}.${action}.`
-							);
-							return;
-						}
-						IOModule.log("INFO", "IO_ACTION", `A user executed an action. Action: ${namespace}.${action}.`);
-
-						let failedGettingSession = false;
-						// load the session from the cache
-						if (socket.session.sessionId)
-							await CacheModule.runJob("HGET", {
-								table: "sessions",
-								key: socket.session.sessionId
-							})
-								.then(session => {
-									// make sure the sockets sessionId isn't set if there is no session
-									if (socket.session.sessionId && session === null) delete socket.session.sessionId;
-								})
-								.catch(() => {
-									failedGettingSession = true;
-									if (typeof cb === "function")
-										cb({
-											status: "error",
-											message: "An error occurred while obtaining your session"
-										});
-								});
-						if (!failedGettingSession)
-							try {
-								// call the action, passing it the session, and the arguments socket.io passed us
-								this.runJob("RUN_ACTION", { namespace, action, session: socket.session, args })
-									.then(response => {
-										if (typeof cb === "function") cb(response);
-									})
-									.catch(err => {
-										if (typeof cb === "function") cb(err);
-									});
-								// actions[namespace][action].apply(
-								// 	null,
-								// 	[socket.session].concat(args).concat([
-								// 		result => {
-								// 			IOModule.log(
-								// 				"INFO",
-								// 				"IO_ACTION",
-								// 				`Response to action. Action: ${namespace}.${action}. Response status: ${result.status}`
-								// 			);
-								// 			// respond to the socket with our message
-								// 			if (typeof cb === "function") cb(result);
-								// 		}
-								// 	])
-								// );
-							} catch (err) {
-								if (typeof cb === "function")
-									cb({
-										status: "error",
-										message: "An error occurred while executing the specified action."
-									});
-
-								IOModule.log(
-									"ERROR",
-									"IO_ACTION_ERROR",
-									`Some type of exception occurred in the action ${namespace}.${action}. Error message: ${err.message}`
-								);
-							} */
-					});
+					socket.listen(name, async args =>
+						IOModule.runJob("RUN_ACTION", { socket, namespace, action, args })
+					);
 				});
 			});
 
@@ -726,6 +620,7 @@ class _IOModule extends CoreClass {
 			const name = `${namespace}.${action}`;
 
 			let cb = args[args.length - 1];
+
 			if (typeof cb !== "function")
 				cb = () => {
 					IOModule.log("INFO", "IO_MODULE", `There was no callback provided for ${name}.`);
@@ -770,6 +665,7 @@ class _IOModule extends CoreClass {
 									status: "error",
 									message: "An error occurred while executing the specified action."
 								});
+
 							reject(err);
 
 							IOModule.log(

+ 1 - 7
backend/logic/stations.js

@@ -1092,13 +1092,7 @@ class _StationsModule extends CoreClass {
 			async.waterfall(
 				[
 					next => {
-						DBModule.runJob(
-							"GET_MODEL",
-							{
-								modelName: "user"
-							},
-							this
-						).then(userModel => {
+						DBModule.runJob("GET_MODEL", { modelName: "user" }, this).then(userModel => {
 							userModel.findOne({ _id: payload.userId }, next);
 						});
 					},

+ 1 - 1
backend/logic/tasks.js

@@ -360,7 +360,7 @@ class _TasksModule extends CoreClass {
 			async.each(
 				Object.keys(StationsModule.userList),
 				(socketId, next) => {
-					IOModule.runJob("SOCKET_FROM_SESSION", { socketId }).then(socket => {
+					IOModule.runJob("SOCKET_FROM_SOCKET_ID", { socketId }).then(socket => {
 						const stationId = StationsModule.userList[socketId];
 
 						if (!socket || Object.keys(socket.rooms).indexOf(`station.${stationId}`) === -1) {

+ 0 - 1
docker-compose.yml

@@ -5,7 +5,6 @@ services:
     build: ./backend
     ports:
       - "${BACKEND_PORT}:8080"
-      - "3030:3030"
     volumes:
       - ./backend:/opt/app
       - ./log:/opt/log

+ 2 - 2
frontend/src/io.js

@@ -59,12 +59,12 @@ export default {
 	},
 
 	removeAllListeners() {
-		Object.keys(this.socket._callbacks).forEach(id => {
+		Object.keys(callbackss).forEach(id => {
 			if (
 				id.indexOf("$event:") !== -1 &&
 				id.indexOf("$event:keep.") === -1
 			)
-				delete this.socket._callbacks[id];
+				delete callbackss[id];
 		});
 	},
 

+ 1 - 1
frontend/src/mixins/SortablePlaylists.vue

@@ -19,7 +19,7 @@ export default {
 			return {
 				animation: 200,
 				group: "description",
-				disabled: false,
+				disabled: this.myUserId !== this.userId,
 				ghostClass: "draggable-list-ghost"
 			};
 		}

+ 1 - 1
frontend/src/pages/Admin/tabs/NewStatistics.vue

@@ -204,7 +204,7 @@ export default {
 	mounted() {
 		io.getSocket(socket => {
 			this.socket = socket;
-			if (this.socket.connected) this.init();
+			if (this.socket.readyState === 1) this.init();
 			io.onConnect(() => this.init());
 		});
 	},

+ 18 - 15
frontend/src/pages/Admin/tabs/News.vue

@@ -248,21 +248,24 @@ export default {
 	mounted() {
 		io.getSocket(socket => {
 			this.socket = socket;
-			this.socket.dispatch("news.index", res => {
-				res.data.forEach(news => {
-					this.addNews(news);
-				});
-			});
-			this.socket.on("event:admin.news.created", news => {
-				this.addNews(news);
-			});
-			this.socket.on("event:admin.news.updated", updatedNews => {
-				this.updateNews(updatedNews);
-			});
-			this.socket.on("event:admin.news.removed", news => {
-				this.removeNews(news._id);
-			});
-			if (this.socket.connected) this.init();
+
+			this.socket.dispatch("news.index", res =>
+				res.data.forEach(news => this.addNews(news))
+			);
+
+			this.socket.on("event:admin.news.created", news =>
+				this.addNews(news)
+			);
+
+			this.socket.on("event:admin.news.updated", updatedNews =>
+				this.updateNews(updatedNews)
+			);
+
+			this.socket.on("event:admin.news.removed", news =>
+				this.removeNews(news._id)
+			);
+
+			if (this.socket.readyState === 1) this.init();
 			io.onConnect(() => this.init());
 		});
 	},

+ 1 - 1
frontend/src/pages/Admin/tabs/Playlists.vue

@@ -82,7 +82,7 @@ export default {
 	mounted() {
 		io.getSocket(socket => {
 			this.socket = socket;
-			if (this.socket.connected) this.init();
+			if (this.socket.readyState === 1) this.init();
 			io.onConnect(() => this.init());
 		});
 	},

+ 6 - 4
frontend/src/pages/Admin/tabs/Punishments.vue

@@ -123,11 +123,13 @@ export default {
 	mounted() {
 		io.getSocket(socket => {
 			this.socket = socket;
-			if (this.socket.connected) this.init();
+
+			if (this.socket.readyState === 1) this.init();
 			io.onConnect(() => this.init());
-			socket.on("event:admin.punishment.added", punishment => {
-				this.punishments.push(punishment);
-			});
+
+			socket.on("event:admin.punishment.added", punishment =>
+				this.punishments.push(punishment)
+			);
 		});
 	},
 	methods: {

+ 2 - 4
frontend/src/pages/Admin/tabs/QueueSongs.vue

@@ -243,10 +243,8 @@ export default {
 				}
 			});
 
-			if (this.socket.connected) this.init();
-			io.onConnect(() => {
-				this.init();
-			});
+			if (this.socket.readyState === 1) this.init();
+			io.onConnect(() => this.init());
 		});
 	},
 	methods: {

+ 6 - 8
frontend/src/pages/Admin/tabs/Reports.vue

@@ -92,7 +92,9 @@ export default {
 	mounted() {
 		io.getSocket(socket => {
 			this.socket = socket;
-			if (this.socket.connected) this.init();
+
+			if (this.socket.readyState === 1) this.init();
+			io.onConnect(() => this.init());
 
 			this.socket.dispatch("reports.index", res => {
 				this.reports = res.data;
@@ -104,13 +106,9 @@ export default {
 				});
 			});
 
-			this.socket.on("event:admin.report.created", report => {
-				this.reports.push(report);
-			});
-
-			io.onConnect(() => {
-				this.init();
-			});
+			this.socket.on("event:admin.report.created", report =>
+				this.reports.push(report)
+			);
 		});
 
 		if (this.$route.query.id) {

+ 11 - 13
frontend/src/pages/Admin/tabs/Songs.vue

@@ -310,22 +310,20 @@ export default {
 		io.getSocket(socket => {
 			this.socket = socket;
 
-			this.socket.on("event:admin.song.added", song => {
-				this.addSong(song);
-			});
+			this.socket.on("event:admin.song.added", song =>
+				this.addSong(song)
+			);
 
-			this.socket.on("event:admin.song.removed", songId => {
-				this.removeSong(songId);
-			});
+			this.socket.on("event:admin.song.removed", songId =>
+				this.removeSong(songId)
+			);
 
-			this.socket.on("event:admin.song.updated", updatedSong => {
-				this.updateSong(updatedSong);
-			});
+			this.socket.on("event:admin.song.updated", updatedSong =>
+				this.updateSong(updatedSong)
+			);
 
-			if (this.socket.connected) this.init();
-			io.onConnect(() => {
-				this.init();
-			});
+			if (this.socket.readyState === 1) this.init();
+			io.onConnect(() => this.init());
 		});
 
 		if (this.$route.query.songId) {

+ 10 - 10
frontend/src/pages/Admin/tabs/Stations.vue

@@ -214,17 +214,17 @@ export default {
 	mounted() {
 		io.getSocket(socket => {
 			this.socket = socket;
-			if (this.socket.connected) this.init();
 
-			this.socket.on("event:admin.station.added", station => {
-				this.stationAdded(station);
-			});
-			this.socket.on("event:admin.station.removed", stationId => {
-				this.stationRemoved(stationId);
-			});
-			io.onConnect(() => {
-				this.init();
-			});
+			if (this.socket.readyState === 1) this.init();
+			io.onConnect(() => this.init());
+
+			this.socket.on("event:admin.station.added", station =>
+				this.stationAdded(station)
+			);
+
+			this.socket.on("event:admin.station.removed", stationId =>
+				this.stationRemoved(stationId)
+			);
 		});
 	},
 	methods: {

+ 2 - 1
frontend/src/pages/Admin/tabs/Statistics.vue

@@ -265,7 +265,8 @@ export default {
 
 		io.getSocket(socket => {
 			this.socket = socket;
-			if (this.socket.connected) this.init();
+			if (this.socket.readyState === 1) this.init();
+
 			io.onConnect(() => this.init());
 		});
 	},

+ 2 - 1
frontend/src/pages/Admin/tabs/Users.vue

@@ -88,7 +88,8 @@ export default {
 	mounted() {
 		io.getSocket(socket => {
 			this.socket = socket;
-			if (this.socket.connected) this.init();
+
+			if (this.socket.readyState === 1) this.init();
 			io.onConnect(() => this.init());
 		});
 	},

+ 1 - 1
frontend/src/pages/Home.vue

@@ -501,7 +501,7 @@ export default {
 		io.getSocket(socket => {
 			this.socket = socket;
 
-			if (this.socket.connected) this.init();
+			if (this.socket.readyState === 1) this.init();
 			io.onConnect(() => this.init());
 
 			this.socket.on("event:stations.created", res => {

+ 4 - 1
frontend/src/pages/Profile/tabs/Playlists.vue

@@ -34,7 +34,10 @@
 					:name="!drag ? 'draggable-list-transition' : null"
 				>
 					<div
-						class="item item-draggable"
+						:class="{
+							item: true,
+							'item-draggable': myUserId === userId
+						}"
 						v-for="playlist in playlists"
 						:key="playlist._id"
 					>

+ 3 - 1
frontend/src/pages/Profile/tabs/RecentActivity.vue

@@ -80,7 +80,9 @@ export default {
 				this.socket.dispatch(
 					"apis.joinRoom",
 					`profile-${this.userId}-activities`,
-					() => {}
+					res => {
+						console.log("res of joining activities room", res);
+					}
 				);
 			}
 

+ 1 - 1
frontend/src/pages/Station/index.vue

@@ -598,7 +598,7 @@ export default {
 		io.getSocket(socket => {
 			this.socket = socket;
 
-			if (this.socket.connected) this.join();
+			if (this.socket.readyState === 1) this.join();
 			io.onConnect(this.join);
 
 			this.socket.dispatch(