/
disk.go
154 lines (128 loc) · 3.04 KB
/
disk.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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package cacher
import (
"context"
"crypto/md5"
"fmt"
"hash"
"io/ioutil"
"os"
"path/filepath"
"time"
"github.com/goproxy/goproxy"
)
// Disk implements the `goproxy.Cacher` by using the disk.
type Disk struct {
// Root is the root of the caches.
Root string `mapstructure:"root"`
}
// NewHash implements the `goproxy.Cacher`.
func (d *Disk) NewHash() hash.Hash {
return md5.New()
}
// Cache implements the `goproxy.Cacher`.
func (d *Disk) Cache(ctx context.Context, name string) (goproxy.Cache, error) {
filename := filepath.Join(d.Root, filepath.FromSlash(name))
file, err := os.Open(filename)
if err != nil {
if os.IsNotExist(err) {
return nil, goproxy.ErrCacheNotFound
}
return nil, err
}
fileInfo, err := file.Stat()
if err != nil {
return nil, err
}
fileMIMEType, err := ioutil.ReadFile(fmt.Sprint(filename, ".mime-type"))
if err != nil {
if os.IsNotExist(err) {
return nil, goproxy.ErrCacheNotFound
}
return nil, err
}
fileChecksum, err := ioutil.ReadFile(fmt.Sprint(filename, ".checksum"))
if err != nil {
if os.IsNotExist(err) {
return nil, goproxy.ErrCacheNotFound
}
return nil, err
}
return &diskCache{
file: file,
name: name,
mimeType: string(fileMIMEType),
size: fileInfo.Size(),
modTime: fileInfo.ModTime(),
checksum: fileChecksum,
}, nil
}
// SetCache implements the `goproxy.Cacher`.
func (d *Disk) SetCache(ctx context.Context, c goproxy.Cache) error {
filename := filepath.Join(d.Root, filepath.FromSlash(c.Name()))
if err := os.MkdirAll(
filepath.Dir(filename),
os.ModePerm,
); err != nil {
return err
}
if err := ioutil.WriteFile(
fmt.Sprint(filename, ".mime-type"),
[]byte(c.MIMEType()),
os.ModePerm,
); err != nil {
return err
}
if err := ioutil.WriteFile(
fmt.Sprint(filename, ".checksum"),
c.Checksum(),
os.ModePerm,
); err != nil {
return err
}
b, err := ioutil.ReadAll(c)
if err != nil {
return err
}
return ioutil.WriteFile(filename, b, os.ModePerm)
}
// diskCache implements the `goproxy.Cache`. It is the cache unit of the `Disk`.
type diskCache struct {
file *os.File
name string
mimeType string
size int64
modTime time.Time
checksum []byte
}
// Read implements the `goproxy.Cache`.
func (dc *diskCache) Read(b []byte) (int, error) {
return dc.file.Read(b)
}
// Seek implements the `goproxy.Cache`.
func (dc *diskCache) Seek(offset int64, whence int) (int64, error) {
return dc.file.Seek(offset, whence)
}
// Close implements the `goproxy.Cache`.
func (dc *diskCache) Close() error {
return dc.file.Close()
}
// Name implements the `goproxy.Cache`.
func (dc *diskCache) Name() string {
return dc.name
}
// MIMEType implements the `goproxy.Cache`.
func (dc *diskCache) MIMEType() string {
return dc.mimeType
}
// Size implements the `goproxy.Cache`.
func (dc *diskCache) Size() int64 {
return dc.size
}
// ModTime implements the `goproxy.Cache`.
func (dc *diskCache) ModTime() time.Time {
return dc.modTime
}
// Checksum implements the `goproxy.Cache`.
func (dc *diskCache) Checksum() []byte {
return dc.checksum
}