Skip to content

Commit

Permalink
Merge branch 'dev' into clashr
Browse files Browse the repository at this point in the history
# Conflicts:
#	hub/executor/executor.go
#	hub/route/configs.go
  • Loading branch information
Doris committed Dec 5, 2019
2 parents 046b3d7 + b0eaf80 commit cc9ab15
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 60 deletions.
14 changes: 14 additions & 0 deletions common/cache/lrucache.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@ import (
// Option is part of Functional Options Pattern
type Option func(*LruCache)

// EvictCallback is used to get a callback when a cache entry is evicted
type EvictCallback func(key interface{}, value interface{})

// WithEvict set the evict callback
func WithEvict(cb EvictCallback) Option {
return func(l *LruCache) {
l.onEvict = cb
}
}

// WithUpdateAgeOnGet update expires when Get element
func WithUpdateAgeOnGet() Option {
return func(l *LruCache) {
Expand Down Expand Up @@ -42,6 +52,7 @@ type LruCache struct {
cache map[interface{}]*list.Element
lru *list.List // Front is least-recent
updateAgeOnGet bool
onEvict EvictCallback
}

// NewLRUCache creates an LruCache
Expand Down Expand Up @@ -148,6 +159,9 @@ func (c *LruCache) deleteElement(le *list.Element) {
c.lru.Remove(le)
e := le.Value.(*entry)
delete(c.cache, e.key)
if c.onEvict != nil {
c.onEvict(e.key, e.value)
}
}

type entry struct {
Expand Down
21 changes: 21 additions & 0 deletions common/cache/lrucache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,24 @@ func TestMaxSize(t *testing.T) {
_, ok = c.Get("foo")
assert.False(t, ok)
}

func TestExist(t *testing.T) {
c := NewLRUCache(WithSize(1))
c.Set(1, 2)
assert.True(t, c.Exist(1))
c.Set(2, 3)
assert.False(t, c.Exist(1))
}

func TestEvict(t *testing.T) {
temp := 0
evict := func(key interface{}, value interface{}) {
temp = key.(int) + value.(int)
}

c := NewLRUCache(WithEvict(evict), WithSize(1))
c.Set(1, 2)
c.Set(2, 3)

assert.Equal(t, temp, 3)
}
54 changes: 7 additions & 47 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@ package config

import (
"fmt"
"io/ioutil"
"net"
"net/url"
"os"
"path/filepath"
"strings"

adapters "github.com/whojave/clash/adapters/outbound"
Expand Down Expand Up @@ -109,40 +107,12 @@ type rawConfig struct {
Rule []string `yaml:"Rule"`
}

// forward compatibility before 1.0
func readRawConfig(path string) ([]byte, error) {
data, err := ioutil.ReadFile(path)
if err == nil && len(data) != 0 {
return data, nil
}

if filepath.Ext(path) != ".yaml" {
return nil, err
}

path = path[:len(path)-5] + ".yml"
if _, err = os.Stat(path); err == nil {
return ioutil.ReadFile(path)
}

return data, nil
}

func readConfig(path string) (*rawConfig, error) {
if _, err := os.Stat(path); os.IsNotExist(err) {
return nil, err
}
data, err := readRawConfig(path)
if err != nil {
return nil, err
}

if len(data) == 0 {
return nil, fmt.Errorf("Configuration file %s is empty", path)
}
// Parse config
func Parse(buf []byte) (*Config, error) {
config := &Config{}

// config with some default value
rawConfig := &rawConfig{
rawCfg := &rawConfig{
AllowLan: false,
BindAddress: "*",
Mode: T.Rule,
Expand All @@ -164,18 +134,10 @@ func readConfig(path string) (*rawConfig, error) {
},
},
}
err = yaml.Unmarshal([]byte(data), &rawConfig)
return rawConfig, err
}

// Parse config
func Parse(path string) (*Config, error) {
config := &Config{}

rawCfg, err := readConfig(path)
if err != nil {
if err := yaml.Unmarshal(buf, &rawCfg); err != nil {
return nil, err
}

config.Experimental = &rawCfg.Experimental

general, err := parseGeneral(rawCfg)
Expand Down Expand Up @@ -226,9 +188,7 @@ func parseGeneral(cfg *rawConfig) (*General, error) {
logLevel := cfg.LogLevel

if externalUI != "" {
if !filepath.IsAbs(externalUI) {
externalUI = filepath.Join(C.Path.HomeDir(), externalUI)
}
externalUI = C.Path.Reslove(externalUI)

if _, err := os.Stat(externalUI); os.IsNotExist(err) {
return nil, fmt.Errorf("external-ui: %s not exist", externalUI)
Expand Down
10 changes: 10 additions & 0 deletions constant/path.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package constant
import (
"os"
P "path"
"path/filepath"
)

const Name = "clash"
Expand Down Expand Up @@ -43,6 +44,15 @@ func (p *path) Config() string {
return p.configFile
}

// Reslove return a absolute path or a relative path with homedir
func (p *path) Reslove(path string) string {
if !filepath.IsAbs(path) {
return filepath.Join(p.HomeDir(), path)
}

return path
}

func (p *path) MMDB() string {
return P.Join(p.homeDir, "Country.mmdb")
}
51 changes: 50 additions & 1 deletion hub/executor/executor.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package executor

import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"github.com/whojave/clash/component/auth"
trie "github.com/whojave/clash/component/domain-trie"
"github.com/whojave/clash/config"
Expand All @@ -12,14 +16,59 @@ import (
T "github.com/whojave/clash/tunnel"
)

// forward compatibility before 1.0
func readRawConfig(path string) ([]byte, error) {
data, err := ioutil.ReadFile(path)
if err == nil && len(data) != 0 {
return data, nil
}

if filepath.Ext(path) != ".yaml" {
return nil, err
}

path = path[:len(path)-5] + ".yml"
if _, fallbackErr := os.Stat(path); fallbackErr == nil {
return ioutil.ReadFile(path)
}

return data, err
}

func readConfig(path string) ([]byte, error) {
if _, err := os.Stat(path); os.IsNotExist(err) {
return nil, err
}
data, err := readRawConfig(path)
if err != nil {
return nil, err
}

if len(data) == 0 {
return nil, fmt.Errorf("Configuration file %s is empty", path)
}

return data, err
}

// Parse config with default config path
func Parse() (*config.Config, error) {
return ParseWithPath(C.Path.Config())
}

// ParseWithPath parse config with custom config path
func ParseWithPath(path string) (*config.Config, error) {
return config.Parse(path)
buf, err := readConfig(path)
if err != nil {
return nil, err
}

return config.Parse(buf)
}

// Parse config with default config path
func ParseWithBytes(buf []byte) (*config.Config, error) {
return ParseWithPath(C.Path.Config())
}

// ApplyConfig dispatch configure to all parts
Expand Down
38 changes: 26 additions & 12 deletions hub/route/configs.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"net/http"
"path/filepath"

"github.com/whojave/clash/config"
"github.com/whojave/clash/hub/executor"
"github.com/whojave/clash/log"
P "github.com/whojave/clash/proxy"
Expand Down Expand Up @@ -77,7 +78,8 @@ func patchConfigs(w http.ResponseWriter, r *http.Request) {
}

type updateConfigRequest struct {
Path string `json:"path"`
Path string `json:"path"`
Payload string `json:"payload"`
}

func updateConfigs(w http.ResponseWriter, r *http.Request) {
Expand All @@ -88,18 +90,30 @@ func updateConfigs(w http.ResponseWriter, r *http.Request) {
return
}

if !filepath.IsAbs(req.Path) {
render.Status(r, http.StatusBadRequest)
render.JSON(w, r, newError("path is not a absoluted path"))
return
}

force := r.URL.Query().Get("force") == "true"
cfg, err := executor.ParseWithPath(req.Path)
if err != nil {
render.Status(r, http.StatusBadRequest)
render.JSON(w, r, newError(err.Error()))
return
var cfg *config.Config
var err error

if req.Payload != "" {
cfg, err = executor.ParseWithBytes([]byte(req.Payload))
if err != nil {
render.Status(r, http.StatusBadRequest)
render.JSON(w, r, newError(err.Error()))
return
}
} else {
if !filepath.IsAbs(req.Path) {
render.Status(r, http.StatusBadRequest)
render.JSON(w, r, newError("path is not a absoluted path"))
return
}

cfg, err = executor.ParseWithPath(req.Path)
if err != nil {
render.Status(r, http.StatusBadRequest)
render.JSON(w, r, newError(err.Error()))
return
}
}

executor.ApplyConfig(cfg, force)
Expand Down

0 comments on commit cc9ab15

Please sign in to comment.