Skip to content

Commit

Permalink
bugfix: all gree
Browse files Browse the repository at this point in the history
  • Loading branch information
vm-001 committed Dec 20, 2023
1 parent 70c1e12 commit cd591cc
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 45 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,10 @@ Router.new({
})

```


## 匹配规则

静态路由优先级最高
长度越长优先级越高
prefix
129 changes: 100 additions & 29 deletions spec/router_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,76 @@ describe("Router", function()
end)

describe("methods", function()

local router = Router.new({
{
paths = { "/aa" },
handler = "1",
methods = { "GET" }
},
{
paths = { "/aa" },
handler = "2",
methods = { "POST" }
},
{
paths = { "/aa/bb*" },
handler = "3",
methods = { "GET" }
},
{
paths = { "/aa/:name" },
handler = "4",
methods = { "POST" }
},
{
paths = { "/cc/dd*" },
handler = "5",
methods = { "GET" }
},
{
paths = { "/cc/:p1/ee/:p2" },
handler = "6",
methods = { "POST" },
},
{
paths = { "/cc/:p1/ee/p2*" },
handler = "7",
methods = { "PUT" },
},
{
paths = { "/cc/:p1/ee/:p2/ff" },
handler = "8",
methods = { "PATCH" },
},
})
it("sanity", function()
assert.equal("1", router:match("/aa", { method = "GET" }))
assert.equal("2", router:match("/aa", { method = "POST" }))
assert.equal("3", router:match("/aa/bb", { method = "GET" }))
assert.equal("4", router:match("/aa/name", { method = "POST" }))
assert.equal("5", router:match("/cc/dd", { method = "GET" }))
assert.equal("6", router:match("/cc/p1/ee/p2", { method = "POST" }))
assert.equal("7", router:match("/cc/p1/ee/p2x", { method = "PUT" }))
assert.equal("8", router:match("/cc/p1/ee/p2/ff", { method = "PATCH" }))
end)
it("path matches multiple routes", function()
-- path matches handler3 and handler4
assert.equal("4", router:match("/aa/bb", { method = "POST" }))
-- path matches handler5 and handler6 and handler7
assert.equal("5", router:match("/cc/dd/ee/p2", { method = "GET" }))
assert.equal("6", router:match("/cc/dd/ee/p2", { method = "POST" }))
assert.equal("7", router:match("/cc/dd/ee/p2", { method = "PUT" }))
-- path matches handler5 and handler7 and handler8
assert.equal("5", router:match("/cc/dd/ee/p2/ff", { method = "GET" }))
--local mobdebug = require "mobdebug"
--mobdebug.start("localhost", 28172)
assert.equal("7", router:match("/cc/dd/ee/p2/ff", { method = "PUT" }))
assert.equal("8", router:match("/cc/dd/ee/p2/ff", { method = "PATCH" }))
end)
end)

describe("priority", function()
it("matches first registered for same priority", function()
describe("matching order", function()
it("first registered first match", function()
local router = Router.new({
{
paths = { "/static" },
Expand Down Expand Up @@ -175,7 +240,34 @@ describe("Router", function()
assert.equal("3", router:match("/param/name"))
assert.equal("5", router:match("/prefix"))
end)
it("matches higher priority", function()
it("static > dynamic", function()
local router = Router.new({
--{
-- paths = { "/aa/bb" },
-- handler = "1",
--},
{
paths = { "/aa/bb*" },
handler = "2",
methods = { "GET" }
},
{
paths = { "/aa/:name" },
handler = "3",
methods = { "POST" }
}
})
--local mobdebug = require "mobdebug"
--mobdebug.start("localhost", 28172)
--assert.equal("3", router:match("/aa/bb", { method = "POST" }))
end)
it("longest path first match", function()

end)
end)

describe("priority", function()
it("highest priority first match", function()
local router = Router.new({
{
paths = { "/static" },
Expand Down Expand Up @@ -250,7 +342,7 @@ describe("Router", function()
end)
end)

describe("match with params binding", function()
pending("match with params binding", function()
it("sanity", function()
local router = Router.new({
{
Expand All @@ -277,29 +369,8 @@ describe("Router", function()
assert.equal("3", router:match("/prefix2/name/id/match", ctx))
assert.same({ name = "name", id = "id" }, ctx.matched)

assert.equal("2", router:match("/prefix2/name/id/match1", ctx))
assert.same({ name = "name/id/match1" }, ctx.matched)
--assert.equal("2", router:match("/prefix2/name/id/match1", ctx))
--assert.same({ name = "name/id/match1" }, ctx.matched)
end)
end)
end)


local function test()
local radix = require("resty.radixtree")
local rx = radix.new({
{
paths = { "/prefix2*name" },
metadata = "2",
priority = 2,
},
{
paths = { "/prefix2/:name/:id/match" },
metadata = "3",
priority = 1,
},
})

ngx.say(rx:match("/prefix2/name/id/match1"))
end

test()
end)
81 changes: 65 additions & 16 deletions src/resty/trie.lua
Original file line number Diff line number Diff line change
Expand Up @@ -169,30 +169,64 @@ function TrieNode:add(path, value, fn)
end

local matched_values = {} -- 叫做 visted_leaf 呢?表示所有访问过的叶子结点?
local branchs = {}
local paths = {}

function TrieNode:traverse(path, ctx)
local binding_params = ctx.matched ~= nil
local param_n = 0

local matched_n = 0
clear_table(matched_values)
local branchs_n = 0
clear_table(branchs)
clear_table(paths)

local node = self
local prefix
local prefix_n
local path_n
local idx


while true do
::continue::

-- 到这里的 node 节点都是 static
if node.type == TYPES.PARAM then
local i = find(path, "/", 1, true) or #path + 1 -- todo 写一个 while 来实现
i = i - 1
if binding_params then
-- todo 参数绑定
end
if i < #path then -- 还没到终点
if node.children_n > 0 then
path = str_sub(path, i + 1)
local first_char = str_sub(path, 1, 1)
idx = node.indexs[first_char]
if idx then
node = node.children[idx]
goto continue
end
end
else
if node.value then
if binding_params then

end
matched_n = matched_n + 1
matched_values[matched_n] = node.value
end
end

goto continue1
end

prefix = node.path
prefix_n = node.path_n
path_n = #path -- path_n 有没有可能可以通过游标去减,而不是每次都 #path?

if path_n > prefix_n then
-- path: /a/b/c
-- prefix: /*
if starts_with(path, prefix, path_n, prefix_n) then
path = str_sub(path, prefix_n + 1)

Expand All @@ -201,8 +235,20 @@ function TrieNode:traverse(path, ctx)
-- 如果子节点中有 catchall 类型,说明 child 节点是能匹配的
matched_n = matched_n + 1
matched_values[matched_n] = node.children[idx].value -- todo 既然这里已经选中了,为什么不做参数绑定呢?
if binding_params then
param_n = param_n + 1
ctx.matched[param_n] = path
end
end

idx = node.indexs[":"]
if idx then
branchs_n = branchs_n + 1
branchs[branchs_n] = node.children[idx]
paths[branchs_n] = path
end


local first_char = str_sub(path, 1, 1)
idx = node.indexs[first_char]
if idx then
Expand All @@ -218,17 +264,7 @@ function TrieNode:traverse(path, ctx)
-- match("/a/john/doge")
-- ctx.matched 就会变成 { "john/doge", "john" }
-- 如果外面参数绑定的时候能先去掉 john,再去掉 "/john/doge" 倒叙,那应该是没问题的?

-- 作用是啥?
idx = node.indexs["*"]
if idx then
matched_n = matched_n + 1
matched_values[matched_n] = node.children[idx].value
if binding_params then
param_n = param_n + 1
ctx.matched[param_n] = path
end
end
--

idx = node.indexs[":"]
if idx then
Expand Down Expand Up @@ -280,11 +316,24 @@ function TrieNode:traverse(path, ctx)
end
end

if matched_n > 0 then
return matched_values, matched_n
--if matched_n > 0 then
-- return matched_values, matched_n
--end
--
--return nil, 0

::continue1::

if branchs_n > 0 then
node = branchs[branchs_n]
--branchs[branchs_n] = nil
path = paths[branchs_n]
--paths[branchs_n] = nil
branchs_n = branchs_n - 1
else
break
end

return nil, 0
end

if matched_n > 0 then
Expand Down
8 changes: 8 additions & 0 deletions src/resty/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ local math_min = math.min
local is_luajit = type(_G.jit) == "table"

local clear_table
local new_table
do
local ok
ok, clear_table = pcall(require, "table.clear")
Expand All @@ -16,6 +17,12 @@ do
end
end
end
ok, new_table = pcall(require, "table.new")
if not ok then
new_table = function()
return {}
end
end
end


Expand Down Expand Up @@ -95,6 +102,7 @@ return {
starts_with = starts_with,
has_wildcard = has_wildcard,
clear_table = clear_table,
new_table = new_table,
breakpoint = breakpoint,
is_luajit = is_luajit,
ends_with = ends_with,
Expand Down

0 comments on commit cd591cc

Please sign in to comment.