/*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 flairModel = require('../../schemas/flairSchema'); const emoteModel = require('../../schemas/emoteSchema'); const permissionModel = require('../../schemas/permissionSchema'); module.exports = class{ constructor(userDB, chanRank, channel, socket){ this.id = userDB.id; this.user = userDB.user; this.rank = userDB.rank; this.highLevel = userDB.highLevel; this.flair = userDB.flair.name; this.chanRank = chanRank; this.channel = channel; this.sockets = [socket.id]; } socketCrawl(cb){ //Crawl through user's sockets (lol) this.sockets.forEach((sockid) => { //get socket based on ID const socket = this.channel.server.io.sockets.sockets.get(sockid); //Callback with socket cb(socket); }); } //My brain keeps going back to using dynamic per-user namespaces for this //but everytime i look into it I come to the conclusion that it's a bad idea, then I toy with making chans namespaces //and using per-user channels for this, but what of gold or mod-only features? or games? //No matter what it'd probably end up hacky, as namespaces where meant for splitting app logic not user comms (like rooms). //at the end of the day there has to be some penance for decent multi-session handling on-top of a library that doesn't do it. //Having to crawl through these sockets is that. Because the other ways seem more gross somehow. emit(eventName, args){ this.socketCrawl((socket)=>{socket.emit(eventName, args)}); } //generic disconnect function, defaults to kick disconnect(reason, type = "Disconnected"){ this.emit("kick",{type, reason}); this.socketCrawl((socket)=>{socket.disconnect()}); } async sendClientMetadata(){ //Get flairList from DB and setup flairList array const flairListDB = await flairModel.find({}); var flairList = []; //Setup our userObj const userObj = { id: this.id, user: this.user, rank: this.rank, chanRank: this.chanRank, highLevel: this.highLevel, flair: this.flair } //For each flair listed in the Database flairListDB.forEach((flair)=>{ //Check if the user has permission to use the current flair if(permissionModel.rankToNum(flair.rank) <= permissionModel.rankToNum(this.rank)){ //If so push a light version of the flair object into our final flair list flairList.push({ name: flair.name, displayName: flair.displayName }); } }); //Send off the metadata to our user's clients this.emit("clientMetadata", {user: userObj, flairList}); } async sendSiteEmotes(){ //Get emote list from DB const emoteList = await emoteModel.getEmotes(); //Send it off to the user this.emit('siteEmotes', emoteList); } updateFlair(flair){ this.flair = flair; this.channel.broadcastUserList(); this.sendClientMetadata(); } updateHighLevel(highLevel){ this.highLevel = highLevel; //TODO: show high-level in userlist this.channel.broadcastUserList(); this.sendClientMetadata(); } }