summaryrefslogtreecommitdiff
path: root/lib/realtime.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/realtime.js')
-rw-r--r--lib/realtime.js167
1 files changed, 66 insertions, 101 deletions
diff --git a/lib/realtime.js b/lib/realtime.js
index 0c68a256..ea3735a6 100644
--- a/lib/realtime.js
+++ b/lib/realtime.js
@@ -13,6 +13,7 @@ var moment = require('moment');
//core
var config = require("./config.js");
var logger = require("./logger.js");
+var history = require("./history.js");
var models = require("./models");
//ot
@@ -63,6 +64,7 @@ function secure(socket, next) {
function emitCheck(note) {
var out = {
+ title: note.title,
updatetime: note.updatetime,
lastchangeuser: note.lastchangeuser,
lastchangeuserprofile: note.lastchangeuserprofile,
@@ -148,7 +150,7 @@ function updateNote(note, callback) {
function finishUpdateNote(note, _note, callback) {
if (!note || !note.server) return callback(null, null);
var body = note.server.document;
- var title = models.Note.parseNoteTitle(body);
+ var title = note.title = models.Note.parseNoteTitle(body);
title = LZString.compressToBase64(title);
body = LZString.compressToBase64(body);
var values = {
@@ -312,6 +314,7 @@ function emitRefresh(socket) {
if (!noteId || !notes[noteId]) return;
var note = notes[noteId];
var out = {
+ title: note.title,
docmaxlength: config.documentmaxlength,
owner: note.owner,
ownerprofile: note.ownerprofile,
@@ -327,6 +330,15 @@ function emitRefresh(socket) {
socket.emit('refresh', out);
}
+function isDuplicatedInSocketQueue(queue, socket) {
+ for (var i = 0; i < queue.length; i++) {
+ if (queue[i] && queue[i].id == socket.id) {
+ return true;
+ }
+ }
+ return false;
+}
+
function clearSocketQueue(queue, socket) {
for (var i = 0; i < queue.length; i++) {
if (!queue[i] || queue[i].id == socket.id) {
@@ -381,6 +393,12 @@ function finishConnection(socket, note, user) {
note.server.setName(socket, user.name);
note.server.setColor(socket, user.color);
+ // update user note history
+ setTimeout(function () {
+ var noteId = note.alias ? note.alias : LZString.compressToBase64(note.id);
+ history.updateHistory(user.userid, noteId, note.server.document);
+ }, 0);
+
emitOnlineUsers(socket);
emitRefresh(socket);
@@ -459,6 +477,8 @@ function startConnection(socket) {
notes[noteId] = {
id: noteId,
+ alias: note.alias,
+ title: LZString.decompressFromBase64(note.title),
owner: owner,
ownerprofile: ownerprofile,
permission: note.permission,
@@ -509,17 +529,23 @@ function disconnect(socket) {
var noteId = socket.noteId;
var note = notes[noteId];
if (note) {
+ // delete user in users
delete note.users[socket.id];
+ // remove sockets in the note socks
do {
var index = note.socks.indexOf(socket);
if (index != -1) {
note.socks.splice(index, 1);
}
} while (index != -1);
+ // remove note in notes if no user inside
if (Object.keys(note.users).length <= 0) {
if (note.server.isDirty) {
updateNote(note, function (err, _note) {
if (err) return logger.error('disconnect note failed: ' + err);
+ // clear server before delete to avoid memory leaks
+ note.server.document = "";
+ note.server.operations = [];
delete note.server;
delete notes[noteId];
if (config.debug) {
@@ -640,108 +666,15 @@ function operationCallback(socket, operation) {
return logger.error('operation callback failed: ' + err);
});
}
+ // update user note history
+ setTimeout(function() {
+ var noteId = note.alias ? note.alias : LZString.compressToBase64(note.id);
+ history.updateHistory(userId, noteId, note.server.document);
+ }, 0);
+
}
// save authorship
- var index = 0;
- var authorships = note.authorship;
- var timestamp = Date.now();
- for (var i = 0; i < operation.length; i++) {
- var op = operation[i];
- if (ot.TextOperation.isRetain(op)) {
- index += op;
- } else if (ot.TextOperation.isInsert(op)) {
- var opStart = index;
- var opEnd = index + op.length;
- var inserted = false;
- // authorship format: [userId, startPos, endPos, createdAt, updatedAt]
- if (authorships.length <= 0) authorships.push([userId, opStart, opEnd, timestamp, timestamp]);
- else {
- for (var j = 0; j < authorships.length; j++) {
- var authorship = authorships[j];
- if (!inserted) {
- var nextAuthorship = authorships[j + 1] || -1;
- if (nextAuthorship != -1 && nextAuthorship[1] >= opEnd || j >= authorships.length - 1) {
- if (authorship[1] < opStart && authorship[2] > opStart) {
- // divide
- var postLength = authorship[2] - opStart;
- authorship[2] = opStart;
- authorship[4] = timestamp;
- authorships.splice(j + 1, 0, [userId, opStart, opEnd, timestamp, timestamp]);
- authorships.splice(j + 2, 0, [authorship[0], opEnd, opEnd + postLength, authorship[3], timestamp]);
- j += 2;
- inserted = true;
- } else if (authorship[1] >= opStart) {
- authorships.splice(j, 0, [userId, opStart, opEnd, timestamp, timestamp]);
- j += 1;
- inserted = true;
- } else if (authorship[2] <= opStart) {
- authorships.splice(j + 1, 0, [userId, opStart, opEnd, timestamp, timestamp]);
- j += 1;
- inserted = true;
- }
- }
- }
- if (authorship[1] >= opStart) {
- authorship[1] += op.length;
- authorship[2] += op.length;
- }
- }
- }
- index += op.length;
- } else if (ot.TextOperation.isDelete(op)) {
- var opStart = index;
- var opEnd = index - op;
- if (operation.length == 1) {
- authorships = [];
- } else if (authorships.length > 0) {
- for (var j = 0; j < authorships.length; j++) {
- var authorship = authorships[j];
- if (authorship[1] >= opStart && authorship[1] <= opEnd && authorship[2] >= opStart && authorship[2] <= opEnd) {
- authorships.splice(j, 1);
- j -= 1;
- } else if (authorship[1] < opStart && authorship[1] < opEnd && authorship[2] > opStart && authorship[2] > opEnd) {
- authorship[2] += op;
- authorship[4] = timestamp;
- } else if (authorship[2] >= opStart && authorship[2] <= opEnd) {
- authorship[2] = opStart;
- authorship[4] = timestamp;
- } else if (authorship[1] >= opStart && authorship[1] <= opEnd) {
- authorship[1] = opEnd;
- authorship[4] = timestamp;
- }
- if (authorship[1] >= opEnd) {
- authorship[1] += op;
- authorship[2] += op;
- }
- }
- }
- index += op;
- }
- }
- // merge
- for (var j = 0; j < authorships.length; j++) {
- var authorship = authorships[j];
- for (var k = j + 1; k < authorships.length; k++) {
- var nextAuthorship = authorships[k];
- if (nextAuthorship && authorship[0] === nextAuthorship[0] && authorship[2] === nextAuthorship[1]) {
- var minTimestamp = Math.min(authorship[3], nextAuthorship[3]);
- var maxTimestamp = Math.max(authorship[3], nextAuthorship[3]);
- authorships.splice(j, 1, [authorship[0], authorship[1], nextAuthorship[2], minTimestamp, maxTimestamp]);
- authorships.splice(k, 1);
- j -= 1;
- break;
- }
- }
- }
- // clear
- for (var j = 0; j < authorships.length; j++) {
- var authorship = authorships[j];
- if (!authorship[0]) {
- authorships.splice(j, 1);
- j -= 1;
- }
- }
- note.authorship = authorships;
+ note.authorship = models.Note.updateAuthorshipByOperation(operation, userId, note.authorship);
}
function connection(socket) {
@@ -753,6 +686,8 @@ function connection(socket) {
if (!noteId) {
return failConnection(404, 'note id not found', socket);
}
+
+ if (isDuplicatedInSocketQueue(socket, connectionSocketQueue)) return;
// store noteId in this socket session
socket.noteId = noteId;
@@ -864,6 +799,35 @@ function connection(socket) {
}
});
+ // delete a note
+ socket.on('delete', function () {
+ //need login to do more actions
+ if (socket.request.user && socket.request.user.logged_in) {
+ var noteId = socket.noteId;
+ if (!noteId || !notes[noteId]) return;
+ var note = notes[noteId];
+ //Only owner can delete note
+ if (note.owner && note.owner == socket.request.user.id) {
+ models.Note.destroy({
+ where: {
+ id: noteId
+ }
+ }).then(function (count) {
+ if (!count) return;
+ for (var i = 0, l = note.socks.length; i < l; i++) {
+ var sock = note.socks[i];
+ if (typeof sock !== 'undefined' && sock) {
+ sock.emit('delete');
+ return sock.disconnect(true);
+ }
+ }
+ }).catch(function (err) {
+ return logger.error('delete note failed: ' + err);
+ });
+ }
+ }
+ });
+
//reveiced when user logout or changed
socket.on('user changed', function () {
logger.info('user changed');
@@ -929,6 +893,7 @@ function connection(socket) {
//when a new client disconnect
socket.on('disconnect', function () {
+ if (isDuplicatedInSocketQueue(socket, disconnectSocketQueue)) return;
disconnectSocketQueue.push(socket);
disconnect(socket);
});