local md5 = require "md5" local code = require "code" local lfsUtil = require "utils.lfsUtil" local staticfile = require "staticfile" local protoUtil = require "utils.protoUtil" local SALT_MD5 = "b8JKMN1UhanX" -- 商城md5 验签 local GAME_SALT_MD5 = "0bdb9a5863c8c9063a42f38a9d5166fe" -- 游戏服加盐 md5 local root = {} local controllerList = {} -- 无控制器 local function l_get_unmatch_controller(res) res.code = 404 res.body = "404 Not Found Controller

404 Not Found

" res.headers["Content-Type"] = "text/html" return res.code, res.body, res.headers end -- 无响应函数处理 local function l_get_unmatch_process(res) res.code = 404 res.body = "404 Not Found Process

404 Not Found

" res.headers["Content-Type"] = "text/html" return res.code, res.body, res.headers end -- 服务器内部错误处理 local function serverError(res) res.code = 500 res.body = "Internal Server Error

500 Internal Server Error

" res.headers["Content-Type"] = "text/html" return res.code, res.body, res.headers end local function l_get_req_headers(isHtml) local headers = { ["Access-Control-Allow-Origin"] = "*", ["Content-Type"] = "application/json", ["Access-Control-Allow-Methods"] = "POST,GET,OPTIONS", ["Access-Control-Allow-Credentials"] = true, ["Access-Control-Allow-Headers"] = "content-type,x-requested-with,x-ui-request,lang" } if isHtml then headers["Content-Type"] = "text/html" end return headers end local function l_get_math_controller_and_func(path) path = string.sub(path, 2, -1) -- 去除/ local data = nil if string.match(path, "_") then data = string.split(path, "_") else data = string.split(path, "/") end local controller = table.remove(data, 1) local func = table.concat(data, "_") return string.format("%s", controller), func end -- 根据协议获取模块 local function _get_cotroller(proto) local data = string.split(proto, "_") return data[1] end -- 匹配静态资源 local function l_is_match_static(path) if not IS_TEST then return false end if path == "/" then path = "/static/index.html" end local offset = path:find("/", 2, true) if not offset then return false end -- 非静态资源 local controller = path:sub(1, offset - 1) if controller ~= "/static" then return false end -- 读取静态文件 local filename = path:sub(offset + 1) local content = staticfile[filename] if content then return true, 200, content end return true, 404, "404 Not found" end -- 匹配GM后台 local function l_is_match_gm_json(path) local offset = path:find("json") if not offset then return false end return true, "/sgm_interface" end local function l_pack_rsp(errCode, resData) local res = {code = errCode, data = resData} return cjson_encode(res) end local function l_pack_gm_rsp(errCode, resData) resData = resData or {} resData.code = errCode or -1 return cjson_encode(resData) end -- 请求 local function GET(path, query) local isStatic, errCode, body = l_is_match_static(path) if isStatic then return errCode, body, l_get_req_headers(true) end local isGmJson, pathData = l_is_match_gm_json(path) if isGmJson then path = pathData body = body or query.body local ok, data = pcall(cjson_decode, body) if not ok then log.error("get params %s", tostring(body)) body = nil else body = data end end local res = {code = 200, body = nil, headers = l_get_req_headers()} local controllerName, method = l_get_math_controller_and_func(path) local controller = controllerList[controllerName] if not controller then log.error("controller[%s] not exist", controllerName) return l_get_unmatch_controller(res) end local func = controller[method] if not func then log.error("controller[%s] has no method[%s] ", controllerName, method) return l_get_unmatch_process(res) end local errCode, ret = func(body or query) if isGmJson then res.body = l_pack_gm_rsp(errCode, ret) else res.body = l_pack_rsp(errCode, ret) end return res.code, res.body, res.headers end local function l_get_gm_param(body) local function split(str, reps) local res = {} str:gsub( "[^" .. reps .. "]+", function(w) table.insert(res, w) end ) return res end local query = {} for index, value in ipairs(split(body, "&")) do for k, v in value:gmatch("([^=]+)=([^=]+)") do query[k] = v end end return query end local function POST(path, body, response) local isStatic, errCode, sbody = l_is_match_static(path) if isStatic then return errCode, sbody, l_get_req_headers(true) end local isGmJson, pathData = l_is_match_gm_json(path) if isGmJson then path = pathData body = cjson_decode(body) end local res = {code = 200, body = nil, headers = l_get_req_headers()} local controllerName, method = l_get_math_controller_and_func(path) local controller = controllerList[controllerName] if not controller then log.error("controller[%s] not exist", controllerName) return l_get_unmatch_controller(res) end local func = controller[method] if not func then log.error("controller[%s] has no method[%s] ", controllerName, method) return l_get_unmatch_process(res) end local param = controllerName == "sgm" and body or l_get_gm_param(body) local errCode, ret = func(param) if isGmJson then res.body = l_pack_gm_rsp(errCode, ret) else res.body = l_pack_rsp(errCode, ret) end return res.code, res.body, res.headers end local function OPTIONS(body) local headers = l_get_req_headers() headers["Content-Type"] = nil return 200, body, headers end local function ERROR() return 200, l_pack_rsp(code.REQUEST_NOT_FOUND), l_get_req_headers() end local function SPROTO(name, args, response) local res = {code = 200, body = nil, headers = l_get_req_headers()} local controllerName = _get_cotroller(name) local controller = controllerList[controllerName] if not controller then log.error("SPROTO controller[%s] not exist", controllerName) res.body = response({code = code.REQUEST_NOT_FOUND}) return res.code, res.body, res.headers end local func = controller[name] if not func then log.error("SPROTO controller[%s] has no name[%s] ", controllerName, name) res.body = response({code = code.REQUEST_NOT_FOUND}) return res.code, res.body, res.headers end local errCode, resData = func(args) resData = resData or {} resData.code = errCode res.body = response(resData) return res.code, res.body, res.headers end -- 解析请求参数 local function l_decode_sproto(ip, headers, path, body) if path ~= "/pb" then return end local sz = headers["content-length"] or #body local ok, pType, pName, args, response = protoUtil:decode_c2s_req(body, sz) if not ok then return end -- pName = pName:gsub("_", "/") -- pName = string.format("/%s", pName) if headers and headers["proxy-client-ip"] then ip = headers["proxy-client-ip"] end args.ip = ip return "SPROTO", pName, args, response end local function l_is_match_sign(path, query, body) log.info("l_is_match_sign path[%s] query[%s]", tostring(path), tostring(query)) local salt = "" local sign = query.sign if path == "/pb" then salt = GAME_SALT_MD5 elseif path == "/json" then salt = SALT_MD5 end log.info("l_is_match_sign salt[%s]", tostring(salt)) if not sign then return false end local genSign = md5.sumhexa(body .. salt) log.info("l_is_match_sign genSign[%s]", tostring(genSign)) if genSign == sign then return true end return false end -- 初始化 function root:init() local files = lfsUtil:get_path_lua_files("nodes/login/controllers") for _, v in ipairs(files) do controllerList[v] = require("controllers." .. v) end end -- 热更新 function root:update() protoUtil:update() end -- 处理http请求 function root:http_request(ip, url, method, headers, path, query, body) log.info( "http_request ip[%s] url[%s] method[%s] headers[%s] path[%s] query[%s]", tostring(ip), tostring(url), tostring(method), tostring(headers), tostring(path), tostring(query) ) if method == "POST" and not l_is_match_sign(path, query, body) then return ERROR() end local smethod, name, args, response = l_decode_sproto(ip, headers, path, body) log.info( "http_request l_decode_sproto smethod[%s] name[%s] args[%s] response[%s]", tostring(smethod), tostring(name), tostring(args), tostring(response) ) smethod = smethod or method if smethod == "OPTIONS" then return OPTIONS() elseif smethod == "GET" then return GET(path, query) elseif smethod == "POST" then return POST(path, body) elseif smethod == "SPROTO" then return SPROTO(name, args, response) else return ERROR() end end return root