connection_cache.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. package ws
  2. import (
  3. "net"
  4. "sync"
  5. "time"
  6. "github.com/v2ray/v2ray-core/common/log"
  7. "github.com/v2ray/v2ray-core/common/signal"
  8. )
  9. type AwaitingConnection struct {
  10. conn *wsconn
  11. expire time.Time
  12. }
  13. func (this *AwaitingConnection) Expired() bool {
  14. return this.expire.Before(time.Now())
  15. }
  16. type ConnectionCache struct {
  17. sync.Mutex
  18. cache map[string][]*AwaitingConnection
  19. cleanupOnce signal.Once
  20. }
  21. func NewConnectionCache() *ConnectionCache {
  22. return &ConnectionCache{
  23. cache: make(map[string][]*AwaitingConnection),
  24. }
  25. }
  26. func (this *ConnectionCache) Cleanup() {
  27. defer this.cleanupOnce.Reset()
  28. for len(this.cache) > 0 {
  29. time.Sleep(time.Second * 7)
  30. this.Lock()
  31. for key, value := range this.cache {
  32. size := len(value)
  33. changed := false
  34. for i := 0; i < size; {
  35. if value[i].Expired() {
  36. value[i].conn.Close()
  37. value[i] = value[size-1]
  38. size--
  39. changed = true
  40. } else {
  41. i++
  42. }
  43. }
  44. if changed {
  45. for i := size; i < len(value); i++ {
  46. value[i] = nil
  47. }
  48. value = value[:size]
  49. this.cache[key] = value
  50. }
  51. }
  52. this.Unlock()
  53. }
  54. }
  55. func (this *ConnectionCache) Recycle(dest string, conn *wsconn) {
  56. this.Lock()
  57. defer this.Unlock()
  58. aconn := &AwaitingConnection{
  59. conn: conn,
  60. expire: time.Now().Add(time.Second * 7),
  61. }
  62. var list []*AwaitingConnection
  63. if v, found := this.cache[dest]; found {
  64. v = append(v, aconn)
  65. list = v
  66. } else {
  67. list = []*AwaitingConnection{aconn}
  68. }
  69. this.cache[dest] = list
  70. go this.cleanupOnce.Do(this.Cleanup)
  71. }
  72. func FindFirstValid(list []*AwaitingConnection) int {
  73. for idx, conn := range list {
  74. if !conn.Expired() && !conn.conn.connClosing {
  75. return idx
  76. }
  77. go conn.conn.Close()
  78. }
  79. return -1
  80. }
  81. func (this *ConnectionCache) Get(dest string) net.Conn {
  82. this.Lock()
  83. defer this.Unlock()
  84. list, found := this.cache[dest]
  85. if !found {
  86. return nil
  87. }
  88. firstValid := FindFirstValid(list)
  89. if firstValid == -1 {
  90. delete(this.cache, dest)
  91. return nil
  92. }
  93. res := list[firstValid].conn
  94. list = list[firstValid+1:]
  95. this.cache[dest] = list
  96. log.Debug("WS:Conn Cache used.")
  97. return res
  98. }