page_upload.go 3.74 KB
Newer Older
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
package main

import (
	"net/http"
	"fmt"
	"time"
	"encoding/json"
	"io"
	"mime/multipart"
	"path/filepath"
	"os"
	"encoding/base64"
	"crypto/rand"
)

type UploadData struct {
	User    UserInfo
	Results []Result
}

func detectMimeType(path string) (string, error) {
	file, err := os.Open(path)
	if err != nil {
		return "", err
	}

	buffer := make([]byte, 512)
	_, err = file.Read(buffer)
	if err != nil {
		return "", err
	}

	return http.DetectContentType(buffer), nil
}

func generateId() string {
	buffer := make([]byte, 4)
	rand.Read(buffer)

	return base64.URLEncoding.WithPadding(base64.NoPadding).EncodeToString(buffer)
}

func writeBody(reader io.ReadCloser, path string) error {
	out, err := os.Create(path)
	if err != nil {
		return err
	}
	defer out.Close()

	_, err = io.Copy(out, reader)
	if err != nil {
		return err
	}
	return out.Close()
}

func createImage(config *Config, body io.ReadCloser, fileHeader *multipart.FileHeader) (Image, error) {
	id := generateId()
	path := filepath.Join(config.SourceFolder, id)

	err := writeBody(body, path)
	if err != nil {
		return Image{}, err
	}

	mimeType, err := detectMimeType(path)
	if err != nil {
		return Image{}, err
	}

	image := Image{
		Id:           id,
		OriginalName: filepath.Base(fileHeader.Filename),
		CreatedAt:    time.Now(),
		MimeType:     mimeType,
	}
	return image, nil
}

func pageUpload(ctx PageContext) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "POST" {
			user := parseUser(r)

			err := r.ParseMultipartForm(32 << 20)
			if err != nil {
Janne Koschinski's avatar
Janne Koschinski committed
87 88 89 90
				if err = returnJson(w, []Result{{
					Success: false,
					Errors:  []string{err.Error()},
				}}); err != nil {
91 92 93 94
					panic(err)
				}
			}

Janne Koschinski's avatar
Janne Koschinski committed
95 96 97 98 99 100 101
			file, header, err := r.FormFile("file")
			if err != nil {
				if err = returnJson(w, []Result{{
					Success: false,
					Errors:  []string{err.Error()},
				}}); err != nil {
					panic(err)
102
				}
Janne Koschinski's avatar
Janne Koschinski committed
103 104 105 106 107 108 109 110 111
				return
			}
			image, err := createImage(ctx.Config, file, header)
			if err != nil {
				if err = returnJson(w, []Result{{
					Success: false,
					Errors:  []string{err.Error()},
				}}); err != nil {
					panic(err)
112
				}
Janne Koschinski's avatar
Janne Koschinski committed
113
				return
114 115 116
			}

			pubsub := ctx.Redis.Subscribe(ctx.Config.ResultChannel)
Janne Koschinski's avatar
Janne Koschinski committed
117 118 119 120
			_, err = ctx.Database.Exec("INSERT INTO images (id, owner, created_at, original_name, type) VALUES ($1, $2, $3, $4, $5)", image.Id, user.Id, image.CreatedAt, image.OriginalName, image.MimeType)
			if err != nil {
				panic(err)
			}
121

Janne Koschinski's avatar
Janne Koschinski committed
122 123 124 125 126 127 128
			data, err := json.Marshal(image)
			if err != nil {
				if err = returnJson(w, []Result{{
					Success: false,
					Errors:  []string{err.Error()},
				}}); err != nil {
					panic(err)
129
				}
Janne Koschinski's avatar
Janne Koschinski committed
130
				return
131 132
			}

Janne Koschinski's avatar
Janne Koschinski committed
133 134 135 136 137 138
			fmt.Printf("Created task %s at %d\n", image.Id, time.Now().Unix())
			ctx.Redis.RPush(fmt.Sprintf("queue:%s", ctx.Config.ImageQueue), data)
			fmt.Printf("Submitted task %s at %d\n", image.Id, time.Now().Unix())

			waiting := true
			for waiting {
139 140
				message, err := pubsub.ReceiveMessage()
				if err != nil {
Janne Koschinski's avatar
Janne Koschinski committed
141 142 143 144
					if err = returnJson(w, []Result{{
						Success: false,
						Errors:  []string{err.Error()},
					}}); err != nil {
145 146 147 148 149 150 151 152
						panic(err)
					}
					return
				}

				result := Result{}
				err = json.Unmarshal([]byte(message.Payload), &result)
				if err != nil {
Janne Koschinski's avatar
Janne Koschinski committed
153 154 155 156
					if err = returnJson(w, []Result{{
						Success: false,
						Errors:  []string{err.Error()},
					}}); err != nil {
157 158 159 160 161 162 163
						panic(err)
					}
					return
				}

				fmt.Printf("Returned task %s at %d\n", result.Id, time.Now().Unix())

Janne Koschinski's avatar
Janne Koschinski committed
164 165
				if result.Id == image.Id {
					waiting = false
166

Janne Koschinski's avatar
Janne Koschinski committed
167 168 169
					if err = returnJson(w, result); err != nil {
						panic(err)
					}
170 171 172 173 174 175 176 177 178 179 180 181 182 183
				}
			}
			return
		} else {
			user := parseUser(r)
			if err := formatTemplate(w, "upload.html", UploadData{
				user,
				[]Result{},
			}); err != nil {
				panic(err)
			}
		}
	})
}