summaryrefslogtreecommitdiff
path: root/lib/realtime.js
diff options
context:
space:
mode:
authorWu Cheng-Han2015-07-11 12:43:08 +0800
committerWu Cheng-Han2015-07-11 12:43:08 +0800
commit556338a9c6964d110c1351a402b425c71c2571fa (patch)
treed5b6d2071e554e65c7bfaa4f2c84ddb034598e01 /lib/realtime.js
parent4702b83adc35f384e214a2a6e9199d08e4494093 (diff)
Added support of operational transformation
Diffstat (limited to '')
-rw-r--r--lib/realtime.js201
1 files changed, 78 insertions, 123 deletions
diff --git a/lib/realtime.js b/lib/realtime.js
index ca9cecd8..66a3c9c5 100644
--- a/lib/realtime.js
+++ b/lib/realtime.js
@@ -16,6 +16,9 @@ var moment = require('moment');
var config = require("../config.js");
var logger = require("./logger.js");
+//ot
+var ot = require("./ot/index.js");
+
//others
var db = require("./db.js");
var Note = require("./note.js");
@@ -60,28 +63,41 @@ function secure(socket, next) {
}
}
+function emitCheck(note) {
+ var out = {
+ updatetime: note.updatetime
+ };
+ for (var i = 0, l = note.socks.length; i < l; i++) {
+ var sock = note.socks[i];
+ sock.emit('check', out);
+ };
+}
+
//actions
var users = {};
var notes = {};
var updater = setInterval(function () {
async.each(Object.keys(notes), function (key, callback) {
var note = notes[key];
- if (note.isDirty) {
+ if (note.server.isDirty) {
if (config.debug)
logger.info("updater found dirty note: " + key);
- var body = LZString.decompressFromUTF16(note.body);
+ var body = note.server.document;
var title = Note.getNoteTitle(body);
title = LZString.compressToBase64(title);
body = LZString.compressToBase64(body);
- db.saveToDB(key, title, body,
- function (err, result) {});
- note.isDirty = false;
+ db.saveToDB(key, title, body, function (err, result) {
+ if (err) return;
+ note.server.isDirty = false;
+ note.updatetime = Date.now();
+ emitCheck(note);
+ });
}
callback();
}, function (err) {
if (err) return logger.error('updater error', err);
});
-}, 5000);
+}, 1000);
function getStatus(callback) {
db.countFromDB(function (err, data) {
@@ -189,9 +205,6 @@ function emitRefresh(socket) {
socket.emit('refresh', {
owner: note.owner,
permission: note.permission,
- body: note.body,
- otk: note.otk,
- hash: note.hash,
updatetime: note.updatetime
});
}
@@ -202,8 +215,13 @@ var isDisconnectBusy = false;
var disconnectSocketQueue = [];
function finishConnection(socket, notename) {
- notes[notename].users[socket.id] = users[socket.id];
- notes[notename].socks.push(socket);
+ var note = notes[notename];
+ note.users[socket.id] = users[socket.id];
+ note.socks.push(socket);
+ note.server.addClient(socket);
+ note.server.setName(socket, users[socket.id].name);
+ note.server.setColor(socket, users[socket.id].color);
+
emitOnlineUsers(socket);
emitRefresh(socket);
@@ -260,18 +278,16 @@ function startConnection(socket) {
return;
}
var body = LZString.decompressFromBase64(data.rows[0].content);
- body = LZString.compressToUTF16(body);
+ //body = LZString.compressToUTF16(body);
var updatetime = data.rows[0].update_time;
+ var server = new ot.EditorSocketIOServer(body, [], notename, ifMayEdit);
notes[notename] = {
owner: owner,
permission: note.permission,
socks: [],
- body: body,
- isDirty: false,
users: {},
- otk: shortId.generate(),
- hash: md5(body),
- updatetime: moment(updatetime).valueOf()
+ updatetime: moment(updatetime).valueOf(),
+ server: server
};
finishConnection(socket, notename);
});
@@ -294,17 +310,18 @@ function disconnect(socket) {
if (users[socket.id]) {
delete users[socket.id];
}
- if (notes[notename]) {
- delete notes[notename].users[socket.id];
+ var note = notes[notename];
+ if (note) {
+ delete note.users[socket.id];
do {
- var index = notes[notename].socks.indexOf(socket);
+ var index = note.socks.indexOf(socket);
if (index != -1) {
- notes[notename].socks.splice(index, 1);
+ note.socks.splice(index, 1);
}
} while (index != -1);
- if (Object.keys(notes[notename].users).length <= 0) {
- if (notes[notename].isDirty) {
- var body = LZString.decompressFromUTF16(notes[notename].body);
+ if (Object.keys(note.users).length <= 0) {
+ if (note.server.isDirty) {
+ var body = note.server.document;
var title = Note.getNoteTitle(body);
title = LZString.compressToBase64(title);
body = LZString.compressToBase64(body);
@@ -363,20 +380,20 @@ function updateUserData(socket, user) {
if (socket.request.user && socket.request.user.logged_in) {
var profile = JSON.parse(socket.request.user.profile);
var photo = null;
- switch(profile.provider) {
- case "facebook":
- photo = 'https://graph.facebook.com/' + profile.id + '/picture';
- break;
- case "twitter":
- photo = profile.photos[0].value;
- break;
- case "github":
- photo = 'https://avatars.githubusercontent.com/u/' + profile.id + '?s=48';
- break;
- case "dropbox":
- //no image api provided, use gravatar
- photo = 'https://www.gravatar.com/avatar/' + md5(profile.emails[0].value);
- break;
+ switch (profile.provider) {
+ case "facebook":
+ photo = 'https://graph.facebook.com/' + profile.id + '/picture';
+ break;
+ case "twitter":
+ photo = profile.photos[0].value;
+ break;
+ case "github":
+ photo = 'https://avatars.githubusercontent.com/u/' + profile.id + '?s=48';
+ break;
+ case "dropbox":
+ //no image api provided, use gravatar
+ photo = 'https://www.gravatar.com/avatar/' + md5(profile.emails[0].value);
+ break;
}
user.photo = photo;
user.name = profile.displayName || profile.username;
@@ -389,6 +406,29 @@ function updateUserData(socket, user) {
}
}
+function ifMayEdit(socket, callback) {
+ var notename = getNotenameFromSocket(socket);
+ if (!notename || !notes[notename]) return;
+ var note = notes[notename];
+ var mayEdit = true;
+ switch (note.permission) {
+ case "freely":
+ //not blocking anyone
+ break;
+ case "editable":
+ //only login user can change
+ if (!socket.request.user || !socket.request.user.logged_in)
+ mayEdit = false;
+ break;
+ case "locked":
+ //only owner can change
+ if (note.owner != socket.request.user._id)
+ mayEdit = false;
+ break;
+ }
+ callback(mayEdit);
+}
+
function connection(socket) {
//split notename from socket
var notename = getNotenameFromSocket(socket);
@@ -442,30 +482,6 @@ function connection(socket) {
emitRefresh(socket);
});
- //received client data updated
- socket.on('update', function (body_) {
- var notename = getNotenameFromSocket(socket);
- if (!notename || !notes[notename]) return;
- if (config.debug)
- logger.info('SERVER received [' + notename + '] data updated: ' + socket.id);
- var note = notes[notename];
- if (note.body != body_) {
- note.body = body_;
- note.hash = md5(body_);
- note.updatetime = Date.now();
- note.isDirty = true;
- }
- var out = {
- id: socket.id,
- hash: note.hash,
- updatetime: note.updatetime
- };
- for (var i = 0, l = note.socks.length; i < l; i++) {
- var sock = note.socks[i];
- sock.emit('check', out);
- };
- });
-
//received user status
socket.on('user status', function (data) {
var notename = getNotenameFromSocket(socket);
@@ -591,67 +607,6 @@ function connection(socket) {
disconnectSocketQueue.push(socket);
disconnect(socket);
});
-
- //when received client change data request
- socket.on('change', function (op) {
- var notename = getNotenameFromSocket(socket);
- if (!notename || !notes[notename]) return;
- var note = notes[notename];
- switch (note.permission) {
- case "freely":
- //not blocking anyone
- break;
- case "editable":
- //only login user can change
- if (!socket.request.user || !socket.request.user.logged_in)
- return;
- break;
- case "locked":
- //only owner can change
- if (note.owner != socket.request.user._id)
- return;
- break;
- }
- op = LZString.decompressFromUTF16(op);
- if (op)
- op = JSON.parse(op);
- else
- return;
- if (config.debug)
- logger.info('SERVER received [' + notename + '] data changed: ' + socket.id + ', op:' + JSON.stringify(op));
- switch (op.origin) {
- case '+input':
- case '+delete':
- case '+transpose':
- case 'paste':
- case 'cut':
- case 'undo':
- case 'redo':
- case 'drag':
- case '*compose':
- case 'case':
- case '+insert':
- case '+insertLine':
- case '+swapLine':
- case '+joinLines':
- case '+duplicateLine':
- case '+sortLines':
- op.id = socket.id;
- op.otk = note.otk;
- op.nextotk = note.otk = shortId.generate();
- var stringop = JSON.stringify(op);
- var compressstringop = LZString.compressToUTF16(stringop);
- for (var i = 0, l = note.socks.length; i < l; i++) {
- var sock = note.socks[i];
- if (config.debug)
- logger.info('SERVER emit sync data out [' + notename + ']: ' + sock.id + ', op:' + stringop);
- sock.emit('change', compressstringop);
- };
- break;
- default:
- logger.info('SERVER received uncaught [' + notename + '] data changed: ' + socket.id + ', op:' + JSON.stringify(op));
- }
- });
}
module.exports = realtime; \ No newline at end of file