UrlCache.js 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. /* eslint-disable
  2. camelcase,
  3. handle-callback-err,
  4. no-return-assign,
  5. */
  6. // TODO: This file was created by bulk-decaffeinate.
  7. // Fix any style issues and re-enable lint.
  8. /*
  9. * decaffeinate suggestions:
  10. * DS101: Remove unnecessary use of Array.from
  11. * DS102: Remove unnecessary code created because of implicit returns
  12. * DS207: Consider shorter variations of null checks
  13. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  14. */
  15. const UrlFetcher = require('./UrlFetcher')
  16. const Settings = require('@overleaf/settings')
  17. const fs = require('fs')
  18. const fse = require('fs-extra')
  19. const Path = require('path')
  20. const { callbackify } = require('util')
  21. const PENDING_DOWNLOADS = new Map()
  22. function getProjectDir(projectId) {
  23. return Path.join(Settings.path.clsiCacheDir, projectId)
  24. }
  25. function getCachePath(projectId, url, lastModified) {
  26. // The url is a filestore URL.
  27. // It is sufficient to look at the path and mtime for uniqueness.
  28. const mtime = (lastModified && lastModified.getTime()) || 0
  29. const key = new URL(url).pathname.replace(/\//g, '-') + '-' + mtime
  30. return Path.join(getProjectDir(projectId), key)
  31. }
  32. async function clearProject(projectId) {
  33. await fse.remove(getProjectDir(projectId))
  34. }
  35. async function createProjectDir(projectId) {
  36. await fs.promises.mkdir(getProjectDir(projectId), { recursive: true })
  37. }
  38. async function downloadUrlToFile(projectId, url, destPath, lastModified) {
  39. const cachePath = getCachePath(projectId, url, lastModified)
  40. try {
  41. await fs.promises.copyFile(cachePath, destPath)
  42. return
  43. } catch (e) {
  44. if (e.code !== 'ENOENT') {
  45. throw e
  46. }
  47. }
  48. await download(url, cachePath)
  49. await fs.promises.copyFile(cachePath, destPath)
  50. }
  51. async function download(url, cachePath) {
  52. let pending = PENDING_DOWNLOADS.get(cachePath)
  53. if (pending) {
  54. return pending
  55. }
  56. pending = UrlFetcher.promises.pipeUrlToFileWithRetry(url, cachePath)
  57. PENDING_DOWNLOADS.set(cachePath, pending)
  58. try {
  59. await pending
  60. } finally {
  61. PENDING_DOWNLOADS.delete(cachePath)
  62. }
  63. }
  64. module.exports = {
  65. clearProject: callbackify(clearProject),
  66. createProjectDir: callbackify(createProjectDir),
  67. downloadUrlToFile: callbackify(downloadUrlToFile),
  68. promises: {
  69. clearProject,
  70. createProjectDir,
  71. downloadUrlToFile,
  72. },
  73. }