user_validator.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. package protocol
  2. import (
  3. "hash"
  4. "sync"
  5. "time"
  6. )
  7. const (
  8. updateIntervalSec = 10
  9. cacheDurationSec = 120
  10. )
  11. type IDHash func(key []byte) hash.Hash
  12. type idEntry struct {
  13. id *ID
  14. userIdx int
  15. lastSec Timestamp
  16. lastSecRemoval Timestamp
  17. }
  18. type UserValidator interface {
  19. Add(user *User) error
  20. Get(timeHash []byte) (*User, Timestamp, bool)
  21. }
  22. type TimedUserValidator struct {
  23. validUsers []*User
  24. userHash map[[16]byte]*indexTimePair
  25. ids []*idEntry
  26. access sync.RWMutex
  27. hasher IDHash
  28. }
  29. type indexTimePair struct {
  30. index int
  31. timeSec Timestamp
  32. }
  33. func NewTimedUserValidator(hasher IDHash) UserValidator {
  34. tus := &TimedUserValidator{
  35. validUsers: make([]*User, 0, 16),
  36. userHash: make(map[[16]byte]*indexTimePair, 512),
  37. access: sync.RWMutex{},
  38. ids: make([]*idEntry, 0, 512),
  39. hasher: hasher,
  40. }
  41. go tus.updateUserHash(time.Tick(updateIntervalSec * time.Second))
  42. return tus
  43. }
  44. func (this *TimedUserValidator) generateNewHashes(nowSec Timestamp, idx int, entry *idEntry) {
  45. var hashValue [16]byte
  46. var hashValueRemoval [16]byte
  47. idHash := this.hasher(entry.id.Bytes())
  48. for entry.lastSec <= nowSec {
  49. idHash.Write(entry.lastSec.Bytes())
  50. idHash.Sum(hashValue[:0])
  51. idHash.Reset()
  52. idHash.Write(entry.lastSecRemoval.Bytes())
  53. idHash.Sum(hashValueRemoval[:0])
  54. idHash.Reset()
  55. this.access.Lock()
  56. this.userHash[hashValue] = &indexTimePair{idx, entry.lastSec}
  57. delete(this.userHash, hashValueRemoval)
  58. this.access.Unlock()
  59. entry.lastSec++
  60. entry.lastSecRemoval++
  61. }
  62. }
  63. func (this *TimedUserValidator) updateUserHash(tick <-chan time.Time) {
  64. for now := range tick {
  65. nowSec := Timestamp(now.Unix() + cacheDurationSec)
  66. for _, entry := range this.ids {
  67. this.generateNewHashes(nowSec, entry.userIdx, entry)
  68. }
  69. }
  70. }
  71. func (this *TimedUserValidator) Add(user *User) error {
  72. idx := len(this.validUsers)
  73. this.validUsers = append(this.validUsers, user)
  74. nowSec := time.Now().Unix()
  75. entry := &idEntry{
  76. id: user.ID,
  77. userIdx: idx,
  78. lastSec: Timestamp(nowSec - cacheDurationSec),
  79. lastSecRemoval: Timestamp(nowSec - cacheDurationSec*3),
  80. }
  81. this.generateNewHashes(Timestamp(nowSec+cacheDurationSec), idx, entry)
  82. this.ids = append(this.ids, entry)
  83. for _, alterid := range user.AlterIDs {
  84. entry := &idEntry{
  85. id: alterid,
  86. userIdx: idx,
  87. lastSec: Timestamp(nowSec - cacheDurationSec),
  88. lastSecRemoval: Timestamp(nowSec - cacheDurationSec*3),
  89. }
  90. this.generateNewHashes(Timestamp(nowSec+cacheDurationSec), idx, entry)
  91. this.ids = append(this.ids, entry)
  92. }
  93. return nil
  94. }
  95. func (this *TimedUserValidator) Get(userHash []byte) (*User, Timestamp, bool) {
  96. defer this.access.RUnlock()
  97. this.access.RLock()
  98. var fixedSizeHash [16]byte
  99. copy(fixedSizeHash[:], userHash)
  100. pair, found := this.userHash[fixedSizeHash]
  101. if found {
  102. return this.validUsers[pair.index], pair.timeSec, true
  103. }
  104. return nil, 0, false
  105. }