Divide the MSB source codes into two repos
[msb/apigateway.git] / openresty-ext / src / assembly / resources / openresty / nginx / luaext / dao / redis_db.lua
1 --[[\r
2 \r
3     Copyright (C) 2016 ZTE, Inc. and others. All rights reserved. (ZTE)\r
4 \r
5     Licensed under the Apache License, Version 2.0 (the "License");\r
6     you may not use this file except in compliance with the License.\r
7     You may obtain a copy of the License at\r
8 \r
9             http://www.apache.org/licenses/LICENSE-2.0\r
10 \r
11     Unless required by applicable law or agreed to in writing, software\r
12     distributed under the License is distributed on an "AS IS" BASIS,\r
13     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
14     See the License for the specific language governing permissions and\r
15     limitations under the License.\r
16 \r
17 --]]\r
18 \r
19 -- the client for redis, include the connection pool management and api implements\r
20 local redis = require('resty.redis')\r
21 local tbl_util  = require('lib.utils.table_util')\r
22 \r
23 local _M = {\r
24 }\r
25 _M._VERSION = '0.0.1'\r
26 _M._DESCRIPTION = 'msb_redis_module'\r
27 \r
28 local mt = { __index = _M }\r
29 \r
30 local tbl_insert = table.insert\r
31 local tbl_sort = table.sort\r
32 local tbl_isempty = tbl_util.isempty\r
33 \r
34 function _M.new(self, conf)\r
35         self.host        = conf.host\r
36         self.port        = conf.port\r
37         self.timeout     = conf.timeout\r
38         self.dbid        = conf.dbid\r
39         self.poolsize    = conf.poolsize\r
40         self.idletimeout = conf.idletimeout\r
41 \r
42         local red = redis:new()\r
43         return setmetatable({redis = red}, mt)\r
44 end\r
45 \r
46 function _M.connectdb(self)\r
47         local host  = self.host\r
48         local port  = self.port\r
49         local dbid  = self.dbid\r
50         local red   = self.redis\r
51 \r
52         if not (host and port) then\r
53                 return nil, 'no host:port avaliable provided'\r
54         end\r
55 \r
56         --set default value\r
57         if not dbid then dbid = 0 end\r
58         local timeout   = self.timeout \r
59         if not timeout then \r
60                 timeout = 1000   -- 1s\r
61         end\r
62 \r
63         red:set_timeout(timeout)\r
64 \r
65         local ok, err \r
66         if host and port then\r
67                 ok, err = red:connect(host, port)\r
68                 if ok then return red:select(dbid) end\r
69         end\r
70 \r
71         return ok, err\r
72 end\r
73 \r
74 function _M.keepalivedb(self)\r
75         local   max_idle_timeout  = self.idletimeout --ms\r
76         local   pool_size         = self.poolsize\r
77 \r
78         if not pool_size then pool_size = 100 end\r
79         if not max_idle_timeout then max_idle_timeout = 90000 end --90s\r
80 \r
81         local ok, err = self.redis:set_keepalive(max_idle_timeout, pool_size)\r
82         if not ok then\r
83                 ngx.log(ngx.ERR, "redis pool keepalive error",err)\r
84                 return\r
85         end\r
86         return\r
87 end\r
88 \r
89 --inner function,only used in this module\r
90 local function _hgetall(red,key)\r
91         local resp,err = red:hgetall(key)\r
92         --if not resp or next(resp) == nil then\r
93         if tbl_isempty(resp) then\r
94                 return nil, "key "..key.." not found"\r
95         end\r
96         local hashinfo = red:array_to_hash(resp)\r
97         return hashinfo,nil\r
98 end\r
99 \r
100 function _M.getserviceinfo(self,key)\r
101         if not key then\r
102                 return nil,'no key is provided'\r
103         end\r
104         local c, err = self:connectdb()\r
105         if not c then\r
106                 return nil, err\r
107         end\r
108 \r
109         local red   = self.redis\r
110         local resp,err = red:get(key) --the key will create dynamically\r
111         self:keepalivedb()\r
112         if not resp or resp == ngx.null then\r
113                 return nil, "key "..key.." not found"\r
114         else\r
115                 return resp,nil\r
116         end\r
117 end\r
118 \r
119 function _M.getbackservers(self,keypattern)\r
120         if not keypattern then\r
121                 return nil,'no keypattern is provided'\r
122         end\r
123         local c, err = self:connectdb()\r
124         if not c then\r
125                 return nil, err\r
126         end\r
127 \r
128         local red = self.redis\r
129 \r
130         local resp, err = red:keys(keypattern)\r
131         if tbl_isempty(resp) then\r
132                 self:keepalivedb()\r
133                 return nil, "no server matched"\r
134         end\r
135 \r
136         local servers = {}\r
137         for i, v in ipairs(resp) do\r
138                 local serverinfo,err = _hgetall(red,v)\r
139                 if serverinfo then\r
140                         tbl_insert(servers,serverinfo)\r
141                 end\r
142         end\r
143         self:keepalivedb()\r
144         return servers,nil\r
145 end\r
146 \r
147 function _M.getcustomsvcnames(self,keypattern)\r
148         if not keypattern then\r
149                 return nil,'no keypattern is provided'\r
150         end\r
151         local c, err = self:connectdb()\r
152         if not c then\r
153                 return nil, err\r
154         end\r
155 \r
156         local red = self.redis\r
157         --store svc names into the Set\r
158         local svcname_set={}\r
159 \r
160         local res, err = red:scan("0","count",50,"match",keypattern)\r
161         if not res then\r
162                 self:keepalivedb()\r
163                 return {}, "failed to scan in getcustomsvcnames()"\r
164         end\r
165 \r
166         local cursor, keys, err = unpack(res)\r
167         for _, svckey in ipairs(keys) do\r
168                 local m, err = ngx.re.match(svckey, "^.+:custom:([^:]+)", "o")\r
169                 if m then\r
170                         svcname_set[m[1]]=true\r
171                 end\r
172         end\r
173 \r
174         while( cursor ~= "0" )\r
175         do\r
176                 res = red:scan(cursor,"count",50,"match",keypattern)\r
177                 if not res then\r
178                         break\r
179                 end\r
180                 cursor, keys, err = unpack(res)\r
181                 for _, svckey in ipairs(keys) do\r
182                         local m, err = ngx.re.match(svckey, "^.+:custom:([^:]+)", "o")\r
183                         if m then\r
184                                 svcname_set[m[1]]=true\r
185                         end\r
186                 end\r
187         end\r
188         self:keepalivedb()\r
189         local svcnames = {}\r
190         for svcname,_ in pairs(svcname_set) do\r
191                 tbl_insert(svcnames,svcname)\r
192         end\r
193         --sort the key_table in reverse order\r
194         tbl_sort(svcnames, function (a, b)\r
195                         return a > b\r
196                 end)\r
197         return svcnames,nil\r
198 end\r
199 return _M