userset.go 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. package core
  2. import (
  3. "time"
  4. v2hash "github.com/v2ray/v2ray-core/hash"
  5. )
  6. const (
  7. updateIntervalSec = 10
  8. cacheDurationSec = 120
  9. )
  10. type UserSet interface {
  11. AddUser(user User) error
  12. GetUser(timeHash []byte) (*ID, int64, bool)
  13. }
  14. type TimedUserSet struct {
  15. validUserIds []ID
  16. userHashes map[string]indexTimePair
  17. }
  18. type indexTimePair struct {
  19. index int
  20. timeSec int64
  21. }
  22. type hashEntry struct {
  23. hash string
  24. timeSec int64
  25. }
  26. func NewTimedUserSet() UserSet {
  27. vuSet := new(TimedUserSet)
  28. vuSet.validUserIds = make([]ID, 0, 16)
  29. vuSet.userHashes = make(map[string]indexTimePair)
  30. go vuSet.updateUserHash(time.Tick(updateIntervalSec * time.Second))
  31. return vuSet
  32. }
  33. func (us *TimedUserSet) updateUserHash(tick <-chan time.Time) {
  34. now := time.Now().UTC()
  35. lastSec := now.Unix() - cacheDurationSec
  36. hash2Remove := make(chan hashEntry, cacheDurationSec*3*len(us.validUserIds))
  37. lastSec2Remove := now.Unix()
  38. idHash := v2hash.NewTimeHash(v2hash.HMACHash{})
  39. for {
  40. now := <-tick
  41. nowSec := now.UTC().Unix()
  42. remove2Sec := nowSec - cacheDurationSec
  43. if remove2Sec > lastSec2Remove {
  44. for lastSec2Remove+1 < remove2Sec {
  45. entry := <-hash2Remove
  46. lastSec2Remove = entry.timeSec
  47. delete(us.userHashes, entry.hash)
  48. }
  49. }
  50. for lastSec < nowSec+cacheDurationSec {
  51. for idx, id := range us.validUserIds {
  52. idHash := idHash.Hash(id.Bytes, lastSec)
  53. hash2Remove <- hashEntry{string(idHash), lastSec}
  54. us.userHashes[string(idHash)] = indexTimePair{idx, lastSec}
  55. }
  56. lastSec++
  57. }
  58. }
  59. }
  60. func (us *TimedUserSet) AddUser(user User) error {
  61. id := user.Id
  62. us.validUserIds = append(us.validUserIds, id)
  63. return nil
  64. }
  65. func (us TimedUserSet) GetUser(userHash []byte) (*ID, int64, bool) {
  66. pair, found := us.userHashes[string(userHash)]
  67. if found {
  68. return &us.validUserIds[pair.index], pair.timeSec, true
  69. }
  70. return nil, 0, false
  71. }