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