const {LogType} = require('loguix') const wlog = new LogType("Server") const fs = require("fs") const path = require("path") const {Server} = require('socket.io') const {createServer} = require('http') const session = require("../server/auth/Session") const users = require("../server/auth/User") const players = require("../player/Player") const {Player} = require("../player/Player") const discordBot = require("../discord/Bot") const discordAuth = require("../server/auth/DiscordAuth") const {Report} = require("../discord/ReportSender") const Finder = require("../player/Finder") const {__glob} = require("../utils/GlobalVars") const playlists = require("../playlists/PlaylistManager") const history = require("../playlists/History") const lyrics = require("../lyrics/Lyrics") const mediaBase = require("../discord/MediaBase") const googleApis = require("../playlists/Google/OAuth2") const youtubeApi = require("../playlists/Google/YoutubeList") const configuration = require("../utils/Database/Configuration") const { List } = require('../player/List') const { restart } = require('../utils/Maintenance') const { isAudioFile } = require('../utils/AudioBufferCheck') const { Song } = require('../player/Song') const { getMediaInformationFromUrl } = require('../media/MediaInformation') const allConnectedUsers = new Array() const guildConnectedUsers = new Map() const UsersBySocket = new Map() //TODO: Refactor this file to implement the fact that server can be joined and leaved and all the events are now handled, so guildId is not required for every event function init() { wlog.step.init("server_init", "Initialisation du serveur Socket.IO") const httpServer = createServer() const io = new Server(httpServer, { cors: { origin: "*" }, }) process.on("PLAYERS_UPDATE", () => { if(io) { // Get all players and send them to client subscribed to the guild for(var guild of discordBot.getGuilds().keys()) { const player = players.getPlayer(guild) if(player) { if(!player.isConnected()) continue; io.to(player.guildId).emit("/PLAYER/UPDATE", player.getState()) wlog.log("Envoi de l'état du player de la guilde : " + player.guildId + " à tous les utilisateurs connectés") } } } }) process.on("USERS_UPDATE", () => { if(io) { // Get all players and send them to client subscribed to the guild for(var guild of discordBot.getGuilds().keys()) { if(guildConnectedUsers.has(guild)) { io.to(guild).emit("/USERS/UPDATE", {"id": guild, "members": guildConnectedUsers.get(guild)} ) io.to("ADMIN").emit("ALL_USERS_UPDATE", allConnectedUsers) wlog.log("Envoi de la liste des utilisateurs connectés (" + guildConnectedUsers.get(guild).length +") à la guilde : " + guild + " à tous les utilisateurs connectés") } } io.sockets.emit("/USER/READY") } }) io.on("connection", async (socket) => { var socketUser; // Make sure Discord Bot is loaded and make an interruption until it is loaded while(!await discordBot.isReady()) { wlog.warn("Attente de traitement : "+ socket.id + " : Le bot Discord n'est pas encore chargé, attente de 0.5 seconde... (Avoid Rate Limit)") await new Promise(resolve => setTimeout(resolve, 500)) } wlog.log(`Connexion d'un client : ${socket.id}`) socket.on("disconnect", () => { handleDisconnect() wlog.log("Déconnexion du client : " + socket.id) }) socket.on("error", (error) => { handleDisconnect() wlog.error("Erreur sur le socket : " + socket.id + " - " + error) }) if(socket.handshake.auth == undefined || socket.handshake.auth == {}) { wlog.warn("Authentification manquant pour le client :" + socket.id) sendSession() return } var token = socket.handshake.auth.token var sessionId = socket.handshake.auth.sessionId var auth_code = socket.handshake.auth.auth_code var inLogin = false if(sessionId) { if(!session.checkSession(sessionId)) { wlog.warn("Session invalide pour le client : " + socket.id) sendSession() return; } else { if(auth_code) { const discordUser = await discordAuth.getDiscordUser(sessionId, auth_code) session.removeSession(sessionId) if(discordUser == "USER_INFO_ERROR" || discordUser == "ACCESS_TOKEN_ERROR") { wlog.warn("Erreur lors de la récupération des informations de l'utilisateur Discord associé à la session : " + sessionId) socket.emit("AUTH_ERROR", discordUser) socket.disconnect() return } else { const loggedUser = await users.addUser(discordUser.auth, discordUser.identity) for(var guild of discordUser.guilds) { if(guild.owner) { users.setGuildOwner(loggedUser.identity.id, guild.id, true) } } const newToken = await loggedUser.createToken() socket.emit("NEW_TOKEN", newToken) token = newToken inLogin = true wlog.log("Utilisateur Discord associé à la session : " + sessionId + " récupéré avec succès") } } else { wlog.warn("Code d'authentification manquant pour le client :" + socket.id) socket.emit("AUTH_ERROR", "Code manquant invalide") socket.disconnect() return } } } if(!token) { wlog.warn("Token manquant pour le client :" + socket.id) socket.emit("AUTH_ERROR", "Token invalide") sendSession() return } socketUser = users.getUserByToken(token) if(!socketUser) { wlog.warn("Token invalide pour le client :" + socket.id) socket.emit("AUTH_ERROR", "Token invalide") sendSession() return } else { if(!socketUser.auth) { wlog.warn("L'utilisateur '" + socketUser.identity.username + "' n'a pas d'authentification Discord Valide") socketUser.clearToken() socket.emit("AUTH_ERROR", "L'authentification Discord de l'utilisateur n'est pas valide") socket.disconnect() return } if(!inLogin) { if(socketUser.needUpdate()) { if (!(await users.updateIdentity(socketUser.identity.id))) { wlog.error("Erreur lors de la mise à jour des informations de l'utilisateur : " + socketUser.identity.id); socket.emit("AUTH_ERROR", "Mise à jour des informations de l'utilisateur impossible"); wlog.log("Déconnexion de l'utilisateur : " + socketUser.identity.username + " (" + socketUser.identity.id + ") - Socket : " + socket.id) socket.disconnect(); return; } socketUser.justUpdated() } else { wlog.log("Pas de mise à jour des informations de l'utilisateur : " + socketUser.identity.id + " car l'utilisateur vient de se connecter") } } else { wlog.log("L'utilisateur '" + socketUser.identity.username + "' s'est connecté via la session : " + sessionId) } } socketUser = users.getUserByToken(token) if(socketUser) { var actualGuildId = null if(allConnectedUsers.includes(socketUser.identity)) { wlog.warn("L'utilisateur '" + socketUser.identity.username + "' est déjà connecté sur un autre appareil") return } else { allConnectedUsers.push(socketUser.identity) UsersBySocket.set(socketUser.identity.id, socket.id) } wlog.log("Utilisateur connecté : " + socketUser.identity.username + " (" + socketUser.identity.id + ") - Socket : " + socket.id) if(socketUser.isFullBanned()) { wlog.warn("Utilisateur banni : " + socketUser.identity.username + " (" + socketUser.identity.id + ") - Socket : " + socket.id) socket.emit("AUTH_ERROR", "Vous êtes banni du serveur") socket.disconnect() } if(socketUser.isAdmin()) { socket.join("ADMIN") wlog.log("Utilisateur admin identifié : " + socketUser.identity.username + " (" + socketUser.identity.id + ")") } process.emit("USERS_UPDATE") // USERS // CHECKED : 24/04/2025 IORequest("/USER/INFO", () => { var guildPresents = new Array(); var guildsOfBot = discordBot.getGuilds() for(var guild of guildsOfBot) { if(guild[1].allMembers.includes(socketUser.identity.id)) { const guildData = guild[1] guildData['members'] = new Array() guildData.serverMember = guild[1].allMembers.length for(var user of guildConnectedUsers.get(guild[0]) || []) { const userData = users.getUserById(user.id) if(userData && userData.identity.id != socketUser.identity.id) { let infos = { id: userData.identity.id, username: userData.identity.username, avatar: userData.identity.avatar, isAdmin: userData.isAdmin(), isOwner: userData.isOwner(guild[0]), isMod: userData.isMod(guild[0]), } guildData.members.push(infos) } } // Send if the bot is connected to the guild if(players.getPlayer(guild[0]) && players.getPlayer(guild[0]).isConnected()) { guildData.connected = true } else { guildData.connected = false } // Leave the room if the user is not in the guild if(socket.rooms.has(guild[0]) && !checkUserGuild(socketUser, guild[0])) { socket.leave(guild[0]) removeGuildConnectedUser(socketUser.identity) wlog.warn("L'utilisateur '" + socketUser.identity.username + "' quitte la room de la guilde : " + guild[0] + " car il n'est pas dans la guilde) /!\\") } guildPresents.push(guildData) } } IOAnswer("/USER/INFO", { identity: socketUser.identity, guilds: guildPresents, labels: socketUser.labels, history: history.getPersonalHistory(socketUser.identity.id), }) wlog.log("Envoi des informations Discord de '" + socketUser.identity.id + "' à '" + socket.id + "'" ) }) IORequest("/USER/HISTORY", () => { IOAnswer("/USER/HISTORY", history.getPersonalHistory(socketUser.identity.id)) }) //CHECKED : 24/04/2025 IORequest("/USER/SIGNOUT", () => { socketUser.removeToken(token) IOAnswer("/USER/SIGNOUT", true) socket.disconnect() }) // CHECKED : 24/04/2025 IORequest("/USERS/LIST", () => { if(!checkUserGuild(socketUser, actualGuildId)) return if(!guildConnectedUsers.has(actualGuildId)) return IOAnswer("/USERS/LIST", false) IOAnswer("/USERS/LIST", guildConnectedUsers.get(actualGuildId)) }) // PLAYERS IORequest("/PLAYER/LYRICS", async () => { if(!checkUserGuild(socketUser, actualGuildId)) return const player = await verifyPlayerAction(actualGuildId) if(!player) return IOAnswer("/PLAYER/LYRICS", false) if(!player.queue?.current) { wlog.warn("Le player de la guilde : " + actualGuildId + " n'a pas de musique en cours") IOAnswer("/PLAYER/LYRICS", false) return } const song = player.queue.current const lyricsData = await lyrics.getLyrics(song.title + " " + song.author) if(!lyricsData) { wlog.warn("Aucune lyrics trouvée pour la musique : " + song.title + " de l'artiste : " + song.author) IOAnswer("/PLAYER/LYRICS", false) return } IOAnswer("/PLAYER/LYRICS", lyricsData) }) //CHECKED : 03/05/2025 IORequest("/PLAYER/PREVIOUS/LIST", () => { if(!checkUserGuild(socketUser, actualGuildId)) return const list = new List(actualGuildId) IOAnswer("/PLAYER/PREVIOUS/LIST", list.getPrevious()) }) // ChECKED : 03/05/2025 IORequest("/GUILD/JOIN", async (guildId) => { if(!checkUserGuild(socketUser, guildId)) return IOAnswer("/GUILD/JOIN", "No guild found or not in the guild") if(socket.rooms.has(guildId)) { wlog.warn("L'utilisateur '" + socketUser.identity.username + "' est déjà dans la room de la guilde : " + guildId) } else { // Make him to leave all the other rooms except the ADMIN room if he is admin await socket.rooms.forEach((room) => { if(room != "ADMIN" && room != guildId && room != socket.id) { socket.leave(room) wlog.log("L'utilisateur '" + socketUser.identity.username + "' quitte la room de la guilde: " + room) removeGuildConnectedUser(socketUser.identity) } }) socket.join(guildId) wlog.log("L'utilisateur '" + socketUser.identity.username + "' rejoint la room de la guilde : " + guildId) addGuildConnectedUser(socketUser.identity, guildId) actualGuildId = guildId IOAnswer("/GUILD/JOIN", true) process.emit("PLAYERS_UPDATE") process.emit("USERS_UPDATE") } }) // CHECKED : 03/05/2025 IORequest("/PLAYER/STATE", async () => { const plaryer = await verifyPlayerAction(actualGuildId) if(!player) return IOAnswer("/PLAYER/STATE", false) IOAnswer("/PLAYER/STATE", await player.getState()) }) // CHECKED : 03/05/2025 IORequest("/PLAYER/PAUSE", () => { handlePlayerAction(actualGuildId, (player) => player.pause(), "/PLAYER/PAUSE"); }); // CHECKED : 03/05/2025 IORequest("/PLAYER/BACKWARD", () => { handlePlayerAction(actualGuildId, (player) => player.previous(), "/PLAYER/BACKWARD"); }); // CHECKED : 03/05/2025 IORequest("/PLAYER/FORWARD", () => { handlePlayerAction(actualGuildId, (player) => player.skip(), "/PLAYER/FORWARD"); }); // CHECKED : 03/05/2025 IORequest("/PLAYER/LOOP", () => { handlePlayerAction(actualGuildId, (player) => player.setLoop(), "/PLAYER/LOOP"); }); // CHECKED : 03/05/2025 IORequest("/PLAYER/SHUFFLE", () => { handlePlayerAction(actualGuildId, (player) => player.setShuffle(), "/PLAYER/SHUFFLE"); }); // CHECKED : 03/05/2025 IORequest("/PLAYER/DISCONNECT", () => { handlePlayerAction(actualGuildId, (player) => player.leave(), "/PLAYER/DISCONNECT"); }); // CHECKED : 03/05/2025 IORequest("/PLAYER/CHANNEL/CHANGE", () => { handlePlayerAction(actualGuildId, (player) => { const channel = getUserChannel() if(!channel) { IOAnswer("/PLAYER/CHANNEL/CHANGE", false) return } player.changeChannel(channel) }, "/PLAYER/CHANNEL/CHANGE"); }); // CHECKED : 03/05/2025 IORequest("/PLAYER/SEEK", (time) => { if(!time) return IOAnswer("/PLAYER/SEEK", false) handlePlayerAction(actualGuildId, (player) => { // Check if current is not null if(player.queue.current == null) { wlog.warn("Le player de la guilde : " + guildId + " n'a pas de musique en cours") IOAnswer("/PLAYER/SEEK", false) return } player.setDuration(time) }, "/PLAYER/SEEK"); }); // CHECKED : 04/05/2025 IORequest("/QUEUE/PLAY", (data) => { if(!data) return IOAnswer("/QUEUE/PLAY/NOW", false) const {index, listType, now} = data if(!index) return IOAnswer("/QUEUE/PLAY/NOW", false) if(!listType) return IOAnswer("/QUEUE/PLAY/NOW", false) if(!checkUserGuild(socketUser, actualGuildId)) return const player = new Player(actualGuildId) if(!connectToPlayer(actualGuildId, player)) return IOAnswer("/QUEUE/PLAY", false) var song; if(listType == "previous") { const previous = player.queue.getPrevious() song = previous[index] } else if(listType == "next") { const next = player.queue.getNext() song = next[index] } if(!song) return IOAnswer("/QUEUE/PLAY/NOW", false) if(listType == "next") player.queue.removeNextByIndex(index) if(now) { player.play(song) } else { player.add(song) } history.addToPersonalHistory(socketUser.identity.id, song) IOAnswer("/QUEUE/PLAY/NOW", true) }) // CHECKED : 04/05/2025 IORequest("/QUEUE/NEXT/DELETE", (index) => { if(!index) return IOAnswer("/QUEUE/NEXT/DELETE", false) handlePlayerAction(actualGuildId, (player) => { const next = player.queue.getNext() if(!next[index]) return IOAnswer("/QUEUE/NEXT/DELETE", false); player.queue.removeNextByIndex(index) }, "/QUEUE/NEXT/DELETE") }) // CHECKED : 04/05/2025 IORequest("/QUEUE/NEXT/DELETEALL", () => { handlePlayerAction(actualGuildId, (player) => player.queue.clearNext(), "/QUEUE/NEXT/DELETEALL") }) // CHECKED : 04/05/2025 IORequest("/QUEUE/NEXT/MOVE", (data) => { if(!data) return IOAnswer("/QUEUE/NEXT/MOVE", false) const {index, newIndex} = data if(!index) return IOAnswer("/QUEUE/NEXT/MOVE", false) if(!newIndex) return IOAnswer("/QUEUE/NEXT/MOVE", false) handlePlayerAction(actualGuildId, (player) => { const next = player.queue.getNext() if(!next[index]) return IOAnswer("/QUEUE/NEXT/MOVE", false); player.queue.moveNext(index, newIndex) }, "/QUEUE/NEXT/MOVE") }) // SEARCH // CHECKED : 24/04/2025 IORequest("/SEARCH", async (query) => { IOAnswer("/SEARCH", await Finder.search(query, true)) }) // CHECKED : 03/05/2025 IORequest("/SEARCH/PLAY", async (data) => { if(!data) return IOAnswer("/SEARCH/PLAY", false) var {song, now} = data if(!song) return IOAnswer("/SEARCH/PLAY", false) if(typeof song == "string") { song = JSON.parse(song) } if(!checkUserGuild(socketUser, actualGuildId)) return const player = new Player(actualGuildId) if(!connectToPlayer(actualGuildId, player)) return IOAnswer("/SEARCH/PLAY", false) if(now) { player.play(song) } else { player.add(song) } history.addToPersonalHistory(socketUser.identity.id, song) IOAnswer("/SEARCH/PLAY", true) }) // CHECKED : 05/05/2025 IORequest("/SEARCH/PLAYLIST", async (data) => { if(!data) return IOAnswer("/SEARCH/PLAYLIST", false) const {url, now} = data if(!url) return IOAnswer("/SEARCH/PLAYLIST", false) const playlist = await Finder.search(url, true, "PLAYLIST") if(!playlist) return IOAnswer("/SEARCH/PLAYLIST", false) const player = new Player(actualGuildId) if(!connectToPlayer(actualGuildId, player)) return IOAnswer("/SEARCH/PLAYLIST", false) player.readPlaylist(playlist, now) IOAnswer("/SEARCH/PLAYLIST", true) }) IORequest("/SEARCH/LYRICS", async (name) => { if(!name) return IOAnswer("/SEARCH/LYRICS", false) const lyricsData = await lyrics.getLyrics(name) if(!lyricsData) return IOAnswer("/SEARCH/LYRICS", false) IOAnswer("/SEARCH/LYRICS", lyricsData) }) // UPLOAD // CHECKED : 29/05/2025 IORequest("/UPLOAD/FILE", async (data) => { if(!data) return IOAnswer("/UPLOAD/FILE", false) if(!data.name) return IOAnswer("/UPLOAD/FILE", false) const file = data.file // Check wav or mp3 if(isAudioFile(file) == false) { wlog.warn("Le fichier envoyé n'est pas un fichier audio valide (MP3/WAV)") return IOAnswer("/UPLOAD/FILE", false) } const url = await mediaBase.postMedia(data) if(!url) return IOAnswer("/UPLOAD/FILE", false) IOAnswer("/UPLOAD/FILE", {"url": url, "name": data.name}) }) // CHECKED : 29/05/2025 IORequest("/UPLOAD/FILE/GET_SONG", async (data) => { if(!data) return IOAnswer("/UPLOAD/FILE/GET_SONG", false) const {name, url} = data if(!url) return IOAnswer("/UPLOAD/FILE/GET_SONG", false) if(!name) return IOAnswer("/UPLOAD/FILE/GET_SONG", false) const song = new Song() if(!song) return IOAnswer("/UPLOAD/FILE/GET_SONG", false) await getMediaInformationFromUrl(song, url) song.type = "attachment" song.author = socketUser.identity.username song.authorId = socketUser.identity.id song.title = name song.url = url IOAnswer("/UPLOAD/FILE/GET_SONG", song) }) // GOOGLE API IORequest("/GOOGLE/AUTH", () => { IOAnswer("/GOOGLE/AUTH", googleApis.createAuthUrl(socketUser.identity.id)) }) IORequest("/GOOGLE/YOUTUBE/ADD_PLAYLIST", async (code) => { if(!code) { IOAnswer("/GOOGLE/YOUTUBE/ADD_PLAYLIST", false) } const token = await googleApis.getAuthorization(socketUser.identity.id, code) if(!token) { IOAnswer("/GOOGLE/YOUTUBE/ADD_PLAYLIST", false) return } playlists.processYoutubeData(socketUser.identity.id, await youtubeApi.getYoutubePlaylists(socketUser.identity.id)) IOAnswer("/GOOGLE/YOUTUBE/ADD_PLAYLIST", true) }) // PLAYLISTS // CHECKED : 30/04/2025 IORequest("/PLAYLISTS/CREATE", async (data) => { if(!data) return IOAnswer("/PLAYLISTS/CREATE", false) const {name, url} = data if(!name) return IOAnswer("/PLAYLISTS/CREATE", false) const playlist = await playlists.addPlaylist(socketUser.identity.id, name, url) if(!playlist) return IOAnswer("/PLAYLISTS/CREATE", false) IOAnswer("/PLAYLISTS/CREATE", true) }) // CHECKED : 30/04/2025 IORequest("/PLAYLISTS/DELETE", (data) => { if(!data) return IOAnswer("/PLAYLISTS/DELETE", false) const {name} = data if(!name) return IOAnswer("/PLAYLISTS/DELETE", false) playlists.removePlaylist(socketUser.identity.id, name) IOAnswer("/PLAYLISTS/DELETE", true) }) // CHECKED : 24/04/2025 IORequest("/PLAYLISTS/LIST", () => { const playlist = playlists.getPlaylistsOfUser(socketUser.identity.id) IOAnswer("/PLAYLISTS/LIST", playlist) }) // CHECKED : 30/04/2025 IORequest("/PLAYLISTS/SEND", (data) => { if(!data) return IOAnswer("/PLAYLISTS/SEND", false) const {name, toId} = data if(!name || !toId) return IOAnswer("/PLAYLISTS/SEND", false) // Check if toId is in the same guilds as the user // Check if the toId exists and have a playlist with the same name const toUser = users.getUserById(toId) if(!toUser) return IOAnswer("/PLAYLISTS/SEND", false) const toPlaylists = playlists.getPlaylistsOfUser(toUser.identity.id) const fromPlaylist = playlists.getPlaylistOfUser(socketUser.identity.id, name) if(!fromPlaylist) return IOAnswer("/PLAYLISTS/SEND", false) if(toPlaylists.find(p => p.name == name)) return IOAnswer("/PLAYLISTS/SEND", false) playlists.copyPlaylist(socketUser.identity.id, toUser.identity.id, name) IOAnswer("/PLAYLISTS/SEND", true) }) // CHECKED : 30/04/2025 IORequest("/PLAYLISTS/RENAME", (data) => { if(!data) return IOAnswer("/PLAYLISTS/RENAME", false) const {name, newName} = data if(!name || !newName) return IOAnswer("/PLAYLISTS/RENAME", false) const playlist = playlists.getPlaylistOfUser(socketUser.identity.id, name) if(!playlist) return IOAnswer("/PLAYLISTS/RENAME", false) playlists.renamePlaylist(socketUser.identity.id, name, newName) IOAnswer("/PLAYLISTS/RENAME", true) }) // CHECKED : 30/04/2025 IORequest("/PLAYLISTS/ADD_SONG", (data) => { if(!data) return IOAnswer("/PLAYLISTS/ADD_SONG", false) const {name, song} = data if(!name || !song) return IOAnswer("/PLAYLISTS/ADD_SONG", false) const playlist = playlists.getPlaylistOfUser(socketUser.identity.id, name) if(!playlist) return IOAnswer("/PLAYLISTS/ADD_SONG", false) playlists.addSong(socketUser.identity.id, name, song) IOAnswer("/PLAYLISTS/ADD_SONG", true) }) // CHECKED : 30/04/2025 IORequest("/PLAYLISTS/REMOVE_SONG", (data) => { if(!data) return IOAnswer("/PLAYLISTS/REMOVE_SONG", false) const {name, songId} = data if(!name || !songId) return IOAnswer("/PLAYLISTS/REMOVE_SONG", false) const playlist = playlists.getPlaylistOfUser(socketUser.identity.id, name) if(!playlist) return IOAnswer("/PLAYLISTS/REMOVE_SONG", false) playlists.removeSong(socketUser.identity.id, name, songId) IOAnswer("/PLAYLISTS/REMOVE_SONG", true) }) // CHECKED : 05/05/2025 IORequest("/PLAYLISTS/PLAY", async (data) => { if(!data) return IOAnswer("/PLAYLISTS/PLAY", false) const {name, now} = data if(!name) return IOAnswer("/PLAYLISTS/PLAY", false) if(!checkUserGuild(socketUser, actualGuildId)) return IOAnswer("/PLAYLISTS/PLAY", false) const playlist = playlists.getPlaylistOfUser(socketUser.identity.id, name) if(!playlist) return IOAnswer("/PLAYLISTS/PLAY", false) const player = new Player(actualGuildId) if(!await connectToPlayer(actualGuildId, player)) return IOAnswer("/PLAYLISTS/PLAY", false) player.readPlaylist(playlist, now) IOAnswer("/PLAYLISTS/PLAY", true) }) // ADMIN if(socketUser.isAdmin()) { // CHECKED : 24/04/2025 IORequest("/ADMIN/LOGS", () => { if(!socketUser.isAdmin()) return IOAnswer("/ADMIN/LOGS", false) const logs_data = new Array() const logs_folder = fs.readdirSync(__glob.LOGS) for(var log of logs_folder) { logs_data.push({"name":log, "value": fs.readFileSync(__glob.LOGS + path.sep + log).toString()}) } IOAnswer("/ADMIN/LOGS", logs_data) }) // CHECKED : 24/04/2025 IORequest("/ADMIN/MAINTENANCE/RESTART", (reason) => { if(!socketUser.isAdmin()) return IOAnswer("/ADMIN/MAINTENANCE/RESTART", false) if(!reason) return IOAnswer("/ADMIN/MAINTENANCE/RESTART", false) restart(reason) }) // CHECKED : 24/04/2025 IORequest("/ADMIN/USERS/SWITCH_ADMIN", (userId) => { if(!socketUser.isAdmin()) return IOAnswer("/ADMIN/USERS/SWITCH_ADMIN", false) if(socketUser.identity.id == userId) return IOAnswer("/ADMIN/USERS/SWITCH_ADMIN", false) if(!users.getUserById(userId)) return IOAnswer("/ADMIN/USERS/SWITCH_ADMIN", false) users.setAdmin(userId) IOAnswer("/ADMIN/USERS/SWITCH_ADMIN", true) }) // CHECKED : 24/04/2025 IORequest("/ADMIN/USERS/FULL_BAN", (userId) => { if(!socketUser.isAdmin()) return IOAnswer("/ADMIN/USERS/FULL_BAN", false) if(socketUser.identity.id == userId) return IOAnswer("/ADMIN/USERS/FULL_BAN", false) if(!users.getUserById(userId)) return IOAnswer("/ADMIN/USERS/FULL_BAN", false) if(users.getUserById(userId).isAdmin()) return IOAnswer("/ADMIN/USERS/FULL_BAN", false) users.setFullBan(userId) IOAnswer("/ADMIN/USERS/FULL_BAN", true) }) // CHECKED : 24/04/2025 IORequest("/ADMIN/USERS/DELETE", (userId) => { if(!socketUser.isAdmin()) return IOAnswer("/ADMIN/USERS/DELETE", false) if(socketUser.identity.id == userId) return IOAnswer("/ADMIN/USERS/DELETE", false) if(!users.getUserById(userId)) return IOAnswer("/ADMIN/USERS/DELETE", false) if(users.getUserById(userId).isAdmin()) return IOAnswer("/ADMIN/USERS/DELETE", false) users.removeUser(userId) const userSocket = UsersBySocket.get(userId) if(userSocket) { const socket = io.sockets.sockets.get(userSocket) if(socket) { socket.emit("AUTH_ERROR", "Votre compte a été supprimé") socket.disconnect() } } IOAnswer("/ADMIN/USERS/DELETE", true) }) // CHECKED : 24/04/2025 IORequest("/ADMIN/PLAYER/GETALLSTATE", async () => { if(!socketUser.isAdmin()) return IOAnswer("/ADMIN/PLAYER/GETTALLSTATE", false) const allPlayers = players.getAllPlayers() const states = new Array() for(var player in allPlayers) { await states.push(await player.getState()) } IOAnswer("/ADMIN/PLAYER/GETALLSTATE", states) }) } // CHECKED : 24/04/2025 IORequest("/OWNER/USERS/SWITCH_MOD", (userId) => { if(userId || actualGuildId) return IOAnswer("/OWNER/USERS/SWITCH_MOD", false) if(socketUser.identity.id == userId) return IOAnswer("/OWNER/USERS/SWITCH_MOD", false) if(!socketUser.isOwner(actualGuildId)) return IOAnswer("/OWNER/USERS/SWITCH_MOD", false) users.setGuildMod(userId, actualGuildId) IOAnswer("/OWNER/USERS/SWITCH_MOD", true) }) // CHECKED : 24/04/2025 IORequest("/MOD/USERS/BAN", (userId) => { if(userId || actualGuildId) return IOAnswer("/MOD/USERS/BAN", false) if(socketUser.identity.id == userId) return IOAnswer("/MOD/USERS/BAN", false) if(!socketUser.isMod(actualGuildId)) return IOAnswer("/MOD/USERS/BAN", false) users.setGuildBan(userId, actualGuildId) IOAnswer("/MOD/USERS/BAN", true) }) // UTILS // CHECKED : 24/04/2025 IORequest("/REPORT", (data) => { if(data.length < 2) return IOAnswer("/REPORT", false) if(!data["level"] || !data["desc"]) return IOAnswer("/REPORT", false) const report = new Report(socketUser.identity.username, data["level"], data["desc"]).send() IOAnswer("/REPORT", true) }) // Functions function getUserChannel() { const membersVoices = discordBot.getMembersVoices() const member = membersVoices.get(socketUser.identity.id) if(member) { const channelId = member.channelId const guildId = member.guildId const channel = discordBot.getChannel(guildId, channelId) if(!channel) { wlog.warn("Le channel vocal n'existe pas : " + channelId) return null } return channel } else { wlog.warn("L'utilisateur '" + socketUser.identity.username + "' n'est pas dans un channel vocal") return null } } /** * @param {Player} player */ function connectToPlayer(guildId, player) { if(!checkUserGuild(socketUser, guildId)) return false if(player.isConnected()) true const channel = getUserChannel() if(!channel) return false player.join(channel) return true } async function verifyPlayerAction(guildId) { if (!checkUserGuild(socketUser, guildId)) return null; const player = players.getPlayer(guildId); if (player) { return player; } else { wlog.warn(`Le player de la guilde : ${guildId} n'existe pas`); return null; } } function checkUserGuild(socketUser, guildId) { if(!guildId) { wlog.warn("Aucun guildId n'est actif pour l'utilisateur : " + socketUser.identity.username) return false } // Check if the guildId is referenced in the bot guilds if(!discordBot.getGuilds().has(guildId)) { wlog.warn("La guilde : " + guildId + " n'est pas référencée dans le bot") return false } if(socketUser.isBanned(guildId)) { wlog.warn("L'utilisateur '" + socketUser.identity.username + "' est banni de la guilde : " + guildId) return false } const allGuilds = discordBot.getGuilds() if(!allGuilds.get(guildId).allMembers.includes(socketUser.identity.id)) { wlog.warn("L'utilisateur '" + socketUser.identity.username + "' n'est pas membre de la guilde : " + guildId) // Si user admin, override if(!socketUser.isAdmin()) { return false } wlog.log("L'utilisateur '" + socketUser.identity.username + "' est admin donc à le droit d'accéder à la guilde : " + guildId) } return true } /** * @param {function(Player)} action - The action to perform on the player. */ async function handlePlayerAction(guildId, action, actionName) { if (!checkUserGuild(socketUser, guildId)) return; const player = players.getPlayer(guildId); if (player) { await action(player); wlog.log(`L'utilisateur '${socketUser.identity.username}' effectue l'action '${actionName}' sur le player de la guilde : ${guildId}`); IOAnswer(actionName, true); } else { wlog.warn(`Le player de la guilde : ${guildId} n'existe pas`); IOAnswer(actionName, false); } } } function handleDisconnect() { if(socketUser) { wlog.log("Déconnexion de l'utilisateur : " + socketUser.identity.username + " (" + socketUser.identity.id + ") - Socket : " + socket.id) allConnectedUsers.splice(allConnectedUsers.indexOf(socketUser.identity), 1) removeGuildConnectedUser(socketUser.identity) process.emit("USERS_UPDATE") // Remove every rooms include admin socket.rooms.forEach((room) => { socket.leave(room) }) UsersBySocket.delete(socketUser.identity.id) } } function sendSession() { const newSession = session.addSession(socket.id) socket.emit("NEW_SESSION", newSession) wlog.log("Envoi d'une nouvelle session : '" + newSession + "' au client : " + socket.id) socket.disconnect() } function IORequest(RequestName, RequestCallback) { socket.on(RequestName, (value) => { wlog.log(socketUser.identity.username + " - Socket : " + socket.id + " - " + RequestName + " - [RECIEVED]") RequestCallback(value) }) } function IOAnswer(AnswerName, AnswerValue) { wlog.log(socketUser.identity.username + " - Socket : " + socket.id + " - " + AnswerName + " - [ANSWERED]") socket.emit(AnswerName, AnswerValue) } }) httpServer.listen(configuration.getPort(), () => { wlog.log(`Le serveur écoute sur le port ${configuration.getPort()}`) wlog.step.end("server_init") }) function addGuildConnectedUser(user, guildId) { // Check if the user is already connected to the guild if(!guildConnectedUsers.has(guildId)) { guildConnectedUsers.set(guildId, new Array()) } const users = guildConnectedUsers.get(guildId) if(users.includes(user)) { wlog.warn("L'utilisateur '" + user.username + "' est déjà connecté à la guilde : " + guildId) return } guildConnectedUsers.get(guildId).push(user) } function removeGuildConnectedUser(user) { for(var guild of guildConnectedUsers.keys()) { const users = guildConnectedUsers.get(guild) if(users.includes(user)) { users.splice(users.indexOf(user), 1) if(users.length == 0) { guildConnectedUsers.delete(guild) } } } } } module.exports = {init}