emoji.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. package static
  2. import (
  3. "io/fs"
  4. "os"
  5. "path/filepath"
  6. "sync"
  7. "time"
  8. "github.com/owncast/owncast/models"
  9. "github.com/owncast/owncast/services/config"
  10. log "github.com/sirupsen/logrus"
  11. )
  12. var (
  13. emojiCacheMu sync.Mutex
  14. emojiCacheData = make([]models.CustomEmoji, 0)
  15. emojiCacheModTime time.Time
  16. )
  17. // UpdateEmojiList will update the cache (if required) and
  18. // return the modifiation time.
  19. func UpdateEmojiList(force bool) (time.Time, error) {
  20. var modTime time.Time
  21. emojiPathInfo, err := os.Stat(config.CustomEmojiPath)
  22. if err != nil {
  23. return modTime, err
  24. }
  25. modTime = emojiPathInfo.ModTime()
  26. if modTime.After(emojiCacheModTime) || force {
  27. emojiCacheMu.Lock()
  28. defer emojiCacheMu.Unlock()
  29. // double-check that another thread didn't update this while waiting.
  30. if modTime.After(emojiCacheModTime) || force {
  31. emojiCacheModTime = modTime
  32. if force {
  33. emojiCacheModTime = time.Now()
  34. }
  35. emojiFS := os.DirFS(config.CustomEmojiPath)
  36. if emojiFS == nil {
  37. return modTime, fmt.Errorf("unable to open custom emoji directory")
  38. }
  39. emojiCacheData = make([]models.CustomEmoji, 0)
  40. walkFunction := func(path string, d os.DirEntry, err error) error {
  41. if d == nil || d.IsDir() {
  42. return nil
  43. }
  44. emojiPath := filepath.Join(config.EmojiDir, path)
  45. fileName := d.Name()
  46. fileBase := fileName[:len(fileName)-len(filepath.Ext(fileName))]
  47. singleEmoji := models.CustomEmoji{Name: fileBase, URL: emojiPath}
  48. emojiCacheData = append(emojiCacheData, singleEmoji)
  49. return nil
  50. }
  51. if err := fs.WalkDir(emojiFS, ".", walkFunction); err != nil {
  52. log.Errorln("unable to fetch emojis: " + err.Error())
  53. }
  54. }
  55. }
  56. return modTime, nil
  57. }
  58. // GetEmojiList returns a list of custom emoji from the emoji directory.
  59. func GetEmojiList() []models.CustomEmoji {
  60. _, err := UpdateEmojiList(false)
  61. if err != nil {
  62. return nil
  63. }
  64. // Lock to make sure this doesn't get updated in the middle of reading
  65. emojiCacheMu.Lock()
  66. defer emojiCacheMu.Unlock()
  67. // return a copy of cache data, ensures underlying slice isn't affected
  68. // by future update
  69. emojiData := make([]models.CustomEmoji, len(emojiCacheData))
  70. copy(emojiData, emojiCacheData)
  71. return emojiData
  72. }