memo/server.js

819 lines
19 KiB
JavaScript
Raw Normal View History

2016-09-13 09:06:15 +02:00
// vim:set noexpandtab:
2014-08-17 12:38:00 -04:00
/**************
SYSTEM INCLUDES
**************/
var http = require('http');
var sys = require('sys');
2011-03-10 08:20:27 -05:00
var async = require('async');
2014-08-17 12:38:00 -04:00
var sanitizer = require('sanitizer');
2014-10-12 17:17:15 -04:00
var compression = require('compression');
2014-08-17 12:38:00 -04:00
var express = require('express');
var conf = require('./config.js').server;
var ga = require('./config.js').googleanalytics;
2011-03-10 08:20:27 -05:00
2014-08-17 12:38:00 -04:00
/**************
LOCAL INCLUDES
**************/
2011-03-10 08:20:27 -05:00
var rooms = require('./lib/rooms.js');
var data = require('./lib/data.js').db;
2011-03-10 08:20:27 -05:00
2014-08-17 12:38:00 -04:00
/**************
GLOBALS
**************/
2011-03-10 08:20:27 -05:00
//Map of sids to user_names
var sids_to_user_names = [];
2014-08-17 12:38:00 -04:00
/**************
SETUP EXPRESS
2014-08-17 12:38:00 -04:00
**************/
var app = express();
var router = express.Router();
2014-08-17 12:38:00 -04:00
2014-10-12 17:17:15 -04:00
app.use(compression());
app.use(conf.baseurl, router);
app.locals.ga = ga.enabled;
app.locals.gaAccount = ga.account;
router.use(express.static(__dirname + '/client'));
2014-08-17 12:38:00 -04:00
var server = require('http').Server(app);
server.listen(conf.port);
console.log('Server running at http://127.0.0.1:' + conf.port + '/');
2014-08-17 12:38:00 -04:00
2014-09-30 08:22:53 -04:00
/**************
SETUP Socket.IO
**************/
var io = require('socket.io')(server, {
path: conf.baseurl == '/' ? '' : conf.baseurl + "/socket.io"
});
2014-09-30 08:22:53 -04:00
2014-08-17 12:38:00 -04:00
/**************
ROUTES
**************/
router.get('/', function(req, res) {
2013-12-08 09:19:17 -05:00
//console.log(req.header('host'));
url = req.header('host') + req.baseUrl;
2014-09-30 08:22:53 -04:00
var connected = io.sockets.connected;
clientsCount = Object.keys(connected).length;
2011-03-10 08:20:27 -05:00
res.render('home.jade', {
2014-09-30 08:22:53 -04:00
url: url,
connected: clientsCount
2011-03-10 08:20:27 -05:00
});
});
router.get('/demo', function(req, res) {
res.render('index.jade', {
pageTitle: 'Framemo - demo',
demo: true
});
});
router.get('/:id', function(req, res){
2011-03-10 08:20:27 -05:00
res.render('index.jade', {
pageTitle: ('Framemo - ' + req.params.id)
2011-03-10 08:20:27 -05:00
});
});
2014-08-17 12:38:00 -04:00
/**************
SOCKET.I0
**************/
2016-09-13 09:06:15 +02:00
//sanitizes text
function scrub( text ) {
if (typeof text != "undefined" && text !== null)
{
2014-09-30 08:02:58 -04:00
2016-09-13 09:06:15 +02:00
//clip the string if it is too long
if (text.length > 65535)
2014-08-17 12:38:00 -04:00
{
2016-09-13 09:06:15 +02:00
text = text.substr(0,65535);
2014-08-17 12:38:00 -04:00
}
2014-09-30 08:02:58 -04:00
2016-09-13 09:06:15 +02:00
return sanitizer.sanitize(text);
}
else
{
return null;
}
}
2014-09-30 08:02:58 -04:00
2016-09-13 09:06:15 +02:00
io.sockets.on('connection', function (client) {
2014-09-30 08:02:58 -04:00
client.on('message', function( message ){
2013-12-08 09:19:17 -05:00
//console.log(message.action + " -- " + sys.inspect(message.data) );
2014-10-12 13:37:45 -04:00
var clean_data = {};
var clean_message = {};
var message_out = {};
2011-03-10 08:20:27 -05:00
if (!message.action) return;
2011-03-10 08:20:27 -05:00
switch (message.action)
{
case 'initializeMe':
initClient(client);
break;
2011-03-10 08:20:27 -05:00
case 'joinRoom':
joinRoom(client, message.data, function(clients) {
client.json.send( { action: 'roomAccept', data: '' } );
2011-03-10 08:20:27 -05:00
});
2011-03-10 08:20:27 -05:00
break;
2011-03-10 08:20:27 -05:00
case 'moveCard':
//report to all other browsers
2014-10-12 13:37:45 -04:00
message_out = {
2011-03-10 08:20:27 -05:00
action: message.action,
data: {
id: scrub(message.data.id),
position: {
left: scrub(message.data.position.left),
top: scrub(message.data.position.top)
}
}
};
2014-10-12 13:37:45 -04:00
broadcastToRoom( client, message_out );
2011-03-10 08:20:27 -05:00
// console.log("-----" + message.data.id);
// console.log(JSON.stringify(message.data));
2011-03-10 08:20:27 -05:00
getRoom(client, function(room) {
2014-10-12 13:37:45 -04:00
db.cardSetXY( room , message.data.id, message.data.position.left, message.data.position.top);
2011-03-10 08:20:27 -05:00
});
2011-03-10 08:20:27 -05:00
break;
2011-03-10 08:20:27 -05:00
case 'createCard':
data = message.data;
2014-10-12 13:37:45 -04:00
clean_data = {};
2011-03-10 08:20:27 -05:00
clean_data.text = scrub(data.text);
clean_data.id = scrub(data.id);
clean_data.x = scrub(data.x);
clean_data.y = scrub(data.y);
clean_data.rot = scrub(data.rot);
clean_data.colour = scrub(data.colour);
2011-03-10 08:20:27 -05:00
getRoom(client, function(room) {
createCard( room, clean_data.id, clean_data.text, clean_data.x, clean_data.y, clean_data.rot, clean_data.colour);
});
2014-10-12 13:37:45 -04:00
message_out = {
2011-03-10 08:20:27 -05:00
action: 'createCard',
data: clean_data
};
2011-03-10 08:20:27 -05:00
//report to all other browsers
broadcastToRoom( client, message_out );
break;
2011-03-10 08:20:27 -05:00
case 'editCard':
2014-10-12 13:37:45 -04:00
clean_data = {};
2011-03-10 08:20:27 -05:00
clean_data.value = scrub(message.data.value);
clean_data.id = scrub(message.data.id);
//send update to database
2011-03-10 08:20:27 -05:00
getRoom(client, function(room) {
db.cardEdit( room , clean_data.id, clean_data.value );
2011-03-10 08:20:27 -05:00
});
2014-10-12 13:37:45 -04:00
message_out = {
2011-03-10 08:20:27 -05:00
action: 'editCard',
data: clean_data
};
broadcastToRoom(client, message_out);
2011-03-10 08:20:27 -05:00
break;
2011-03-10 08:20:27 -05:00
case 'deleteCard':
2014-10-12 13:37:45 -04:00
clean_message = {
2011-03-10 08:20:27 -05:00
action: 'deleteCard',
data: { id: scrub(message.data.id) }
2014-10-12 13:37:45 -04:00
};
2011-03-10 08:20:27 -05:00
getRoom( client, function(room) {
db.deleteCard ( room, clean_message.data.id );
2011-03-10 08:20:27 -05:00
});
2011-03-10 08:20:27 -05:00
//report to all other browsers
broadcastToRoom( client, clean_message );
break;
case 'createColumn':
2014-10-12 13:37:45 -04:00
clean_message = { data: scrub(message.data) };
2011-03-10 08:20:27 -05:00
getRoom( client, function(room) {
db.createColumn( room, clean_message.data, function() {} );
2011-03-10 08:20:27 -05:00
});
2011-03-10 08:20:27 -05:00
broadcastToRoom( client, clean_message );
2011-03-10 08:20:27 -05:00
break;
2011-03-10 08:20:27 -05:00
case 'deleteColumn':
getRoom( client, function(room) {
db.deleteColumn(room);
2011-03-10 08:20:27 -05:00
});
broadcastToRoom( client, { action: 'deleteColumn' } );
2011-03-10 08:20:27 -05:00
break;
case 'updateColumns':
var columns = message.data;
if (!(columns instanceof Array))
break;
var clean_columns = [];
2014-10-12 13:37:45 -04:00
for (var i in columns)
{
clean_columns[i] = scrub( columns[i] );
}
getRoom( client, function(room) {
db.setColumns( room, clean_columns );
});
2011-03-10 08:20:27 -05:00
broadcastToRoom( client, { action: 'updateColumns', data: clean_columns } );
2011-03-10 08:20:27 -05:00
break;
2011-03-10 08:20:27 -05:00
case 'changeTheme':
2014-10-12 13:37:45 -04:00
clean_message = {};
clean_message.data = scrub(message.data);
2011-03-10 08:20:27 -05:00
getRoom( client, function(room) {
db.setTheme( room, clean_message.data );
2011-03-10 08:20:27 -05:00
});
clean_message.action = 'changeTheme';
broadcastToRoom( client, clean_message );
2011-03-10 08:20:27 -05:00
break;
2011-03-10 08:20:27 -05:00
case 'setUserName':
2014-10-12 13:37:45 -04:00
clean_message = {};
clean_message.data = scrub(message.data);
setUserName(client, clean_message.data);
2011-03-10 08:20:27 -05:00
var msg = {};
msg.action = 'nameChangeAnnounce';
2011-09-05 22:17:30 -04:00
msg.data = { sid: client.id, user_name: clean_message.data };
2011-03-10 08:20:27 -05:00
broadcastToRoom( client, msg );
break;
2011-03-10 08:20:27 -05:00
case 'addSticker':
var cardId = scrub(message.data.cardId);
var stickerId = scrub(message.data.stickerId);
2011-03-10 08:20:27 -05:00
getRoom(client, function(room) {
db.addSticker( room , cardId, stickerId );
2011-03-10 08:20:27 -05:00
});
2011-03-10 08:20:27 -05:00
broadcastToRoom( client, { action: 'addSticker', data: { cardId: cardId, stickerId: stickerId }});
break;
2014-09-30 08:02:58 -04:00
2011-05-27 01:08:25 -04:00
case 'setBoardSize':
var size = {};
2014-09-30 08:02:58 -04:00
size.width = scrub(message.data.width);
2011-05-27 01:08:25 -04:00
size.height = scrub(message.data.height);
2014-09-30 08:02:58 -04:00
2011-05-27 01:08:25 -04:00
getRoom(client, function(room) {
db.setBoardSize( room, size );
});
2014-09-30 08:02:58 -04:00
2011-05-27 01:08:25 -04:00
broadcastToRoom( client, { action: 'setBoardSize', data: size } );
break;
2016-09-13 09:06:15 +02:00
case 'exportTxt':
exportBoard( 'txt', client, message.data );
break;
case 'exportCsv':
exportBoard( 'csv', client, message.data );
break;
case 'exportJson':
exportJson( client, message.data );
break;
case 'importJson':
importJson( client, message.data );
break;
case 'createRevision':
createRevision( client, message.data );
break;
case 'deleteRevision':
deleteRevision( client, message.data );
break;
case 'exportRevision':
exportRevision( client, message.data );
break;
2011-03-10 08:20:27 -05:00
default:
2013-12-08 09:19:17 -05:00
//console.log('unknown action');
2011-03-10 08:20:27 -05:00
break;
}
});
client.on('disconnect', function() {
2011-03-10 08:20:27 -05:00
leaveRoom(client);
});
//tell all others that someone has connected
//client.broadcast('someone has connected');
});
2014-08-17 12:38:00 -04:00
/**************
FUNCTIONS
**************/
2011-03-10 08:20:27 -05:00
function initClient ( client )
{
//console.log ('initClient Started');
getRoom(client, function(room) {
db.getAllCards( room , function (cards) {
client.json.send(
2011-03-10 08:20:27 -05:00
{
action: 'initCards',
data: cards
}
);
2011-03-10 08:20:27 -05:00
});
db.getAllColumns ( room, function (columns) {
client.json.send(
2011-03-10 08:20:27 -05:00
{
action: 'initColumns',
data: columns
}
);
});
db.getRevisions( room, function (revisions) {
client.json.send(
{
action: 'initRevisions',
data: (revisions !== null) ? Object.keys(revisions) : new Array()
}
);
});
db.getTheme( room, function(theme) {
2014-09-30 08:02:58 -04:00
if (theme === null) theme = 'bigcards';
client.json.send(
2011-03-10 08:20:27 -05:00
{
action: 'changeTheme',
data: theme
2011-03-10 08:20:27 -05:00
}
);
});
2014-09-30 08:02:58 -04:00
2011-05-27 01:08:25 -04:00
db.getBoardSize( room, function(size) {
2014-10-12 13:37:45 -04:00
if (size !== null) {
client.json.send(
2011-05-27 01:08:25 -04:00
{
action: 'setBoardSize',
data: size
}
);
}
});
2011-03-10 08:20:27 -05:00
roommates_clients = rooms.room_clients(room);
roommates = [];
2011-03-10 08:20:27 -05:00
var j = 0;
2014-09-30 08:02:58 -04:00
for (var i in roommates_clients)
2011-03-10 08:20:27 -05:00
{
2011-09-05 22:17:30 -04:00
if (roommates_clients[i].id != client.id)
2011-03-10 08:20:27 -05:00
{
roommates[j] = {
2011-09-05 22:17:30 -04:00
sid: roommates_clients[i].id,
user_name: sids_to_user_names[roommates_clients[i].id]
2011-03-10 08:20:27 -05:00
};
j++;
}
}
2013-12-08 09:19:17 -05:00
//console.log('initialusers: ' + roommates);
client.json.send(
2011-03-10 08:20:27 -05:00
{
action: 'initialUsers',
data: roommates
}
2014-09-30 08:02:58 -04:00
);
2011-03-10 08:20:27 -05:00
});
}
function joinRoom (client, room, successFunction)
{
var msg = {};
msg.action = 'join-announce';
2011-09-05 22:17:30 -04:00
msg.data = { sid: client.id, user_name: client.user_name };
2011-03-10 08:20:27 -05:00
rooms.add_to_room_and_announce(client, room, msg);
successFunction();
}
function leaveRoom (client)
{
2013-12-08 09:19:17 -05:00
//console.log (client.id + ' just left');
2011-03-10 08:20:27 -05:00
var msg = {};
msg.action = 'leave-announce';
2011-09-05 22:17:30 -04:00
msg.data = { sid: client.id };
2011-03-10 08:20:27 -05:00
rooms.remove_from_all_rooms_and_announce(client, msg);
2011-09-05 22:17:30 -04:00
delete sids_to_user_names[client.id];
2011-03-10 08:20:27 -05:00
}
function broadcastToRoom ( client, message ) {
rooms.broadcast_to_roommates(client, message);
}
//----------------CARD FUNCTIONS
function createCard( room, id, text, x, y, rot, colour ) {
var card = {
2011-03-10 08:20:27 -05:00
id: id,
colour: colour,
rot: rot,
x: x,
y: y,
text: text,
sticker: null
2011-03-10 08:20:27 -05:00
};
db.createCard(room, id, card);
2011-03-10 08:20:27 -05:00
}
function roundRand( max )
{
return Math.floor(Math.random() * max);
}
//------------ROOM STUFF
// Get Room name for the given Session ID
function getRoom( client , callback )
{
room = rooms.get_room( client );
2011-09-05 22:17:30 -04:00
//console.log( 'client: ' + client.id + " is in " + room);
2011-03-10 08:20:27 -05:00
callback(room);
}
function setUserName ( client, name )
{
client.user_name = name;
2011-09-05 22:17:30 -04:00
sids_to_user_names[client.id] = name;
2013-12-08 09:19:17 -05:00
//console.log('sids to user names: ');
2011-03-10 08:20:27 -05:00
console.dir(sids_to_user_names);
}
function cleanAndInitializeDemoRoom()
{
// DUMMY DATA
2011-03-12 14:54:02 -05:00
db.clearRoom('/demo', function() {
2016-08-04 13:10:29 +02:00
db.createColumn( '/demo', 'Pas commencé' );
db.createColumn( '/demo', 'Commencé' );
db.createColumn( '/demo', 'En test' );
db.createColumn( '/demo', 'Validation' );
db.createColumn( '/demo', 'Terminé' );
2011-03-10 08:20:27 -05:00
2016-08-04 13:10:29 +02:00
createCard('/demo', 'card1', 'Salut, c\'est fun', roundRand(600), roundRand(300), Math.random() * 10 - 5, 'yellow');
createCard('/demo', 'card2', 'Salut, c\'est une nouvelle histoire.', roundRand(600), roundRand(300), Math.random() * 10 - 5, 'white');
2011-03-10 08:20:27 -05:00
createCard('/demo', 'card3', '.', roundRand(600), roundRand(300), Math.random() * 10 - 5, 'blue');
createCard('/demo', 'card4', '.', roundRand(600), roundRand(300), Math.random() * 10 - 5, 'green');
2016-08-04 13:10:29 +02:00
createCard('/demo', 'card5', 'Salut, c\'est fun', roundRand(600), roundRand(300), Math.random() * 10 - 5, 'yellow');
createCard('/demo', 'card6', 'Salut, c\'est un nouveau mémo.', roundRand(600), roundRand(300), Math.random() * 10 - 5, 'yellow');
2011-03-10 08:20:27 -05:00
createCard('/demo', 'card7', '.', roundRand(600), roundRand(300), Math.random() * 10 - 5, 'blue');
createCard('/demo', 'card8', '.', roundRand(600), roundRand(300), Math.random() * 10 - 5, 'green');
});
}
2016-09-13 09:06:15 +02:00
// Export board in txt or csv
function exportBoard( format, client, data )
{
var result = new Array();
getRoom(client, function(room) {
db.getAllCards( room , function (cards) {
db.getAllColumns ( room, function (columns) {
var text = new Array();
var cols = {};
if (columns.length > 0) {
for (var i = 0; i < columns.length; i++) {
cols[columns[i]] = new Array();
for (var j = 0; j < cards.length; j++) {
if (i === 0) {
if (cards[j]['x'] < (i + 1) * data) {
cols[columns[i]].push(cards[j]);
}
} else if (i + 1 === columns.length) {
if (cards[j]['x'] >= i * data) {
cols[columns[i]].push(cards[j]);
}
} else if (cards[j]['x'] >= i * data && cards[j]['x'] < (i + 1) * data) {
cols[columns[i]].push(cards[j]);
}
}
cols[columns[i]].sort(function(a, b) {
if (a['y'] === b['y']) {
return (a['x'] - b['x']);
} else {
return a['y'] - b['y'];
}
});
}
if (format === 'txt') {
for (var i = 0; i < columns.length; i++) {
if (i === 0) {
text.push("# "+columns[i]);
} else {
text.push("\n# "+columns[i]);
}
for (var j = 0; j < cols[columns[i]].length; j++) {
text.push('- '+cols[columns[i]][j]['text']);
}
}
} else if (format === 'csv') {
var max = 0;
var line = new Array();
2017-02-19 22:54:30 +01:00
var patt_vuln = new RegExp("^[=+\-@]");
2016-09-13 09:06:15 +02:00
for (var i = 0; i < columns.length; i++) {
if (cols[columns[i]].length > max) {
max = cols[columns[i]].length;
}
2017-02-19 22:54:30 +01:00
var val = columns[i].replace(/"/g,'""');
if (patt_vuln.test(val)) { // prevent CSV Formula Injection
var val = "'"+val;
}
line.push('"'+val+'"');
2016-09-13 09:06:15 +02:00
}
text.push(line.join(','));
for (var j = 0; j < max; j++) {
line = new Array();
for (var i = 0; i < columns.length; i++) {
var val = (cols[columns[i]][j] !== undefined) ? cols[columns[i]][j]['text'].replace(/"/g,'""') : '';
2017-02-19 22:54:30 +01:00
if (patt_vuln.test(val)) { // prevent CSV Formula Injection
var val = "'"+val;
}
2016-09-13 09:06:15 +02:00
line.push('"'+val+'"');
}
text.push(line.join(','));
}
}
} else {
for (var j = 0; j < cards.length; j++) {
if (format === 'txt') {
text.push('- '+cards[j]['text']);
} else if (format === 'csv') {
text.push('"'+cards[j]['text'].replace(/"/g,'""')+'"\n');
}
}
}
var result;
if (format === 'txt' || format === 'csv') {
result = text.join("\n");
} else if (format === 'json') {
result = JSON.stringify(cols);
}
client.json.send(
{
action: 'export',
data: {
filename: room.replace('/', '')+'.'+format,
text: result
}
}
);
});
});
});
}
// Export board in json, suitable for import
function exportJson( client, data )
{
var result = new Array();
getRoom(client, function(room) {
db.getAllCards( room , function (cards) {
db.getAllColumns ( room, function (columns) {
db.getTheme( room, function(theme) {
db.getBoardSize( room, function(size) {
if (theme === null) theme = 'bigcards';
if (size === null) size = { width: data.width, height: data.height };
result = JSON.stringify({
cards: cards,
columns: columns,
theme: theme,
size: size
});
client.json.send(
{
action: 'export',
data: {
filename: room.replace('/', '')+'.json',
text: result
}
}
);
});
});
});
});
});
}
// Import board from json
function importJson( client, data )
{
getRoom(client, function(room) {
db.clearRoom(room, function() {
db.getAllCards( room , function (cards) {
for (var i = 0; i < cards.length; i++) {
db.deleteCard ( room, cards[i].id );
}
cards = data.cards;
var cards2 = new Array();
for (var i = 0; i < cards.length; i++) {
var card = cards[i];
if (card.id !== undefined && card.colour !== undefined
&& card.rot !== undefined && card.x !== undefined
&& card.y !== undefined && card.text !== undefined
&& card.sticker !== undefined) {
var c = {
id: card.id,
colour: card.colour,
rot: card.rot,
x: card.x,
y: card.y,
text: scrub(card.text),
sticker: card.sticker
};
db.createCard(room, c.id, c);
cards2.push(c);
}
}
var msg = { action: 'initCards', data: cards2 };
broadcastToRoom(client, msg);
client.json.send(msg);
});
db.getAllColumns ( room, function (columns) {
for (var i = 0; i < columns.length; i++) {
db.deleteColumn(room);
}
columns = data.columns;
var columns2 = new Array();
for (var i = 0; i < columns.length; i++) {
var column = scrub(columns[i]);
if (typeof(column) === 'string') {
db.createColumn(room, column);
columns2.push(column);
}
}
msg = { action: 'initColumns', data: columns2 };
broadcastToRoom(client, msg);
client.json.send(msg);
});
var size = data.size;
if (size.width !== undefined && size.height !== undefined) {
size = { width: scrub(size.width), height: scrub(size.height) };
db.setBoardSize( room, size );
msg = { action: 'setBoardSize', data: size };
broadcastToRoom(client, msg);
client.json.send(msg);
}
data.theme = scrub(data.theme);
if (data.theme === 'smallcards' || data.theme === 'bigcards') {
db.setTheme( room, data.theme );
msg = { action: 'changeTheme', data: data.theme };
broadcastToRoom(client, msg);
client.json.send(msg);
}
});
});
}
//
2011-03-10 08:20:27 -05:00
function createRevision( client, data )
{
var result = new Array();
getRoom(client, function(room) {
db.getAllCards( room , function (cards) {
db.getAllColumns ( room, function (columns) {
db.getTheme( room, function(theme) {
db.getBoardSize( room, function(size) {
if (theme === null) theme = 'bigcards';
if (size === null) size = { width: data.width, height: data.height };
result = {
cards: cards,
columns: columns,
theme: theme,
size: size
};
var timestamp = Date.now();
db.getRevisions( room, function(revisions) {
if (revisions === null) revisions = {};
revisions[timestamp+''] = result;
db.setRevisions( room, revisions );
msg = { action: 'addRevision', data: timestamp };
broadcastToRoom(client, msg);
client.json.send(msg);
});
});
});
});
});
});
}
function deleteRevision( client, timestamp )
{
getRoom(client, function(room) {
db.getRevisions( room, function(revisions) {
if (revisions !== null && revisions[timestamp+''] !== undefined) {
delete revisions[timestamp+''];
db.setRevisions( room, revisions );
}
msg = { action: 'deleteRevision', data: timestamp };
broadcastToRoom(client, msg);
client.json.send(msg);
});
});
}
function exportRevision ( client, timestamp )
{
getRoom(client, function(room) {
db.getRevisions( room, function(revisions) {
if (revisions !== null && revisions[timestamp+''] !== undefined) {
client.json.send(
{
action: 'export',
data: {
filename: room.replace('/', '')+'-'+timestamp+'.json',
text: JSON.stringify(revisions[timestamp+''])
}
}
);
} else {
client.json.send(
{
action: 'message',
data: 'Unable to find revision '+timestamp+'.'
}
);
}
});
});
}
2014-08-17 12:38:00 -04:00
/**************
SETUP DATABASE ON FIRST RUN
**************/
// (runs only once on startup)
var db = new data(function() {
cleanAndInitializeDemoRoom();
2011-03-12 14:54:02 -05:00
});