[READ-ONLY] Mirror of https://github.com/andrioid/s3preview. Preview serving microservice for s3. Generates and uploads any missing thumbnails. Redirects to existing.
1package main
2
3import (
4 "fmt"
5 "github.com/disintegration/imaging"
6 "github.com/gorilla/mux"
7 "github.com/rlmcpherson/s3gof3r"
8 _ "image/jpeg"
9 _ "image/png"
10 "log"
11 "net/http"
12 //"net/url"
13 //"image/color"
14 "path"
15)
16
17func registerHandlers(r *mux.Router) {
18 //r.HandleFunc("/passthrough/{object:[0-9a-z/_.-]+}", PassthroughHandler)
19 r.HandleFunc("/{object:[0-9A-Za-z/_.-]+}", ThumbnailHandler)
20 //r.HandleFunc("/{object:[0-9a-z/-_.]+}/{previewType:[a-zA-Z0-9_-]+}", ThumbnailHandler)
21 r.HandleFunc("/", HelloHandler)
22}
23
24func HelloHandler(rw http.ResponseWriter, r *http.Request) {
25 fmt.Fprintf(rw, "s3preview - See https://github.com/andrioid/s3preview for more information.")
26}
27
28func ThumbnailHandler(rw http.ResponseWriter, r *http.Request) {
29 object := mux.Vars(r)["object"]
30 previewType := r.FormValue("t")
31
32 if previewType == "" {
33 http.Error(rw, "Preview Type empty. E.g. Add ?t=small to your URL", 400)
34 //fmt.Fprintf(rw, "previewType empty. Add \"/passthrough/\" in front of your URL to see the original")
35 return
36 }
37
38 typeOptions, ok := configuration.Previews[previewType]
39
40 if ok != true {
41 http.Error(rw, "previewType not configured", 400)
42 return
43 }
44
45 k, err := s3gof3r.EnvKeys() // get S3 keys from environment
46 if err != nil {
47 fmt.Fprint(rw, err.Error())
48 return
49 }
50
51 // Create s3 path for thumbnail
52 s3path := path.Join(configuration.Preview_Prefix, previewType, object)
53 s3url := fmt.Sprintf("http://%s.%s/%s", configuration.Preview_Bucket, configuration.StorageDomain, path.Join(configuration.Preview_Prefix, previewType, object))
54
55 // Ask Mr. Bloom
56 exists := previewBloom.TestString(s3path)
57
58 if exists == true {
59 // Thumbnail exists, redirect and return
60 //fmt.Fprintf(rw, "Redirecting to: %s", s3url)
61
62 http.Redirect(rw, r, s3url, 301)
63 return
64 }
65
66 // Fetch image and generate stuff
67 // - TODO: Check if we're too busy to create the thumbnail now. Return a temporary error 502 if we are.
68 // - TODO: Add the object into preview queue for later processing
69
70 // Open bucket to put file into
71 s3 := s3gof3r.New("", k)
72 b := s3.Bucket(configuration.Asset_Bucket)
73
74 rb, _, err := b.GetReader(path.Join(configuration.Asset_Prefix, object), nil)
75
76 if err != nil {
77 fmt.Fprint(rw, err.Error())
78 return
79 }
80
81 orgImg, err := imaging.Decode(rb)
82 log.Printf("GET %s", path.Join(configuration.Asset_Prefix, object))
83
84 if err != nil {
85 http.Error(rw, err.Error(), 400)
86 return
87 }
88
89 dstImg, err := Preview(&orgImg, typeOptions)
90
91 if err != nil {
92 http.Error(rw, err.Error(), 400)
93 return
94 }
95
96 // Put into Preview Bucket
97 pb := s3.Bucket(configuration.Preview_Bucket)
98
99 hdr := make(http.Header)
100 hdr.Add("Content-Type", "image/jpg")
101
102 prw, err := pb.PutWriter(s3path, hdr, nil)
103
104 if err = imaging.Encode(prw, dstImg, imaging.JPEG); err != nil {
105 http.Error(rw, err.Error(), 400)
106 return
107 }
108
109 if err = prw.Close(); err != nil {
110 fmt.Fprintf(rw, err.Error())
111 return
112 }
113 log.Printf("PUT %s", s3path)
114
115 previewBloom.AddString(s3path)
116
117 // Output to browser
118 err = imaging.Encode(rw, dstImg, imaging.JPEG)
119 if err != nil {
120 fmt.Fprintf(rw, err.Error())
121 return
122
123 }
124}