cache.go 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. package currency
  2. import (
  3. "sync"
  4. "time"
  5. )
  6. type memoryCache struct {
  7. mu sync.RWMutex
  8. data map[string]*cachedRates
  9. ttl time.Duration
  10. janitor *time.Ticker
  11. }
  12. func newMemoryCache(ttl time.Duration) *memoryCache {
  13. if ttl == 0 {
  14. ttl = 24 * time.Hour
  15. }
  16. cache := &memoryCache{
  17. data: make(map[string]*cachedRates),
  18. ttl: ttl,
  19. janitor: time.NewTicker(ttl / 2),
  20. }
  21. go cache.cleanup()
  22. return cache
  23. }
  24. func (c *memoryCache) get(baseCurrency string) (*cachedRates, bool) {
  25. c.mu.RLock()
  26. defer c.mu.RUnlock()
  27. rates, exists := c.data[baseCurrency]
  28. if !exists {
  29. return nil, false
  30. }
  31. if time.Now().After(rates.validUntil) {
  32. return nil, false
  33. }
  34. return rates, true
  35. }
  36. func (c *memoryCache) set(baseCurrency string, rates *cachedRates) {
  37. c.mu.Lock()
  38. defer c.mu.Unlock()
  39. rates.validUntil = rates.fetchedAt.Add(c.ttl)
  40. c.data[baseCurrency] = rates
  41. }
  42. func (c *memoryCache) clear() {
  43. c.mu.Lock()
  44. defer c.mu.Unlock()
  45. c.data = make(map[string]*cachedRates)
  46. }
  47. func (c *memoryCache) cleanup() {
  48. for range c.janitor.C {
  49. c.removeExpired()
  50. }
  51. }
  52. func (c *memoryCache) removeExpired() {
  53. c.mu.Lock()
  54. defer c.mu.Unlock()
  55. now := time.Now()
  56. for key, rates := range c.data {
  57. if now.After(rates.validUntil) {
  58. delete(c.data, key)
  59. }
  60. }
  61. }
  62. func (c *memoryCache) stop() {
  63. if c.janitor != nil {
  64. c.janitor.Stop()
  65. }
  66. }
  67. func (c *memoryCache) stats() (entries int, oldestEntry time.Time) {
  68. c.mu.RLock()
  69. defer c.mu.RUnlock()
  70. entries = len(c.data)
  71. for _, rates := range c.data {
  72. if oldestEntry.IsZero() || rates.fetchedAt.Before(oldestEntry) {
  73. oldestEntry = rates.fetchedAt
  74. }
  75. }
  76. return entries, oldestEntry
  77. }