|
|
@@ -0,0 +1,107 @@
|
|
|
+package hub
|
|
|
+
|
|
|
+import (
|
|
|
+ "net"
|
|
|
+ "sync"
|
|
|
+ "time"
|
|
|
+)
|
|
|
+
|
|
|
+type AwaitingConnection struct {
|
|
|
+ conn net.Conn
|
|
|
+ expire time.Time
|
|
|
+}
|
|
|
+
|
|
|
+func (this *AwaitingConnection) Expired() bool {
|
|
|
+ return this.expire.Before(time.Now())
|
|
|
+}
|
|
|
+
|
|
|
+type ConnectionCache struct {
|
|
|
+ sync.Mutex
|
|
|
+ cache map[string][]*AwaitingConnection
|
|
|
+}
|
|
|
+
|
|
|
+func NewConnectionCache() *ConnectionCache {
|
|
|
+ c := &ConnectionCache{
|
|
|
+ cache: make(map[string][]*AwaitingConnection),
|
|
|
+ }
|
|
|
+ go c.Cleanup()
|
|
|
+ return c
|
|
|
+}
|
|
|
+
|
|
|
+func (this *ConnectionCache) Cleanup() {
|
|
|
+ for {
|
|
|
+ time.Sleep(time.Second * 4)
|
|
|
+ this.Lock()
|
|
|
+ for key, value := range this.cache {
|
|
|
+ size := len(value)
|
|
|
+ changed := false
|
|
|
+ for i := 0; i < size; {
|
|
|
+ if value[i].Expired() {
|
|
|
+ value[i].conn.Close()
|
|
|
+ value[i] = value[size-1]
|
|
|
+ size--
|
|
|
+ changed = true
|
|
|
+ } else {
|
|
|
+ i++
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if changed {
|
|
|
+ for i := size; i < len(value); i++ {
|
|
|
+ value[i] = nil
|
|
|
+ }
|
|
|
+ value = value[:size]
|
|
|
+ this.cache[key] = value
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.Unlock()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (this *ConnectionCache) Recycle(dest string, conn net.Conn) {
|
|
|
+ this.Lock()
|
|
|
+ defer this.Unlock()
|
|
|
+
|
|
|
+ aconn := &AwaitingConnection{
|
|
|
+ conn: conn,
|
|
|
+ expire: time.Now().Add(time.Second * 4),
|
|
|
+ }
|
|
|
+
|
|
|
+ var list []*AwaitingConnection
|
|
|
+ if v, found := this.cache[dest]; found {
|
|
|
+ v = append(v, aconn)
|
|
|
+ list = v
|
|
|
+ } else {
|
|
|
+ list = []*AwaitingConnection{aconn}
|
|
|
+ }
|
|
|
+ this.cache[dest] = list
|
|
|
+}
|
|
|
+
|
|
|
+func FindFirstValid(list []*AwaitingConnection) int {
|
|
|
+ for idx, conn := range list {
|
|
|
+ if !conn.Expired() {
|
|
|
+ return idx
|
|
|
+ }
|
|
|
+ conn.conn.Close()
|
|
|
+ }
|
|
|
+ return -1
|
|
|
+}
|
|
|
+
|
|
|
+func (this *ConnectionCache) Get(dest string) net.Conn {
|
|
|
+ this.Lock()
|
|
|
+ defer this.Unlock()
|
|
|
+
|
|
|
+ list, found := this.cache[dest]
|
|
|
+ if !found {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ firstValid := FindFirstValid(list)
|
|
|
+ if firstValid == -1 {
|
|
|
+ delete(this.cache, dest)
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ res := list[firstValid].conn
|
|
|
+ list = list[firstValid+1:]
|
|
|
+ this.cache[dest] = list
|
|
|
+ return res
|
|
|
+}
|