nicklasos
3/7/2016 - 10:04 AM

Websockets. Who else editing this page.

Websockets. Who else editing this page.

'use strict';

var _ = require('lodash');
var app = require('http').createServer((req, res) => res.end());
var io = require('socket.io')(app);

app.listen(8080);

class RoomManager {
    constructor() {
        this.users = {};
        this.rooms = {};
    }

    add(userId, email, room) {
        _.set(this.users, userId, {
            email: email,
            room: room
        });

        if (!this.rooms.hasOwnProperty(room)) {
            this.rooms[room] = [];
        }

        this.rooms[room].push(userId);
    }

    remove(userId) {
        var room;
        if (this.users.hasOwnProperty(userId)) {
            room = this.users[userId].room;
            delete this.users[userId];
        }

        var index = _.get(this.rooms, room, '').indexOf(userId);
        if (index > -1) {
            this.rooms[room].splice(index, 1);
        }
    }

    getEmailsFrom(room) {
        var users = _.get(this.rooms, room, []);

        return _.uniq(users
            .filter(id => this.users.hasOwnProperty(id))
            .map(id => this.users[id].email));
    }

    getUserRoom(userId) {
        return _.get(this.users, [userId, 'room'], null);
    }
}

var roomManager = new RoomManager();

io.on('connection', function (socket) {
    socket.on('joinRoom', function (data) {
        roomManager.add(socket.id, data.email, data.room);
        socket.join(data.room);

        io.to(data.room).emit('message', {
            users: roomManager.getEmailsFrom(data.room)
        });
    });

    socket.on('disconnect', function () {
        var room = roomManager.getUserRoom(socket.id);
        roomManager.remove(socket.id);
        if (room) {
            io.to(room).emit('message', {
                users: roomManager.getEmailsFrom(room)
            });
        }
    });
});

if (process.env.NODE_ENV == 'test') {
    var assert = require('assert');

    var rm = new RoomManager();

    rm.add(1, 'foo@gmail.com', 'cards');
    rm.add(2, 'bar@gmail.com', 'cards');
    rm.add(3, 'bar@gmail.com', 'cards');

    rm.add(4, 'foo@gmail.com', 'levels');

    assert.deepEqual(rm.getEmailsFrom('cards'), ['foo@gmail.com', 'bar@gmail.com']);
    assert.deepEqual(rm.getEmailsFrom('levels'), ['foo@gmail.com']);

    assert.equal(rm.getUserRoom(1), 'cards');
    assert.equal(rm.getUserRoom(4), 'levels');

    rm.remove(4);
    assert.deepEqual(rm.getEmailsFrom('levels'), []);
    assert.deepStrictEqual(rm.getUserRoom(4), null);

    rm.remove(3);
    assert.deepEqual(rm.getEmailsFrom('cards'), ['foo@gmail.com', 'bar@gmail.com']);

    rm.remove(2);
    assert.deepEqual(rm.getEmailsFrom('cards'), ['foo@gmail.com']);
}
(function () {
    var socket = io($('#ws-url').val());
    var email = $('#user-name').val();
    var editUrls = [
        'filemanager/edit',
        'media/update',
        'courses/show',
        'screenshot/index',
        'card/update',
        'skin/update',
        'layer/update',
        'concepts/edit'
    ];

    var channel = window.location.pathname;

    editUrls.forEach(function (url) {
        if (channel.indexOf(url) >= 0) {
            socket.emit('joinRoom', {
                room: channel,
                email: email
            });
        }
    });

    var firstJoin = true;

    socket.on('message', function (data) {
        var users = data.users;

        if (users.length > 1) {
            $.gritter.add({
                title: users.length + ' users are editing this page.',
                text: users.join('<br>')
            });
        } else {
            if (!firstJoin) {
                $.gritter.add({
                    text: 'Nobody else is editing this page.'
                });
            }

        }
        
        firstJoin = false;
    });
})();