UrlCache.js 2.2 KB

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