Merge pull request #188 in YUNIONIO/onecloud from ~QIUJIAN/onecloud:hotfix/qj-redundant-params to release/2.2.0

* commit '1a30516b0f82d34401c0f78ff69317a343c0aafa':
  minor fixes
  修正:radix match params只包含匹配的参数
This commit is contained in:
邱剑
2018-09-12 14:53:37 +08:00
11 changed files with 90 additions and 51 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)
+3 -3
View File
@@ -31,10 +31,10 @@ func fetchById(manager IModelManager, idStr string) (IModel, error) {
}
}
func fetchByName(manager IModelManager, ownerProjId string, idStr string) (IModel, error) {
func fetchByName(manager IModelManager, owner string, idStr string) (IModel, error) {
q := manager.Query()
q = manager.FilterByName(q, idStr)
q = manager.FilterByOwner(q, ownerProjId)
q = manager.FilterByOwner(q, owner)
count := q.Count()
if count == 1 {
obj, err := NewModelObject(manager)
@@ -101,7 +101,7 @@ func fetchItemByName(manager IModelManager, ctx context.Context, userCred mcclie
}
}
q = manager.FilterByName(q, idStr)
q = manager.FilterByOwner(q, userCred.GetProjectId())
q = manager.FilterByOwner(q, manager.GetOwnerId(userCred))
count := q.Count()
if count == 1 {
item, err := NewModelObject(manager)
+1 -1
View File
@@ -37,7 +37,7 @@ type IModelManager interface {
FilterById(q *sqlchemy.SQuery, idStr string) *sqlchemy.SQuery
FilterByNotId(q *sqlchemy.SQuery, idStr string) *sqlchemy.SQuery
FilterByName(q *sqlchemy.SQuery, name string) *sqlchemy.SQuery
FilterByOwner(q *sqlchemy.SQuery, ownerProjId string) *sqlchemy.SQuery
FilterByOwner(q *sqlchemy.SQuery, owner string) *sqlchemy.SQuery
GetOwnerId(userCred mcclient.TokenCredential) string
+1 -1
View File
@@ -104,7 +104,7 @@ func (manager *SModelBaseManager) FilterByName(q *sqlchemy.SQuery, name string)
return q
}
func (manager *SModelBaseManager) FilterByOwner(q *sqlchemy.SQuery, ownerProjId string) *sqlchemy.SQuery {
func (manager *SModelBaseManager) FilterByOwner(q *sqlchemy.SQuery, owner string) *sqlchemy.SQuery {
return q
}
+2 -2
View File
@@ -7,11 +7,11 @@ import (
"yunion.io/x/pkg/util/stringutils"
)
func isNameUnique(manager IModelManager, ownerProjId string, name string) bool {
func isNameUnique(manager IModelManager, owner string, name string) bool {
q := manager.Query()
q = manager.FilterByName(q, name)
if !globalVirtualResourceNamespace {
q = manager.FilterByOwner(q, ownerProjId)
q = manager.FilterByOwner(q, owner)
}
return q.Count() == 0
}
+3 -3
View File
@@ -349,9 +349,9 @@ func (self *SOpsLogManager) FilterByName(q *sqlchemy.SQuery, name string) *sqlch
return q
}
func (self *SOpsLogManager) FilterByOwner(q *sqlchemy.SQuery, ownerProjId string) *sqlchemy.SQuery {
if len(ownerProjId) > 0 {
return q.Equals("owner_project_id", ownerProjId)
func (self *SOpsLogManager) FilterByOwner(q *sqlchemy.SQuery, owner string) *sqlchemy.SQuery {
if len(owner) > 0 {
return q.Equals("owner_project_id", owner)
} else {
return q
}
+2 -2
View File
@@ -22,8 +22,8 @@ func NewSharableVirtualResourceBaseManager(dt interface{}, tableName string, key
return SSharableVirtualResourceBaseManager{SVirtualResourceBaseManager: NewVirtualResourceBaseManager(dt, tableName, keyword, keywordPlural)}
}
func (manager *SSharableVirtualResourceBaseManager) FilterByOwner(q *sqlchemy.SQuery, ownerProjId string) *sqlchemy.SQuery {
q = q.Filter(sqlchemy.OR(sqlchemy.Equals(q.Field("tenant_id"), ownerProjId), sqlchemy.IsTrue(q.Field("is_public"))))
func (manager *SSharableVirtualResourceBaseManager) FilterByOwner(q *sqlchemy.SQuery, owner string) *sqlchemy.SQuery {
q = q.Filter(sqlchemy.OR(sqlchemy.Equals(q.Field("tenant_id"), owner), sqlchemy.IsTrue(q.Field("is_public"))))
q = q.Filter(sqlchemy.OR(sqlchemy.IsNull(q.Field("pending_deleted")), sqlchemy.IsFalse(q.Field("pending_deleted"))))
q = q.Filter(sqlchemy.OR(sqlchemy.IsNull(q.Field("is_system")), sqlchemy.IsFalse(q.Field("is_system"))))
return q
+1 -1
View File
@@ -87,7 +87,7 @@ func (manager *STaskManager) FilterByName(q *sqlchemy.SQuery, name string) *sqlc
return q
}
func (manager *STaskManager) FilterByOwner(q *sqlchemy.SQuery, ownerProjId string) *sqlchemy.SQuery {
func (manager *STaskManager) FilterByOwner(q *sqlchemy.SQuery, owner string) *sqlchemy.SQuery {
return q
}
+2 -2
View File
@@ -49,8 +49,8 @@ func (model *SVirtualResourceBase) GetOwnerProjectId() string {
return model.ProjectId
}
func (manager *SVirtualResourceBaseManager) FilterByOwner(q *sqlchemy.SQuery, ownerProjId string) *sqlchemy.SQuery {
q = q.Equals("tenant_id", ownerProjId)
func (manager *SVirtualResourceBaseManager) FilterByOwner(q *sqlchemy.SQuery, owner string) *sqlchemy.SQuery {
q = q.Equals("tenant_id", owner)
q = q.Filter(sqlchemy.OR(sqlchemy.IsNull(q.Field("pending_deleted")), sqlchemy.IsFalse(q.Field("pending_deleted"))))
q = q.Filter(sqlchemy.OR(sqlchemy.IsNull(q.Field("is_system")), sqlchemy.IsFalse(q.Field("is_system"))))
return q
+2 -2
View File
@@ -116,8 +116,8 @@ func totalKeypairCount(userId string) int {
return q.Count()
}
func (manager *SKeypairManager) FilterByOwner(q *sqlchemy.SQuery, ownerId string) *sqlchemy.SQuery {
return q.Equals("owner_id", ownerId)
func (manager *SKeypairManager) FilterByOwner(q *sqlchemy.SQuery, owner string) *sqlchemy.SQuery {
return q.Equals("owner_id", owner)
}
func (self *SKeypair) GetOwnerProjectId() string {