channelManager now tracks all active connectedUser objects for a given user.
This commit is contained in:
parent
261dce7b29
commit
6222535c47
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1,6 +1,9 @@
|
|||
node_modules/
|
||||
log/crash/*
|
||||
!log/crash
|
||||
www/doc/*/*
|
||||
!www/doc/client
|
||||
!www/doc/server
|
||||
package-lock.json
|
||||
config.json
|
||||
config.json.old
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ Canopy - 0.3-INDEV - Hotfix 1
|
|||
|
||||
Canopy - /ˈkæ.nə.pi/:
|
||||
- The upper layer of foliage and branches of a forest, containing the majority of animal life.
|
||||
- An honest attempt at an freedom/privacy respecting, libre, and open-source refrence implementation of what a stoner streaming service can be.
|
||||
|
||||
Canopy is a community chat & synced video embedding web application, intended to replace fore.st as the server software for ourfore.st.
|
||||
This new codebase intends to solve the following issues with the current CyTube based software:
|
||||
|
|
@ -22,10 +23,11 @@ The Canopy codebase does not, nor will it ever contain:
|
|||
- Cryptocurrency/Blockchain integration
|
||||
- 'Analytics/Telemtry' spyware
|
||||
- The use of video sources which require proprietary 'Digital ~~Rights Management~~ Ristricitons Malware' such as Widevine.
|
||||
- The use of large language models, stable diffusion, or generative AI in either development or function.
|
||||
|
||||
Thirdparty media providers may or may not contain all of the above atrocities :P (though browser-side DRM extensions will never be required), always use an ad-blocker!
|
||||
|
||||
Our current goal is to create a cleaner, more modern, purpose-built codebase that has feature-parity with the current version of fore.st, while writing improvements where possible. Once this is accomplished, and ourfore.st has been migrated, work will continue to re-create features from TTN, while also building completely new ones as well.
|
||||
Our current goal is to create a cleaner, more modern, purpose-built back-end that has feature-parity with the current version of fore.st, writing improvements where possible. Paired with this functionality, are a mix of engineering and artistic choices which attempt to re-create the power-user friendly UX of desktop sites from the early 2010's, with the 'aged like wine' looks that late oughts/early web 2.0 designs graced us with. Making sure that pageloads are low, and GPU use is non-existant along the way, to ensure everything is usable, even on low-end machines.
|
||||
|
||||
## License
|
||||
Canopy is written by the community, and provided under the GNU Affero General Public License v3 in order to prevent Canopy from being used in proprietary software or shitcoin scams.
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "canopy-of",
|
||||
"version": "0.3",
|
||||
"name": "canopy-of-indev",
|
||||
"version": "0.4",
|
||||
"license": "AGPL-3.0-only",
|
||||
"dependencies": {
|
||||
"altcha": "^1.0.7",
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ class activeChannel{
|
|||
* @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access
|
||||
* @param {Mongoose.Document} chanDB - Channnel Document Passthrough to save on DB Access
|
||||
* @param {Socket} socket - Requesting Socket
|
||||
* @returns {activeUser} active user object generated by the new connection
|
||||
*/
|
||||
async handleConnection(userDB, chanDB, socket){
|
||||
//get current user object from the userlist
|
||||
|
|
@ -104,10 +105,13 @@ class activeChannel{
|
|||
this.playlistHandler.defineListeners(socket);
|
||||
|
||||
//Hand off the connection initiation to it's user object
|
||||
await userObj.handleConnection(userDB, chanDB, socket)
|
||||
const activeUser = await userObj.handleConnection(userDB, chanDB, socket)
|
||||
|
||||
//Send out the userlist
|
||||
this.broadcastUserList(socket.chan);
|
||||
|
||||
//Return active user connection object for use by the channelManager object
|
||||
return activeUser;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -115,11 +119,11 @@ class activeChannel{
|
|||
* @param {Socket} socket - Requesting Socket
|
||||
*/
|
||||
handleDisconnect(socket){
|
||||
//If we have more than one active connection
|
||||
if(this.userList.get(socket.user.user).sockets.length > 1){
|
||||
//temporarily store userObj
|
||||
var userObj = this.userList.get(socket.user.user);
|
||||
let userObj = this.userList.get(socket.user.user);
|
||||
|
||||
//If we have more than one active connection
|
||||
if(userObj.sockets.length > 1){
|
||||
//Filter out disconnecting socket from socket list, and set as current socket list for user
|
||||
userObj.sockets = userObj.sockets.filter((id) => {
|
||||
return id != socket.id;
|
||||
|
|
@ -127,7 +131,11 @@ class activeChannel{
|
|||
|
||||
//Update the userlist
|
||||
this.userList.set(socket.user.user, userObj);
|
||||
//If this is the last one
|
||||
}else{
|
||||
//Tell the server to handle the disconnection of this user object
|
||||
this.server.handleUserDisconnect(userObj);
|
||||
|
||||
//If this is the last connection for this user, remove them from the userlist
|
||||
this.userList.delete(socket.user.user);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ const chatHandler = require('./chatHandler');
|
|||
class channelManager{
|
||||
/**
|
||||
* Instantiates object containing global server-side channel conection management logic
|
||||
* @param {Server} io - Socket.io server instanced passed down from server.js
|
||||
* @param {Socket.io} io - Socket.io server instanced passed down from server.js
|
||||
*/
|
||||
constructor(io){
|
||||
/**
|
||||
|
|
@ -46,6 +46,11 @@ class channelManager{
|
|||
*/
|
||||
this.activeChannels = new Map;
|
||||
|
||||
/**
|
||||
* Map containing all active users. This may be redundant, however it improves preformance for user-specific inter-channel functionality
|
||||
*/
|
||||
this.activeUsers = new Map;
|
||||
|
||||
/**
|
||||
* Global Chat Handler Object
|
||||
*/
|
||||
|
|
@ -88,13 +93,48 @@ class channelManager{
|
|||
return;
|
||||
}
|
||||
|
||||
//Connection accepted past this point
|
||||
|
||||
//Define listeners for inter-channel classes
|
||||
this.defineListeners(socket);
|
||||
this.chatHandler.defineListeners(socket);
|
||||
|
||||
//Hand off the connection to it's given active channel object
|
||||
//Lil' hacky to pass chanDB like that, but why double up on DB calls?
|
||||
activeChan.handleConnection(userDB, chanDB, socket);
|
||||
const activeUser = await activeChan.handleConnection(userDB, chanDB, socket);
|
||||
|
||||
//Pull status from server-wide activeUsers map
|
||||
let status = this.activeUsers.get(activeUser.user);
|
||||
|
||||
//If this user isn't connected anywhere else
|
||||
if(status == null){
|
||||
//initiate the entry
|
||||
this.activeUsers.set(activeUser.user, [activeUser]);
|
||||
//otherwise
|
||||
}else{
|
||||
//Push user to array by default
|
||||
let pushUser = true;
|
||||
|
||||
//For each active connection within the status map
|
||||
for(let curUser of status){
|
||||
//If we're already listing this active user (we're splitting a user connection amongst several sockets)
|
||||
if(curUser.channel.name == activeUser.channel.name){
|
||||
//don't need to push it again
|
||||
pushUser = false;
|
||||
}
|
||||
}
|
||||
|
||||
//if the user is flagged as un-added
|
||||
if(pushUser){
|
||||
//Add their connection object into the status array we pulled
|
||||
status.push(activeUser);
|
||||
|
||||
//Set status entry to updated array
|
||||
this.activeUsers.set(activeUser.set, status);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}else{
|
||||
//Toss out anon's
|
||||
socket.emit("kick", {type: "disconnected", reason: "You must log-in to join this channel!"});
|
||||
|
|
@ -217,6 +257,34 @@ class channelManager{
|
|||
activeChan.handleDisconnect(socket, reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a disconnection event for a single active user within a given channel (when all sockets disconnect)
|
||||
* @param {*} userObj
|
||||
*/
|
||||
handleUserDisconnect(userObj){
|
||||
//Create array to hold
|
||||
let stillConnected = [];
|
||||
|
||||
//Crawl through all known user connections
|
||||
this.crawlConnections(userObj.user, (curUser)=>{
|
||||
//If we have a matching username from a different channel
|
||||
if(curUser.user == userObj.user && userObj.channel.name != curUser.channel.name){
|
||||
//Keep current user
|
||||
stillConnected.push(curUser);
|
||||
}
|
||||
});
|
||||
|
||||
//If we have anyone left
|
||||
if(stillConnected.length > 0){
|
||||
//save the remainder to the status map, otherwise unset the value.
|
||||
this.activeUsers.set(userObj.user, stillConnected);
|
||||
//Otherwise
|
||||
}else{
|
||||
//Delete the user from the status map
|
||||
this.activeUsers.delete(userObj.user);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pulls user information by socket
|
||||
* @param {Socket} socket - Socket to check
|
||||
|
|
@ -257,30 +325,28 @@ class channelManager{
|
|||
* @param {Function} cb - Callback function to run active connections of a given user against
|
||||
*/
|
||||
crawlConnections(user, cb){
|
||||
//For each channel
|
||||
this.activeChannels.forEach((channel) => {
|
||||
//Check and see if the user is connected
|
||||
const foundUser = channel.userList.get(user);
|
||||
//Pull connection list from status map
|
||||
const list = this.activeUsers.get(user);
|
||||
|
||||
//If we found a user and this channel hasn't been added to the list
|
||||
if(foundUser){
|
||||
cb(foundUser);
|
||||
//If we have active connections
|
||||
if(list != null){
|
||||
//For each connection
|
||||
for(let user of list){
|
||||
//Run the callback against it
|
||||
cb(user);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates through connections by a given username, and runs them through a given callback function/method
|
||||
* This function is deprecated. Instead use channelManager.activeUsers.get(user)
|
||||
* @param {String} user - Username to crawl connections against
|
||||
* @param {Function} cb - Callback function to run active connections of a given user against
|
||||
*/
|
||||
getConnections(user){
|
||||
//Create a list to store our connections
|
||||
var connections = [];
|
||||
|
||||
//crawl through connections
|
||||
//this.crawlConnections(user,(foundUser)=>{connections.push(foundUser)});
|
||||
this.crawlConnections(user,(foundUser)=>{connections.push(foundUser)});
|
||||
const connections = this.activeUsers.get(user);
|
||||
|
||||
//return connects
|
||||
return connections;
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ class connectedUser{
|
|||
* @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access
|
||||
* @param {Mongoose.Document} chanDB - Channnel Document Passthrough to save on DB Access
|
||||
* @param {Socket} socket - Requesting Socket
|
||||
* @returns {activeUser} active user object generated by the new connection
|
||||
*/
|
||||
async handleConnection(userDB, chanDB, socket){
|
||||
//send metadata to client
|
||||
|
|
@ -115,6 +116,10 @@ class connectedUser{
|
|||
//Tattoo hashed IP address to user account for seven days
|
||||
await userDB.tattooIPRecord(socket.handshake.address);
|
||||
}
|
||||
|
||||
|
||||
//Return active user object for use by activeChannel and channelManager objects
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
52
src/app/channel/message.js
Normal file
52
src/app/channel/message.js
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024-2025 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/>.*/
|
||||
|
||||
/**
|
||||
* Class representing a single chat message
|
||||
*/
|
||||
class message{
|
||||
/**
|
||||
* Instantiates a chat message object
|
||||
* @param {connectedUser} sender - User who sent the message
|
||||
* @param {Array} recipients - Array of connected users who are supposed to receive the message
|
||||
* @param {String} msg - Contents of the message, with links replaced with numbered file-seperator markers
|
||||
* @param {Array} links - Array of URLs/Links included in the message.
|
||||
*/
|
||||
constructor(sender, recipients, msg, links){
|
||||
|
||||
/**
|
||||
* User who sent the message
|
||||
*/
|
||||
this.sender = sender;
|
||||
|
||||
/**
|
||||
* Array of strings containing usernames to send message to
|
||||
*/
|
||||
this.recipients = recipients;
|
||||
|
||||
/**
|
||||
* Contenst of the messages, with links replaced with numbered file-seperator markers
|
||||
*/
|
||||
this.msg = msg;
|
||||
|
||||
/**
|
||||
* Array of URLs/Links included in the message.
|
||||
*/
|
||||
this.links = links;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = message;
|
||||
Loading…
Reference in a new issue