2024-11-08 05:21:56 -05:00
|
|
|
import { callbackify } from 'node:util'
|
|
|
|
import { setTimeout } from 'node:timers/promises'
|
2023-01-13 07:42:29 -05:00
|
|
|
import logger from '@overleaf/logger'
|
|
|
|
import Metrics from '@overleaf/metrics'
|
|
|
|
import Settings from '@overleaf/settings'
|
2024-04-11 08:35:16 -04:00
|
|
|
import {
|
|
|
|
fetchNothing,
|
|
|
|
fetchJson,
|
|
|
|
RequestFailedError,
|
|
|
|
} from '@overleaf/fetch-utils'
|
2023-01-13 07:42:29 -05:00
|
|
|
import * as Errors from './Errors.js'
|
|
|
|
import * as RedisManager from './RedisManager.js'
|
|
|
|
|
2024-04-11 08:35:16 -04:00
|
|
|
let RETRY_TIMEOUT_MS = 5000
|
2023-01-13 07:42:29 -05:00
|
|
|
|
2024-04-11 08:35:16 -04:00
|
|
|
async function getHistoryId(projectId) {
|
2023-01-13 07:42:29 -05:00
|
|
|
Metrics.inc('history_id_cache_requests_total')
|
2024-04-11 08:35:16 -04:00
|
|
|
const cachedHistoryId =
|
|
|
|
await RedisManager.promises.getCachedHistoryId(projectId)
|
|
|
|
if (cachedHistoryId) {
|
|
|
|
Metrics.inc('history_id_cache_hits_total')
|
|
|
|
return cachedHistoryId
|
|
|
|
} else {
|
|
|
|
const project = await _getProjectDetails(projectId)
|
|
|
|
const historyId =
|
|
|
|
project.overleaf &&
|
|
|
|
project.overleaf.history &&
|
|
|
|
project.overleaf.history.id
|
|
|
|
if (historyId != null) {
|
|
|
|
await RedisManager.promises.setCachedHistoryId(projectId, historyId)
|
2023-01-13 07:42:29 -05:00
|
|
|
}
|
2024-04-11 08:35:16 -04:00
|
|
|
return historyId
|
|
|
|
}
|
2023-01-13 07:42:29 -05:00
|
|
|
}
|
|
|
|
|
2024-06-18 10:00:00 -04:00
|
|
|
async function requestResync(projectId, opts = {}) {
|
2024-04-11 08:35:16 -04:00
|
|
|
try {
|
2024-06-18 10:00:00 -04:00
|
|
|
const body = {}
|
|
|
|
if (opts.historyRangesMigration) {
|
|
|
|
body.historyRangesMigration = opts.historyRangesMigration
|
|
|
|
}
|
2024-04-11 08:35:16 -04:00
|
|
|
await fetchNothing(
|
|
|
|
`${Settings.apis.web.url}/project/${projectId}/history/resync`,
|
|
|
|
{
|
|
|
|
method: 'POST',
|
|
|
|
signal: AbortSignal.timeout(6 * 60000),
|
|
|
|
basicAuth: {
|
|
|
|
user: Settings.apis.web.user,
|
|
|
|
password: Settings.apis.web.pass,
|
|
|
|
},
|
2024-06-18 10:00:00 -04:00
|
|
|
json: body,
|
2024-04-11 08:35:16 -04:00
|
|
|
}
|
|
|
|
)
|
|
|
|
} catch (err) {
|
|
|
|
if (err instanceof RequestFailedError && err.response.status === 404) {
|
|
|
|
throw new Errors.NotFoundError('got a 404 from web api').withCause(err)
|
|
|
|
} else {
|
|
|
|
throw err
|
|
|
|
}
|
|
|
|
}
|
2023-01-13 07:42:29 -05:00
|
|
|
}
|
|
|
|
|
2024-04-11 08:35:16 -04:00
|
|
|
async function _getProjectDetails(projectId, callback) {
|
2023-01-13 07:42:29 -05:00
|
|
|
logger.debug({ projectId }, 'getting project details from web')
|
2024-04-11 08:35:16 -04:00
|
|
|
let attempts = 0
|
|
|
|
while (true) {
|
|
|
|
attempts += 1
|
|
|
|
try {
|
|
|
|
return await fetchJson(
|
|
|
|
`${Settings.apis.web.url}/project/${projectId}/details`,
|
|
|
|
{
|
|
|
|
signal: AbortSignal.timeout(16000),
|
|
|
|
basicAuth: {
|
|
|
|
user: Settings.apis.web.user,
|
|
|
|
password: Settings.apis.web.pass,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
)
|
|
|
|
} catch (err) {
|
|
|
|
if (err instanceof RequestFailedError && err.response.status === 404) {
|
|
|
|
throw new Errors.NotFoundError('got a 404 from web api').withCause(err)
|
|
|
|
} else if (attempts < 2) {
|
|
|
|
// retry after 5 seconds
|
|
|
|
await setTimeout(RETRY_TIMEOUT_MS)
|
2023-01-13 07:42:29 -05:00
|
|
|
} else {
|
2024-04-11 08:35:16 -04:00
|
|
|
throw err
|
2023-01-13 07:42:29 -05:00
|
|
|
}
|
|
|
|
}
|
2024-04-11 08:35:16 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Adjust the retry timeout in tests
|
|
|
|
*/
|
|
|
|
export async function setRetryTimeoutMs(timeoutMs) {
|
|
|
|
RETRY_TIMEOUT_MS = timeoutMs
|
2023-01-13 07:42:29 -05:00
|
|
|
}
|
|
|
|
|
2024-04-11 08:35:16 -04:00
|
|
|
// EXPORTS
|
|
|
|
|
|
|
|
const getHistoryIdCb = callbackify(getHistoryId)
|
|
|
|
const requestResyncCb = callbackify(requestResync)
|
|
|
|
|
|
|
|
export { getHistoryIdCb as getHistoryId, requestResyncCb as requestResync }
|
|
|
|
|
2023-01-13 07:42:29 -05:00
|
|
|
export const promises = {
|
2024-04-11 08:35:16 -04:00
|
|
|
getHistoryId,
|
|
|
|
requestResync,
|
2023-01-13 07:42:29 -05:00
|
|
|
}
|