-
Notifications
You must be signed in to change notification settings - Fork 10.3k
/
Copy pathcache-image.js
82 lines (71 loc) · 2.41 KB
/
cache-image.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
const crypto = require(`crypto`)
const { resolve, parse } = require(`path`)
const { pathExists, createWriteStream } = require(`fs-extra`)
const downloadWithRetry = require(`./download-with-retry`).default
const inFlightImageCache = new Map()
module.exports = async function cacheImage(store, image, options) {
const program = store.getState().program
const CACHE_DIR = resolve(`${program.directory}/.cache/contentful/assets/`)
const {
file: { url, fileName, details },
} = image
const {
width,
height,
maxWidth,
maxHeight,
resizingBehavior,
cropFocus,
background,
} = options
const userWidth = maxWidth || width
const userHeight = maxHeight || height
const aspectRatio = details.image.height / details.image.width
const resultingWidth = Math.round(userWidth || 800)
const resultingHeight = Math.round(userHeight || resultingWidth * aspectRatio)
const params = [`w=${resultingWidth}`, `h=${resultingHeight}`]
if (resizingBehavior) {
params.push(`fit=${resizingBehavior}`)
}
if (cropFocus) {
params.push(`f=${cropFocus}`)
}
if (background) {
params.push(`bg=${background}`)
}
const optionsHash = crypto
.createHash(`md5`)
.update(JSON.stringify([url, ...params]))
.digest(`hex`)
const { name, ext } = parse(fileName)
const absolutePath = resolve(CACHE_DIR, `${name}-${optionsHash}${ext}`)
// Query the filesystem for file existence
const alreadyExists = await pathExists(absolutePath)
// Whether the file exists or not, if we are downloading it then await
const inFlight = inFlightImageCache.get(absolutePath)
if (inFlight) {
await inFlight
} else if (!alreadyExists) {
// File doesn't exist and is not being download yet
const downloadPromise = new Promise((resolve, reject) => {
const previewUrl = `http:${url}?${params.join(`&`)}`
downloadWithRetry({
url: previewUrl,
responseType: `stream`,
})
.then(response => {
const file = createWriteStream(absolutePath)
response.data.pipe(file)
file.on(`finish`, resolve)
file.on(`error`, reject)
})
.catch(reject)
})
inFlightImageCache.set(absolutePath, downloadPromise)
await downloadPromise
// When the file is downloaded, remove the promise from the cache
inFlightImageCache.delete(absolutePath)
}
// Now the file should be completely downloaded
return absolutePath
}