/
cache.go
133 lines (102 loc) · 3.06 KB
/
cache.go
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package main
import (
"bufio"
"fmt"
"github.com/bradberger/optimizer"
"github.com/mailgun/log"
"image"
"io"
"io/ioutil"
"net/http"
"os"
"path"
)
func initCacheDir() {
if useFileCache {
if err := os.MkdirAll(tmpDir, os.FileMode(0775)); err != nil {
useFileCache = false
log.Errorf("Couldn't create tmp dir %s: %s", tmpDir, err)
} else {
if err := ioutil.WriteFile(fmt.Sprintf("%s/lock", tmpDir), []byte(version), 0664); err != nil {
useFileCache = false
log.Errorf("Couldn't write to tmp dir %s: %s", tmpDir, err)
}
}
if useFileCache {
log.Infof("Caching via filesystem enabled")
log.Infof("Using %v as cache path", tmpDir)
}
}
}
// cacheOptimizedImageWriter Returns a file and a writer for the image resource.
// Be careful to flush the writer and close the file manually, as this function
// doesn't do that.
func fileCacheWriter(fileName string) (f *os.File, w *bufio.Writer) {
dir := path.Dir(fileName)
err := os.MkdirAll(dir, os.FileMode(0775))
if err != nil {
log.Errorf("Error caching image %s: %s", fileName, err)
return
}
f, err = os.Create(fileName)
if err != nil {
log.Errorf("Error caching image %s: %s", fileName, err)
return
}
w = bufio.NewWriter(f)
return
}
func writeAndCacheImg(w io.Writer, img image.Image, opts optimizer.Options, fileName string) {
f, cacheWriter := fileCacheWriter(fileName)
defer f.Close()
multi := io.MultiWriter(w, cacheWriter)
// Write image response.
optimizer.Encode(multi, img, opts)
cacheWriter.Flush()
return
}
func writeAndCache(w io.Writer, r io.Reader, fileName string) {
f, cacheWriter := fileCacheWriter(fileName)
defer f.Close()
multi := io.MultiWriter(w, cacheWriter)
io.Copy(multi, r)
}
func cacheFile(fileName string, data []byte) {
if useFileCache && len(data) > 0 {
go func(fileName string, data []byte) {
fileName = path.Clean(fileName)
dir := path.Dir(fileName)
if err := os.MkdirAll(dir, os.FileMode(0775)); err != nil {
log.Errorf("Error caching image %s: %s", fileName, err)
return
}
if err := ioutil.WriteFile(fileName, data, 0644); err != nil {
log.Errorf("Error caching image %s: %s", fileName, err)
return
}
}(fileName, data)
}
}
func cacheTmpFile(fileName string, data []byte) {
cacheFile(fmt.Sprintf("%s/%s", tmpDir, fileName), data)
}
func cacheDomainFile(domain string, filePath string, data []byte) {
cacheTmpFile(fmt.Sprintf("%s/%s", domain, filePath), data)
}
func getOptimizedImgCachePath(domain string, imagePath string, opts optimizer.Options) string {
cacheExt := path.Ext(imagePath)
if opts.Mime == "image/webp" {
cacheExt = ".webp"
}
return fmt.Sprintf("%s/%s/%s/%s--%vpx@%v--%v%s", tmpDir, domain, path.Dir(imagePath), path.Base(imagePath), opts.Width, opts.Dpr, opts.Quality, cacheExt)
}
func getImageFromCache(imagePath string) (body []byte, err error) {
body, err = ioutil.ReadFile(path.Clean(imagePath))
if err != nil && len(body) == 0 {
err = fmt.Errorf("Empty image file %s")
}
return
}
func addCacheHeader(w *http.ResponseWriter, str string) {
(*w).Header().Set("X-Cached", str)
}