summaryrefslogtreecommitdiff
path: root/internal/router/client-cache.go
blob: 3104a66f322e94cb792935262f0ba8ce93648c78 (plain)
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
package router

import (
	"encoding/base64"
	"log/slog"
	"sync"

	"golang.org/x/crypto/argon2"
)

type ClientCache struct {
	hashMap      map[string]string
	mutexLikeMap map[string]*sync.Mutex
	mutexHashMap map[string]*sync.Mutex
	likePageMap  map[string]map[string]struct{}
	salt         []byte
}

var CCache *ClientCache

func NewClientCache(salt []byte) *ClientCache {
	return &ClientCache{
		hashMap:      make(map[string]string),
		mutexLikeMap: make(map[string]*sync.Mutex),
		mutexHashMap: make(map[string]*sync.Mutex),
		likePageMap:  make(map[string]map[string]struct{}),
		salt:         salt,
	}
}

func (c *ClientCache) GetHash(id string) string {
	if val, ok := c.hashMap[id]; ok {
		slog.Debug("gave an old hash", slog.String("hash", val))
		return val
	}

	if _, ok := c.mutexHashMap[id]; !ok {
		c.mutexHashMap[id] = &sync.Mutex{}
	}
	c.mutexHashMap[id].Lock()
	defer c.mutexHashMap[id].Unlock()

	if val, ok := c.hashMap[id]; ok {
		slog.Debug("gave a newly generated hash", slog.String("hash", val))
		return val
	}

	c.hashMap[id] = base64.RawStdEncoding.EncodeToString(argon2.IDKey([]byte(id), c.salt, 1, 64*1024, 4, 32))
	slog.Debug("generated hash", slog.String("hash", c.hashMap[id]))
	return c.hashMap[id]
}

func (c *ClientCache) GetLikeStatus(id string, page string) bool {
	if _, ok := c.likePageMap[page]; !ok {
		return false
	}
	_, ok := c.likePageMap[page][c.GetHash(id)]
	return ok
}

func (c *ClientCache) LikeOn(id string, page string) (alreadyLiked bool) {
	if _, ok := c.mutexLikeMap[id]; !ok {
		c.mutexLikeMap[id] = &sync.Mutex{}
	}
	c.mutexLikeMap[id].Lock()
	defer c.mutexLikeMap[id].Unlock()

	hash := c.GetHash(id)

	if userSet, ok := c.likePageMap[page]; ok {
		_, alreadyLiked = userSet[hash]
		c.likePageMap[page][hash] = struct{}{}
		return
	}

	c.likePageMap[page] = make(map[string]struct{})
	c.likePageMap[page][hash] = struct{}{}
	return
}

func (c *ClientCache) LikeOff(id string, page string) (alreadyUnliked bool) {
	if _, ok := c.mutexLikeMap[id]; !ok {
		c.mutexLikeMap[id] = &sync.Mutex{}
	}
	c.mutexLikeMap[id].Lock()
	defer c.mutexLikeMap[id].Unlock()

	if _, ok := c.likePageMap[page]; !ok {
		return true
	}
	hash := c.GetHash(id)
	if _, ok := c.likePageMap[page][hash]; !ok {
		return true
	}

	delete(c.likePageMap[page], hash)
	return false
}