From c8e919af3330af3f8c53ce17da5f4b48a6ff84be Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Tue, 11 Sep 2018 23:57:19 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=EF=BC=9Aradix=20match=20para?= =?UTF-8?q?ms=E5=8F=AA=E5=8C=85=E5=90=AB=E5=8C=B9=E9=85=8D=E7=9A=84?= =?UTF-8?q?=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/appsrv/radix.go | 95 +++++++++++++++++++++++++++------------- pkg/appsrv/radix_test.go | 12 +++-- 2 files changed, 73 insertions(+), 34 deletions(-) diff --git a/pkg/appsrv/radix.go b/pkg/appsrv/radix.go index 380bee48c1..67ddd20a95 100644 --- a/pkg/appsrv/radix.go +++ b/pkg/appsrv/radix.go @@ -3,24 +3,26 @@ package appsrv import ( "fmt" "strings" + ) type RadixNode struct { data interface{} + fullPath []string next []*RadixNode parent *RadixNode matchNext *RadixNode - matchTable []string + // matchTable []string segment string } func NewRadix() *RadixNode { return &RadixNode{data: nil, - next: make([]*RadixNode, 0), - matchNext: nil, - matchTable: nil, - parent: nil, - segment: ""} + fullPath: nil, + next: make([]*RadixNode, 0), + matchNext: nil, + parent: nil, + segment: ""} } func (r *RadixNode) String() string { @@ -50,11 +52,21 @@ func isMatchSegment(seg string) bool { } func (r *RadixNode) Add(segments []string, data interface{}) error { + return r.add(segments, segments, data) +} + +func (r *RadixNode) add(path []string, segments []string, data interface{}) error { + // log.Debugf("add %#v %#v", path, segments) + if len(segments) == 0 { if r.data != nil { return fmt.Errorf("Duplicate data for node %s", r.String()) } else { r.data = data + r.fullPath = make([]string, len(path)) + for i := 0; i < len(path); i += 1 { + r.fullPath[i] = path[i] + } return nil } } @@ -65,18 +77,18 @@ func (r *RadixNode) Add(segments []string, data interface{}) error { return fmt.Errorf("%s has been registered, %s conflict with %s", r.matchNext.String(), r.matchNext.segment, segments[0]) } */ nextNode = r.matchNext - nextNode.matchTable = append(nextNode.matchTable, segments[0]) + // nextNode.matchTable = append(nextNode.matchTable, segments[0]) } else { nextNode = NewRadix() nextNode.segment = "<*>" nextNode.parent = r - nextNode.matchTable = []string{segments[0]} + // nextNode.matchTable = []string{segments[0]} r.matchNext = nextNode } } else { - for _, node := range r.next { - if node.segment == segments[0] { - nextNode = node + for i := 0; i < len(r.next); i += 1 { + if r.next[i].segment == segments[0] { + nextNode = r.next[i] break } } @@ -87,42 +99,46 @@ func (r *RadixNode) Add(segments []string, data interface{}) error { r.next = append(r.next, nextNode) } } - return nextNode.Add(segments[1:], data) + return nextNode.add(path, segments[1:], data) } func (r *RadixNode) Match(segments []string, params map[string]string) interface{} { + data, allPaths := r.match(segments) + // log.Debugf("%#v", allPaths) + for i := 0; i < len(segments); i += 1 { + for j := 0; j < len(allPaths); j += 1 { + if i < len(allPaths[j]) && isMatchSegment(allPaths[j][i]) { + params[allPaths[j][i]] = segments[i] + } + } + } + return data +} + +func (r *RadixNode) match(segments []string) (interface{}, [][]string) { if len(segments) == 0 { - return r.data + return r.data, r.getAllFullPaths() } else { - var ret interface{} = nil + var retData interface{} = nil + var retPath [][]string = nil exactMatch := false for _, node := range r.next { if node.segment == segments[0] { - ret = node.Match(segments[1:], params) - if ret != nil { - // log.Debugf("Match %s ret %#v", node.segment, ret) + retData, retPath = node.match(segments[1:]) + if retData != nil { exactMatch = true - } else { - // log.Debugf("No match %s ret %#v", node.segment, ret) } break } } - if ret != nil { - return ret + if retData != nil { + return retData, retPath } else { if !exactMatch && r.matchNext != nil { - ret = r.matchNext.Match(segments[1:], params) - if ret != nil { - for _, segname := range r.matchNext.matchTable { - if _, ok := params[segname]; !ok { - params[segname] = segments[0] - } - } - } - return ret + retData, retPath = r.matchNext.match(segments[1:]) + return retData, retPath } else { - return r.data + return r.data, r.getAllFullPaths() } } } @@ -139,3 +155,20 @@ func (r *RadixNode) Walk(f func(path string, data interface{})) { r.matchNext.Walk(f) } } + +func (r *RadixNode) getAllFullPaths() [][]string { + if r.fullPath != nil { + return [][]string{r.fullPath} + }else { + ret := make([][]string, 0) + for _, node := range r.next { + fp := node.getAllFullPaths() + ret = append(ret, fp...) + } + if r.matchNext != nil { + fp := r.matchNext.getAllFullPaths() + ret = append(ret, fp...) + } + return ret + } +} diff --git a/pkg/appsrv/radix_test.go b/pkg/appsrv/radix_test.go index fe978ceec3..ef87a46398 100644 --- a/pkg/appsrv/radix_test.go +++ b/pkg/appsrv/radix_test.go @@ -61,10 +61,16 @@ func TestRadixNode(t *testing.T) { func TestParams(t *testing.T) { r := NewRadix() - r.Add([]string{"POST", "clouds", ""}, "classAction") - r.Add([]string{"POST", "clouds", "", ""}, "objectAction") + r.Add([]string{"POST", "clouds", ""}, "classAction") + r.Add([]string{"POST", "clouds", "", "sync"}, "objectSyncAction") + r.Add([]string{"POST", "clouds", "", ""}, "objectAction") params := make(map[string]string) - ret := r.Match([]string{"POST", "clouds", "id", "sync"}, params) + ret := r.Match([]string{"POST", "clouds", "myid", "sync"}, params) + t.Logf("match: %s", ret) + t.Logf("params: %s", params) + + params = make(map[string]string) + ret = r.Match([]string{"POST", "clouds", "myid", "start"}, params) t.Logf("match: %s", ret) t.Logf("params: %s", params)