/*Canopy - The next generation of stoner streaming software Copyright (C) 2024 Rainbownapkin and the TTN Community This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see .*/ //Local Imports const channelModel = require('../../schemas/channelSchema'); const flairModel = require('../../schemas/flairSchema'); const userModel = require('../../schemas/userSchema'); const loggerUtils = require('../../utils/loggerUtils'); const activeChannel = require('./activeChannel'); const chatHandler = require('./chatHandler'); module.exports = class{ constructor(io){ //Set the socket.io server this.io = io; //Load this.activeChannels = new Map; //Load server components this.chatHandler = new chatHandler(this); //Handle connections from socket.io io.on("connection", this.handleConnection.bind(this) ); } async handleConnection(socket){ //Prevent logged out connections and authenticate socket if(socket.request.session.user != null){ try{ //Authenticate socket const userDB = await this.authSocket(socket); //Get the active channel based on the socket var activeChan = await this.getActiveChan(socket); //Define listeners this.defineListeners(socket); this.chatHandler.defineListeners(socket); //Connect the socket to it's given channel activeChan.handleConnection(userDB, socket); }catch(err){ //Flip a table if something fucks up return loggerUtils.socketCriticalExceptionHandler(socket, err); } }else{ //Toss out anon's socket.disconnect("Unauthenticated"); return; } } async authSocket(socket){ //Find the user in the Database since the session won't store enough data to fulfill our needs :P const userDB = await userModel.findOne({user: socket.request.session.user.user}); if(userDB == null){ throw new Error("User not found!"); } //Set socket user and channel values socket.user = { id: userDB.id, user: userDB.user, }; return userDB; } async getActiveChan(socket){ socket.chan = socket.handshake.headers.referer.split('/c/')[1]; //Check if channel exists if(await channelModel.findOne({name: socket.chan}) == null){ throw new Error("Channel not found!") } //Check if current channel is active var activeChan = this.activeChannels.get(socket.chan); if(!activeChan){ //If not, make it so activeChan = new activeChannel(this, socket.chan); this.activeChannels.set(socket.chan, activeChan); } //Return whatever the active channel is (new or old) return activeChan; } defineListeners(socket){ //Socket Listeners socket.conn.on("close", (reason) => {this.handleDisconnect(socket, reason)}); } handleDisconnect(socket, reason){ var activeChan = this.activeChannels.get(socket.chan); activeChan.handleDisconnect(socket, reason); } getSocketInfo(socket){ const channel = this.activeChannels.get(socket.chan); return channel.userList.get(socket.user.user); } }