/*Canopy - The next generation of stoner streaming software Copyright (C) 2024-2026 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 includes const server = require('../server'); const {userModel} = require('../schemas/user/userSchema'); //User activity map to keep us from constantly reading off of the DB let activityMap = new Map(); //How much difference between last write and now until we hit the DB again (in millis) //Defaults to two minutes const tolerance = 2 * (60 * 1000); //How long a user has to be in-active to be considered offline //Defaults to five minutes const offlineTimeout = 5 * (60 * 1000); module.exports.getPresence = async function(user, userDB){ //If we don't have a user if(user == null || user == '' || user == 'Tokebot'){ //Drop that shit return; } //Set status as offline let status = "Offline" //Attempt to pull from activity map to save on DB pull let activity = activityMap.get(user); //Pull current epoch in millis const now = new Date().getTime(); //If we couldn't find anything in RAM if(activity == null){ //If we wheren't handed a free user doc if(userDB == null){ //Pull one from the username userDB = await userModel.findOne({user: user}); } //If for some reason we can't find a user doc if(userDB == null){ //Bail with empty status object return { status, activeConnections: [], lastActive: 0 } } //Pull last active date from userDB activity = userDB.lastActive.getTime(); } //Pull active connections for user from the channel manager const activeConnections = server.channelManager.getConnections(user); //If the user is connected to at least one channel if(activeConnections != null && activeConnections.length > 0){ status = "Streaming"; //Otherwise, if it's been five minutes }else if(now - activity < offlineTimeout){ status = "Recently Active"; } //Assemble and return status object return { status, activeConnections, lastActive: activity } } module.exports.presenceMiddleware = function(req, res, next){ //Pull user from session const user = req.session.user; //if we have a user object if(user != null){ //Handle Presence module.exports.handlePresence(user.user); } //Go on to next part of the middleware chain next(); } module.exports.handlePresence = async function(user, userDB, noSave = false){ //If we don't have a user if(user == null || user == ''){ //Drop that shit return; } //Get current date as epoch (millis) const now = new Date(); const millis = now.getTime(); //Check last user activity const activity = activityMap.get(user); //If we have no recorded activity, or if the the time between now and the last activity is greater than two minutes if(activity == null || millis - activity > tolerance){ //Set last user activity activityMap.set(user, millis); //If we wheren't handed a free user doc if(userDB == null){ //Pull one from the username userDB = await userModel.findOne({user: user}); } //Set last active in user's DB document userDB.lastActive = now; //If saving is enabled if(!noSave){ //Save document to await userDB.save(); } } }