var app = require('http').createServer(),
    io = require('socket.io').listen(app),
    spawn = require('child_process').spawn,
    fs = require('fs');

var generateUserid = function() {
    var id = (Math.random().toString(36)+'00000000000000000').slice(2, 8);
    if (connectedUsers[id] === undefined) return id;
    else return generateUserid();
};

var connectedUsers = {};

io.of('/ruby').on('connection', function(socket) {

    var ruby,
        userid,
        socketOn = false;

    socket.on('codeBuild', function(data) {
        console.log(data);

        var fileSaveError,
            codeLoadError;

        // Save file
        fs.writeFile('games/' + userid + '.rb', data.fileContent, function(error) {
            fileSaveError = error;

            // Emit file saved
            socket.emit('buildStatus', {
                output: error || 'Code saved.'
            });

            // Check file syntax?

            // Kill old IRB
            if (ruby) {
              oldRuby = ruby;
              oldRuby.kill();
            }

            // Start IRB
            ruby = spawn('irb');

            ruby.stdout.setEncoding('utf8');
            ruby.stderr.setEncoding('utf8');

            // Funnel file into IRB
            socketOn = false;
            ruby.stdin.write(data.fileContent + '\n', function(error) {
                codeLoadError = error;

                // Emit code loaded
                socket.emit('buildStatus', {
                    output: error || 'Game loaded.'
                });

                if (!fileSaveError && !codeLoadError) {
                    socket.emit('buildStatus', {
                        output: 'Build successful!'
                    });
                } else {
                    socket.emit('terminalError', {
                        output: 'Build failed!'
                    });
                }
            });

            // Bind events on IRB
            ruby.stdout.on('data', function(data) {
                console.log('stdout: ' + data);
                if (socketOn) {
                    console.log('socket on');
                    socket.emit('terminalOutput', {
                        output: data
                    });
                }
            });

            ruby.stderr.on('data', function(data) {
                console.log('stderr: ' + data);
                socket.emit('terminalError', {
                    output: data
                });
            });

            ruby.on('close', function(code) {
                console.log('Exit code: ' + code);
            });

        });
    });

    socket.on('terminalInput', function(data) {
        console.log(data);
        socketOn = true;
        if (ruby) {
            ruby.stdin.write(data.input + '\n');
        }
        else {
            socket.emit('terminalError', {
                output: 'Game not built!'
            });
        }
    });

    socket.on('reportUserid', function(data) {
        console.log(data.userid);
        console.log(connectedUsers[data.userid]);
        if (data.userid && !connectedUsers[data.userid]) {
            userid = data.userid;
        } else userid = generateUserid();

        connectedUsers[userid] = true;
        socket.emit('confirmUserid', { userid: userid });

        fs.readFile('games/' + userid + '.rb', function(error, contents) {
            if (error) {
                fs.readFile('games/game.rb', function(error, contents) {
                    socket.emit('ready', {
                        output: 'Ready!',
                        fileContent: contents.toString()
                    });
                });
            } else {
                socket.emit('ready', {
                    output: 'Ready! Welcome back.',
                    fileContent: contents.toString()
                });
            }
        });
    });

    socket.on('disconnect', function() {
        console.log('User ' + userid + 'disconnected.');
        connectedUsers[userid] = false;
        console.log(connectedUsers);
    });

});

app.listen(process.env.PORT || 8888);

@@ -3063,55 +3063,181 @@
     
-if (data.userid && !connectedUsers%5Bdata.userid%5D
+var oldSocket = connectedUsers%5Bdata.userid%5D;%0A        var newOrAuthenticatedUser = !oldSocket %7C%7C oldSocket === data.authid;%0A%0A        if (data.userid && newOrAuthenticatedUser
 ) %7B%0A
@@ -3309,24 +3309,94 @@
 eUserid();%0A%0A
+        // Store socket id because XHR polling causes race conditions%0A
         conn
@@ -3416,20 +3416,25 @@
 erid%5D = 
-true
+socket.id
 ;%0A      
@@ -3465,16 +3465,28 @@
 erid', %7B
+%0A           
  userid:
@@ -3492,16 +3492,55 @@
 : userid
+,%0A            authid: socket.id%0A       
  %7D);%0A%0A  
@@ -4213,32 +4213,144 @@
 cted.');%0A       
+ // Only set to false if user doesn't already have a new socket%0A        if (socket.id == connectedUsers%5Buserid%5D)
  connectedUsers%5B

Use previous socket id to validate right to a user id