var express = require('express'), knox = require('knox'), fs = require('fs'), app = express(), http = require('http'), server = http.createServer(app), io = require('socket.io').listen(server); var s3 = knox.createClient({ key: process.env.ASDF_S3_KEY, secret: process.env.ASDF_S3_SECRET, bucket: 'cocoapaint' }); app.configure(function(){ app.use(express.logger()); app.use(express.methodOverride()); app.use(express.bodyParser()); app.use(express.static(__dirname + '/public')); }); /******************************* ROUTES */ app.get('/latest', function(req, res){ var data = { 'image_url': Images.latest() }; res.setHeader('Content-Type', 'application/json'); res.send(JSON.stringify(data)); }); app.post('/upload', function(req, res) { var nick = req.body.nick; if (nick in game.images) return; if (game.state != State.DRAWING) return; var image = new Buffer(req.body.image, 'base64'); var filename = "/test/" + nick + "-" + Date.now() + "-" + "test" + ".png"; var s3req = s3.putBuffer(image, filename, { 'Content-Length': image.length, 'Content-Type': 'image/png', 'x-amz-acl': 'public-read' }, function(err, s3res){ if (200 == s3res.statusCode) { console.log('saved to %s', s3req.url); var imageData = { 'nick': nick, 'url': s3req.url } game.pushImage( imageData ); } }); }); /******************************* WEBSOCKETS */ var State = { RESET: -1, WAITING: 0, DRAWING: 1, VOTING: 2, WINNING: 3, }; var Delay = { DRAWING: 60, VOTING: 30, WINNING: 30, } function Channel() { this.state = State.WAITING; this.messages = []; this.message_id = 0; this.players = {}; this.playerCount = 0; this.images = {}; this.imageCount = 0; this.word = ""; this.timer = null; } Channel.prototype.join = function(user, socket){ this.playerCount++; } Channel.prototype.part = function(){ this.playerCount = Math.max( 0, this.playerCount - 1 ); } Channel.prototype.pushMessage = function(message){ if (this.messages.length > 20) this.messages.shift(); this.messages.push(message); } Channel.prototype.report = function(){ return { state: this.state, messages: this.messages, players: this.players } } Channel.prototype.pushImage = function(image){ this.imageCount++; this.images[ image.nick ] = image; io.sockets.emit( 'event-image', imageData ); if (this.imageCount == this.playerCount) this.startVoting(); } Channel.prototype.checkState = function(){ if ( this.hasEnoughPlayers() ) { if (this.state <= State.WAITING) { this.newRound(); } } else { if (this.state > State.WAITING) { this.state = State.WAITING; } } } Channel.prototype.newWord = function(){ return choice(WORDS); } Channel.prototype.newRound = function(){ this.state = State.DRAWING; this.word = this.newWord(); this.images = {}; this.imageCount = 0; io.sockets.emit( 'event-state', this.getState() ); this.setTimeout( this.startVoting, Delay.DRAWING ); } Channel.prototype.startVoting = function(){ this.state = State.VOTING; io.sockets.emit( 'event-state', this.getState() ); this.setTimeout( this.startWinning, Delay.VOTING ); } Channel.prototype.startWinning = function(){ this.state = State.WINNING; io.sockets.emit( 'event-state', this.getState() ); this.setTimeout( this.startWinning, Delay.WINNING ); } Channel.prototype.setTimeout = function( callback, delay ){ var owner = this; if (this.timeout) clearTimeout( this.timeout ); this.timeout = setTimeout( function(){ callback.call( owner ) }, delay ); } Channel.prototype.getState = function(){ return { state: this.state, word: this.word, players: this.players, images: this.images, imageCount: this.imageCount, } } Channel.prototype.hasEnoughPlayers = function(){ var count = 0; for (var i in this.players) { if (++count > 2) return true; } return false; } var game = new Channel (); io.sockets.on( 'connection', function(socket){ socket.emit( 'event-welcome', game.report() ); socket.on( 'event-join', function(data){ game.join(data, socket); game.checkState(); socket.broadcast.emit('event-join', data); } ); socket.on( 'event-message', function(data){ game.pushMessage(data); socket.broadcast.emit('event-message', data); } ); socket.on( 'disconnect', function(data){ game.part(data, socket); game.checkState(); socket.broadcast.emit('event-part', data); } ); }); /******************************* ETC */ function choice (l) { return l[ rand(l.length) ] } function rand (n) { return Math.floor( Math.random() * n ) } /******************************* DONE */ var port = process.env.PORT || 5000; server.listen(port); console.log('Listening on port ' + port);