memory.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. package store
  2. import (
  3. "container/list"
  4. "sync"
  5. "time"
  6. )
  7. // NewMemoryStore An internal store for captcha ids and their values.
  8. func NewMemoryStore(gcInterval, expiration time.Duration) Store {
  9. mstore := &memoryStore{
  10. data: make(map[string]*dataItem),
  11. list: list.New(),
  12. ticker: time.NewTicker(gcInterval),
  13. expiration: expiration,
  14. }
  15. go mstore.gc()
  16. return mstore
  17. }
  18. type dataItem struct {
  19. id string
  20. value []byte
  21. expiredAt time.Time
  22. }
  23. // memoryStore memory store
  24. type memoryStore struct {
  25. sync.RWMutex
  26. data map[string]*dataItem
  27. list *list.List
  28. ticker *time.Ticker
  29. expiration time.Duration
  30. }
  31. func (s *memoryStore) gc() {
  32. for range s.ticker.C {
  33. s.RLock()
  34. e := s.list.Front()
  35. s.RUnlock()
  36. for e != nil {
  37. item := e.Value.(*dataItem)
  38. if item.expiredAt.Before(time.Now()) {
  39. s.Lock()
  40. s.list.Remove(e)
  41. delete(s.data, item.id)
  42. e = e.Next()
  43. s.Unlock()
  44. } else {
  45. break
  46. }
  47. }
  48. }
  49. }
  50. func (s *memoryStore) Set(id string, digits []byte) {
  51. s.Lock()
  52. defer s.Unlock()
  53. expiredAt := time.Now().Add(s.expiration)
  54. if _, ok := s.data[id]; ok {
  55. e := s.list.Front()
  56. for e != nil {
  57. item := e.Value.(*dataItem)
  58. if item.id == id {
  59. item.value = digits
  60. item.expiredAt = expiredAt
  61. s.list.MoveToBack(e)
  62. break
  63. }
  64. e = e.Next()
  65. }
  66. return
  67. }
  68. item := &dataItem{
  69. id: id,
  70. value: digits,
  71. expiredAt: expiredAt,
  72. }
  73. s.data[id] = item
  74. s.list.PushBack(item)
  75. }
  76. func (s *memoryStore) Get(id string, clear bool) []byte {
  77. s.RLock()
  78. item, ok := s.data[id]
  79. s.RUnlock()
  80. if !ok {
  81. return nil
  82. }
  83. if clear {
  84. s.remove(id)
  85. }
  86. return item.value
  87. }
  88. func (s *memoryStore) remove(id string) {
  89. s.RLock()
  90. e := s.list.Front()
  91. for e != nil {
  92. item := e.Value.(*dataItem)
  93. if item.id == id {
  94. break
  95. }
  96. e = e.Next()
  97. }
  98. s.RUnlock()
  99. s.Lock()
  100. s.list.Remove(e)
  101. delete(s.data, id)
  102. s.Unlock()
  103. }