diff --git a/common/cache/cache.go b/common/cache/cache.go deleted file mode 100644 index e587d77b..00000000 --- a/common/cache/cache.go +++ /dev/null @@ -1,106 +0,0 @@ -package cache - -import ( - "runtime" - "sync" - "time" -) - -// Cache store element with a expired time -type Cache struct { - *cache -} - -type cache struct { - mapping sync.Map - janitor *janitor -} - -type element struct { - Expired time.Time - Payload any -} - -// Put element in Cache with its ttl -func (c *cache) Put(key any, payload any, ttl time.Duration) { - c.mapping.Store(key, &element{ - Payload: payload, - Expired: time.Now().Add(ttl), - }) -} - -// Get element in Cache, and drop when it expired -func (c *cache) Get(key any) any { - item, exist := c.mapping.Load(key) - if !exist { - return nil - } - elm := item.(*element) - // expired - if time.Since(elm.Expired) > 0 { - c.mapping.Delete(key) - return nil - } - return elm.Payload -} - -// GetWithExpire element in Cache with Expire Time -func (c *cache) GetWithExpire(key any) (payload any, expired time.Time) { - item, exist := c.mapping.Load(key) - if !exist { - return - } - elm := item.(*element) - // expired - if time.Since(elm.Expired) > 0 { - c.mapping.Delete(key) - return - } - return elm.Payload, elm.Expired -} - -func (c *cache) cleanup() { - c.mapping.Range(func(k, v any) bool { - key := k.(string) - elm := v.(*element) - if time.Since(elm.Expired) > 0 { - c.mapping.Delete(key) - } - return true - }) -} - -type janitor struct { - interval time.Duration - stop chan struct{} -} - -func (j *janitor) process(c *cache) { - ticker := time.NewTicker(j.interval) - for { - select { - case <-ticker.C: - c.cleanup() - case <-j.stop: - ticker.Stop() - return - } - } -} - -func stopJanitor(c *Cache) { - c.janitor.stop <- struct{}{} -} - -// New return *Cache -func New(interval time.Duration) *Cache { - j := &janitor{ - interval: interval, - stop: make(chan struct{}), - } - c := &cache{janitor: j} - go j.process(c) - C := &Cache{c} - runtime.SetFinalizer(C, stopJanitor) - return C -} diff --git a/common/cache/cache_test.go b/common/cache/cache_test.go deleted file mode 100644 index cf4a3914..00000000 --- a/common/cache/cache_test.go +++ /dev/null @@ -1,70 +0,0 @@ -package cache - -import ( - "runtime" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -func TestCache_Basic(t *testing.T) { - interval := 200 * time.Millisecond - ttl := 20 * time.Millisecond - c := New(interval) - c.Put("int", 1, ttl) - c.Put("string", "a", ttl) - - i := c.Get("int") - assert.Equal(t, i.(int), 1, "should recv 1") - - s := c.Get("string") - assert.Equal(t, s.(string), "a", "should recv 'a'") -} - -func TestCache_TTL(t *testing.T) { - interval := 200 * time.Millisecond - ttl := 20 * time.Millisecond - now := time.Now() - c := New(interval) - c.Put("int", 1, ttl) - c.Put("int2", 2, ttl) - - i := c.Get("int") - _, expired := c.GetWithExpire("int2") - assert.Equal(t, i.(int), 1, "should recv 1") - assert.True(t, now.Before(expired)) - - time.Sleep(ttl * 2) - i = c.Get("int") - j, _ := c.GetWithExpire("int2") - assert.Nil(t, i, "should recv nil") - assert.Nil(t, j, "should recv nil") -} - -func TestCache_AutoCleanup(t *testing.T) { - interval := 10 * time.Millisecond - ttl := 15 * time.Millisecond - c := New(interval) - c.Put("int", 1, ttl) - - time.Sleep(ttl * 2) - i := c.Get("int") - j, _ := c.GetWithExpire("int") - assert.Nil(t, i, "should recv nil") - assert.Nil(t, j, "should recv nil") -} - -func TestCache_AutoGC(t *testing.T) { - sign := make(chan struct{}) - go func() { - interval := 10 * time.Millisecond - ttl := 15 * time.Millisecond - c := New(interval) - c.Put("int", 1, ttl) - sign <- struct{}{} - }() - - <-sign - runtime.GC() -} diff --git a/common/cache/lrucache.go b/common/cache/lrucache.go index 25a1b48e..e0f5d20c 100644 --- a/common/cache/lrucache.go +++ b/common/cache/lrucache.go @@ -64,8 +64,8 @@ type LruCache struct { onEvict EvictCallback } -// NewLRUCache creates an LruCache -func NewLRUCache(options ...Option) *LruCache { +// New creates an LruCache +func New(options ...Option) *LruCache { lc := &LruCache{ lru: list.New(), cache: make(map[any]*list.Element), diff --git a/common/cache/lrucache_test.go b/common/cache/lrucache_test.go index 1a910b4a..1a09975d 100644 --- a/common/cache/lrucache_test.go +++ b/common/cache/lrucache_test.go @@ -19,7 +19,7 @@ var entries = []struct { } func TestLRUCache(t *testing.T) { - c := NewLRUCache() + c := New() for _, e := range entries { c.Set(e.key, e.value) @@ -45,7 +45,7 @@ func TestLRUCache(t *testing.T) { } func TestLRUMaxAge(t *testing.T) { - c := NewLRUCache(WithAge(86400)) + c := New(WithAge(86400)) now := time.Now().Unix() expected := now + 86400 @@ -88,7 +88,7 @@ func TestLRUMaxAge(t *testing.T) { } func TestLRUpdateOnGet(t *testing.T) { - c := NewLRUCache(WithAge(86400), WithUpdateAgeOnGet()) + c := New(WithAge(86400), WithUpdateAgeOnGet()) now := time.Now().Unix() expires := now + 86400/2 @@ -103,7 +103,7 @@ func TestLRUpdateOnGet(t *testing.T) { } func TestMaxSize(t *testing.T) { - c := NewLRUCache(WithSize(2)) + c := New(WithSize(2)) // Add one expired entry c.Set("foo", "bar") _, ok := c.Get("foo") @@ -117,7 +117,7 @@ func TestMaxSize(t *testing.T) { } func TestExist(t *testing.T) { - c := NewLRUCache(WithSize(1)) + c := New(WithSize(1)) c.Set(1, 2) assert.True(t, c.Exist(1)) c.Set(2, 3) @@ -130,7 +130,7 @@ func TestEvict(t *testing.T) { temp = key.(int) + value.(int) } - c := NewLRUCache(WithEvict(evict), WithSize(1)) + c := New(WithEvict(evict), WithSize(1)) c.Set(1, 2) c.Set(2, 3) @@ -138,7 +138,7 @@ func TestEvict(t *testing.T) { } func TestSetWithExpire(t *testing.T) { - c := NewLRUCache(WithAge(1)) + c := New(WithAge(1)) now := time.Now().Unix() tenSecBefore := time.Unix(now-10, 0) @@ -152,7 +152,7 @@ func TestSetWithExpire(t *testing.T) { } func TestStale(t *testing.T) { - c := NewLRUCache(WithAge(1), WithStale(true)) + c := New(WithAge(1), WithStale(true)) now := time.Now().Unix() tenSecBefore := time.Unix(now-10, 0) @@ -165,11 +165,11 @@ func TestStale(t *testing.T) { } func TestCloneTo(t *testing.T) { - o := NewLRUCache(WithSize(10)) + o := New(WithSize(10)) o.Set("1", 1) o.Set("2", 2) - n := NewLRUCache(WithSize(2)) + n := New(WithSize(2)) n.Set("3", 3) n.Set("4", 4) diff --git a/component/fakeip/pool.go b/component/fakeip/pool.go index e6730a05..1d39b112 100644 --- a/component/fakeip/pool.go +++ b/component/fakeip/pool.go @@ -168,7 +168,7 @@ func New(options Options) (*Pool, error) { } } else { pool.store = &memoryStore{ - cache: cache.NewLRUCache(cache.WithSize(options.Size * 2)), + cache: cache.New(cache.WithSize(options.Size * 2)), } } diff --git a/dns/enhancer.go b/dns/enhancer.go index 76f0f262..16ae0202 100644 --- a/dns/enhancer.go +++ b/dns/enhancer.go @@ -78,7 +78,7 @@ func NewEnhancer(cfg Config) *ResolverEnhancer { if cfg.EnhancedMode != C.DNSNormal { fakePool = cfg.Pool - mapping = cache.NewLRUCache(cache.WithSize(4096), cache.WithStale(true)) + mapping = cache.New(cache.WithSize(4096), cache.WithStale(true)) } return &ResolverEnhancer{ diff --git a/dns/resolver.go b/dns/resolver.go index 5eeda77f..2f993600 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -363,13 +363,13 @@ type Config struct { func NewResolver(config Config) *Resolver { defaultResolver := &Resolver{ main: transform(config.Default, nil), - lruCache: cache.NewLRUCache(cache.WithSize(4096), cache.WithStale(true)), + lruCache: cache.New(cache.WithSize(4096), cache.WithStale(true)), } r := &Resolver{ ipv6: config.IPv6, main: transform(config.Main, defaultResolver), - lruCache: cache.NewLRUCache(cache.WithSize(4096), cache.WithStale(true)), + lruCache: cache.New(cache.WithSize(4096), cache.WithStale(true)), hosts: config.Hosts, } diff --git a/listener/http/proxy.go b/listener/http/proxy.go index 32701e62..989d1196 100644 --- a/listener/http/proxy.go +++ b/listener/http/proxy.go @@ -5,7 +5,6 @@ import ( "net" "net/http" "strings" - "time" "github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/common/cache" @@ -15,7 +14,7 @@ import ( "github.com/Dreamacro/clash/log" ) -func HandleConn(c net.Conn, in chan<- C.ConnContext, cache *cache.Cache) { +func HandleConn(c net.Conn, in chan<- C.ConnContext, cache *cache.LruCache) { client := newClient(c.RemoteAddr(), in) defer client.CloseIdleConnections() @@ -99,7 +98,7 @@ func HandleConn(c net.Conn, in chan<- C.ConnContext, cache *cache.Cache) { conn.Close() } -func authenticate(request *http.Request, cache *cache.Cache) *http.Response { +func authenticate(request *http.Request, cache *cache.LruCache) *http.Response { authenticator := authStore.Authenticator() if authenticator != nil { credential := parseBasicProxyAuthorization(request) @@ -109,11 +108,11 @@ func authenticate(request *http.Request, cache *cache.Cache) *http.Response { return resp } - var authed any - if authed = cache.Get(credential); authed == nil { + authed, exist := cache.Get(credential) + if !exist { user, pass, err := decodeBasicProxyAuthorization(credential) authed = err == nil && authenticator.Verify(user, pass) - cache.Put(credential, authed, time.Minute) + cache.Set(credential, authed) } if !authed.(bool) { log.Infoln("Auth failed from %s", request.RemoteAddr) diff --git a/listener/http/server.go b/listener/http/server.go index bfdd9f1b..1c21cd63 100644 --- a/listener/http/server.go +++ b/listener/http/server.go @@ -2,7 +2,6 @@ package http import ( "net" - "time" "github.com/Dreamacro/clash/common/cache" C "github.com/Dreamacro/clash/constant" @@ -40,9 +39,9 @@ func NewWithAuthenticate(addr string, in chan<- C.ConnContext, authenticate bool return nil, err } - var c *cache.Cache + var c *cache.LruCache if authenticate { - c = cache.New(time.Second * 30) + c = cache.New(cache.WithAge(30)) } hl := &Listener{ diff --git a/listener/mixed/mixed.go b/listener/mixed/mixed.go index 57fd055e..f720e49f 100644 --- a/listener/mixed/mixed.go +++ b/listener/mixed/mixed.go @@ -2,7 +2,6 @@ package mixed import ( "net" - "time" "github.com/Dreamacro/clash/common/cache" N "github.com/Dreamacro/clash/common/net" @@ -16,7 +15,7 @@ import ( type Listener struct { listener net.Listener addr string - cache *cache.Cache + cache *cache.LruCache closed bool } @@ -45,7 +44,7 @@ func New(addr string, in chan<- C.ConnContext) (*Listener, error) { ml := &Listener{ listener: l, addr: addr, - cache: cache.New(30 * time.Second), + cache: cache.New(cache.WithAge(30)), } go func() { for { @@ -63,7 +62,7 @@ func New(addr string, in chan<- C.ConnContext) (*Listener, error) { return ml, nil } -func handleConn(conn net.Conn, in chan<- C.ConnContext, cache *cache.Cache) { +func handleConn(conn net.Conn, in chan<- C.ConnContext, cache *cache.LruCache) { conn.(*net.TCPConn).SetKeepAlive(true) bufConn := N.NewBufferedConn(conn)