UrlCache.js 2.2 KB

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