2019-05-29 05:21:06 -04:00
|
|
|
/* eslint-disable
|
|
|
|
camelcase,
|
2020-12-15 05:23:54 -05:00
|
|
|
node/handle-callback-err,
|
2019-05-29 05:21:06 -04:00
|
|
|
max-len,
|
|
|
|
*/
|
|
|
|
// TODO: This file was created by bulk-decaffeinate.
|
|
|
|
// Fix any style issues and re-enable lint.
|
|
|
|
/*
|
|
|
|
* decaffeinate suggestions:
|
|
|
|
* DS102: Remove unnecessary code created because of implicit returns
|
|
|
|
* DS207: Consider shorter variations of null checks
|
|
|
|
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
|
|
|
*/
|
|
|
|
let rclient_secondary
|
2020-08-11 05:35:08 -04:00
|
|
|
const OError = require('@overleaf/o-error')
|
2021-07-07 05:38:56 -04:00
|
|
|
const Settings = require('@overleaf/settings')
|
2021-03-18 04:39:39 -04:00
|
|
|
const request = require('request').defaults({ timeout: 30 * 1000 })
|
2019-05-29 05:21:06 -04:00
|
|
|
const RedisWrapper = require('../../infrastructure/RedisWrapper')
|
|
|
|
const rclient = RedisWrapper.client('clsi_cookie')
|
|
|
|
if (Settings.redis.clsi_cookie_secondary != null) {
|
|
|
|
rclient_secondary = RedisWrapper.client('clsi_cookie_secondary')
|
|
|
|
}
|
|
|
|
const Cookie = require('cookie')
|
2021-11-10 08:40:18 -05:00
|
|
|
const logger = require('@overleaf/logger')
|
2021-08-31 08:46:23 -04:00
|
|
|
const Metrics = require('@overleaf/metrics')
|
2019-05-29 05:21:06 -04:00
|
|
|
|
|
|
|
const clsiCookiesEnabled =
|
|
|
|
(Settings.clsiCookie != null ? Settings.clsiCookie.key : undefined) != null &&
|
|
|
|
Settings.clsiCookie.key.length !== 0
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
module.exports = function (backendGroup) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return {
|
2021-08-23 04:07:10 -04:00
|
|
|
buildKey(project_id, user_id) {
|
2019-05-29 05:21:06 -04:00
|
|
|
if (backendGroup != null) {
|
2021-08-23 04:07:10 -04:00
|
|
|
return `clsiserver:${backendGroup}:${project_id}:${user_id}`
|
2019-05-29 05:21:06 -04:00
|
|
|
} else {
|
2021-08-23 04:07:10 -04:00
|
|
|
return `clsiserver:${project_id}:${user_id}`
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2021-08-23 04:07:10 -04:00
|
|
|
_getServerId(project_id, user_id, callback) {
|
2019-05-29 05:21:06 -04:00
|
|
|
if (callback == null) {
|
2021-10-27 05:49:18 -04:00
|
|
|
callback = function () {}
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
2021-08-23 04:07:10 -04:00
|
|
|
return rclient.get(
|
|
|
|
this.buildKey(project_id, user_id),
|
|
|
|
(err, serverId) => {
|
|
|
|
if (err != null) {
|
|
|
|
return callback(err)
|
|
|
|
}
|
|
|
|
if (serverId == null || serverId === '') {
|
|
|
|
return this._populateServerIdViaRequest(
|
|
|
|
project_id,
|
|
|
|
user_id,
|
|
|
|
callback
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
return callback(null, serverId)
|
|
|
|
}
|
2021-08-20 07:00:03 -04:00
|
|
|
}
|
2021-08-23 04:07:10 -04:00
|
|
|
)
|
2019-05-29 05:21:06 -04:00
|
|
|
},
|
|
|
|
|
2021-08-23 04:07:10 -04:00
|
|
|
_populateServerIdViaRequest(project_id, user_id, callback) {
|
2019-05-29 05:21:06 -04:00
|
|
|
if (callback == null) {
|
2021-10-27 05:49:18 -04:00
|
|
|
callback = function () {}
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
const url = `${Settings.apis.clsi.url}/project/${project_id}/status`
|
2021-08-23 04:07:10 -04:00
|
|
|
request.post(url, (err, res, body) => {
|
2019-05-29 05:21:06 -04:00
|
|
|
if (err != null) {
|
2020-08-11 05:35:08 -04:00
|
|
|
OError.tag(err, 'error getting initial server id for project', {
|
2021-04-27 03:52:58 -04:00
|
|
|
project_id,
|
2020-08-11 05:35:08 -04:00
|
|
|
})
|
2019-05-29 05:21:06 -04:00
|
|
|
return callback(err)
|
|
|
|
}
|
2021-08-31 08:46:23 -04:00
|
|
|
this.setServerId(
|
|
|
|
project_id,
|
|
|
|
user_id,
|
|
|
|
res,
|
|
|
|
null,
|
|
|
|
function (err, serverId) {
|
|
|
|
if (err != null) {
|
|
|
|
logger.warn(
|
|
|
|
{ err, project_id },
|
|
|
|
'error setting server id via populate request'
|
|
|
|
)
|
|
|
|
}
|
|
|
|
return callback(err, serverId)
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
2021-08-31 08:46:23 -04:00
|
|
|
)
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
},
|
|
|
|
|
|
|
|
_parseServerIdFromResponse(response) {
|
|
|
|
const cookies = Cookie.parse(
|
|
|
|
(response.headers['set-cookie'] != null
|
|
|
|
? response.headers['set-cookie'][0]
|
|
|
|
: undefined) || ''
|
|
|
|
)
|
|
|
|
return cookies != null ? cookies[Settings.clsiCookie.key] : undefined
|
|
|
|
},
|
|
|
|
|
2021-08-31 08:46:23 -04:00
|
|
|
setServerId(project_id, user_id, response, previous, callback) {
|
2019-05-29 05:21:06 -04:00
|
|
|
if (callback == null) {
|
2021-10-27 05:49:18 -04:00
|
|
|
callback = function () {}
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
if (!clsiCookiesEnabled) {
|
|
|
|
return callback()
|
|
|
|
}
|
|
|
|
const serverId = this._parseServerIdFromResponse(response)
|
|
|
|
if (serverId == null) {
|
|
|
|
// We don't get a cookie back if it hasn't changed
|
2021-08-20 07:00:03 -04:00
|
|
|
return rclient.expire(
|
2021-08-23 04:07:10 -04:00
|
|
|
this.buildKey(project_id, user_id),
|
2019-05-29 05:21:06 -04:00
|
|
|
Settings.clsiCookie.ttl,
|
2021-07-26 09:13:03 -04:00
|
|
|
err => callback(err, undefined)
|
2019-05-29 05:21:06 -04:00
|
|
|
)
|
|
|
|
}
|
2021-08-31 08:46:23 -04:00
|
|
|
if (!previous) {
|
|
|
|
// Initial assignment of a user+project or after clearing cache.
|
|
|
|
Metrics.inc('clsi-lb-assign-initial-backend')
|
|
|
|
} else {
|
|
|
|
Metrics.inc('clsi-lb-switch-backend')
|
|
|
|
}
|
2019-05-29 05:21:06 -04:00
|
|
|
if (rclient_secondary != null) {
|
2021-08-23 04:07:10 -04:00
|
|
|
this._setServerIdInRedis(
|
|
|
|
rclient_secondary,
|
|
|
|
project_id,
|
|
|
|
user_id,
|
2021-10-27 05:49:18 -04:00
|
|
|
serverId,
|
|
|
|
() => {}
|
2021-08-23 04:07:10 -04:00
|
|
|
)
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
2021-08-23 04:07:10 -04:00
|
|
|
this._setServerIdInRedis(rclient, project_id, user_id, serverId, err =>
|
2019-05-29 05:21:06 -04:00
|
|
|
callback(err, serverId)
|
|
|
|
)
|
|
|
|
},
|
|
|
|
|
2021-08-23 04:07:10 -04:00
|
|
|
_setServerIdInRedis(rclient, project_id, user_id, serverId, callback) {
|
2019-05-29 05:21:06 -04:00
|
|
|
if (callback == null) {
|
2021-10-27 05:49:18 -04:00
|
|
|
callback = function () {}
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
2021-03-18 04:39:39 -04:00
|
|
|
rclient.setex(
|
2021-08-23 04:07:10 -04:00
|
|
|
this.buildKey(project_id, user_id),
|
2021-03-18 04:39:39 -04:00
|
|
|
Settings.clsiCookie.ttl,
|
|
|
|
serverId,
|
|
|
|
callback
|
|
|
|
)
|
2019-05-29 05:21:06 -04:00
|
|
|
},
|
|
|
|
|
2021-08-23 04:07:10 -04:00
|
|
|
clearServerId(project_id, user_id, callback) {
|
2019-05-29 05:21:06 -04:00
|
|
|
if (callback == null) {
|
2021-10-27 05:49:18 -04:00
|
|
|
callback = function () {}
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
if (!clsiCookiesEnabled) {
|
|
|
|
return callback()
|
|
|
|
}
|
2021-08-23 04:07:10 -04:00
|
|
|
return rclient.del(this.buildKey(project_id, user_id), callback)
|
2019-05-29 05:21:06 -04:00
|
|
|
},
|
|
|
|
|
2021-08-23 04:07:10 -04:00
|
|
|
getCookieJar(project_id, user_id, callback) {
|
2019-05-29 05:21:06 -04:00
|
|
|
if (callback == null) {
|
2021-10-27 05:49:18 -04:00
|
|
|
callback = function () {}
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
if (!clsiCookiesEnabled) {
|
2021-07-26 09:13:03 -04:00
|
|
|
return callback(null, request.jar(), undefined)
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
2021-08-23 04:07:10 -04:00
|
|
|
return this._getServerId(project_id, user_id, (err, serverId) => {
|
2019-05-29 05:21:06 -04:00
|
|
|
if (err != null) {
|
2020-08-11 05:35:08 -04:00
|
|
|
OError.tag(err, 'error getting server id', {
|
2021-04-27 03:52:58 -04:00
|
|
|
project_id,
|
2020-08-11 05:35:08 -04:00
|
|
|
})
|
2019-05-29 05:21:06 -04:00
|
|
|
return callback(err)
|
|
|
|
}
|
|
|
|
const serverCookie = request.cookie(
|
|
|
|
`${Settings.clsiCookie.key}=${serverId}`
|
|
|
|
)
|
|
|
|
const jar = request.jar()
|
|
|
|
jar.setCookie(serverCookie, Settings.apis.clsi.url)
|
2021-07-26 09:13:03 -04:00
|
|
|
return callback(null, jar, serverId)
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
2021-04-27 03:52:58 -04:00
|
|
|
},
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
}
|