hashStorage.go 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. package global
  2. import (
  3. "crypto/md5"
  4. "encoding/hex"
  5. "regexp"
  6. "sync"
  7. "time"
  8. "x-ui/util/common"
  9. )
  10. type HashEntry struct {
  11. Hash string
  12. Value string
  13. Timestamp time.Time
  14. }
  15. type HashStorage struct {
  16. sync.RWMutex
  17. Data map[string]HashEntry
  18. Expiration time.Duration
  19. ForceSave bool
  20. }
  21. func NewHashStorage(expiration time.Duration, forceSave bool) *HashStorage {
  22. return &HashStorage{
  23. Data: make(map[string]HashEntry),
  24. Expiration: expiration,
  25. ForceSave: forceSave,
  26. }
  27. }
  28. func (h *HashStorage) AddHash(query string) string {
  29. if h.ForceSave {
  30. return h.saveValue(query)
  31. }
  32. // we only need to hash for more than 64 chars by default
  33. if len(query) <= 64 {
  34. return query
  35. }
  36. return h.saveValue(query)
  37. }
  38. func (h *HashStorage) saveValue(query string) string {
  39. h.Lock()
  40. defer h.Unlock()
  41. md5Hash := md5.Sum([]byte(query))
  42. md5HashString := hex.EncodeToString(md5Hash[:])
  43. entry := HashEntry{
  44. Hash: md5HashString,
  45. Value: query,
  46. Timestamp: time.Now(),
  47. }
  48. h.Data[md5HashString] = entry
  49. return md5HashString
  50. }
  51. func (h *HashStorage) GetValue(hash string) (string, error) {
  52. h.RLock()
  53. defer h.RUnlock()
  54. entry, exists := h.Data[hash]
  55. if !exists {
  56. if h.isMD5(hash) {
  57. return "", common.NewError("hash not found in storage!")
  58. }
  59. return hash, nil
  60. }
  61. return entry.Value, nil
  62. }
  63. func (h *HashStorage) isMD5(hash string) bool {
  64. match, _ := regexp.MatchString("^[a-f0-9]{32}$", hash)
  65. return match
  66. }
  67. func (h *HashStorage) RemoveExpiredHashes() {
  68. h.Lock()
  69. defer h.Unlock()
  70. now := time.Now()
  71. for hash, entry := range h.Data {
  72. if now.Sub(entry.Timestamp) > h.Expiration {
  73. delete(h.Data, hash)
  74. }
  75. }
  76. }
  77. func (h *HashStorage) Reset() {
  78. h.Lock()
  79. defer h.Unlock()
  80. h.Data = make(map[string]HashEntry)
  81. }