canopy/src/app/channel/connectedUser.js

113 lines
4.1 KiB
JavaScript

/*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 <https://www.gnu.org/licenses/>.*/
//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();
}
}