webapp.lua 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. local md5 = require "md5"
  2. local code = require "code"
  3. local const = require("const.const")
  4. local lfsUtil = require "utils.lfsUtil"
  5. local staticfile = require "staticfile"
  6. local protoUtil = require "utils.protoUtil"
  7. local root = {}
  8. local controllerList = {}
  9. -- 无控制器
  10. local function l_get_unmatch_controller(res)
  11. res.code = 404
  12. res.body = "<html><head><title>404 Not Found Controller </title></head><body> <p>404 Not Found</p></body></html>"
  13. res.headers["Content-Type"] = "text/html"
  14. return res.code, res.body, res.headers
  15. end
  16. -- 无响应函数处理
  17. local function l_get_unmatch_process(res)
  18. res.code = 404
  19. res.body = "<html><head><title>404 Not Found Process </title></head><body> <p>404 Not Found</p></body></html>"
  20. res.headers["Content-Type"] = "text/html"
  21. return res.code, res.body, res.headers
  22. end
  23. -- 服务器内部错误处理
  24. local function serverError(res)
  25. res.code = 500
  26. res.body =
  27. "<html><head><title>Internal Server Error</title></head><body> <p>500 Internal Server Error</p></body></html>"
  28. res.headers["Content-Type"] = "text/html"
  29. return res.code, res.body, res.headers
  30. end
  31. local function l_get_req_headers(isHtml)
  32. local headers = {
  33. ["Access-Control-Allow-Origin"] = "*",
  34. ["Content-Type"] = "application/json",
  35. ["Access-Control-Allow-Methods"] = "POST,GET,OPTIONS",
  36. ["Access-Control-Allow-Credentials"] = true,
  37. ["Access-Control-Allow-Headers"] = "content-type,x-requested-with,x-ui-request,lang"
  38. }
  39. if isHtml then
  40. headers["Content-Type"] = "text/html"
  41. end
  42. return headers
  43. end
  44. local function l_get_math_controller_and_func(path)
  45. path = string.sub(path, 2, -1) -- 去除/
  46. local data = nil
  47. if string.match(path, "_") then
  48. data = string.split(path, "_")
  49. else
  50. data = string.split(path, "/")
  51. end
  52. local controller = table.remove(data, 1)
  53. local func = table.concat(data, "_")
  54. return string.format("%s", controller), func
  55. end
  56. -- 根据协议获取模块
  57. local function _get_cotroller(proto)
  58. local data = string.split(proto, "_")
  59. return data[1]
  60. end
  61. -- 匹配静态资源
  62. local function l_is_match_static(path)
  63. if not IS_TEST then
  64. return false
  65. end
  66. if path == "/" then
  67. path = "/static/index.html"
  68. end
  69. local offset = path:find("/", 2, true)
  70. if not offset then
  71. return false
  72. end
  73. -- 非静态资源
  74. local controller = path:sub(1, offset - 1)
  75. if controller ~= "/static" then
  76. return false
  77. end
  78. -- 读取静态文件
  79. local filename = path:sub(offset + 1)
  80. local content = staticfile[filename]
  81. if content then
  82. return true, 200, content
  83. end
  84. return true, 404, "404 Not found"
  85. end
  86. -- 匹配GM后台
  87. local function l_is_match_gm_json(path)
  88. local offset = path:find("json")
  89. if not offset then
  90. return false
  91. end
  92. return true, "/sgm_interface"
  93. end
  94. local function l_pack_rsp(errCode, resData)
  95. local res = {code = errCode, data = resData}
  96. return cjson_encode(res)
  97. end
  98. local function l_pack_gm_rsp(errCode, resData)
  99. resData = resData or {}
  100. resData.code = errCode or -1
  101. return cjson_encode(resData)
  102. end
  103. -- 请求
  104. local function GET(path, query)
  105. local isStatic, errCode, body = l_is_match_static(path)
  106. if isStatic then
  107. return errCode, body, l_get_req_headers(true)
  108. end
  109. local isGmJson, pathData = l_is_match_gm_json(path)
  110. if isGmJson then
  111. path = pathData
  112. body = body or query.body
  113. local ok, data = pcall(cjson_decode, body)
  114. if not ok then
  115. log.error("get params %s", tostring(body))
  116. body = nil
  117. else
  118. body = data
  119. end
  120. end
  121. local res = {code = 200, body = nil, headers = l_get_req_headers()}
  122. local controllerName, method = l_get_math_controller_and_func(path)
  123. local controller = controllerList[controllerName]
  124. if not controller then
  125. log.error("controller[%s] not exist", controllerName)
  126. return l_get_unmatch_controller(res)
  127. end
  128. local func = controller[method]
  129. if not func then
  130. log.error("controller[%s] has no method[%s] ", controllerName, method)
  131. return l_get_unmatch_process(res)
  132. end
  133. local errCode, ret = func(body or query)
  134. if isGmJson then
  135. res.body = l_pack_gm_rsp(errCode, ret)
  136. else
  137. res.body = l_pack_rsp(errCode, ret)
  138. end
  139. return res.code, res.body, res.headers
  140. end
  141. local function l_get_gm_param(body)
  142. local function split(str, reps)
  143. local res = {}
  144. str:gsub(
  145. "[^" .. reps .. "]+",
  146. function(w)
  147. table.insert(res, w)
  148. end
  149. )
  150. return res
  151. end
  152. local query = {}
  153. for index, value in ipairs(split(body, "&")) do
  154. for k, v in value:gmatch("([^=]+)=([^=]+)") do
  155. query[k] = v
  156. end
  157. end
  158. return query
  159. end
  160. local function POST(path, body, response)
  161. local isStatic, errCode, sbody = l_is_match_static(path)
  162. if isStatic then
  163. return errCode, sbody, l_get_req_headers(true)
  164. end
  165. local data = cjson_decode(body)
  166. local name = data.name
  167. log.info("POST body[%s] name[%s]", tostring(body), tostring(name))
  168. local res = {code = 200, body = nil, headers = l_get_req_headers()}
  169. local controllerName = _get_cotroller(name)
  170. local controller = controllerList[controllerName]
  171. if not controller then
  172. log.error("controller[%s] not exist", controllerName)
  173. return l_get_unmatch_controller(res)
  174. end
  175. local func = controller[name]
  176. if not func then
  177. log.error("controller[%s] has no method[%s] ", controllerName, method)
  178. return l_get_unmatch_process(res)
  179. end
  180. local isGmJson = controllerName == "gm"
  181. local param = isGmJson and data.data or l_get_gm_param(body)
  182. local errCode, ret = func(param)
  183. if isGmJson then
  184. res.body = l_pack_gm_rsp(errCode, ret)
  185. else
  186. res.body = l_pack_rsp(errCode, ret)
  187. end
  188. return res.code, res.body, res.headers
  189. end
  190. local function OPTIONS(body)
  191. local headers = l_get_req_headers()
  192. headers["Content-Type"] = nil
  193. return 200, body, headers
  194. end
  195. local function ERROR()
  196. return 200, l_pack_rsp(code.REQUEST_NOT_FOUND), l_get_req_headers()
  197. end
  198. local function SPROTO(name, args, response)
  199. local res = {code = 200, body = nil, headers = l_get_req_headers()}
  200. local controllerName = _get_cotroller(name)
  201. local controller = controllerList[controllerName]
  202. if not controller then
  203. log.error("SPROTO controller[%s] not exist", controllerName)
  204. res.body = response({code = code.REQUEST_NOT_FOUND})
  205. return res.code, res.body, res.headers
  206. end
  207. local func = controller[name]
  208. if not func then
  209. log.error("SPROTO controller[%s] has no name[%s] ", controllerName, name)
  210. res.body = response({code = code.REQUEST_NOT_FOUND})
  211. return res.code, res.body, res.headers
  212. end
  213. local errCode, resData = func(args)
  214. resData = resData or {}
  215. resData.code = errCode
  216. res.body = response(resData)
  217. return res.code, res.body, res.headers
  218. end
  219. -- 解析请求参数
  220. local function l_decode_sproto(ip, headers, path, body)
  221. if path ~= "/pb" then
  222. return
  223. end
  224. local sz = headers["content-length"] or #body
  225. local ok, pType, pName, args, response = protoUtil:decode_c2s_req(body, sz)
  226. if not ok then
  227. return
  228. end
  229. -- pName = pName:gsub("_", "/")
  230. -- pName = string.format("/%s", pName)
  231. if headers and headers["proxy-client-ip"] then
  232. ip = headers["proxy-client-ip"]
  233. end
  234. args.ip = ip
  235. return "SPROTO", pName, args, response
  236. end
  237. local function l_is_match_sign(path, query, body)
  238. log.info("l_is_match_sign path[%s] query[%s]", tostring(path), tostring(query))
  239. local salt = ""
  240. local sign = query.sign
  241. if path == "/pb" then
  242. salt = const.GAME_SALT_MD5
  243. elseif path == "/json" then
  244. salt = const.SALT_MD5
  245. end
  246. log.info("l_is_match_sign salt[%s]", tostring(salt))
  247. if not sign then
  248. return false
  249. end
  250. local genSign = md5.sumhexa(body .. salt)
  251. log.info("l_is_match_sign genSign[%s]", tostring(genSign))
  252. if genSign == sign then
  253. return true
  254. end
  255. return false
  256. end
  257. -- 初始化
  258. function root:init()
  259. local files = lfsUtil:get_path_lua_files("nodes/web/controllers")
  260. for _, v in ipairs(files) do
  261. controllerList[v] = require("controllers." .. v)
  262. end
  263. end
  264. -- 热更新
  265. function root:update()
  266. protoUtil:update()
  267. end
  268. -- 处理http请求
  269. function root:http_request(ip, url, method, headers, path, query, body)
  270. log.info(
  271. "http_request ip[%s] url[%s] method[%s] headers[%s] path[%s] query[%s]",
  272. tostring(ip),
  273. tostring(url),
  274. tostring(method),
  275. tostring(headers),
  276. tostring(path),
  277. tostring(query)
  278. )
  279. if method == "POST" and not l_is_match_sign(path, query, body) then
  280. return ERROR()
  281. end
  282. local smethod, name, args, response = l_decode_sproto(ip, headers, path, body)
  283. log.info(
  284. "http_request l_decode_sproto smethod[%s] name[%s] args[%s] response[%s]",
  285. tostring(smethod),
  286. tostring(name),
  287. tostring(args),
  288. tostring(response)
  289. )
  290. smethod = smethod or method
  291. if smethod == "OPTIONS" then
  292. return OPTIONS()
  293. elseif smethod == "GET" then
  294. return GET(path, query)
  295. elseif smethod == "POST" then
  296. return POST(path, body)
  297. elseif smethod == "SPROTO" then
  298. return SPROTO(name, args, response)
  299. else
  300. return ERROR()
  301. end
  302. end
  303. return root