2014-03-05 10:59:40 -05:00
|
|
|
UpdatesManager = require "./UpdatesManager"
|
2014-03-04 09:05:17 -05:00
|
|
|
DocumentUpdaterManager = require "./DocumentUpdaterManager"
|
|
|
|
DiffGenerator = require "./DiffGenerator"
|
2014-03-04 10:27:03 -05:00
|
|
|
logger = require "logger-sharelatex"
|
2014-03-04 09:05:17 -05:00
|
|
|
|
2014-03-04 08:02:48 -05:00
|
|
|
module.exports = DiffManager =
|
2017-06-28 10:38:31 -04:00
|
|
|
getLatestDocAndUpdates: (project_id, doc_id, fromVersion, callback = (error, content, version, updates) ->) ->
|
2016-09-30 06:36:47 -04:00
|
|
|
# Get updates last, since then they must be ahead and it
|
|
|
|
# might be possible to rewind to the same version as the doc.
|
|
|
|
DocumentUpdaterManager.getDocument project_id, doc_id, (error, content, version) ->
|
2014-03-04 09:05:17 -05:00
|
|
|
return callback(error) if error?
|
2017-06-28 10:38:31 -04:00
|
|
|
if !fromVersion? # If we haven't been given a version, just return lastest doc and no updates
|
|
|
|
return callback(null, content, version, [])
|
|
|
|
UpdatesManager.getDocUpdatesWithUserInfo project_id, doc_id, from: fromVersion, (error, updates) ->
|
2014-03-04 09:05:17 -05:00
|
|
|
return callback(error) if error?
|
2014-03-10 12:03:03 -04:00
|
|
|
callback(null, content, version, updates)
|
2014-03-04 09:05:17 -05:00
|
|
|
|
2014-03-06 05:45:51 -05:00
|
|
|
getDiff: (project_id, doc_id, fromVersion, toVersion, callback = (error, diff) ->) ->
|
2014-03-10 12:03:03 -04:00
|
|
|
DiffManager.getDocumentBeforeVersion project_id, doc_id, fromVersion, (error, startingContent, updates) ->
|
2015-10-16 06:24:50 -04:00
|
|
|
if error?
|
|
|
|
if error.message == "broken-history"
|
|
|
|
return callback(null, "history unavailable")
|
|
|
|
else
|
|
|
|
return callback(error)
|
2014-03-04 10:27:03 -05:00
|
|
|
|
2014-03-04 09:05:17 -05:00
|
|
|
updatesToApply = []
|
2014-03-10 12:03:03 -04:00
|
|
|
for update in updates.slice().reverse()
|
2014-03-06 05:45:51 -05:00
|
|
|
if update.v <= toVersion
|
2014-03-04 09:05:17 -05:00
|
|
|
updatesToApply.push update
|
|
|
|
|
|
|
|
try
|
|
|
|
diff = DiffGenerator.buildDiff startingContent, updatesToApply
|
|
|
|
catch e
|
|
|
|
return callback(e)
|
|
|
|
|
2014-03-10 12:03:03 -04:00
|
|
|
callback(null, diff)
|
|
|
|
|
2016-09-30 06:36:47 -04:00
|
|
|
getDocumentBeforeVersion: (project_id, doc_id, version, _callback = (error, document, rewoundUpdates) ->) ->
|
|
|
|
# Whichever order we get the latest document and the latest updates,
|
|
|
|
# there is potential for updates to be applied between them so that
|
|
|
|
# they do not return the same 'latest' versions.
|
|
|
|
# If this happens, we just retry and hopefully get them at the compatible
|
|
|
|
# versions.
|
|
|
|
retries = 3
|
|
|
|
callback = (error, args...) ->
|
|
|
|
if error?
|
|
|
|
if error.retry and retries > 0
|
2016-09-30 08:38:47 -04:00
|
|
|
logger.warn {error, project_id, doc_id, version, retries}, "retrying getDocumentBeforeVersion"
|
2016-09-30 06:36:47 -04:00
|
|
|
retry()
|
|
|
|
else
|
|
|
|
_callback(error)
|
|
|
|
else
|
|
|
|
_callback(null, args...)
|
|
|
|
|
|
|
|
do retry = () ->
|
|
|
|
retries--
|
|
|
|
DiffManager._tryGetDocumentBeforeVersion(project_id, doc_id, version, callback)
|
|
|
|
|
|
|
|
_tryGetDocumentBeforeVersion: (project_id, doc_id, version, callback = (error, document, rewoundUpdates) ->) ->
|
2014-03-10 12:03:03 -04:00
|
|
|
logger.log project_id: project_id, doc_id: doc_id, version: version, "getting document before version"
|
2017-06-28 10:38:31 -04:00
|
|
|
DiffManager.getLatestDocAndUpdates project_id, doc_id, version, (error, content, version, updates) ->
|
2014-03-10 12:03:03 -04:00
|
|
|
return callback(error) if error?
|
|
|
|
|
2015-10-16 06:24:50 -04:00
|
|
|
# bail out if we hit a broken update
|
|
|
|
for u in updates when u.broken
|
|
|
|
return callback new Error "broken-history"
|
|
|
|
|
2015-12-18 07:38:42 -05:00
|
|
|
# discard any updates which are ahead of this document version
|
|
|
|
while updates[0]?.v >= version
|
|
|
|
updates.shift()
|
|
|
|
|
2014-03-10 12:03:03 -04:00
|
|
|
lastUpdate = updates[0]
|
|
|
|
if lastUpdate? and lastUpdate.v != version - 1
|
2016-09-30 06:36:47 -04:00
|
|
|
error = new Error("latest update version, #{lastUpdate.v}, does not match doc version, #{version}")
|
|
|
|
error.retry = true
|
2016-09-30 08:36:31 -04:00
|
|
|
return callback error
|
2016-09-22 06:13:26 -04:00
|
|
|
|
|
|
|
logger.log {docVersion: version, lastUpdateVersion: lastUpdate?.v, updateCount: updates.length}, "rewinding updates"
|
2014-03-10 12:03:03 -04:00
|
|
|
|
2015-12-04 08:57:15 -05:00
|
|
|
tryUpdates = updates.slice().reverse()
|
|
|
|
|
2014-03-10 12:03:03 -04:00
|
|
|
try
|
2015-12-04 08:57:15 -05:00
|
|
|
startingContent = DiffGenerator.rewindUpdates content, tryUpdates
|
|
|
|
# tryUpdates is reversed, and any unapplied ops are marked as broken
|
2014-03-10 12:03:03 -04:00
|
|
|
catch e
|
|
|
|
return callback(e)
|
2015-12-04 08:57:15 -05:00
|
|
|
|
|
|
|
callback(null, startingContent, tryUpdates)
|