pr_27505.patch 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. diff --git a/services/history-v1/storage/lib/project_key.js b/services/history-v1/storage/lib/project_key.js
  2. index 03fb2a5141ef..8727576b29f5 100644
  3. --- a/services/history-v1/storage/lib/project_key.js
  4. +++ b/services/history-v1/storage/lib/project_key.js
  5. @@ -1,5 +1,4 @@
  6. // Keep in sync with services/web/app/src/Features/History/project_key.js
  7. -const _ = require('lodash')
  8. const path = require('node:path')
  9. //
  10. @@ -13,7 +12,7 @@ function format(projectId) {
  11. }
  12. function pad(number) {
  13. - return _.padStart(number, 9, '0')
  14. + return (number || 0).toString().padStart(9, '0')
  15. }
  16. function naiveReverse(string) {
  17. diff --git a/services/web/app/src/Features/History/project_key.js b/services/web/app/src/Features/History/project_key.js
  18. index a4722db09afd..1630bdad0b2b 100644
  19. --- a/services/web/app/src/Features/History/project_key.js
  20. +++ b/services/web/app/src/Features/History/project_key.js
  21. @@ -1,5 +1,4 @@
  22. // Keep in sync with services/history-v1/storage/lib/project_key.js
  23. -const _ = require('lodash')
  24. const path = require('node:path')
  25. //
  26. @@ -13,7 +12,7 @@ function format(projectId) {
  27. }
  28. function pad(number) {
  29. - return _.padStart(number, 9, '0')
  30. + return (number || 0).toString().padStart(9, '0')
  31. }
  32. function naiveReverse(string) {
  33. diff --git a/libraries/object-persistor/src/FSPersistor.js b/libraries/object-persistor/src/FSPersistor.js
  34. index 38a81407df12..0b5891d2b2ed 100644
  35. --- a/libraries/object-persistor/src/FSPersistor.js
  36. +++ b/libraries/object-persistor/src/FSPersistor.js
  37. @@ -86,7 +86,7 @@ module.exports = class FSPersistor extends AbstractPersistor {
  38. metric: 'fs.ingress', // ingress to us from disk
  39. bucket: location,
  40. })
  41. - const fsPath = this._getFsPath(location, name)
  42. + const fsPath = this._getFsPath(location, name, opts.useSubdirectories)
  43. try {
  44. opts.fd = await fsPromises.open(fsPath, 'r')
  45. @@ -295,9 +295,9 @@ module.exports = class FSPersistor extends AbstractPersistor {
  46. await fsPromises.rm(dirPath, { force: true, recursive: true })
  47. }
  48. - _getFsPath(location, key) {
  49. + _getFsPath(location, key, useSubdirectories = false) {
  50. key = key.replace(/\/$/, '')
  51. - if (!this.useSubdirectories) {
  52. + if (!this.useSubdirectories && !useSubdirectories) {
  53. key = key.replace(/\//g, '_')
  54. }
  55. return Path.join(location, key)
  56. diff --git a/services/filestore/app.js b/services/filestore/app.js
  57. index 24741e079c93..e69515ed7de0 100644
  58. --- a/services/filestore/app.js
  59. +++ b/services/filestore/app.js
  60. @@ -119,6 +119,17 @@ app.get(
  61. fileController.getFile
  62. )
  63. +app.get(
  64. + '/history/global/hash/:hash',
  65. + keyBuilder.globalBlobFileKeyMiddleware,
  66. + fileController.getFile
  67. +)
  68. +app.get(
  69. + '/history/project/:historyId/hash/:hash',
  70. + keyBuilder.projectBlobFileKeyMiddleware,
  71. + fileController.getFile
  72. +)
  73. +
  74. app.get('/status', function (req, res) {
  75. if (settings.shuttingDown) {
  76. res.sendStatus(503) // Service unavailable
  77. diff --git a/services/filestore/app/js/FileController.js b/services/filestore/app/js/FileController.js
  78. index 127bbcc20f83..2f77bd015da9 100644
  79. --- a/services/filestore/app/js/FileController.js
  80. +++ b/services/filestore/app/js/FileController.js
  81. @@ -25,6 +25,7 @@ function getFile(req, res, next) {
  82. format,
  83. style,
  84. }
  85. + if (req.useSubdirectories) options.useSubdirectories = true
  86. metrics.inc('getFile')
  87. req.requestLogger.setMessage('getting file')
  88. diff --git a/services/filestore/app/js/KeyBuilder.js b/services/filestore/app/js/KeyBuilder.js
  89. index f67a0e81d7ef..66c738171033 100644
  90. --- a/services/filestore/app/js/KeyBuilder.js
  91. +++ b/services/filestore/app/js/KeyBuilder.js
  92. @@ -1,4 +1,5 @@
  93. const settings = require('@overleaf/settings')
  94. +const projectKey = require('./project_key')
  95. module.exports = {
  96. getConvertedFolderKey,
  97. @@ -6,6 +7,8 @@ module.exports = {
  98. userFileKeyMiddleware,
  99. userProjectKeyMiddleware,
  100. bucketFileKeyMiddleware,
  101. + globalBlobFileKeyMiddleware,
  102. + projectBlobFileKeyMiddleware,
  103. templateFileKeyMiddleware,
  104. }
  105. @@ -50,6 +53,22 @@ function bucketFileKeyMiddleware(req, res, next) {
  106. next()
  107. }
  108. +function globalBlobFileKeyMiddleware(req, res, next) {
  109. + req.bucket = settings.filestore.stores.global_blobs
  110. + const { hash } = req.params
  111. + req.key = `${hash.slice(0, 2)}/${hash.slice(2, 4)}/${hash.slice(4)}`
  112. + req.useSubdirectories = true
  113. + next()
  114. +}
  115. +
  116. +function projectBlobFileKeyMiddleware(req, res, next) {
  117. + req.bucket = settings.filestore.stores.project_blobs
  118. + const { historyId, hash } = req.params
  119. + req.key = `${projectKey.format(historyId)}/${hash.slice(0, 2)}/${hash.slice(2)}`
  120. + req.useSubdirectories = true
  121. + next()
  122. +}
  123. +
  124. function templateFileKeyMiddleware(req, res, next) {
  125. const {
  126. template_id: templateId,
  127. diff --git a/services/web/app/src/Features/History/project_key.js b/services/filestore/app/js/project_key.js
  128. similarity index 100%
  129. rename from services/web/app/src/Features/History/project_key.js
  130. rename to services/filestore/app/js/project_key.js
  131. diff --git a/services/history-v1/storage/lib/project_key.js b/services/history-v1/storage/lib/project_key.js
  132. index 8727576b29f5..6ad239dd12cb 100644
  133. --- a/services/history-v1/storage/lib/project_key.js
  134. +++ b/services/history-v1/storage/lib/project_key.js
  135. @@ -1,4 +1,4 @@
  136. -// Keep in sync with services/web/app/src/Features/History/project_key.js
  137. +// Keep in sync with services/filestore/app/js/project_key.js
  138. const path = require('node:path')
  139. //
  140. diff --git a/services/web/app/src/Features/Compile/ClsiManager.js b/services/web/app/src/Features/Compile/ClsiManager.js
  141. index 6f11297248ee..19370684dd80 100644
  142. --- a/services/web/app/src/Features/Compile/ClsiManager.js
  143. +++ b/services/web/app/src/Features/Compile/ClsiManager.js
  144. @@ -26,7 +26,7 @@ const DocumentUpdaterHandler = require('../DocumentUpdater/DocumentUpdaterHandle
  145. const Metrics = require('@overleaf/metrics')
  146. const Errors = require('../Errors/Errors')
  147. const ClsiCacheHandler = require('./ClsiCacheHandler')
  148. -const { getBlobLocation } = require('../History/HistoryManager')
  149. +const { getFilestoreBlobURL } = require('../History/HistoryManager')
  150. const VALID_COMPILERS = ['pdflatex', 'latex', 'xelatex', 'lualatex']
  151. const OUTPUT_FILE_TIMEOUT_MS = 60000
  152. @@ -755,8 +755,7 @@ function _finaliseRequest(projectId, options, project, docs, files) {
  153. let url = filestoreURL
  154. let fallbackURL
  155. if (file.hash && Features.hasFeature('project-history-blobs')) {
  156. - const { bucket, key } = getBlobLocation(historyId, file.hash)
  157. - url = `${Settings.apis.filestore.url}/bucket/${bucket}/key/${key}`
  158. + url = getFilestoreBlobURL(historyId, file.hash)
  159. fallbackURL = filestoreURL
  160. }
  161. resources.push({
  162. diff --git a/services/web/app/src/Features/History/HistoryManager.js b/services/web/app/src/Features/History/HistoryManager.js
  163. index 42d7e229bf97..a2fb201399d1 100644
  164. --- a/services/web/app/src/Features/History/HistoryManager.js
  165. +++ b/services/web/app/src/Features/History/HistoryManager.js
  166. @@ -15,11 +15,6 @@ const { db, ObjectId, waitForDb } = require('../../infrastructure/mongodb')
  167. const Metrics = require('@overleaf/metrics')
  168. const logger = require('@overleaf/logger')
  169. const { NotFoundError } = require('../Errors/Errors')
  170. -const projectKey = require('./project_key')
  171. -
  172. -// BEGIN copy from services/history-v1/storage/lib/blob_store/index.js
  173. -
  174. -const GLOBAL_BLOBS = new Set() // CHANGE FROM SOURCE: only store hashes.
  175. const HISTORY_V1_URL = settings.apis.v1_history.url
  176. const HISTORY_V1_BASIC_AUTH = {
  177. @@ -27,27 +22,9 @@ const HISTORY_V1_BASIC_AUTH = {
  178. password: settings.apis.v1_history.pass,
  179. }
  180. -function makeGlobalKey(hash) {
  181. - return `${hash.slice(0, 2)}/${hash.slice(2, 4)}/${hash.slice(4)}`
  182. -}
  183. -
  184. -function makeProjectKey(projectId, hash) {
  185. - return `${projectKey.format(projectId)}/${hash.slice(0, 2)}/${hash.slice(2)}`
  186. -}
  187. +// BEGIN copy from services/history-v1/storage/lib/blob_store/index.js
  188. -function getBlobLocation(projectId, hash) {
  189. - if (GLOBAL_BLOBS.has(hash)) {
  190. - return {
  191. - bucket: settings.apis.v1_history.buckets.globalBlobs,
  192. - key: makeGlobalKey(hash),
  193. - }
  194. - } else {
  195. - return {
  196. - bucket: settings.apis.v1_history.buckets.projectBlobs,
  197. - key: makeProjectKey(projectId, hash),
  198. - }
  199. - }
  200. -}
  201. +const GLOBAL_BLOBS = new Set() // CHANGE FROM SOURCE: only store hashes.
  202. async function loadGlobalBlobs() {
  203. await waitForDb() // CHANGE FROM SOURCE: wait for db before running query.
  204. @@ -59,6 +36,14 @@ async function loadGlobalBlobs() {
  205. // END copy from services/history-v1/storage/lib/blob_store/index.js
  206. +function getFilestoreBlobURL(historyId, hash) {
  207. + if (GLOBAL_BLOBS.has(hash)) {
  208. + return `${settings.apis.filestore.url}/history/global/hash/${hash}`
  209. + } else {
  210. + return `${settings.apis.filestore.url}/history/project/${historyId}/hash/${hash}`
  211. + }
  212. +}
  213. +
  214. async function initializeProject(projectId) {
  215. const body = await fetchJson(`${settings.apis.project_history.url}/project`, {
  216. method: 'POST',
  217. @@ -421,7 +406,7 @@ function _userView(user) {
  218. const loadGlobalBlobsPromise = loadGlobalBlobs()
  219. module.exports = {
  220. - getBlobLocation,
  221. + getFilestoreBlobURL,
  222. loadGlobalBlobsPromise,
  223. initializeProject: callbackify(initializeProject),
  224. flushProject: callbackify(flushProject),