修正:radix match params只包含匹配的参数

This commit is contained in:
Qiu Jian
2018-09-11 23:57:19 +08:00
parent 3b6b0c3795
commit c8e919af33
2 changed files with 73 additions and 34 deletions
+64 -31
View File
@@ -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
}
}
+9 -3
View File
@@ -61,10 +61,16 @@ func TestRadixNode(t *testing.T) {
func TestParams(t *testing.T) {
r := NewRadix()
r.Add([]string{"POST", "clouds", "<action>"}, "classAction")
r.Add([]string{"POST", "clouds", "<resid>", "<action>"}, "objectAction")
r.Add([]string{"POST", "clouds", "<cls_action>"}, "classAction")
r.Add([]string{"POST", "clouds", "<resid>", "sync"}, "objectSyncAction")
r.Add([]string{"POST", "clouds", "<resid>", "<obj_action>"}, "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)