| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485 |
- // emoji_favorites.go handles persistence of the user's favorite emoji list,
- // stored as a JSON file in the cache directory.
- package chat
- import (
- "encoding/json"
- "log/slog"
- "os"
- "path/filepath"
- "sync"
- "github.com/ayn2op/discordo/internal/consts"
- )
- const maxFavoriteEmoji = 10
- // maxFavoritesFileSize is the upper bound on the emoji favorites JSON file (4 KiB).
- const maxFavoritesFileSize = 4096
- // maxFavoriteEmojiLen is the maximum byte length of a single emoji favorite string.
- const maxFavoriteEmojiLen = 64
- type emojiFavorites struct {
- Favorites []string `json:"favorites"`
- mu sync.RWMutex
- }
- var emojiFavoritesPath = filepath.Join(consts.CacheDir(), "emoji_favorites.json")
- func loadEmojiFavorites() *emojiFavorites {
- ef := &emojiFavorites{}
- data, err := os.ReadFile(emojiFavoritesPath)
- if err != nil {
- return ef
- }
- if len(data) > maxFavoritesFileSize {
- slog.Warn("emoji favorites file too large, ignoring", "size", len(data))
- return ef
- }
- if err := json.Unmarshal(data, ef); err != nil {
- slog.Warn("failed to parse emoji favorites", "err", err)
- return &emojiFavorites{}
- }
- // Reject any favorite strings that exceed the length limit.
- valid := ef.Favorites[:0]
- for _, e := range ef.Favorites {
- if len(e) <= maxFavoriteEmojiLen {
- valid = append(valid, e)
- } else {
- slog.Warn("emoji favorite too long, skipping", "len", len(e))
- }
- }
- ef.Favorites = valid
- return ef
- }
- // save persists favorites to disk. The caller must hold ef.mu.
- func (ef *emojiFavorites) save() {
- atomicSaveJSON(emojiFavoritesPath, ef)
- }
- func (ef *emojiFavorites) toggle(emoji string) {
- ef.mu.Lock()
- defer ef.mu.Unlock()
- for i, e := range ef.Favorites {
- if e == emoji {
- ef.Favorites = append(ef.Favorites[:i], ef.Favorites[i+1:]...)
- ef.save()
- return
- }
- }
- if len(ef.Favorites) >= maxFavoriteEmoji {
- return
- }
- ef.Favorites = append(ef.Favorites, emoji)
- ef.save()
- }
- func (ef *emojiFavorites) list() []string {
- ef.mu.RLock()
- defer ef.mu.RUnlock()
- out := make([]string, len(ef.Favorites))
- copy(out, ef.Favorites)
- return out
- }
|