mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-27 03:58:02 -05:00
Migrate editor-socketio-server.js to TypeScript
Signed-off-by: David Mehren <dmehren1@gmail.com>
This commit is contained in:
parent
c7478157e2
commit
dc3a3f2994
3 changed files with 157 additions and 165 deletions
|
@ -1,164 +0,0 @@
|
|||
'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 logger = require('../logger');
|
||||
|
||||
function EditorSocketIOServer(document, operations, docId, mayWrite, operationCallback) {
|
||||
EventEmitter.call(this);
|
||||
Server.call(this, document, operations);
|
||||
this.users = {};
|
||||
this.docId = docId;
|
||||
this.mayWrite = mayWrite || function (_, cb) {
|
||||
cb(true);
|
||||
};
|
||||
this.operationCallback = operationCallback;
|
||||
}
|
||||
|
||||
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', docOut);
|
||||
socket.on('operation', function (revision, operation, selection) {
|
||||
socket.origin = 'operation';
|
||||
self.mayWrite(socket, function (mayWrite) {
|
||||
if (!mayWrite) {
|
||||
logger.info("User doesn't have the right to edit.");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
self.onOperation(socket, revision, operation, selection);
|
||||
if (typeof self.operationCallback === 'function')
|
||||
self.operationCallback(socket, operation);
|
||||
} catch (err) {
|
||||
setTimeout(function() {
|
||||
var docOut = {
|
||||
str: self.document,
|
||||
revision: self.operations.length,
|
||||
clients: self.users,
|
||||
force: true
|
||||
};
|
||||
socket.emit('doc', docOut);
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
});
|
||||
socket.on('get_operations', function (base, head) {
|
||||
self.onGetOperations(socket, base, head);
|
||||
});
|
||||
socket.on('selection', function (obj) {
|
||||
socket.origin = 'selection';
|
||||
self.mayWrite(socket, function (mayWrite) {
|
||||
if (!mayWrite) {
|
||||
logger.info("User doesn't have the right to edit.");
|
||||
return;
|
||||
}
|
||||
self.updateSelection(socket, obj && Selection.fromJSON(obj));
|
||||
});
|
||||
});
|
||||
socket.on('disconnect', function () {
|
||||
logger.debug("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) {
|
||||
logger.error("Invalid operation received: ");
|
||||
logger.error(exc);
|
||||
throw new Error(exc);
|
||||
}
|
||||
|
||||
try {
|
||||
var clientId = socket.id;
|
||||
var wrappedPrime = this.receiveOperation(revision, wrapped);
|
||||
if(!wrappedPrime) return;
|
||||
logger.debug("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
|
||||
);
|
||||
//set document is dirty
|
||||
this.isDirty = true;
|
||||
} catch (exc) {
|
||||
logger.error(exc);
|
||||
throw new Error(exc);
|
||||
}
|
||||
};
|
||||
|
||||
EditorSocketIOServer.prototype.onGetOperations = function (socket, base, head) {
|
||||
var operations = this.operations.slice(base, head).map(function (op) {
|
||||
return op.wrapped.toJSON();
|
||||
});
|
||||
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;
|
155
lib/ot/editor-socketio-server.ts
Executable file
155
lib/ot/editor-socketio-server.ts
Executable file
|
@ -0,0 +1,155 @@
|
|||
import { EventEmitter } from 'events'
|
||||
import { logger } from '../logger'
|
||||
import Selection from './selection'
|
||||
import Server from './server'
|
||||
import TextOperation from './text-operation'
|
||||
import WrappedOperation from './wrapped-operation'
|
||||
|
||||
export class EditorSocketIOServer extends Server {
|
||||
private readonly users: {}
|
||||
private readonly docId: any
|
||||
private mayWrite: any
|
||||
|
||||
constructor (document, operations, docId, mayWrite, operationCallback) {
|
||||
super(document, operations)
|
||||
// Whatever that does?
|
||||
EventEmitter.call(this)
|
||||
this.users = {}
|
||||
this.docId = docId
|
||||
this.mayWrite = mayWrite || function (_, cb) {
|
||||
cb(true)
|
||||
}
|
||||
this.operationCallback = operationCallback
|
||||
}
|
||||
|
||||
addClient (socket) {
|
||||
const self = this
|
||||
socket.join(this.docId)
|
||||
const docOut = {
|
||||
str: this.document,
|
||||
revision: this.operations.length,
|
||||
clients: this.users
|
||||
}
|
||||
socket.emit('doc', docOut)
|
||||
socket.on('operation', function (revision, operation, selection) {
|
||||
socket.origin = 'operation'
|
||||
self.mayWrite(socket, function (mayWrite) {
|
||||
if (!mayWrite) {
|
||||
logger.info("User doesn't have the right to edit.")
|
||||
return
|
||||
}
|
||||
try {
|
||||
self.onOperation(socket, revision, operation, selection)
|
||||
if (typeof self.operationCallback === 'function')
|
||||
self.operationCallback(socket, operation)
|
||||
} catch (err) {
|
||||
setTimeout(function () {
|
||||
const docOut = {
|
||||
str: self.document,
|
||||
revision: self.operations.length,
|
||||
clients: self.users,
|
||||
force: true
|
||||
}
|
||||
socket.emit('doc', docOut)
|
||||
}, 100)
|
||||
}
|
||||
})
|
||||
})
|
||||
socket.on('get_operations', function (base, head) {
|
||||
self.onGetOperations(socket, base, head)
|
||||
})
|
||||
socket.on('selection', function (obj) {
|
||||
socket.origin = 'selection'
|
||||
self.mayWrite(socket, function (mayWrite) {
|
||||
if (!mayWrite) {
|
||||
logger.info("User doesn't have the right to edit.")
|
||||
return
|
||||
}
|
||||
self.updateSelection(socket, obj && Selection.fromJSON(obj))
|
||||
})
|
||||
})
|
||||
socket.on('disconnect', function () {
|
||||
logger.debug("Disconnect")
|
||||
socket.leave(self.docId)
|
||||
self.onDisconnect(socket)
|
||||
/*
|
||||
if (socket.manager && socket.manager.sockets.clients(self.docId).length === 0) {
|
||||
self.emit('empty-room');
|
||||
}
|
||||
*/
|
||||
})
|
||||
};
|
||||
|
||||
onOperation (socket, revision, operation, selection) {
|
||||
let wrapped
|
||||
try {
|
||||
wrapped = new WrappedOperation(
|
||||
TextOperation.fromJSON(operation),
|
||||
selection && Selection.fromJSON(selection)
|
||||
)
|
||||
} catch (exc) {
|
||||
logger.error("Invalid operation received: ")
|
||||
logger.error(exc)
|
||||
throw new Error(exc)
|
||||
}
|
||||
|
||||
try {
|
||||
const clientId = socket.id
|
||||
const wrappedPrime = this.receiveOperation(revision, wrapped)
|
||||
if (!wrappedPrime) return
|
||||
logger.debug("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
|
||||
)
|
||||
//set document is dirty
|
||||
this.isDirty = true
|
||||
} catch (exc) {
|
||||
logger.error(exc)
|
||||
throw new Error(exc)
|
||||
}
|
||||
};
|
||||
|
||||
onGetOperations (socket, base, head) {
|
||||
const operations = this.operations.slice(base, head).map(function (op) {
|
||||
return op.wrapped.toJSON()
|
||||
})
|
||||
socket.emit('operations', head, operations)
|
||||
};
|
||||
|
||||
updateSelection (socket, selection) {
|
||||
const 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)
|
||||
};
|
||||
|
||||
setName (socket, name) {
|
||||
const clientId = socket.id
|
||||
this.getClient(clientId).name = name
|
||||
socket.broadcast.to(this.docId).emit('set_name', clientId, name)
|
||||
};
|
||||
|
||||
setColor (socket, color) {
|
||||
const clientId = socket.id
|
||||
this.getClient(clientId).color = color
|
||||
socket.broadcast.to(this.docId).emit('set_color', clientId, color)
|
||||
};
|
||||
|
||||
getClient (clientId) {
|
||||
return this.users[clientId] || (this.users[clientId] = {})
|
||||
};
|
||||
|
||||
onDisconnect (socket) {
|
||||
const clientId = socket.id
|
||||
delete this.users[clientId]
|
||||
socket.broadcast.to(this.docId).emit('client_left', clientId)
|
||||
};
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ import async from 'async'
|
|||
import cookieParser from 'cookie-parser'
|
||||
import cookie from 'cookie'
|
||||
import Chance from 'chance'
|
||||
import { EditorSocketIOServer } from './ot/editor-socketio-server'
|
||||
|
||||
const chance = new Chance()
|
||||
|
||||
|
@ -577,7 +578,7 @@ function startConnection (socket) {
|
|||
const body = note.content
|
||||
const createtime = note.createdAt
|
||||
const updatetime = note.lastchangeAt
|
||||
const server = new ot.EditorSocketIOServer(body, [], noteId, ifMayEdit, operationCallback)
|
||||
const server = new EditorSocketIOServer(body, [], noteId, ifMayEdit, operationCallback)
|
||||
|
||||
const authors = {}
|
||||
for (let i = 0; i < note.authors.length; i++) {
|
||||
|
|
Loading…
Reference in a new issue