Implement lock mechanisms for spreadsheets

pull/1/head
yflory 6 years ago
parent 2ac176eeec
commit ec2f21ec64

@ -4,7 +4,8 @@ www/common/pdfjs/
www/common/tippy/ www/common/tippy/
www/common/highlight/ www/common/highlight/
www/common/jquery-ui/ www/common/jquery-ui/
www/common/onlyoffice/* www/common/onlyoffice/sdkjs
www/common/onlyoffice/web-apps
server.js server.js
www/common/old-media-tag.js www/common/old-media-tag.js

@ -68,7 +68,15 @@ define([
hashes: {}, hashes: {},
ids: {} ids: {}
}; };
var oldIds = {};
var oldLocks = {};
var myUniqueOOId;
var myOOId; var myOOId;
var sessionId = Hash.createChannelId();
var getId = function () {
return metadataMgr.getNetfluxId() + '-' + privateData.clientId;
};
var deleteOffline = function () { var deleteOffline = function () {
var ids = content.ids; var ids = content.ids;
@ -88,11 +96,22 @@ define([
var ids = content.ids; var ids = content.ids;
// Check if the provided id is in the ID list // Check if the provided id is in the ID list
return Object.keys(ids).some(function (id) { return Object.keys(ids).some(function (id) {
return ooid === ids[id]; return ooid === ids[id].ooid;
});
};
var getUserIndex = function () {
var i = 1;
var ids = content.ids || {};
Object.keys(ids).forEach(function (k) {
if (ids[k] && ids[k].index && ids[k].index >= i) {
i = ids[k].index + 1;
}
}); });
return i;
}; };
var setMyId = function (netfluxId) { var setMyId = function () {
// Remove ids for users that have left the channel // Remove ids for users that have left the channel
deleteOffline(); deleteOffline();
var ids = content.ids; var ids = content.ids;
@ -104,8 +123,13 @@ define([
myOOId = Util.createRandomInteger(); myOOId = Util.createRandomInteger();
} }
} }
var myId = (netfluxId || metadataMgr.getNetfluxId()) + '-' + privateData.clientId; var myId = getId();
ids[myId] = myOOId; ids[myId] = {
ooid: myOOId,
index: getUserIndex(),
netflux: metadataMgr.getNetfluxId()
};
oldIds = JSON.parse(JSON.stringify(ids));
APP.onLocal(); APP.onLocal();
}; };
@ -116,6 +140,7 @@ define([
if (content.ids[tabId]) { if (content.ids[tabId]) {
console.log('delete'); console.log('delete');
delete content.ids[tabId]; delete content.ids[tabId];
delete content.locks[tabId];
APP.onLocal(); APP.onLocal();
console.log(content.ids); console.log(content.ids);
} }
@ -289,6 +314,233 @@ define([
cb(); cb();
}; };
var getParticipants = function () {
var users = metadataMgr.getMetadata().users;
var i = 1;
var p = Object.keys(content.ids || {}).map(function (id) {
var nId = id.slice(0,32);
var ooId = content.ids[id].ooid;
var idx = content.ids[id].index;
if (!ooId || ooId === myOOId) { return; }
if (idx >= i) { i = idx + 1; }
return {
id: String(ooId) + idx,
idOriginal: String(ooId),
username: (users[nId] || {}).name || Messages.anonymous,
indexUser: idx,
connectionId: content.ids[id].netflux || Hash.createChannelId(),
isCloseCoAuthoring:false,
view: false
};
});
if (!myUniqueOOId) { myUniqueOOId = String(myOOId) + i; }
p.push({
id: myUniqueOOId,
idOriginal: String(myOOId),
username: metadataMgr.getUserData().name || Messages.anonymous,
indexUser: i,
connectionId: metadataMgr.getNetfluxId() || Hash.createChannelId(),
isCloseCoAuthoring:false,
view: false
});
console.log(p.filter(Boolean));
return {
index: i,
list: p.filter(Boolean)
};
};
var handleNewIds = function (o, n) {
console.log('handle nw ids');
if (stringify(o) === stringify(n)) { return; }
console.log(n);
var p = getParticipants();
ooChannel.send({
type: "connectState",
participantsTimestamp: +new Date(),
participants: p.list,
waitAuth: false
});
/*
Object.keys(n).forEach(function (id) {
var nId = id.slice(0,32);
if (!o[id]) {
console.log('new user');
ooChannel.send({
type: "connectState",
state: true,
user: {
id: String(n[id].ooid) + "1",
idOriginal: String(n[id].ooid),
username: (users[nId] || {}).name || Messages.anonymous,
indexUser: n[id].index,
view: false
}
});
return;
}
});
Object.keys(o).forEach(function (id) {
var nId = id.slice(0,32);
if (!n[id]) {
console.log('leaving user');
ooChannel.send({
type: "connectState",
state: false,
user: {
id: String(o[id].ooid) + "1",
idOriginal: String(o[id].ooid),
username: (users[nId] || {}).name || Messages.anonymous,
indexUser: o[id].index,
view: false
}
});
return;
}
});
*/
};
var handleNewLocks = function (o, n) {
Object.keys(n).forEach(function (id) {
if (!o[id]) {
console.log('new lock');
ooChannel.send({
type: "getLock",
locks: getLock()
});
return;
}
if (stringify(n[id]) !== stringify(o[id])) {
console.log('changed lock');
ooChannel.send({
type: "releaseLock",
locks: [o[id]]
});
ooChannel.send({
type: "getLock",
locks: getLock()
});
}
});
Object.keys(o).forEach(function (id) {
if (!n[id]) {
console.log('released lock');
ooChannel.send({
type: "releaseLock",
locks: [o[id]]
});
return;
}
});
};
var handleAuth = function (obj, send) {
ooChannel.ready = true;
var changes = [];
ooChannel.queue.forEach(function (data) {
Array.prototype.push.apply(changes, data.msg.changes);
});
var p = getParticipants();
send({
type: "authChanges",
changes: changes
});
send({
type: "auth",
result: 1,
sessionId: sessionId, //"08e77705-dc5c-477d-b73a-b1a7cbca1e9b",
// XXX add all users from chainpad
participants: p.list,
locks: [],
changes: [],
changesIndex: 0,
indexUser: p.index,
buildVersion: "5.2.6",
buildNumber: 2,
licenseType: 3,
"g_cAscSpellCheckUrl": "/spellchecker",
"settings":{"spellcheckerUrl":"/spellchecker","reconnection":{"attempts":50,"delay":2000}}
});
send({
type: "documentOpen",
data: {"type":"open","status":"ok","data":{"Editor.bin":obj.openCmd.url}}
});
var last = ooChannel.queue.pop();
ooChannel.lastHash = last.hash;
ooChannel.cpIndex += ooChannel.queue.length;
deleteOfflineLocks();
APP.onLocal();
handleNewLocks(oldLocks, content.locks || {});
/*setTimeout(function () {
if (ooChannel.queue) {
ooChannel.queue.forEach(function (data) {
send(data.msg);
ooChannel.lastHash = data.hash;
ooChannel.cpIndex++;
});
}
deleteOfflineLocks();
APP.onLocal();
handleNewLocks(oldLocks, content.locks || {});
}, 200);*/
};
var deleteOfflineLocks = function () {
var locks = content.locks || {};
var users = Object.keys(metadataMgr.getMetadata().users);
console.log('delete offline locks');
console.log(users);
Object.keys(locks).forEach(function (id) {
var nId = id.slice(0,32);
console.log(nId);
if (users.indexOf(nId) === -1) {
console.log('deleted');
ooChannel.send({
type: "releaseLock",
locks: [locks[id]]
});
delete content.locks[id];
}
});
};
var getLock = function () {
return Object.keys(content.locks).map(function (id) {
return content.locks[id];
});
};
var handleLock = function (obj, send) {
console.log('handle lock');
content.locks = content.locks || {};
deleteOfflineLocks();
// XXX store in chainpad
var msg = {
time: now(),
user: myUniqueOOId,
block: obj.block && obj.block[0],
}
var myId = getId();
/*if (content.locks[myId]) {
send({
type: "releaseLock",
locks: [content.locks[myId]]
});
}*/
content.locks[myId] = msg;
oldLocks = JSON.parse(JSON.stringify(content.locks));
APP.onLocal();
send({
type: "getLock",
locks: getLock()
});
//APP.realtime.onSettle(function () {
console.log(getLock());
console.log(oldLocks);
//});
};
var parseChanges = function (changes) { var parseChanges = function (changes) {
try { try {
changes = JSON.parse(changes); changes = JSON.parse(changes);
@ -300,8 +552,8 @@ define([
docid: "fresh", docid: "fresh",
change: '"' + change + '"', change: '"' + change + '"',
time: now(), time: now(),
user: "test", // XXX get username user: myUniqueOOId, // XXX get username
useridoriginal: "test" // get user id from worker? useridoriginal: String(myOOId) // get user id from worker?
}; };
}); });
}; };
@ -326,37 +578,7 @@ define([
var msg, msg2; var msg, msg2;
switch (obj.type) { switch (obj.type) {
case "auth": case "auth":
ooChannel.ready = true; handleAuth(obj, send);
send({
type: "auth",
result: 1,
sessionId: "08e77705-dc5c-477d-b73a-b1a7cbca1e9b",
participants: [{
id: "myid1",
idOriginal: "myid",
username: "User",
indexUser: 1,
view: false
}],
locks: [],
changes: [],
changesIndex: 0,
indexUser: 1,
"g_cAscSpellCheckUrl": "/spellchecker"
});
send({
type: "documentOpen",
data: {"type":"open","status":"ok","data":{"Editor.bin":obj.openCmd.url}}
});
setTimeout(function () {
if (ooChannel.queue) {
ooChannel.queue.forEach(function (data) {
send(data.msg);
ooChannel.lastHash = data.hash;
ooChannel.cpIndex++;
});
}
}, 2000);
break; break;
case "isSaveLock": case "isSaveLock":
msg = { msg = {
@ -366,16 +588,7 @@ define([
send(msg); send(msg);
break; break;
case "getLock": case "getLock":
msg = { handleLock(obj, send);
type: "getLock",
locks: [{
time: now(),
user: "myid1",
block: obj.block && obj.block[0],
sessionId: "08e77705-dc5c-477d-b73a-b1a7cbca1e9b"
}]
}
send(msg);
break; break;
case "getMessages": case "getMessages":
send({ type: "message" }); send({ type: "message" });
@ -385,12 +598,14 @@ define([
send({ send({
type: "unSaveLock", type: "unSaveLock",
index: ooChannel.cpIndex, index: ooChannel.cpIndex,
time: +new Date()
}); });
// Send the change
rtChannel.sendMsg({ rtChannel.sendMsg({
type: "saveChanges", type: "saveChanges",
changes: parseChanges(obj.changes), changes: parseChanges(obj.changes),
changesIndex: ooChannel.cpIndex || 0, changesIndex: ooChannel.cpIndex || 0,
locks: [], // XXX take from userdoc? locks: [content.locks[getId()]], // XXX take from userdoc?
excelAdditionalInfo: null excelAdditionalInfo: null
}, null, function (err, hash) { }, null, function (err, hash) {
ooChannel.cpIndex++; ooChannel.cpIndex++;
@ -398,8 +613,29 @@ define([
if (ooChannel.cpIndex % CHECKPOINT_INTERVAL === 0) { if (ooChannel.cpIndex % CHECKPOINT_INTERVAL === 0) {
makeCheckpoint(); makeCheckpoint();
} }
// Remove my lock
delete content.locks[getId()];
oldLocks = JSON.parse(JSON.stringify(content.locks));
APP.onLocal();
}); });
break; break;
case "unLockDocument":
if (obj.releaseLocks && content.locks[getId()]) {
send({
type: "releaseLock",
locks: [content.locks[getId()]]
});
delete content.locks[getId()];
APP.onLocal();
}
if (obj.isSave) {
send({
type: "unSaveLock",
time: -1,
index: -1
});
}
break;
} }
}); });
}); });
@ -421,6 +657,7 @@ define([
"permissions": { "permissions": {
"download": false, // FIXME: download/export is not working, so we use false "download": false, // FIXME: download/export is not working, so we use false
// to remove the button // to remove the button
"print": false,
} }
}, },
"documentType": file.doc, "documentType": file.doc,
@ -432,8 +669,8 @@ define([
} }
}, },
"user": { "user": {
"id": "myid", //"c0c3bf82-20d7-4663-bf6d-7fa39c598b1d", "id": String(myOOId), //"c0c3bf82-20d7-4663-bf6d-7fa39c598b1d",
"name": "User", //"John Smith" "firstname": metadataMgr.getUserData().name || Messages.anonymous,
}, },
"mode": readOnly || lock ? "view" : "edit" "mode": readOnly || lock ? "view" : "edit"
}, },
@ -521,7 +758,7 @@ define([
var cpNfInner; var cpNfInner;
config = { config = {
patchTransformer: ChainPad.NaiveJSONTransformer, patchTransformer: ChainPad.SmartJSONTransformer,
// cryptpad debug logging (default is 1) // cryptpad debug logging (default is 1)
// logLevel: 0, // logLevel: 0,
validateContent: function (content) { validateContent: function (content) {
@ -554,7 +791,7 @@ define([
if (initializing) { return; } if (initializing) { return; }
if (readOnly) { return; } if (readOnly) { return; }
console.log('onLocal, data avalable'); console.error('onLocal, data available');
// Update metadata // Update metadata
var content = stringifyInner(); var content = stringifyInner();
APP.realtime.contentUpdate(content); APP.realtime.contentUpdate(content);
@ -657,9 +894,9 @@ define([
} }
openRtChannel(function () { openRtChannel(function () {
setMyId();
loadDocument(newDoc); loadDocument(newDoc);
initializing = false; initializing = false;
setMyId();
setEditable(!readOnly); setEditable(!readOnly);
UI.removeLoadingScreen(); UI.removeLoadingScreen();
}); });
@ -674,6 +911,18 @@ define([
metadataMgr.updateMetadata(json.metadata); metadataMgr.updateMetadata(json.metadata);
} }
content = json.content; content = json.content;
console.log(content);
if (content.ids) {
handleNewIds(oldIds, content.ids);
oldIds = JSON.parse(JSON.stringify(content.ids));
}
if (content.locks) {
console.log(content.locks);
console.log(oldLocks);
handleNewLocks(oldLocks, content.locks);
// XXX send locks to oo
oldLocks = JSON.parse(JSON.stringify(content.locks));
}
}; };
config.onAbort = function () { config.onAbort = function () {

@ -4186,85 +4186,87 @@ AscBrowser.convertToRetinaValue = function(value, isScale)
}); });
}; };
DocsCoApi.prototype._initSocksJs = function () { DocsCoApi.prototype._initSocksJs = function () {
var t = this; var t = this;
var sockjs; var sockjs;
sockjs = this.sockjs = {}; sockjs = this.sockjs = {};
var send = function (data) { var send = function (data) {
setTimeout(function () { setTimeout(function () {
console.log(data); console.log(data);
sockjs.onmessage({ sockjs.onmessage({
data: JSON.stringify(data) data: JSON.stringify(data)
}); });
}); });
}; };
var license = { var license = {
type: 'license', type: 'license',
license: { license: {
type: 3, type: 3,
light: false, mode: 0,
trial: false, //light: false,
rights: 1, //trial: false,
buildVersion: "5.2.6", rights: 1,
buildNumber: 5, buildVersion: "5.2.6",
branding: false buildNumber: 2,
} //branding: false
}; }
};
var channel;
var channel;
require([
'/common/outer/worker-channel.js', require([
'/common/common-util.js' '/common/outer/worker-channel.js',
], function (Channel, Util) { '/common/common-util.js'
var msgEv = Util.mkEvent(); ], function (Channel, Util) {
var p = window.parent; var msgEv = Util.mkEvent();
window.addEventListener('message', function (msg) { var p = window.parent;
if (msg.source !== p) { return; } window.addEventListener('message', function (msg) {
msgEv.fire(msg); if (msg.source !== p) { return; }
}); msgEv.fire(msg);
var postMsg = function (data) { });
p.postMessage(data, '*'); var postMsg = function (data) {
}; p.postMessage(data, '*');
Channel.create(msgEv, postMsg, function (chan) { };
channel = chan; Channel.create(msgEv, postMsg, function (chan) {
send(license); channel = chan;
send(license);
chan.on('CMD', function (obj) { chan.on('CMD', function (obj) {
send(obj); send(obj);
}); });
}); });
}); });
sockjs.onopen = function() { sockjs.onopen = function() {
t._state = ConnectionState.WaitAuth; t._state = ConnectionState.WaitAuth;
t.onFirstConnect(); t.onFirstConnect();
}; };
sockjs.onopen(); sockjs.onopen();
sockjs.close = function () { sockjs.close = function () {
console.error('Close realtime'); console.error('Close realtime');
}; };
sockjs.send = function (data) { sockjs.send = function (data) {
console.log(data); console.log(data);
try { try {
var obj = JSON.parse(data); var obj = JSON.parse(data);
} catch (e) { } catch (e) {
console.error(e); console.error(e);
return; return;
} }
if (channel) { if (channel) {
channel.event('CMD', obj); channel.event('CMD', obj);
} }
}; };
sockjs.onmessage = function (e) { sockjs.onmessage = function (e) {
t._onServerMessage(e.data); t._onServerMessage(e.data);
}; };
return sockjs; return sockjs;
}; };
DocsCoApi.prototype._onServerOpen = function () { DocsCoApi.prototype._onServerOpen = function () {
if (this.reconnectTimeout) { if (this.reconnectTimeout) {

@ -4186,105 +4186,86 @@ AscBrowser.convertToRetinaValue = function(value, isScale)
}); });
}; };
DocsCoApi.prototype._initSocksJs = function () { DocsCoApi.prototype._initSocksJs = function () {
var t = this; var t = this;
var sockjs; var sockjs;
sockjs = this.sockjs = {}; sockjs = this.sockjs = {};
var send = function (data) { var send = function (data) {
setTimeout(function () { setTimeout(function () {
console.log(data); console.log(data);
this.onmessage({ sockjs.onmessage({
data: JSON.stringify(data) data: JSON.stringify(data)
}); });
}); });
}; };
var license = { var license = {
type: 'license', type: 'license',
license: { license: {
type: 3, type: 3,
light: false, light: false,
trial: false, trial: false,
rights: 1, rights: 1,
buildVersion: "4.3.3", buildVersion: "5.2.6",
buildNumber: 4, buildNumber: 5,
branding: false branding: false
} }
}; };
var channel; var channel;
send(license); require([
'/common/outer/worker-channel.js',
require([ '/common/common-util.js'
'/common/outer/worker-channel.js', ], function (Channel, Util) {
'/common/common-util.js' var msgEv = Util.mkEvent();
], function (Channel, Util) { var p = window.parent;
var msgEv = Util.mkEvent(); window.addEventListener('message', function (msg) {
var p = window.parent; if (msg.source !== p) { return; }
window.addEventListener('message', function (msg) { msgEv.fire(msg);
if (msg.source !== p) { return; } });
msgEv.fire(msg); var postMsg = function (data) {
}); p.postMessage(data, '*');
var postMsg = function (data) { };
p.postMessage(data, '*'); Channel.create(msgEv, postMsg, function (chan) {
}; channel = chan;
Channel.create(msgEv, postMsg, function (chan) { send(license);
channel = chan;
send(license); chan.on('CMD', function (obj) {
chan.on('RTMSG', function (data) { send(obj);
console.log('receiving RTMSG', data); });
}); });
}); });
});
sockjs.onopen = function() {
sockjs.onopen = function() { t._state = ConnectionState.WaitAuth;
t._state = ConnectionState.WaitAuth; t.onFirstConnect();
t.onFirstConnect(); };
}; sockjs.onopen();
sockjs.onopen();
sockjs.close = function () {
sockjs.close = function () { console.error('Close realtime');
console.error('Close realtime'); };
};
sockjs.send = function (data) {
sockjs.send = function (data) { console.log(data);
console.log(data); try {
try { var obj = JSON.parse(data);
var obj = JSON.parse(data); } catch (e) {
} catch (e) { console.error(e);
console.error(e); return;
return; }
} if (channel) {
var msg, msg2; channel.event('CMD', obj);
switch (obj.type) { }
case 'auth': };
msg = {
"type":"auth",
"result":1,
"sessionId":"08e77705-dc5c-477d-b73a-b1a7cbca1e9b",
"sessionTimeConnect":+new Date(),
"participants":[]
};
msg2 = {
"type":"documentOpen",
"data":{"type":"open","status":"ok","data":{"Editor.bin":obj.openCmd.url}}
};
send(msg);
send(msg2);
break;
case 'getMessages':
msg = {};
break;
}
};
sockjs.onmessage = function (e) { sockjs.onmessage = function (e) {
t._onServerMessage(e.data); t._onServerMessage(e.data);
}; };
return sockjs; return sockjs;
}; };
DocsCoApi.prototype._onServerOpen = function () { DocsCoApi.prototype._onServerOpen = function () {
if (this.reconnectTimeout) { if (this.reconnectTimeout) {

@ -4186,105 +4186,86 @@ AscBrowser.convertToRetinaValue = function(value, isScale)
}); });
}; };
DocsCoApi.prototype._initSocksJs = function () { DocsCoApi.prototype._initSocksJs = function () {
var t = this; var t = this;
var sockjs; var sockjs;
sockjs = this.sockjs = {}; sockjs = this.sockjs = {};
var send = function (data) { var send = function (data) {
setTimeout(function () { setTimeout(function () {
console.log(data); console.log(data);
this.onmessage({ sockjs.onmessage({
data: JSON.stringify(data) data: JSON.stringify(data)
}); });
}); });
}; };
var license = { var license = {
type: 'license', type: 'license',
license: { license: {
type: 3, type: 3,
light: false, light: false,
trial: false, trial: false,
rights: 1, rights: 1,
buildVersion: "4.3.3", buildVersion: "5.2.6",
buildNumber: 4, buildNumber: 5,
branding: false branding: false
} }
}; };
var channel; var channel;
send(license); require([
'/common/outer/worker-channel.js',
require([ '/common/common-util.js'
'/common/outer/worker-channel.js', ], function (Channel, Util) {
'/common/common-util.js' var msgEv = Util.mkEvent();
], function (Channel, Util) { var p = window.parent;
var msgEv = Util.mkEvent(); window.addEventListener('message', function (msg) {
var p = window.parent; if (msg.source !== p) { return; }
window.addEventListener('message', function (msg) { msgEv.fire(msg);
if (msg.source !== p) { return; } });
msgEv.fire(msg); var postMsg = function (data) {
}); p.postMessage(data, '*');
var postMsg = function (data) { };
p.postMessage(data, '*'); Channel.create(msgEv, postMsg, function (chan) {
}; channel = chan;
Channel.create(msgEv, postMsg, function (chan) { send(license);
channel = chan;
send(license); chan.on('CMD', function (obj) {
chan.on('RTMSG', function (data) { send(obj);
console.log('receiving RTMSG', data); });
}); });
}); });
});
sockjs.onopen = function() {
sockjs.onopen = function() { t._state = ConnectionState.WaitAuth;
t._state = ConnectionState.WaitAuth; t.onFirstConnect();
t.onFirstConnect(); };
}; sockjs.onopen();
sockjs.onopen();
sockjs.close = function () {
sockjs.close = function () { console.error('Close realtime');
console.error('Close realtime'); };
};
sockjs.send = function (data) {
sockjs.send = function (data) { console.log(data);
console.log(data); try {
try { var obj = JSON.parse(data);
var obj = JSON.parse(data); } catch (e) {
} catch (e) { console.error(e);
console.error(e); return;
return; }
} if (channel) {
var msg, msg2; channel.event('CMD', obj);
switch (obj.type) { }
case 'auth': };
msg = {
"type":"auth",
"result":1,
"sessionId":"08e77705-dc5c-477d-b73a-b1a7cbca1e9b",
"sessionTimeConnect":+new Date(),
"participants":[]
};
msg2 = {
"type":"documentOpen",
"data":{"type":"open","status":"ok","data":{"Editor.bin":obj.openCmd.url}}
};
send(msg);
send(msg2);
break;
case 'getMessages':
msg = {};
break;
}
};
sockjs.onmessage = function (e) { sockjs.onmessage = function (e) {
t._onServerMessage(e.data); t._onServerMessage(e.data);
}; };
return sockjs; return sockjs;
}; };
DocsCoApi.prototype._onServerOpen = function () { DocsCoApi.prototype._onServerOpen = function () {
if (this.reconnectTimeout) { if (this.reconnectTimeout) {

Loading…
Cancel
Save