diff --git a/adapters/outbound/base.go b/adapters/outbound/base.go index f255111b..710afad0 100644 --- a/adapters/outbound/base.go +++ b/adapters/outbound/base.go @@ -193,3 +193,9 @@ func (p *Proxy) URLTest(ctx context.Context, url string) (t uint16, err error) { func NewProxy(adapter C.ProxyAdapter) *Proxy { return &Proxy{adapter, queue.New(10), true} } + +// ProxyGroupOption contain the common options for all kind of ProxyGroup +type ProxyGroupOption struct { + Name string `proxy:"name"` + Proxies []string `proxy:"proxies"` +} diff --git a/config/config.go b/config/config.go index 080a6e49..e1baac8f 100644 --- a/config/config.go +++ b/config/config.go @@ -302,7 +302,7 @@ func parseProxies(cfg *rawConfig) (map[string]C.Proxy, error) { } // check if any loop exists and sort the ProxyGroups - if err := proxyGroupsDagSort(groupsConfig); err != nil { + if err := proxyGroupsDagSort(groupsConfig, decoder); err != nil { return nil, err } diff --git a/config/utils.go b/config/utils.go index f2832f56..e263d68b 100644 --- a/config/utils.go +++ b/config/utils.go @@ -4,6 +4,8 @@ import ( "fmt" "strings" + adapters "github.com/Dreamacro/clash/adapters/outbound" + "github.com/Dreamacro/clash/common/structure" C "github.com/Dreamacro/clash/constant" ) @@ -38,9 +40,9 @@ func or(pointers ...*int) *int { // Check if ProxyGroups form DAG(Directed Acyclic Graph), and sort all ProxyGroups by dependency order. // Meanwhile, record the original index in the config file. // If loop is detected, return an error with location of loop. -func proxyGroupsDagSort(groupsConfig []map[string]interface{}) error { +func proxyGroupsDagSort(groupsConfig []map[string]interface{}, decoder *structure.Decoder) error { - type Node struct { + type graphNode struct { indegree int // topological order topo int @@ -51,32 +53,31 @@ func proxyGroupsDagSort(groupsConfig []map[string]interface{}) error { from []string } - graph := make(map[string]*Node) + graph := make(map[string]*graphNode) // Step 1.1 build dependency graph - for idx, mapping := range groupsConfig { - groupName, existName := mapping["name"].(string) - if !existName { - return fmt.Errorf("ProxyGroup %d: missing name", idx) + for _, mapping := range groupsConfig { + option := &adapters.ProxyGroupOption{} + err := decoder.Decode(mapping, option) + groupName := option.Name + if err != nil { + return fmt.Errorf("ProxyGroup %s: %s", groupName, err.Error()) } + if node, ok := graph[groupName]; ok { if node.data != nil { return fmt.Errorf("ProxyGroup %s: duplicate group name", groupName) } node.data = mapping } else { - graph[groupName] = &Node{0, -1, mapping, 0, nil} + graph[groupName] = &graphNode{0, -1, mapping, 0, nil} } - proxies, existProxies := mapping["proxies"] - if !existProxies { - return fmt.Errorf("ProxyGroup %s: the `proxies` field is requried", groupName) - } - for _, proxy := range proxies.([]interface{}) { - proxy := proxy.(string) + + for _, proxy := range option.Proxies { if node, ex := graph[proxy]; ex { node.indegree++ } else { - graph[proxy] = &Node{1, -1, nil, 0, nil} + graph[proxy] = &graphNode{1, -1, nil, 0, nil} } } }