1
1
/*
2
- * jQuery File Upload Plugin GAE Go Example 2.0
2
+ * jQuery File Upload Plugin GAE Go Example 2.1
3
3
* https://github.com/blueimp/jQuery-File-Upload
4
4
*
5
5
* Copyright 2011, Sebastian Tschan
@@ -14,37 +14,29 @@ package app
14
14
import (
15
15
"appengine"
16
16
"appengine/blobstore"
17
- "appengine/memcache "
17
+ "appengine/image "
18
18
"appengine/taskqueue"
19
19
"bytes"
20
- "encoding/base64"
21
20
"encoding/json"
22
21
"fmt"
23
- "image"
24
- "image/png"
25
22
"io"
26
23
"log"
27
24
"mime/multipart"
28
25
"net/http"
29
26
"net/url"
30
27
"regexp"
31
- "resize"
32
28
"strings"
33
29
"time"
34
30
)
35
31
36
- import _ "image/gif"
37
- import _ "image/jpeg"
38
-
39
32
const (
40
- WEBSITE = "http://blueimp.github.com/jQuery-File-Upload/"
41
- MIN_FILE_SIZE = 1 // bytes
42
- MAX_FILE_SIZE = 5000000 // bytes
43
- IMAGE_TYPES = "image/(gif|p?jpeg|(x-)?png)"
44
- ACCEPT_FILE_TYPES = IMAGE_TYPES
45
- EXPIRATION_TIME = 300 // seconds
46
- THUMBNAIL_MAX_WIDTH = 80
47
- THUMBNAIL_MAX_HEIGHT = THUMBNAIL_MAX_WIDTH
33
+ WEBSITE = "http://blueimp.github.com/jQuery-File-Upload/"
34
+ MIN_FILE_SIZE = 1 // bytes
35
+ MAX_FILE_SIZE = 5000000 // bytes
36
+ IMAGE_TYPES = "image/(gif|p?jpeg|(x-)?png)"
37
+ ACCEPT_FILE_TYPES = IMAGE_TYPES
38
+ EXPIRATION_TIME = 300 // seconds
39
+ THUMBNAIL_PARAM = "=s80"
48
40
)
49
41
50
42
var (
@@ -94,49 +86,19 @@ func (fi *FileInfo) CreateUrls(r *http.Request, c appengine.Context) {
94
86
escape (string (fi .Name ))
95
87
fi .DeleteUrl = fi .Url
96
88
fi .DeleteType = "DELETE"
97
- if fi .ThumbnailUrl != "" && - 1 == strings .Index (
98
- r .Header .Get ("Accept" ),
99
- "application/json" ,
100
- ) {
101
- fi .ThumbnailUrl = uString + "thumbnails/" +
102
- escape (string (fi .Key ))
103
- }
104
- }
105
-
106
- func (fi * FileInfo ) CreateThumbnail (r io.Reader , c appengine.Context ) (data []byte , err error ) {
107
- defer func () {
108
- if rec := recover (); rec != nil {
109
- log .Println (rec )
110
- // 1x1 pixel transparent GIf, bas64 encoded:
111
- s := "R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="
112
- data , _ = base64 .StdEncoding .DecodeString (s )
113
- fi .ThumbnailUrl = "data:image/gif;base64," + s
114
- }
115
- memcache .Add (c , & memcache.Item {
116
- Key : string (fi .Key ),
117
- Value : data ,
118
- Expiration : EXPIRATION_TIME ,
119
- })
120
- }()
121
- img , _ , err := image .Decode (r )
122
- check (err )
123
- if bounds := img .Bounds (); bounds .Dx () > THUMBNAIL_MAX_WIDTH ||
124
- bounds .Dy () > THUMBNAIL_MAX_HEIGHT {
125
- w , h := THUMBNAIL_MAX_WIDTH , THUMBNAIL_MAX_HEIGHT
126
- if bounds .Dx () > bounds .Dy () {
127
- h = bounds .Dy () * h / bounds .Dx ()
128
- } else {
129
- w = bounds .Dx () * w / bounds .Dy ()
130
- }
131
- img = resize .Resize (img , img .Bounds (), w , h )
89
+ if imageTypes .MatchString (fi .Type ) {
90
+ servingUrl , err := image .ServingURL (
91
+ c ,
92
+ fi .Key ,
93
+ & image.ServingURLOptions {
94
+ Secure : strings .HasSuffix (u .Scheme , "s" ),
95
+ Size : 0 ,
96
+ Crop : false ,
97
+ },
98
+ )
99
+ check (err )
100
+ fi .ThumbnailUrl = servingUrl .String () + THUMBNAIL_PARAM
132
101
}
133
- var b bytes.Buffer
134
- err = png .Encode (& b , img )
135
- check (err )
136
- data = b .Bytes ()
137
- fi .ThumbnailUrl = "data:image/png;base64," +
138
- base64 .StdEncoding .EncodeToString (data )
139
- return
140
102
}
141
103
142
104
func check (err error ) {
@@ -174,7 +136,6 @@ func handleUpload(r *http.Request, p *multipart.Part) (fi *FileInfo) {
174
136
fi .Error = rec .(error ).Error ()
175
137
}
176
138
}()
177
- var b bytes.Buffer
178
139
lr := & io.LimitedReader {R : p , N : MAX_FILE_SIZE + 1 }
179
140
context := appengine .NewContext (r )
180
141
w , err := blobstore .Create (context , fi .Type )
@@ -189,17 +150,10 @@ func handleUpload(r *http.Request, p *multipart.Part) (fi *FileInfo) {
189
150
return
190
151
}
191
152
delayedDelete (context , fi )
192
- if b .Len () > 0 {
193
- fi .CreateThumbnail (& b , context )
194
- }
195
153
fi .CreateUrls (r , context )
196
154
}()
197
155
check (err )
198
- var wr io.Writer = w
199
- if imageTypes .MatchString (fi .Type ) {
200
- wr = io .MultiWriter (& b , w )
201
- }
202
- _ , err = io .Copy (wr , lr )
156
+ _ , err = io .Copy (w , lr )
203
157
return
204
158
}
205
159
@@ -253,7 +207,7 @@ func get(w http.ResponseWriter, r *http.Request) {
253
207
fmt .Sprintf ("attachment; filename=%s;" , parts [2 ]),
254
208
)
255
209
}
256
- blobstore .Send (w , appengine . BlobKey ( key ) )
210
+ blobstore .Send (w , blobKey )
257
211
return
258
212
}
259
213
}
@@ -285,48 +239,12 @@ func delete(w http.ResponseWriter, r *http.Request) {
285
239
}
286
240
if key := parts [1 ]; key != "" {
287
241
c := appengine .NewContext (r )
288
- blobstore .Delete (c , appengine .BlobKey (key ))
289
- memcache .Delete (c , key )
290
- }
291
- }
292
-
293
- func serveThumbnail (w http.ResponseWriter , r * http.Request ) {
294
- parts := strings .Split (r .URL .Path , "/" )
295
- if len (parts ) == 3 {
296
- if key := parts [2 ]; key != "" {
297
- var data []byte
298
- c := appengine .NewContext (r )
299
- item , err := memcache .Get (c , key )
300
- if err == nil {
301
- data = item .Value
302
- } else {
303
- blobKey := appengine .BlobKey (key )
304
- if _ , err = blobstore .Stat (c , blobKey ); err == nil {
305
- fi := FileInfo {Key : blobKey }
306
- data , _ = fi .CreateThumbnail (
307
- blobstore .NewReader (c , blobKey ),
308
- c ,
309
- )
310
- }
311
- }
312
- if err == nil && len (data ) > 3 {
313
- w .Header ().Add (
314
- "Cache-Control" ,
315
- fmt .Sprintf ("public,max-age=%d" , EXPIRATION_TIME ),
316
- )
317
- contentType := "image/png"
318
- if string (data [:3 ]) == "GIF" {
319
- contentType = "image/gif"
320
- } else if string (data [1 :4 ]) != "PNG" {
321
- contentType = "image/jpeg"
322
- }
323
- w .Header ().Set ("Content-Type" , contentType )
324
- fmt .Fprintln (w , string (data ))
325
- return
326
- }
327
- }
242
+ blobKey := appengine .BlobKey (key )
243
+ err := blobstore .Delete (c , blobKey )
244
+ check (err )
245
+ err = image .DeleteServingURL (c , blobKey )
246
+ check (err )
328
247
}
329
- http .Error (w , "404 Not Found" , http .StatusNotFound )
330
248
}
331
249
332
250
func handle (w http.ResponseWriter , r * http.Request ) {
@@ -357,5 +275,4 @@ func handle(w http.ResponseWriter, r *http.Request) {
357
275
358
276
func init () {
359
277
http .HandleFunc ("/" , handle )
360
- http .HandleFunc ("/thumbnails/" , serveThumbnail )
361
278
}
0 commit comments