get.js 6.1 KB

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