reprogl

Форк
0
/
avatar.go 
117 строк · 2.3 Кб
1
package handlers
2

3
import (
4
	"bufio"
5
	"bytes"
6
	"errors"
7
	"image"
8
	"image/png"
9
	"io/fs"
10
	"net/http"
11
	"os"
12
	"os/exec"
13
	"strconv"
14
	"time"
15

16
	"github.com/go-chi/chi/v5"
17
	"xelbot.com/reprogl/container"
18
	"xelbot.com/reprogl/models"
19
	"xelbot.com/reprogl/utils/avatar"
20
	"xelbot.com/reprogl/utils/hashid"
21
)
22

23
func AvatarGenerator(app *container.Application) http.HandlerFunc {
24
	return func(w http.ResponseWriter, r *http.Request) {
25
		hash := chi.URLParam(r, "hash")
26

27
		writeAvatar(w, app, hash, 80)
28
	}
29
}
30

31
func AvatarGeneratorWithSize(app *container.Application) http.HandlerFunc {
32
	return func(w http.ResponseWriter, r *http.Request) {
33
		hash := chi.URLParam(r, "hash")
34
		sizeStr := chi.URLParam(r, "size")
35

36
		size, err := strconv.Atoi(sizeStr)
37
		if err != nil {
38
			app.NotFound(w)
39
			return
40
		}
41

42
		writeAvatar(w, app, hash, size)
43
	}
44
}
45

46
func writeAvatar(w http.ResponseWriter, app *container.Application, hash string, size int) {
47
	hashModel, err := hashid.Decode(hash, true)
48
	if err != nil {
49
		app.NotFound(w)
50
		return
51
	}
52

53
	img, err := avatar.GenerateAvatar(hashModel, app, size)
54
	if err != nil {
55
		if errors.Is(err, models.RecordNotFound) || errors.Is(err, avatar.InvalidSize) {
56
			app.NotFound(w)
57
		} else {
58
			app.ServerError(w, err)
59
		}
60

61
		return
62
	}
63

64
	expires := time.Now().Add(container.AvatarTTL * time.Second)
65

66
	cacheControl(w, container.AvatarTTL)
67
	setExpires(w, expires)
68
	w.Header().Set("Content-Type", "image/png")
69

70
	rawImage, err := pngquantPipe(img)
71
	if err != nil {
72
		panic(err)
73
	}
74

75
	saveToFile(hash, size, rawImage)
76

77
	_, err = w.Write(rawImage)
78
	if err != nil {
79
		app.ServerError(w, err)
80
	}
81
}
82

83
func pngquantPipe(avatarImage image.Image) ([]byte, error) {
84
	buf := new(bytes.Buffer)
85
	err := png.Encode(buf, avatarImage)
86
	if err != nil {
87
		return []byte{}, err
88
	}
89

90
	quantBuf := new(bytes.Buffer)
91

92
	cmd := exec.Command("/usr/bin/pngquant", "-s1", "--quality=60-80", "-")
93
	cmd.Stdin = bufio.NewReader(buf)
94
	cmd.Stderr = os.Stderr
95
	cmd.Stdout = quantBuf
96

97
	err = cmd.Run()
98
	if err != nil {
99
		return []byte{}, err
100
	}
101

102
	return quantBuf.Bytes(), nil
103
}
104

105
func saveToFile(hash string, size int, rawImage []byte) {
106
	var postfix string
107
	if size != 80 {
108
		postfix = ".w" + strconv.Itoa(size)
109
	}
110

111
	filename := "public/images/avatar/" + hash + postfix + ".png"
112
	f, err := os.Open(filename)
113
	if errors.Is(err, fs.ErrNotExist) {
114
		_ = os.WriteFile(filename, rawImage, 0644)
115
	}
116
	_ = f.Close()
117
}
118

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.