18cd9c7aa631f35c56a3c5072cb8d6a46111c10ea3f5eef675a44534d938c37b84283ded87e602c2ff10c3154fe2e4fc5bf4206c5384cf3470c8f0bd02f75d 6.7 KB

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