forked from goproxy/goproxy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcacher.go
154 lines (128 loc) · 3.45 KB
/
cacher.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 goproxy
import (
"context"
"errors"
"hash"
"io"
"mime"
"os"
"path"
"strings"
"time"
)
// ErrCacheNotFound is the error resulting if a path search failed to find a
// cache.
var ErrCacheNotFound = errors.New("cache not found")
// Cacher is the interface that defines a set of methods used to cache module
// files for the `Goproxy`.
//
// If you are looking for some useful implementations of the `Cacher`, simply
// visit the "github.com/goproxy/goproxy/cacher" package.
type Cacher interface {
// NewHash returns a new instance of the `hash.Hash` used to compute the
// checksums of the caches in the underlying cacher.
NewHash() hash.Hash
// Cache returns the matched `Cache` for the name from the underlying
// cacher. It returns the `ErrCacheNotFound` if not found.
//
// It is the caller's responsibility to close the returned `Cache`.
Cache(ctx context.Context, name string) (Cache, error)
// SetCache sets the c to the underlying cacher.
//
// It is the caller's responsibility to close the c.
SetCache(ctx context.Context, c Cache) error
}
// Cache is the cache unit of the `Cacher`.
type Cache interface {
io.Reader
io.Seeker
io.Closer
// Name returns the unique Unix path style name of the underlying cache.
Name() string
// MIMEType returns the MIME type of the underlying cache.
MIMEType() string
// Size returns the length in bytes of the underlying cache.
Size() int64
// ModTime returns the modification time of the underlying cache.
ModTime() time.Time
// Checksum returns the checksum of the underlying cache.
Checksum() []byte
}
// tempCache implements the `Cache`.
type tempCache struct {
file *os.File
name string
mimeType string
size int64
modTime time.Time
checksum []byte
}
// newTempCache returns a new instance of the `tempCache` with the filename,
// name, and fileHash.
func newTempCache(filename, name string, fileHash hash.Hash) (Cache, error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
var mimeType string
switch ext := strings.ToLower(path.Ext(name)); ext {
case ".info":
mimeType = "application/json; charset=utf-8"
case ".mod":
mimeType = "text/plain; charset=utf-8"
case ".zip":
mimeType = "application/zip"
default:
mimeType = mime.TypeByExtension(ext)
}
fileInfo, err := file.Stat()
if err != nil {
return nil, err
}
if _, err := io.Copy(fileHash, file); err != nil {
return nil, err
}
if _, err := file.Seek(0, io.SeekStart); err != nil {
return nil, err
}
return &tempCache{
file: file,
name: name,
mimeType: mimeType,
size: fileInfo.Size(),
modTime: fileInfo.ModTime(),
checksum: fileHash.Sum(nil),
}, nil
}
// Read implements the `Cache`.
func (tc *tempCache) Read(b []byte) (int, error) {
return tc.file.Read(b)
}
// Seek implements the `Cache`.
func (tc *tempCache) Seek(offset int64, whence int) (int64, error) {
return tc.file.Seek(offset, whence)
}
// Close implements the `Cache`.
func (tc *tempCache) Close() error {
return tc.file.Close()
}
// Name implements the `Cache`.
func (tc *tempCache) Name() string {
return tc.name
}
// MIMEType implements the `Cache`.
func (tc *tempCache) MIMEType() string {
return tc.mimeType
}
// Size implements the `Cache`.
func (tc *tempCache) Size() int64 {
return tc.size
}
// ModTime implements the `Cache`.
func (tc *tempCache) ModTime() time.Time {
return tc.modTime
}
// Checksum implements the `Cache`.
func (tc *tempCache) Checksum() []byte {
return tc.checksum
}