diff options
Diffstat (limited to 'lib/ot/editor-socketio-server.js')
-rwxr-xr-x | lib/ot/editor-socketio-server.js | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/lib/ot/editor-socketio-server.js b/lib/ot/editor-socketio-server.js new file mode 100755 index 00000000..aae156fc --- /dev/null +++ b/lib/ot/editor-socketio-server.js @@ -0,0 +1,146 @@ +'use strict'; + +var EventEmitter = require('events').EventEmitter; +var TextOperation = require('./text-operation'); +var WrappedOperation = require('./wrapped-operation'); +var Server = require('./server'); +var Selection = require('./selection'); +var util = require('util'); + +var LZString = require('lz-string'); + +function EditorSocketIOServer(document, operations, docId, mayWrite) { + EventEmitter.call(this); + Server.call(this, document, operations); + this.users = {}; + this.docId = docId; + this.mayWrite = mayWrite || function (_, cb) { + cb(true); + }; +} + +util.inherits(EditorSocketIOServer, Server); +extend(EditorSocketIOServer.prototype, EventEmitter.prototype); + +function extend(target, source) { + for (var key in source) { + if (source.hasOwnProperty(key)) { + target[key] = source[key]; + } + } +} + +EditorSocketIOServer.prototype.addClient = function (socket) { + var self = this; + socket.join(this.docId); + var docOut = { + str: this.document, + revision: this.operations.length, + clients: this.users + }; + socket.emit('doc', LZString.compressToUTF16(JSON.stringify(docOut))); + socket.on('operation', function (revision, operation, selection) { + operation = LZString.decompressFromUTF16(operation); + operation = JSON.parse(operation); + self.mayWrite(socket, function (mayWrite) { + if (!mayWrite) { + console.log("User doesn't have the right to edit."); + return; + } + self.onOperation(socket, revision, operation, selection); + }); + }); + socket.on('get_operations', function (base, head) { + self.onGetOperations(socket, base, head); + }); + socket.on('selection', function (obj) { + self.mayWrite(socket, function (mayWrite) { + if (!mayWrite) { + console.log("User doesn't have the right to edit."); + return; + } + self.updateSelection(socket, obj && Selection.fromJSON(obj)); + }); + }); + socket.on('disconnect', function () { + //console.log("Disconnect"); + socket.leave(self.docId); + self.onDisconnect(socket); + /* + if (socket.manager && socket.manager.sockets.clients(self.docId).length === 0) { + self.emit('empty-room'); + } + */ + }); +}; + +EditorSocketIOServer.prototype.onOperation = function (socket, revision, operation, selection) { + var wrapped; + try { + wrapped = new WrappedOperation( + TextOperation.fromJSON(operation), + selection && Selection.fromJSON(selection) + ); + } catch (exc) { + console.error("Invalid operation received: " + exc); + return; + } + + try { + var clientId = socket.id; + var wrappedPrime = this.receiveOperation(revision, wrapped); + //console.log("new operation: " + JSON.stringify(wrapped)); + this.getClient(clientId).selection = wrappedPrime.meta; + revision = this.operations.length; + socket.emit('ack', revision); + socket.broadcast.in(this.docId).emit( + 'operation', clientId, revision, + wrappedPrime.wrapped.toJSON(), wrappedPrime.meta + ); + this.isDirty = true; + } catch (exc) { + console.error(exc); + } +}; + +EditorSocketIOServer.prototype.onGetOperations = function (socket, base, head) { + var operations = this.operations.slice(base, head).map(function (op) { + return op.wrapped.toJSON(); + }); + operations = LZString.compressToUTF16(JSON.stringify(operations)); + socket.emit('operations', head, operations); +}; + +EditorSocketIOServer.prototype.updateSelection = function (socket, selection) { + var clientId = socket.id; + if (selection) { + this.getClient(clientId).selection = selection; + } else { + delete this.getClient(clientId).selection; + } + socket.broadcast.to(this.docId).emit('selection', clientId, selection); +}; + +EditorSocketIOServer.prototype.setName = function (socket, name) { + var clientId = socket.id; + this.getClient(clientId).name = name; + socket.broadcast.to(this.docId).emit('set_name', clientId, name); +}; + +EditorSocketIOServer.prototype.setColor = function (socket, color) { + var clientId = socket.id; + this.getClient(clientId).color = color; + socket.broadcast.to(this.docId).emit('set_color', clientId, color); +}; + +EditorSocketIOServer.prototype.getClient = function (clientId) { + return this.users[clientId] || (this.users[clientId] = {}); +}; + +EditorSocketIOServer.prototype.onDisconnect = function (socket) { + var clientId = socket.id; + delete this.users[clientId]; + socket.broadcast.to(this.docId).emit('client_left', clientId); +}; + +module.exports = EditorSocketIOServer;
\ No newline at end of file |