260 lines
12 KiB
JavaScript
Executable File
260 lines
12 KiB
JavaScript
Executable File
/**
|
|
* This returns the folder where the presentation files will be
|
|
* stored for that particular presentationID.
|
|
* @param {string} presentationID the presentationID being looked up for a folder
|
|
* @return {string} the relative URL for where the images will be stored
|
|
*/
|
|
//exports.presentationImageFolder = function(presentationID) {
|
|
//return 'public/images/presentation' + presentationID;
|
|
//return 'public/images/presentations/'+presentationID;
|
|
//};
|
|
exports.presentationImageFolder = function(meetingID,presentationID) {
|
|
return '/var/bigbluebutton/' + meetingID + "/" + meetingID + "/" + presentationID + "/pngs";
|
|
};
|
|
|
|
/**
|
|
* When requesting the homepage a potential meetingID and sessionIDare extracted
|
|
* from the user's cookie. If they match with a user that is in the databaseunder
|
|
* the same data, they are instantly redirected to join into the meeting.
|
|
* If they are not, they will be redirected to the index page where they can enter
|
|
* their login details.
|
|
* @param {Object} req Request object from the client
|
|
* @param {Object} res Response object to the client
|
|
* @return {undefined} Response object is sent back to the client.
|
|
*/
|
|
exports.get_index = function(req, res) {
|
|
redisAction.isValidSession(req.cookies.meetingid, req.cookies.sessionid, function (reply) {
|
|
if(!reply) {
|
|
redisAction.getMeetings(function (meetings){
|
|
res.render('index', { title: 'BigBlueButton HTML5 Client', max_u: max_username_length, meetings: meetings });
|
|
});
|
|
}
|
|
else {
|
|
res.redirect('/chat');
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Given a meetingID, sessionID and username a meeting will be created
|
|
* and a user with the username will be joined.The callback returns either true or false depending on whether
|
|
* the meeting was created successfully or not.
|
|
* @param {string} meetingID the meeting ID of the meeting we are creating and/or connecting to
|
|
* @param {string} sessionID the session ID of the user that is connecting to the meeting
|
|
* @param {string} username username of the users that that is connecting to the meeting
|
|
* @param {Function} callback the callback function returns true if meeting successfully started and joined, false otherwise
|
|
* @return {undefined} callback is used to send the status back to the caller of this function
|
|
*/
|
|
function makeMeeting(meetingID, sessionID, username, callback) {
|
|
if((username) && (meetingID) && (username.length <= max_username_length) && (meetingID.split(' ').length == 1)) {
|
|
var publicID = (new Date()).getTime();
|
|
redisAction.isMeetingRunning(meetingID, function(isRunning) {
|
|
if(!isRunning) {
|
|
redisAction.createMeeting(meetingID, function() {
|
|
redisAction.setCurrentTool(meetingID, 'line');
|
|
redisAction.setPresenter(meetingID, sessionID, publicID);
|
|
});
|
|
}
|
|
});
|
|
redisAction.createUser(meetingID, sessionID);
|
|
store.get(redisAction.getCurrentPresentationString(meetingID), function (err, currPresID) {
|
|
if(!currPresID) {
|
|
redisAction.createPresentation(meetingID, true, function (presentationID) {
|
|
redisAction.createPage(meetingID, presentationID, 'default.png', true, function (pageID) {
|
|
redisAction.setViewBox(meetingID, JSON.stringify([0, 0, 1, 1]));
|
|
var folder = routes.presentationImageFolder(meetingID,presentationID);
|
|
fs.mkdir(folder, 0777 , function (reply) {
|
|
newFile = fs.createWriteStream(folder + '/default.png');
|
|
oldFile = fs.createReadStream('images/default.png');
|
|
newFile.once('open', function (fd) {
|
|
util.pump(oldFile, newFile);
|
|
redisAction.setImageSize(meetingID, presentationID, pageID, 800, 600);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}
|
|
});
|
|
redisAction.setIDs(meetingID, sessionID, publicID, function() {
|
|
redisAction.updateUserProperties(meetingID, sessionID, ["username", username,
|
|
"meetingID", meetingID, "refreshing", false, "dupSess", false, "sockets", 0, 'pubID', publicID]);
|
|
callback(true);
|
|
});
|
|
}
|
|
else callback(false);
|
|
}
|
|
|
|
/**
|
|
* Upon submitting their login details from the index page via a POST request,
|
|
* a meeting will be created and joined. If an error occurs, which usually
|
|
* results in using a username/meetingID that is too long, they will be redirected
|
|
* to the index page again.
|
|
* @param {Object} req Request object from the client
|
|
* @param {Object} res Response object to the client
|
|
* @return {undefined} Response object is sent back to the client.
|
|
*/
|
|
exports.post_index = function(req, res) {
|
|
var username = sanitizer.escape(req.body.user.name);
|
|
var meetingID = sanitizer.escape(req.body.meeting.id);
|
|
var sessionID = req.sessionID;
|
|
makeMeeting(meetingID, sessionID, username, function(join) {
|
|
if(join) {
|
|
res.cookie('sessionid', sessionID); //save the id so socketio can get the username
|
|
res.cookie('meetingid', meetingID);
|
|
res.redirect('/chat');
|
|
}
|
|
else res.redirect('/');
|
|
});
|
|
};
|
|
|
|
/**
|
|
* When a user logs out, their session is destroyed,
|
|
* and their cookies are cleared.
|
|
* @param {Object} req Request object from the client
|
|
* @param {Object} res Response object to the client
|
|
* @return {undefined} Response object is sent back to the client.
|
|
*/
|
|
exports.logout = function(req, res) {
|
|
req.session.destroy(); //end the session
|
|
res.cookie('sessionid', null); //clear the cookie from the client
|
|
res.cookie('meetingid', null);
|
|
};
|
|
|
|
/**
|
|
* The join URL is used to connect to a meeting immediately without
|
|
* going to the login screen.
|
|
* Example:
|
|
* localhost:3000/join?meetingid=123&fullname=Ryan&checksum=password
|
|
* This will connect under the meetingID 123 with the name "Ryan" as
|
|
* long as the checksum string is equal on the server side.
|
|
* @param {Object} req Request object from the client
|
|
* @param {Object} res Response object to the client
|
|
* @return {undefined} Response object is sent back to the client.
|
|
*/
|
|
exports.join = function(req, res) {
|
|
var query = req.query;
|
|
if(query) {
|
|
var meetingID = query.meetingid;
|
|
var username = query.fullname;
|
|
var checksum = query.checksum;
|
|
var sessionID = req.sessionID;
|
|
// checksum is checked here against a simple keyword for now
|
|
if(checksum == "password") {
|
|
//create meeting
|
|
makeMeeting(meetingID, sessionID, username, function(join) {
|
|
//if the meeting was created successfully
|
|
if(join) {
|
|
//store the cookies
|
|
res.cookie('sessionid', sessionID); //save the id so socketio can get the username
|
|
res.cookie('meetingid', meetingID);
|
|
res.redirect('/chat');
|
|
}
|
|
else res.redirect('/');
|
|
});
|
|
}
|
|
else res.redirect('/');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* When we return to the chat page (or open a new tab when already logged in)
|
|
* @param {Object} req Request object from the client
|
|
* @param {Object} res Response object to the client
|
|
* @return {undefined} Response object is sent back to the client.
|
|
*/
|
|
exports.get_chat = function(req, res) {
|
|
//requiresLogin before this verifies that a user is logged in...
|
|
var meetingID = req.cookies.meetingid;
|
|
redisAction.getUserProperty(meetingID, req.cookies.sessionid, "username", function (username) {
|
|
res.render('chat', { title: 'BigBlueButton HTML5 Client', user: username, max_chat_length: max_chat_length, meetingID : meetingID });
|
|
});
|
|
};
|
|
|
|
|
|
/**
|
|
* POSTing a file from the client page, the images will be
|
|
* converted and their URLs will be send via SocketIO if
|
|
* successful. If unsuccessful, a status of failed will be sent.
|
|
* @param {Object} req Request object from the client
|
|
* @param {Object} res Response object to the client
|
|
* @return {undefined} Response object is sent back to the client.
|
|
*/
|
|
exports.post_chat = function(req, res) {
|
|
// the client must send a file
|
|
if(req.files.image.size !== 0) {
|
|
var meetingID = req.cookies.meetingid;
|
|
var sessionID = req.cookies.sessionid;
|
|
pub.publish(meetingID, JSON.stringify(['uploadStatus', "Processing..."]));
|
|
redisAction.isValidSession(meetingID, sessionID, function (reply) {
|
|
var file = req.files.image.path;
|
|
var pageIDs = [];
|
|
redisAction.getCurrentPresentationID(meetingID, function(prevPresID) {
|
|
redisAction.getCurrentPageID(meetingID, prevPresID, function(prevPageID) {
|
|
redisAction.createPresentation(meetingID, false, function (presentationID) {
|
|
redisAction.setViewBox(meetingID, JSON.stringify([0, 0, 1, 1]));
|
|
var folder = routes.presentationImageFolder(meetingID,presentationID);
|
|
//make the directory the presentation files will go into.
|
|
fs.mkdir(folder, 0777 , function (reply) {
|
|
// ImageMagick call to convert file to PNG images named slide0.png, slide1.png, slide2.png, etc...
|
|
im.convert(['-quality', '50', '-density', '150x150', file, folder + '/slide%d.png'], function (err) {
|
|
if(!err) {
|
|
//counts how many files are in the folder for the presentation to get the slide count.
|
|
exec("ls -1 " + folder + "/ | wc -l", function (error, stdout, stdouterr) {
|
|
var numOfPages = parseInt(stdout, 10);
|
|
var numComplete = 0;
|
|
// interate through each of the files and create a page for each of them.
|
|
for(var i = 0; i < numOfPages; i++) {
|
|
var setCurrent = true;
|
|
if(i !== 0) setCurrent = false;
|
|
redisAction.createPage(meetingID, presentationID, "slide" + i + ".png", setCurrent, function (pageID, imageName) {
|
|
//ImageMagick call to get the image size from each of the converted images.
|
|
im.identify(folder + "/" + imageName, function(err, features) {
|
|
if (err) throw err;
|
|
else redisAction.setImageSize(meetingID, presentationID, pageID, features.width, features.height, function() {
|
|
pageIDs.push(pageID);
|
|
numComplete++;
|
|
if(numComplete == numOfPages) {
|
|
// Once complete, set the current presentation to the new one
|
|
// and publish the new slides to all members of the meeting.
|
|
redisAction.setCurrentPresentation(meetingID, presentationID, function() {
|
|
pub.publish(meetingID, JSON.stringify(['clrPaper']));
|
|
socketAction.publishSlides(meetingID, null, function() {
|
|
socketAction.publishViewBox(meetingID);
|
|
pub.publish(meetingID, JSON.stringify(['uploadStatus', "Upload succeeded", true]));
|
|
});
|
|
});
|
|
}
|
|
});
|
|
});
|
|
});
|
|
}
|
|
});
|
|
}
|
|
else {
|
|
console.log(err);
|
|
fs.rmdir(folder, function() {
|
|
console.log("Deleted invalid presentation folder");
|
|
pub.publish(meetingID, JSON.stringify(['uploadStatus', "Invalid file", true]));
|
|
});
|
|
}
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}
|
|
res.redirect('/chat');
|
|
};
|
|
|
|
/**
|
|
* Any other page that we have not defined yet.
|
|
* @param {Object} req Request object from the client
|
|
* @param {Object} res Response object to the client
|
|
* @return {undefined} Response object is sent back to the client.
|
|
*/
|
|
exports.error404 = function(req, res) {
|
|
console.log("User tried to access: " + req.url);
|
|
res.send("Page not found", 404);
|
|
};
|