You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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