get.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. 'use strict'
  2. const util = require('util')
  3. const fs = require('fs')
  4. const index = require('./lib/entry-index')
  5. const memo = require('./lib/memoization')
  6. const read = require('./lib/content/read')
  7. const Minipass = require('minipass')
  8. const Collect = require('minipass-collect')
  9. const Pipeline = require('minipass-pipeline')
  10. const writeFile = util.promisify(fs.writeFile)
  11. module.exports = function get (cache, key, opts) {
  12. return getData(false, cache, key, opts)
  13. }
  14. module.exports.byDigest = function getByDigest (cache, digest, opts) {
  15. return getData(true, cache, digest, opts)
  16. }
  17. function getData (byDigest, cache, key, opts = {}) {
  18. const { integrity, memoize, size } = opts
  19. const memoized = byDigest
  20. ? memo.get.byDigest(cache, key, opts)
  21. : memo.get(cache, key, opts)
  22. if (memoized && memoize !== false) {
  23. return Promise.resolve(
  24. byDigest
  25. ? memoized
  26. : {
  27. metadata: memoized.entry.metadata,
  28. data: memoized.data,
  29. integrity: memoized.entry.integrity,
  30. size: memoized.entry.size,
  31. }
  32. )
  33. }
  34. return (byDigest ? Promise.resolve(null) : index.find(cache, key, opts)).then(
  35. (entry) => {
  36. if (!entry && !byDigest)
  37. throw new index.NotFoundError(cache, key)
  38. return read(cache, byDigest ? key : entry.integrity, {
  39. integrity,
  40. size,
  41. })
  42. .then((data) =>
  43. byDigest
  44. ? data
  45. : {
  46. data,
  47. metadata: entry.metadata,
  48. size: entry.size,
  49. integrity: entry.integrity,
  50. }
  51. )
  52. .then((res) => {
  53. if (memoize && byDigest)
  54. memo.put.byDigest(cache, key, res, opts)
  55. else if (memoize)
  56. memo.put(cache, entry, res.data, opts)
  57. return res
  58. })
  59. }
  60. )
  61. }
  62. module.exports.sync = function get (cache, key, opts) {
  63. return getDataSync(false, cache, key, opts)
  64. }
  65. module.exports.sync.byDigest = function getByDigest (cache, digest, opts) {
  66. return getDataSync(true, cache, digest, opts)
  67. }
  68. function getDataSync (byDigest, cache, key, opts = {}) {
  69. const { integrity, memoize, size } = opts
  70. const memoized = byDigest
  71. ? memo.get.byDigest(cache, key, opts)
  72. : memo.get(cache, key, opts)
  73. if (memoized && memoize !== false) {
  74. return byDigest
  75. ? memoized
  76. : {
  77. metadata: memoized.entry.metadata,
  78. data: memoized.data,
  79. integrity: memoized.entry.integrity,
  80. size: memoized.entry.size,
  81. }
  82. }
  83. const entry = !byDigest && index.find.sync(cache, key, opts)
  84. if (!entry && !byDigest)
  85. throw new index.NotFoundError(cache, key)
  86. const data = read.sync(cache, byDigest ? key : entry.integrity, {
  87. integrity: integrity,
  88. size: size,
  89. })
  90. const res = byDigest
  91. ? data
  92. : {
  93. metadata: entry.metadata,
  94. data: data,
  95. size: entry.size,
  96. integrity: entry.integrity,
  97. }
  98. if (memoize && byDigest)
  99. memo.put.byDigest(cache, key, res, opts)
  100. else if (memoize)
  101. memo.put(cache, entry, res.data, opts)
  102. return res
  103. }
  104. module.exports.stream = getStream
  105. const getMemoizedStream = (memoized) => {
  106. const stream = new Minipass()
  107. stream.on('newListener', function (ev, cb) {
  108. ev === 'metadata' && cb(memoized.entry.metadata)
  109. ev === 'integrity' && cb(memoized.entry.integrity)
  110. ev === 'size' && cb(memoized.entry.size)
  111. })
  112. stream.end(memoized.data)
  113. return stream
  114. }
  115. function getStream (cache, key, opts = {}) {
  116. const { memoize, size } = opts
  117. const memoized = memo.get(cache, key, opts)
  118. if (memoized && memoize !== false)
  119. return getMemoizedStream(memoized)
  120. const stream = new Pipeline()
  121. index
  122. .find(cache, key)
  123. .then((entry) => {
  124. if (!entry)
  125. throw new index.NotFoundError(cache, key)
  126. stream.emit('metadata', entry.metadata)
  127. stream.emit('integrity', entry.integrity)
  128. stream.emit('size', entry.size)
  129. stream.on('newListener', function (ev, cb) {
  130. ev === 'metadata' && cb(entry.metadata)
  131. ev === 'integrity' && cb(entry.integrity)
  132. ev === 'size' && cb(entry.size)
  133. })
  134. const src = read.readStream(
  135. cache,
  136. entry.integrity,
  137. { ...opts, size: typeof size !== 'number' ? entry.size : size }
  138. )
  139. if (memoize) {
  140. const memoStream = new Collect.PassThrough()
  141. memoStream.on('collect', data => memo.put(cache, entry, data, opts))
  142. stream.unshift(memoStream)
  143. }
  144. stream.unshift(src)
  145. })
  146. .catch((err) => stream.emit('error', err))
  147. return stream
  148. }
  149. module.exports.stream.byDigest = getStreamDigest
  150. function getStreamDigest (cache, integrity, opts = {}) {
  151. const { memoize } = opts
  152. const memoized = memo.get.byDigest(cache, integrity, opts)
  153. if (memoized && memoize !== false) {
  154. const stream = new Minipass()
  155. stream.end(memoized)
  156. return stream
  157. } else {
  158. const stream = read.readStream(cache, integrity, opts)
  159. if (!memoize)
  160. return stream
  161. const memoStream = new Collect.PassThrough()
  162. memoStream.on('collect', data => memo.put.byDigest(
  163. cache,
  164. integrity,
  165. data,
  166. opts
  167. ))
  168. return new Pipeline(stream, memoStream)
  169. }
  170. }
  171. module.exports.info = info
  172. function info (cache, key, opts = {}) {
  173. const { memoize } = opts
  174. const memoized = memo.get(cache, key, opts)
  175. if (memoized && memoize !== false)
  176. return Promise.resolve(memoized.entry)
  177. else
  178. return index.find(cache, key)
  179. }
  180. module.exports.hasContent = read.hasContent
  181. function cp (cache, key, dest, opts) {
  182. return copy(false, cache, key, dest, opts)
  183. }
  184. module.exports.copy = cp
  185. function cpDigest (cache, digest, dest, opts) {
  186. return copy(true, cache, digest, dest, opts)
  187. }
  188. module.exports.copy.byDigest = cpDigest
  189. function copy (byDigest, cache, key, dest, opts = {}) {
  190. if (read.copy) {
  191. return (byDigest
  192. ? Promise.resolve(null)
  193. : index.find(cache, key, opts)
  194. ).then((entry) => {
  195. if (!entry && !byDigest)
  196. throw new index.NotFoundError(cache, key)
  197. return read
  198. .copy(cache, byDigest ? key : entry.integrity, dest, opts)
  199. .then(() => {
  200. return byDigest
  201. ? key
  202. : {
  203. metadata: entry.metadata,
  204. size: entry.size,
  205. integrity: entry.integrity,
  206. }
  207. })
  208. })
  209. }
  210. return getData(byDigest, cache, key, opts).then((res) => {
  211. return writeFile(dest, byDigest ? res : res.data).then(() => {
  212. return byDigest
  213. ? key
  214. : {
  215. metadata: res.metadata,
  216. size: res.size,
  217. integrity: res.integrity,
  218. }
  219. })
  220. })
  221. }