user_validator.go 3.3 KB

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