bigbluebutton-Github/labs/bbb-html5-client/routes/socketio.js
2012-09-07 15:02:21 -04:00

570 lines
22 KiB
JavaScript

/**
* Publish usernames to all the sockets
* @param {string} meetingID ID of the meeting
* @param {string} sessionID ID of the user
* @param {Function} callback callback to call when finished
* @return {undefined} publish to Redis PubSub
*/
exports.publishUsernames = function(meetingID, sessionID, callback) {
var usernames = [];
redisAction.getUsers(meetingID, function (users) {
for (var i = users.length - 1; i >= 0; i--){
usernames.push({ 'name' : users[i].username, 'id' : users[i].pubID });
};
var receivers = sessionID != undefined ? sessionID : meetingID;
pub.publish(receivers, JSON.stringify(['user list change', usernames]));
if(callback) callback(true);
});
store.scard(redisAction.getUsersString(meetingID), function(err, cardinality) {
if(cardinality == '0') {
redisAction.processMeeting(meetingID);
if(callback) callback(false);
}
});
};
/**
* Publish presenter to appropriate clients.
* @param {string} meetingID ID of the meeting
* @param {string} sessionID ID of the user
* @param {Function} callback callback to call when finished
* @return {undefined} publish to Redis PubSub
*/
exports.publishPresenter = function(meetingID, sessionID, callback) {
redisAction.getPresenterPublicID(meetingID, function(publicID) {
var receivers = sessionID != undefined ? sessionID : meetingID;
pub.publish(receivers, JSON.stringify(['setPresenter', publicID]));
if(callback) callback(true);
});
};
/**
* Get all messages from Redis and publish to a specific sessionID (user)
* @param {string} meetingID ID of the meeting
* @param {string} sessionID ID of the user
* @param {Function} callback callback to call when finished
* @return {undefined} publish to Redis PubSub
*/
exports.publishMessages = function(meetingID, sessionID, callback) {
var messages = [];
redisAction.getCurrentPresentationID(meetingID, function(presentationID) {
redisAction.getCurrentPageID(meetingID, presentationID, function(pageID) {
redisAction.getItems(meetingID, presentationID, pageID, 'messages', function (messages) {
var receivers = sessionID != undefined ? sessionID : meetingID;
pub.publish(receivers, JSON.stringify(['all_messages', messages]));
if(callback) callback();
});
});
});
};
/**
* Publish list of slides from Redis to the appropriate clients
* @param {string} meetingID ID of the meeting
* @param {string} sessionID ID of the user
* @param {Function} callback callback to call when finished
* @return {undefined} publish to Redis PubSub
*/
exports.publishSlides = function(meetingID, sessionID, callback) {
var slides = [];
redisAction.getCurrentPresentationID(meetingID, function(presentationID) {
redisAction.getPageIDs(meetingID, presentationID, function(presentationID, pageIDs) {
var numOfSlides = pageIDs.length;
var slideCount = 0;
for(var i = 0; i < numOfSlides; i++) {
redisAction.getPageImage(meetingID, presentationID, pageIDs[i], function(pageID, filename) {
redisAction.getImageSize(meetingID, presentationID, pageID, function(width, height) {
slides.push(['images/presentation' +presentationID+'/'+filename, width, height]);
if(slides.length == numOfSlides) {
var receivers = sessionID != undefined ? sessionID : meetingID;
pub.publish(receivers, JSON.stringify(['all_slides', slides]));
if(callback) callback();
}
});
});
}
});
});
};
/**
* Publish list of shapes from Redis to appropriate clients
* @param {string} meetingID ID of the meeting
* @param {string} sessionID ID of the user
* @param {Function} callback callback to call when finished
* @return {undefined} publish to Redis PubSub
*/
exports.publishShapes = function(meetingID, sessionID, callback) {
var shapes = [];
redisAction.getCurrentPresentationID(meetingID, function(presentationID) {
redisAction.getCurrentPageID(meetingID, presentationID, function(pageID) {
redisAction.getItems(meetingID, presentationID, pageID, 'currentshapes', function (shapes) {
var receivers = sessionID != undefined ? sessionID : meetingID;
pub.publish(receivers, JSON.stringify(['all_shapes', shapes]));
if(callback) callback();
});
});
});
};
/**
* Publish viewbox from Redis to appropriate clients
* @param {string} meetingID ID of the meeting
* @param {string} sessionID ID of the user
* @param {Function} callback callback to call when finished
* @return {undefined} publish to Redis PubSub
*/
exports.publishViewBox = function(meetingID, sessionID, callback) {
redisAction.getCurrentPresentationID(meetingID, function(presentationID) {
redisAction.getViewBox(meetingID, function(viewBox) {
viewBox = JSON.parse(viewBox);
var receivers = sessionID != undefined ? sessionID : meetingID;
pub.publish(receivers, JSON.stringify(['paper', viewBox[0], viewBox[1], viewBox[2], viewBox[3]]));
if(callback) callback();
});
});
};
/**
* Publish tool from Redis to appropriate clients
* @param {string} meetingID ID of the meeting
* @param {string} sessionID ID of the user
* @param {string} tool [description]
* @param {Function} callback callback to call when finished
* @return {undefined} publish to Redis PubSub
*/
exports.publishTool = function(meetingID, sessionID, tool, callback) {
redisAction.getCurrentTool(meetingID, function(tool) {
var receivers = sessionID != undefined ? sessionID : meetingID;
pub.publish(receivers, JSON.stringify(['toolChanged', tool]));
if(callback) callback();
});
};
/**
* All socket IO events that can be emitted by the client
* @param {[type]} socket [description]
*/
exports.SocketOnConnection = function(socket) {
//When a user sends a message...
socket.on('msg', function (msg) {
msg = sanitizer.escape(msg);
var handshake = socket.handshake;
var sessionID = handshake.sessionID;
var meetingID = handshake.meetingID;
redisAction.isValidSession(meetingID, sessionID, function (reply) {
if(reply) {
if(msg.length > max_chat_length) {
pub.publish(sessionID, JSON.stringify(['msg', 'System', 'Message too long.']));
}
else {
var username = handshake.username;
pub.publish(meetingID, JSON.stringify(['msg', username, msg]));
var messageID = rack(); //get a randomly generated id for the message
//try later taking these nulls out and see if the function still works
store.rpush(redisAction.getMessagesString(meetingID, null, null), messageID); //store the messageID in the list of messages
store.hmset(redisAction.getMessageString(meetingID, null, null, messageID), 'message', msg, 'username', username);
}
}
});
});
/**
* When a user connects to the socket...
* @return {undefined} publish to Redis PubSub
*/
socket.on('user connect', function () {
var handshake = socket.handshake;
var sessionID = handshake.sessionID;
var meetingID = handshake.meetingID;
redisAction.isValidSession(meetingID, sessionID, function (reply) {
if(reply) {
var username = handshake.username;
var socketID = socket.id;
socket.join(meetingID); //join the socket Room with value of the meetingID
socket.join(sessionID); //join the socket Room with value of the sessionID
//add socket to list of sockets.
redisAction.getUserProperties(meetingID, sessionID, function(properties) {
var numOfSockets = parseInt(properties.sockets, 10);
numOfSockets+=1;
store.hset(redisAction.getUserString(meetingID, sessionID), 'sockets', numOfSockets);
if ((properties.refreshing == 'false') && (properties.dupSess == 'false')) {
//all of the next sessions created with this sessionID are duplicates
store.hset(redisAction.getUserString(meetingID, sessionID), 'dupSess', true);
socketAction.publishUsernames(meetingID, null, function() {
socketAction.publishPresenter(meetingID);
});
}
else {
store.hset(redisAction.getUserString(meetingID, sessionID), 'refreshing', false);
socketAction.publishUsernames(meetingID, sessionID, function() {
socketAction.publishPresenter(meetingID, sessionID);
});
}
socketAction.publishMessages(meetingID, sessionID);
socketAction.publishSlides(meetingID, sessionID, function() {
socketAction.publishTool(meetingID, sessionID);
socketAction.publishShapes(meetingID, sessionID);
socketAction.publishViewBox(meetingID, sessionID);
});
});
}
});
});
/**
* When a user disconnects from the socket...
* @return {undefined} publish to Redis PubSub
*/
socket.on('disconnect', function () {
var handshake = socket.handshake;
var sessionID = handshake.sessionID;
var meetingID = handshake.meetingID;
//check if user is still in database
redisAction.isValidSession(meetingID, sessionID, function (isValid) {
if(isValid) {
var username = handshake.username;
var socketID = socket.id;
redisAction.updateUserProperties(meetingID, sessionID, ['refreshing', true], function(success) {
setTimeout(function () {
//in one second, check again...
redisAction.isValidSession(meetingID, sessionID, function (isValid) {
if(isValid) {
redisAction.getUserProperties(meetingID, sessionID, function(properties) {
var numOfSockets = parseInt(properties.sockets, 10);
numOfSockets-=1;
if(numOfSockets == 0) {
redisAction.deleteUser(meetingID, sessionID, function() {
socketAction.publishUsernames(meetingID);
});
}
else {
redisAction.updateUserProperties(meetingID, sessionID, ['sockets', numOfSockets]);
}
});
}
else {
socketAction.publishUsernames(meetingID);
socketAction.publishPresenter(meetingID, sessionID);
}
});
}, 1000);
});
}
});
});
/**
* When the user logs out
* @return {undefined} publish to Redis PubSub
*/
socket.on('logout', function() {
var handshake = socket.handshake;
var sessionID = handshake.sessionID;
var meetingID = handshake.meetingID;
redisAction.isValidSession(meetingID, sessionID, function (isValid) {
if(isValid) {
//initialize local variables
var username = handshake.username;
//remove the user from the list of users
store.srem(redisAction.getUsersString(meetingID), sessionID, function(numDeleted) {
//delete key from database
store.del(redisAction.getUserString(meetingID, sessionID), function(reply) {
pub.publish(sessionID, JSON.stringify(['logout'])); //send to all users on same session (all tabs)
socket.disconnect(); //disconnect own socket
});
});
}
socketAction.publishUsernames(meetingID);
});
});
/**
* A user clicks to change to previous slide
* @return {undefined} publish to Redis PubSub
*/
socket.on('prevslide', function () {
var handshake = socket.handshake;
var sessionID = handshake.sessionID;
var meetingID = handshake.meetingID;
redisAction.getPresenterSessionID(meetingID, function(presenterID) {
if(presenterID == sessionID) {
redisAction.getCurrentPresentationID(meetingID, function(presentationID) {
redisAction.changeToPrevPage(meetingID, presentationID, function(pageID){
redisAction.getPageImage(meetingID, presentationID, pageID, function(pageID, filename) {
pub.publish(meetingID, JSON.stringify(['changeslide', 'images/presentation' + presentationID + '/'+filename]));
pub.publish(meetingID, JSON.stringify(['clrPaper']));
socketAction.publishShapes(meetingID);
});
});
});
}
});
});
/**
* A user clicks to change to next slide
* @return {undefined} publish to Redis PubSub
*/
socket.on('nextslide', function () {
var handshake = socket.handshake;
var sessionID = handshake.sessionID;
var meetingID = handshake.meetingID;
redisAction.getPresenterSessionID(meetingID, function(presenterID) {
if(presenterID == sessionID) {
redisAction.getCurrentPresentationID(meetingID, function(presentationID) {
redisAction.changeToNextPage(meetingID, presentationID, function(pageID){
redisAction.getPageImage(meetingID, presentationID, pageID, function(pageID, filename) {
pub.publish(meetingID, JSON.stringify(['changeslide', 'images/presentation' + presentationID + '/'+filename]));
pub.publish(meetingID, JSON.stringify(['clrPaper']));
socketAction.publishShapes(meetingID);
});
});
});
}
});
});
/**
* When a rectangle creation event is received
* @param {string} shape type of shape
* @param {Object} data information needed to draw the shape
* @return {undefined} publish to Redis PubSub
*/
socket.on('makeShape', function (shape, data) {
var meetingID = socket.handshake.meetingID;
redisAction.getPresenterSessionID(meetingID, function(presenterID) {
if(presenterID == socket.handshake.sessionID) {
pub.publish(meetingID, JSON.stringify(['makeShape', shape, data]));
}
});
});
/**
* When a update shape event is received
* @param {string} shape type of shape
* @param {Object} data information needed to draw the shape
* @return {undefined} publish to Redis PubSub
*/
socket.on('updShape', function (shape, data) {
var meetingID = socket.handshake.meetingID;
redisAction.getPresenterSessionID(meetingID, function(presenterID) {
if(presenterID == socket.handshake.sessionID) {
pub.publish(meetingID, JSON.stringify(['updShape', shape, data]));
}
});
});
/**
* When a cursor move event is received
* @param {[type]} x x coord of cursor as a percentage of width
* @param {[type]} y y coord of cursor as a percentage of height
* @return {undefined} publish to Redis PubSub
*/
socket.on('mvCur', function (x, y) {
var meetingID = socket.handshake.meetingID;
redisAction.getPresenterSessionID(meetingID, function(presenterID) {
if(presenterID == socket.handshake.sessionID) {
pub.publish(meetingID, JSON.stringify(['mvCur', x, y]));
}
});
});
/**
* When a clear Paper event is received
* @return {undefined} publish to Redis PubSub
*/
socket.on('clrPaper', function () {
var meetingID = socket.handshake.meetingID;
var sessionID = socket.handshake.sessionID;
redisAction.getPresenterSessionID(meetingID, function(presenterID) {
if(presenterID == socket.handshake.sessionID) {
redisAction.getCurrentPresentationID(meetingID, function(presentationID) {
redisAction.getCurrentPageID(meetingID, presentationID, function(pageID) {
redisAction.getItemIDs(meetingID, presentationID, pageID, 'currentshapes', function(meetingID, presentationID, pageID, itemIDs, itemName) {
redisAction.deleteItemList(meetingID, presentationID, pageID, itemName, itemIDs);
});
pub.publish(meetingID, JSON.stringify(['clrPaper']));
socketAction.publishTool(meetingID, sessionID);
});
});
}
});
});
/**
* When the user wishes to set the presenter to another user
* @param {[type]} publicID public ID of user to make presenter
* @return {undefined} publish to Redis PubSub
*/
socket.on('setPresenter', function (publicID) {
console.log('setting presenter to' + publicID);
var meetingID = socket.handshake.meetingID;
redisAction.setPresenterFromPublicID(meetingID, publicID, function(success) {
if(success) {
pub.publish(meetingID, JSON.stringify(['setPresenter', publicID]));
}
});
});
/**
* When a user is updating the viewBox of the paper
* @param {number} cx x-offset from corner as a percentage of width
* @param {number} cy y-offset from corner as a percentage of height
* @param {number} sw width of page as a percentage of original width
* @param {number} sh height of page as a percentage of original height
* @return {undefined} publish to Redis PubSub
*/
socket.on('paper', function (cx, cy, sw, sh) {
var meetingID = socket.handshake.meetingID;
redisAction.getPresenterSessionID(meetingID, function(presenterID) {
if(presenterID == socket.handshake.sessionID) {
pub.publish(socket.handshake.meetingID, JSON.stringify(['paper', cx, cy, sw, sh]));
if(!sw && !sh) {
redisAction.getViewBox(socket.handshake.meetingID, function(viewbox) {
var viewbox = JSON.parse(viewbox);
redisAction.setViewBox(socket.handshake.meetingID, JSON.stringify([cx, cy, viewbox[2], viewbox[3]]));
});
}
else redisAction.setViewBox(socket.handshake.meetingID, JSON.stringify([cx, cy, sw, sh]));
}
});
});
/**
* When a user is zooming
* @param {number} delta amount the mouse scroll has moved
* @return {undefined} publish to Redis PubSub
*/
socket.on('zoom', function(delta) {
var meetingID = socket.handshake.meetingID;
redisAction.getPresenterSessionID(meetingID, function(presenterID) {
if(presenterID == socket.handshake.sessionID) {
pub.publish(meetingID, JSON.stringify(['zoom', delta]));
}
});
});
/**
* When a user finishes panning
* @return {undefined} publish to Redis PubSub
*/
socket.on('panStop', function() {
var meetingID = socket.handshake.meetingID;
redisAction.getPresenterSessionID(meetingID, function(presenterID) {
if(presenterID == socket.handshake.sessionID) {
pub.publish(meetingID, JSON.stringify(['panStop']));
}
});
});
/**
* Undoing the last shape
* @return {undefined} publish to Redis PubSub
*/
socket.on('undo', function() {
var meetingID = socket.handshake.meetingID;
redisAction.getPresenterSessionID(meetingID, function(presenterID) {
if(presenterID == socket.handshake.sessionID) {
redisAction.getCurrentPresentationID(meetingID, function(presentationID) {
redisAction.getCurrentPageID(meetingID, presentationID, function(pageID) {
//pop the last shape off the current list of shapes
store.rpop(redisAction.getCurrentShapesString(meetingID, presentationID, pageID), function(err, reply) {
socketAction.publishShapes(meetingID);
});
});
});
}
});
});
/**
* Telling everyone the current text has been finished
* @return {undefined} publish to Redis PubSub
*/
socket.on('textDone', function() {
var meetingID = socket.handshake.meetingID;
redisAction.getPresenterSessionID(meetingID, function(presenterID) {
if(presenterID == socket.handshake.sessionID) {
pub.publish(meetingID, JSON.stringify(['textDone']));
}
});
});
/**
* Saving a shape to Redis. Does not provide feedback to client(s)
* @param {string} shape type of shape
* @param {Object} data information needed to recreate shape
* @return {undefined} publish to Redis PubSub
*/
socket.on('saveShape', function (shape, data) {
var handshake = socket.handshake;
var meetingID = handshake.meetingID;
redisAction.getPresenterSessionID(meetingID, function(presenterID) {
if(presenterID == handshake.sessionID) {
redisAction.getCurrentPresentationID(meetingID, function(presentationID) {
redisAction.getCurrentPageID(meetingID, presentationID, function(pageID) {
var shapeID = rack(); //get a randomly generated id for the shape
store.rpush(redisAction.getCurrentShapesString(meetingID, presentationID, pageID), shapeID);
store.hmset(redisAction.getShapeString(meetingID, presentationID, pageID, shapeID),
'shape', shape, 'data', data, function(err, reply) {
});
});
});
}
});
});
/**
* Changing the currently set tool.
* Set the current tool in Redis, then publish
* the tool change to the members
* @param {string} tool name of the tool to change to
* @return {undefined} publish to Redis PubSub
*/
socket.on('changeTool', function (tool) {
var handshake = socket.handshake;
var meetingID = handshake.meetingID;
redisAction.getPresenterSessionID(meetingID, function(presenterID) {
if(presenterID == socket.handshake.sessionID) {
redisAction.setCurrentTool(meetingID, tool, function(success) {
if(success) {
pub.publish(meetingID, JSON.stringify(['toolChanged', tool]));
}
});
}
});
});
/**
* If a user requests all the shapes,
* publish the shapes to everyone.
* Only reason this happens is when its fit changes.
* @return {undefined} publish to Redis PubSub
*/
socket.on('all_shapes', function(){
var handshake = socket.handshake;
var meetingID = handshake.meetingID;
var sessionID = handshake.sessionID;
socketAction.publishShapes(meetingID);
});
/**
* Updating the fit of the image to the whiteboard
* @param {boolean} fit true for fit to page and false for fit to width
* @return {undefined} publish to Redis PubSub
*/
socket.on('fitToPage', function(fit) {
var handshake = socket.handshake;
var meetingID = handshake.meetingID;
redisAction.getPresenterSessionID(meetingID, function(presenterID) {
if(presenterID == sockt.handshake.sessionID) {
pub.publish(meetingID, JSON.stringify(['fitToPage', fit]));
}
});
});
};