aboutsummaryrefslogtreecommitdiffstats
path: root/msb-core/openresty-ext/src/assembly/resources/openresty/nginx/luaext/customrouter.lua
blob: d1f476a538c9e8340945ec5651764f5f9b9a9fe4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
--[[

    Copyright 2016 2015-2016 ZTE, Inc. and others. All rights reserved.

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

        Author: Zhaoxing Meng
        email: meng.zhaoxing1@zte.com.cn

]]
-- put red into the connection pool of size 100,
-- with 10 seconds max idle time
local function close_redis(red)
	if not red then
		return
	end
	--release connection to the pool
	local pool_max_idle_time = 10000
	local pool_size = 100
	local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)
	if not ok then
		ngx.log(ngx.ERR, "set keepalive error:", err)
	end
	return
end

local function query_ipurl_updatecache(red,key)
	local keyprefix = "msb:routing:custom:"..key


	local infokey=keyprefix..":info"
	-- first of all check whether the status is 1(enabled)
	local status = red:hget(infokey,"status")
	if not (status=="1")  then
		ngx.log(ngx.WARN, key.."is disabled.status=", status)
		return nil
	end

	-- Try to get url for key
	local url, err = red:hget(infokey,"url")
	ngx.log(ngx.WARN, "==url:", url)
	if not url or url == ngx.null then
		return nil
	end

	-- Try to get ip:port for key
	local serverkey=keyprefix..":lb:server1"
	local server, err = red:hget(serverkey,"ip")..":"..red:hget(serverkey,"port")
	ngx.log(ngx.WARN, "==server:", server)
	if not server or server == ngx.null then
		return nil
	end

	-- get the local cache
	local cache = ngx.shared.ceryx
	local uri = ngx.var.uri
	-- Save found key to local cache for 5 seconds
	cache:set("custom:key:"..uri,key,5)   
	cache:set("custom:server:"..uri,server,5)
	cache:set("custom:url:"..uri,url,5)

	ngx.var.key = key
	ngx.var.server = server
	ngx.var.url = url
	return true
end

local function query_allkeys_updatecache(red)
	-- Try to get all keys start with "msb:routing:custom:"
	local allkeys, err = red:keys("msb:routing:custom:*")
	if not allkeys or allkeys == ngx.null then
		ngx.log(ngx.ERR,err)
		return ""
	end
	--把所有键值处理后放到集合中,去除重复
	local key_set={}
	for key, value in ipairs(allkeys) do
		name = string.gsub(string.gsub(string.gsub(value,"msb:routing:custom:",""),":info",""),":lb:server1","")
		key_set[name]=true						   
	end
	--取出所有的�?放到table中准备排�?
	local key_table = {}
	local index = 1
	for key,_ in pairs(key_set) do
		--为了避免效率问题,暂时不用table.insert()
		--table.insert(key_table,key)
		key_table[index] = key
		index = index + 1
	end
	--对所有键进行倒序排序,用于实现最长前缀匹配
	table.sort(key_table, function (a, b)
			return a > b
		end)

	local servicenames = ""
	local delimiter = "<>"
	for i=1,#key_table do
		servicenames=servicenames..key_table[i]..delimiter
	end

	-- get the local cache
	local cache = ngx.shared.ceryx
	-- Save all keys to local cache for 30 seconds(0.5 minutes)
	cache:set("customrouter:allkeys", servicenames, 30)
	return servicenames;
end

local function query_router_info()
	local uri = ngx.var.uri
	ngx.log(ngx.WARN, "==uri:", uri)

	-- Check if key exists in local cache
	local cache = ngx.shared.ceryx
	local key, flags = cache:get("custom:key:"..uri)   
	local server, flags = cache:get("custom:server:"..uri)
	local url, flags = cache:get("custom:url:"..uri)   
	if key and server and url then
		ngx.var.key = key
		ngx.var.server = server
		ngx.var.url = url
		ngx.log(ngx.WARN, "==using custom cache:", key.."&&"..server.."&&"..url)
		return
	end

	local redis = require "resty.redis"
	local red = redis:new()
	red:set_timeout(1000) -- 1000 ms
	local redis_host = "127.0.0.1" 
	local redis_port = 6379 
	local res, err = red:connect(redis_host, redis_port)

	-- Return if could not connect to Redis
	if not res then
		ngx.log(ngx.ERR, "connect to redis error:", err)
		return
	end

	-- Check if all servicenames exists in local cache
	local servicenames, flags = cache:get("customrouter:allkeys")
	if servicenames then 
		ngx.log(ngx.WARN,"==get all keys from cache:",servicenames)
	else
		servicenames = query_allkeys_updatecache(red)
	end

	local delimiter = "<>"
	-- '.-' 表示最短匹�?
	for key in string.gmatch(servicenames,"(.-)"..delimiter) do
		ngx.log(ngx.WARN, "==key_table key:", key)
		local from, to, err = ngx.re.find(uri, "^"..key.."(/(.*))?$", "jo")
		--判断key是否为输入uri�?前缀"
		if from then
			ngx.log(ngx.WARN,"Matched! start-end:",from,"-",to)
			local result = query_ipurl_updatecache(red,key)
			if result then
				break
			end
		else
			ngx.log(ngx.WARN,"not Matched")
			if err then
				ngx.log(ngx.WARN,"ngx.re.find throw error: ",err)
				return
			end
		end
	end

	return close_redis(red)
end

local function rewrite_router_url()
	local server=ngx.var.server
	if server=="fallback" then
		ngx.status = ngx.HTTP_NOT_FOUND
		ngx.exit(ngx.status)
	end
	local url=ngx.var.url
	local key=ngx.var.key
	local rewriteduri = ngx.re.sub(ngx.var.uri, "^"..key.."(.*)", url.."$1", "o")
	ngx.log(ngx.WARN, "==rewrited uri:", rewriteduri)
	ngx.req.set_uri(rewriteduri)
end

query_router_info()
rewrite_router_url()