user_validator.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  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. account := user.Account.(*VMessAccount)
  94. nowSec := time.Now().Unix()
  95. entry := &idEntry{
  96. id: account.ID,
  97. userIdx: idx,
  98. lastSec: Timestamp(nowSec - cacheDurationSec),
  99. lastSecRemoval: Timestamp(nowSec - cacheDurationSec*3),
  100. }
  101. this.generateNewHashes(Timestamp(nowSec+cacheDurationSec), idx, entry)
  102. this.ids = append(this.ids, entry)
  103. for _, alterid := range account.AlterIDs {
  104. entry := &idEntry{
  105. id: alterid,
  106. userIdx: idx,
  107. lastSec: Timestamp(nowSec - cacheDurationSec),
  108. lastSecRemoval: Timestamp(nowSec - cacheDurationSec*3),
  109. }
  110. this.generateNewHashes(Timestamp(nowSec+cacheDurationSec), idx, entry)
  111. this.ids = append(this.ids, entry)
  112. }
  113. return nil
  114. }
  115. func (this *TimedUserValidator) Get(userHash []byte) (*User, Timestamp, bool) {
  116. defer this.access.RUnlock()
  117. this.access.RLock()
  118. var fixedSizeHash [16]byte
  119. copy(fixedSizeHash[:], userHash)
  120. pair, found := this.userHash[fixedSizeHash]
  121. if found {
  122. return this.validUsers[pair.index], pair.timeSec, true
  123. }
  124. return nil, 0, false
  125. }