This repository has been archived by the owner on Oct 3, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 74
/
assets.go
193 lines (172 loc) · 4.43 KB
/
assets.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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
// Package assets manages imager file asset allocation and deallocation
package assets
import (
"meguca/common"
"meguca/config"
"meguca/util"
"os"
"path/filepath"
)
const fileCreationFlags = os.O_WRONLY | os.O_CREATE | os.O_EXCL
// Only used in tests, but we still need them exported
var (
// StdJPEG is a JPEG sample image standard struct. Only used in tests.
StdJPEG = common.Image{
ImageCommon: common.ImageCommon{
SHA1: "012a2f912c9ee93ceb0ccb8684a29ec571990a94",
FileType: common.JPEG,
Dims: StdDims["jpeg"],
MD5: "YOQQklgfezKbBXuEAsqopw",
Size: 300792,
},
Name: "sample.jpg",
Spoiler: true,
}
// StdDims contains esulting dimentions after thumbnailing sample images.
// Only used in tests.
StdDims = map[string][4]uint16{
"jpeg": {0x43c, 0x371, 0x96, 0x79},
"png": {0x500, 0x2d0, 0x96, 0x54},
"gif": {0x248, 0x2d0, 0x79, 0x96},
"pdf": {0x253, 0x34a, 0x69, 0x96},
}
)
// GetFilePaths generates file paths of the source file and its thumbnail
func GetFilePaths(SHA1 string, fileType, thumbType uint8) (paths [2]string) {
paths[0] = util.ConcatStrings(
"/images/src/",
SHA1,
".",
common.Extensions[fileType],
)
paths[1] = util.ConcatStrings(
"/images/thumb/",
SHA1,
".",
common.Extensions[thumbType],
)
for i := range paths {
paths[i] = filepath.FromSlash(paths[i][1:])
}
return
}
// RelativeSourcePath returns an file's source path relative to the root path
func RelativeSourcePath(fileType uint8, SHA1 string) string {
return util.ConcatStrings(
"/assets/images/src/",
SHA1,
".",
common.Extensions[fileType],
)
}
func relativeThumbPath(thumbType uint8, SHA1 string) string {
return util.ConcatStrings(
"/assets/images/thumb/",
SHA1,
".",
common.Extensions[thumbType],
)
}
// ImageSearchPath returns the relative path used for image search file lookups.
// If files is not JPEG, PNG or GIF, returns the thumbnail instead of the source
// file.
func ImageSearchPath(img common.ImageCommon) string {
switch img.FileType {
case common.JPEG, common.PNG, common.GIF:
if img.Size < 8<<20 {
return RelativeSourcePath(img.FileType, img.SHA1)
}
}
return relativeThumbPath(img.ThumbType, img.SHA1)
}
func imageRoot() string {
r := config.Get().ImageRootOverride
if r != "" {
return r
}
return "/assets/images"
}
// ThumbPath returns the path to the thumbnail of an image
func ThumbPath(thumbType uint8, SHA1 string) string {
return util.ConcatStrings(
imageRoot(),
"/thumb/",
SHA1,
".",
common.Extensions[thumbType],
)
}
// SourcePath returns the path to the source file on an image
func SourcePath(fileType uint8, SHA1 string) string {
return util.ConcatStrings(
imageRoot(),
"/src/",
SHA1,
".",
common.Extensions[fileType],
)
}
// Write writes file assets to disk
func Write(SHA1 string, fileType, thumbType uint8, src, thumb []byte) error {
paths := GetFilePaths(SHA1, fileType, thumbType)
ch := make(chan error)
go func() {
if thumb == nil {
ch <- nil
} else {
ch <- writeFile(paths[1], thumb)
}
}()
for _, err := range [...]error{writeFile(paths[0], src), <-ch} {
switch {
// Ignore files already written by another thread or process
case err == nil, os.IsExist(err):
default:
return err
}
}
return nil
}
// Write a single file to disk with the appropriate permissions and flags
func writeFile(path string, data []byte) error {
file, err := os.OpenFile(path, fileCreationFlags, 0660)
if err != nil {
return err
}
defer file.Close()
_, err = file.Write(data)
return err
}
// Delete deletes file assets belonging to a single upload
func Delete(SHA1 string, fileType, thumbType uint8) error {
for _, path := range GetFilePaths(SHA1, fileType, thumbType) {
// Ignore somehow absent images
if err := os.Remove(path); err != nil && !os.IsNotExist(err) {
return err
}
}
return nil
}
// CreateDirs creates directories for processed image storage
func CreateDirs() error {
for _, dir := range [...]string{"src", "thumb"} {
path := filepath.Join("images", dir)
if err := os.MkdirAll(path, 0700); err != nil {
return err
}
}
return nil
}
// DeleteDirs recursively deletes the image storage folder. Only used for
// cleaning up after tests.
func DeleteDirs() error {
return os.RemoveAll("images")
}
// ResetDirs removes all contents from the image storage directories. Only
// used for cleaning up after tests.
func ResetDirs() error {
if err := DeleteDirs(); err != nil {
return err
}
return CreateDirs()
}