userset.go 1.8 KB

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