| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- RedisManager = require "./RedisManager"
- ProjectHistoryRedisManager = require "./ProjectHistoryRedisManager"
- DocumentManager = require "./DocumentManager"
- HistoryManager = require "./HistoryManager"
- async = require "async"
- logger = require "logger-sharelatex"
- Metrics = require "./Metrics"
- Errors = require "./Errors"
- module.exports = ProjectManager =
- flushProjectWithLocks: (project_id, _callback = (error) ->) ->
- timer = new Metrics.Timer("projectManager.flushProjectWithLocks")
- callback = (args...) ->
- timer.done()
- _callback(args...)
- RedisManager.getDocIdsInProject project_id, (error, doc_ids) ->
- return callback(error) if error?
- jobs = []
- errors = []
- for doc_id in (doc_ids or [])
- do (doc_id) ->
- jobs.push (callback) ->
- DocumentManager.flushDocIfLoadedWithLock project_id, doc_id, (error) ->
- if error? and error instanceof Errors.NotFoundError
- logger.warn err: error, project_id: project_id, doc_id: doc_id, "found deleted doc when flushing"
- callback()
- else if error?
- logger.error err: error, project_id: project_id, doc_id: doc_id, "error flushing doc"
- errors.push(error)
- callback()
- else
- callback()
- logger.log project_id: project_id, doc_ids: doc_ids, "flushing docs"
- async.series jobs, () ->
- if errors.length > 0
- callback new Error("Errors flushing docs. See log for details")
- else
- callback(null)
- flushAndDeleteProjectWithLocks: (project_id, _callback = (error) ->) ->
- timer = new Metrics.Timer("projectManager.flushAndDeleteProjectWithLocks")
- callback = (args...) ->
- timer.done()
- _callback(args...)
- RedisManager.getDocIdsInProject project_id, (error, doc_ids) ->
- return callback(error) if error?
- jobs = []
- errors = []
- for doc_id in (doc_ids or [])
- do (doc_id) ->
- jobs.push (callback) ->
- DocumentManager.flushAndDeleteDocWithLock project_id, doc_id, (error) ->
- if error?
- logger.error err: error, project_id: project_id, doc_id: doc_id, "error deleting doc"
- errors.push(error)
- callback()
- logger.log project_id: project_id, doc_ids: doc_ids, "deleting docs"
- async.series jobs, () ->
- # There is no harm in flushing project history if the previous call
- # failed and sometimes it is required
- HistoryManager.flushProjectChangesAsync project_id
- if errors.length > 0
- callback new Error("Errors deleting docs. See log for details")
- else
- callback(null)
- getProjectDocsAndFlushIfOld: (project_id, projectStateHash, excludeVersions = {}, _callback = (error, docs) ->) ->
- timer = new Metrics.Timer("projectManager.getProjectDocsAndFlushIfOld")
- callback = (args...) ->
- timer.done()
- _callback(args...)
- RedisManager.checkOrSetProjectState project_id, projectStateHash, (error, projectStateChanged) ->
- if error?
- logger.error err: error, project_id: project_id, "error getting/setting project state in getProjectDocsAndFlushIfOld"
- return callback(error)
- # we can't return docs if project structure has changed
- if projectStateChanged
- return callback Errors.ProjectStateChangedError("project state changed")
- # project structure hasn't changed, return doc content from redis
- RedisManager.getDocIdsInProject project_id, (error, doc_ids) ->
- if error?
- logger.error err: error, project_id: project_id, "error getting doc ids in getProjectDocs"
- return callback(error)
- jobs = []
- for doc_id in doc_ids or []
- do (doc_id) ->
- jobs.push (cb) ->
- # get the doc lines from redis
- DocumentManager.getDocAndFlushIfOldWithLock project_id, doc_id, (err, lines, version) ->
- if err?
- logger.error err:err, project_id: project_id, doc_id: doc_id, "error getting project doc lines in getProjectDocsAndFlushIfOld"
- return cb(err)
- doc = {_id:doc_id, lines:lines, v:version} # create a doc object to return
- cb(null, doc)
- async.series jobs, (error, docs) ->
- return callback(error) if error?
- callback(null, docs)
- clearProjectState: (project_id, callback = (error) ->) ->
- RedisManager.clearProjectState project_id, callback
- updateProjectWithLocks: (project_id, user_id, docUpdates, fileUpdates, version, _callback = (error) ->) ->
- timer = new Metrics.Timer("projectManager.updateProject")
- callback = (args...) ->
- timer.done()
- _callback(args...)
- project_version = version
- project_subversion = 0 # project versions can have multiple operations
- project_ops_length = 0
- handleDocUpdate = (projectUpdate, cb) ->
- doc_id = projectUpdate.id
- projectUpdate.version = "#{project_version}.#{project_subversion++}"
- if projectUpdate.docLines?
- ProjectHistoryRedisManager.queueAddEntity project_id, 'doc', doc_id, user_id, projectUpdate, (error, count) ->
- project_ops_length = count
- cb(error)
- else
- DocumentManager.renameDocWithLock project_id, doc_id, user_id, projectUpdate, (error, count) ->
- project_ops_length = count
- cb(error)
- handleFileUpdate = (projectUpdate, cb) ->
- file_id = projectUpdate.id
- projectUpdate.version = "#{project_version}.#{project_subversion++}"
- if projectUpdate.url?
- ProjectHistoryRedisManager.queueAddEntity project_id, 'file', file_id, user_id, projectUpdate, (error, count) ->
- project_ops_length = count
- cb(error)
- else
- ProjectHistoryRedisManager.queueRenameEntity project_id, 'file', file_id, user_id, projectUpdate, (error, count) ->
- project_ops_length = count
- cb(error)
- async.eachSeries docUpdates, handleDocUpdate, (error) ->
- return callback(error) if error?
- async.eachSeries fileUpdates, handleFileUpdate, (error) ->
- return callback(error) if error?
- if HistoryManager.shouldFlushHistoryOps(project_ops_length, docUpdates.length + fileUpdates.length, HistoryManager.FLUSH_PROJECT_EVERY_N_OPS)
- HistoryManager.flushProjectChangesAsync project_id
- callback()
|