mirror of
https://github.com/overleaf/overleaf.git
synced 2024-12-29 05:52:33 +00:00
aa9d6c8dc9
* [misc] decaff cleanup: RoomManager * [misc] decaff cleanup: RedisClientManager * [misc] decaff cleanup: SafeJsonParse * [misc] decaff cleanup: WebApiManager * [misc] decaff cleanup: WebsocketController * [misc] decaff cleanup: WebsocketLoadBalancer * [misc] decaff cleanup: SessionSockets * [misc] decaff cleanup: HttpController * [misc] decaff cleanup: HttpApiController * [misc] decaff cleanup: HealthCheckManager * [misc] decaff cleanup: EventLogger * [misc] decaff cleanup: Errors o-error will eliminate most of it -- when we migrate over. * [misc] decaff cleanup: DrainManager * [misc] decaff cleanup: DocumentUpdaterManager * [misc] decaff cleanup: DocumentUpdaterController: no-unused-vars * [misc] decaff cleanup: DocumentUpdaterController: Array.from * [misc] decaff cleanup: DocumentUpdaterController: implicit return * [misc] decaff cleanup: DocumentUpdaterController: IIFE * [misc] decaff cleanup: DocumentUpdaterController: null checks * [misc] decaff cleanup: DocumentUpdaterController: simpler loops * [misc] decaff cleanup: DocumentUpdaterController: move module name def * [misc] decaff cleanup: ConnectedUsersManager: handle-callback-err * [misc] decaff cleanup: ConnectedUsersManager: implicit returns * [misc] decaff cleanup: ConnectedUsersManager: null checks * [misc] decaff cleanup: ChannelManager: no-unused-vars * [misc] decaff cleanup: ChannelManager: implicit returns * [misc] decaff cleanup: ChannelManager: other cleanup - var -> const - drop variable assignment before return * [misc] decaff cleanup: AuthorizationManager: handle-callback-err Note: This requires a change in WebsocketController to provide a dummy callback. * [misc] decaff cleanup: AuthorizationManager: Array.from * [misc] decaff cleanup: AuthorizationManager: implicit returns * [misc] decaff cleanup: AuthorizationManager: null checks * [misc] decaff cleanup: Router: handle-callback-err * [misc] decaff cleanup: Router: standard/no-callback-literal * [misc] decaff cleanup: Router: Array.from * [misc] decaff cleanup: Router: implicit returns * [misc] decaff cleanup: Router: refactor __guard__ wrapper * [misc] decaff cleanup: Router: null checks And a minor bug fix: user.id -> user._id * [misc] decaff cleanup: Router: move variable declarations to assignments * [misc] decaff cleanup: app: implicit returns * [misc] decaff cleanup: app: __guard__ * [misc] decaff cleanup: app: null checks * [misc] decaff cleanup: app: function definitions * [misc] decaff cleanup: app: drop unused next argument * [misc] decaff cleanup: app: var -> const
143 lines
4.5 KiB
JavaScript
143 lines
4.5 KiB
JavaScript
/* eslint-disable
|
|
camelcase,
|
|
*/
|
|
const request = require('request')
|
|
const _ = require('underscore')
|
|
const logger = require('logger-sharelatex')
|
|
const settings = require('settings-sharelatex')
|
|
const metrics = require('metrics-sharelatex')
|
|
|
|
const rclient = require('redis-sharelatex').createClient(
|
|
settings.redis.documentupdater
|
|
)
|
|
const Keys = settings.redis.documentupdater.key_schema
|
|
|
|
module.exports = {
|
|
getDocument(project_id, doc_id, fromVersion, callback) {
|
|
const timer = new metrics.Timer('get-document')
|
|
const url = `${settings.apis.documentupdater.url}/project/${project_id}/doc/${doc_id}?fromVersion=${fromVersion}`
|
|
logger.log(
|
|
{ project_id, doc_id, fromVersion },
|
|
'getting doc from document updater'
|
|
)
|
|
request.get(url, function (err, res, body) {
|
|
timer.done()
|
|
if (err) {
|
|
logger.error(
|
|
{ err, url, project_id, doc_id },
|
|
'error getting doc from doc updater'
|
|
)
|
|
return callback(err)
|
|
}
|
|
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
logger.log(
|
|
{ project_id, doc_id },
|
|
'got doc from document document updater'
|
|
)
|
|
try {
|
|
body = JSON.parse(body)
|
|
} catch (error) {
|
|
return callback(error)
|
|
}
|
|
body = body || {}
|
|
callback(null, body.lines, body.version, body.ranges, body.ops)
|
|
} else if ([404, 422].includes(res.statusCode)) {
|
|
err = new Error('doc updater could not load requested ops')
|
|
err.statusCode = res.statusCode
|
|
logger.warn(
|
|
{ err, project_id, doc_id, url, fromVersion },
|
|
'doc updater could not load requested ops'
|
|
)
|
|
callback(err)
|
|
} else {
|
|
err = new Error(
|
|
`doc updater returned a non-success status code: ${res.statusCode}`
|
|
)
|
|
err.statusCode = res.statusCode
|
|
logger.error(
|
|
{ err, project_id, doc_id, url },
|
|
`doc updater returned a non-success status code: ${res.statusCode}`
|
|
)
|
|
callback(err)
|
|
}
|
|
})
|
|
},
|
|
|
|
flushProjectToMongoAndDelete(project_id, callback) {
|
|
// this method is called when the last connected user leaves the project
|
|
logger.log({ project_id }, 'deleting project from document updater')
|
|
const timer = new metrics.Timer('delete.mongo.project')
|
|
// flush the project in the background when all users have left
|
|
const url =
|
|
`${settings.apis.documentupdater.url}/project/${project_id}?background=true` +
|
|
(settings.shutDownInProgress ? '&shutdown=true' : '')
|
|
request.del(url, function (err, res) {
|
|
timer.done()
|
|
if (err) {
|
|
logger.error(
|
|
{ err, project_id },
|
|
'error deleting project from document updater'
|
|
)
|
|
callback(err)
|
|
} else if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
logger.log({ project_id }, 'deleted project from document updater')
|
|
callback(null)
|
|
} else {
|
|
err = new Error(
|
|
`document updater returned a failure status code: ${res.statusCode}`
|
|
)
|
|
err.statusCode = res.statusCode
|
|
logger.error(
|
|
{ err, project_id },
|
|
`document updater returned failure status code: ${res.statusCode}`
|
|
)
|
|
callback(err)
|
|
}
|
|
})
|
|
},
|
|
|
|
queueChange(project_id, doc_id, change, callback) {
|
|
const allowedKeys = [
|
|
'doc',
|
|
'op',
|
|
'v',
|
|
'dupIfSource',
|
|
'meta',
|
|
'lastV',
|
|
'hash'
|
|
]
|
|
change = _.pick(change, allowedKeys)
|
|
const jsonChange = JSON.stringify(change)
|
|
if (jsonChange.indexOf('\u0000') !== -1) {
|
|
// memory corruption check
|
|
const error = new Error('null bytes found in op')
|
|
logger.error(
|
|
{ err: error, project_id, doc_id, jsonChange },
|
|
error.message
|
|
)
|
|
return callback(error)
|
|
}
|
|
|
|
const updateSize = jsonChange.length
|
|
if (updateSize > settings.maxUpdateSize) {
|
|
const error = new Error('update is too large')
|
|
error.updateSize = updateSize
|
|
return callback(error)
|
|
}
|
|
|
|
// record metric for each update added to queue
|
|
metrics.summary('redis.pendingUpdates', updateSize, { status: 'push' })
|
|
|
|
const doc_key = `${project_id}:${doc_id}`
|
|
// Push onto pendingUpdates for doc_id first, because once the doc updater
|
|
// gets an entry on pending-updates-list, it starts processing.
|
|
rclient.rpush(Keys.pendingUpdates({ doc_id }), jsonChange, function (
|
|
error
|
|
) {
|
|
if (error) {
|
|
return callback(error)
|
|
}
|
|
rclient.rpush('pending-updates-list', doc_key, callback)
|
|
})
|
|
}
|
|
}
|