|
@@ -6,6 +6,7 @@ Keys = require "./UpdateKeys"
|
|
|
{EventEmitter} = require "events"
|
|
{EventEmitter} = require "events"
|
|
|
util = require "util"
|
|
util = require "util"
|
|
|
RealTimeRedisManager = require "./RealTimeRedisManager"
|
|
RealTimeRedisManager = require "./RealTimeRedisManager"
|
|
|
|
|
+crypto = require "crypto"
|
|
|
|
|
|
|
|
ShareJsModel:: = {}
|
|
ShareJsModel:: = {}
|
|
|
util.inherits ShareJsModel, EventEmitter
|
|
util.inherits ShareJsModel, EventEmitter
|
|
@@ -22,7 +23,8 @@ module.exports = ShareJsUpdateManager =
|
|
|
applyUpdate: (project_id, doc_id, update, lines, version, callback = (error, updatedDocLines) ->) ->
|
|
applyUpdate: (project_id, doc_id, update, lines, version, callback = (error, updatedDocLines) ->) ->
|
|
|
logger.log project_id: project_id, doc_id: doc_id, update: update, "applying sharejs updates"
|
|
logger.log project_id: project_id, doc_id: doc_id, update: update, "applying sharejs updates"
|
|
|
jobs = []
|
|
jobs = []
|
|
|
-
|
|
|
|
|
|
|
+ # record the update version before it is modified
|
|
|
|
|
+ incomingUpdateVersion = update.version
|
|
|
# We could use a global model for all docs, but we're hitting issues with the
|
|
# We could use a global model for all docs, but we're hitting issues with the
|
|
|
# internal state of ShareJS not being accessible for clearing caches, and
|
|
# internal state of ShareJS not being accessible for clearing caches, and
|
|
|
# getting stuck due to queued callbacks (line 260 of sharejs/server/model.coffee)
|
|
# getting stuck due to queued callbacks (line 260 of sharejs/server/model.coffee)
|
|
@@ -42,6 +44,10 @@ module.exports = ShareJsUpdateManager =
|
|
|
logger.log project_id: project_id, doc_id: doc_id, error: error, "applied update"
|
|
logger.log project_id: project_id, doc_id: doc_id, error: error, "applied update"
|
|
|
model.getSnapshot doc_key, (error, data) =>
|
|
model.getSnapshot doc_key, (error, data) =>
|
|
|
return callback(error) if error?
|
|
return callback(error) if error?
|
|
|
|
|
+ # only check hash when present and no other updates have been applied
|
|
|
|
|
+ if update.hash? and incomingUpdateVersion == version
|
|
|
|
|
+ ourHash = ShareJsUpdateManager._computeHash(data.snapshot)
|
|
|
|
|
+ return callback(new Error("Invalid hash")) if ourHash != update.hash
|
|
|
docLines = data.snapshot.split(/\r\n|\n|\r/)
|
|
docLines = data.snapshot.split(/\r\n|\n|\r/)
|
|
|
callback(null, docLines, data.v, model.db.appliedOps[doc_key] or [])
|
|
callback(null, docLines, data.v, model.db.appliedOps[doc_key] or [])
|
|
|
|
|
|
|
@@ -53,3 +59,9 @@ module.exports = ShareJsUpdateManager =
|
|
|
_sendOp: (project_id, doc_id, op) ->
|
|
_sendOp: (project_id, doc_id, op) ->
|
|
|
RealTimeRedisManager.sendData {project_id, doc_id, op}
|
|
RealTimeRedisManager.sendData {project_id, doc_id, op}
|
|
|
|
|
|
|
|
|
|
+ _computeHash: (content) ->
|
|
|
|
|
+ return crypto.createHash('sha1')
|
|
|
|
|
+ .update("blob " + content.length + "\x00")
|
|
|
|
|
+ .update(content, 'utf8')
|
|
|
|
|
+ .digest('hex')
|
|
|
|
|
+
|