2025-02-18 17:39:10 +04:00
|
|
|
local json = require("cjson")
|
|
|
|
|
local http = require("resty.http")
|
2025-07-17 15:40:46 +04:00
|
|
|
local cache = require("cache.cache")
|
2025-07-28 21:16:56 +04:00
|
|
|
local request_utils = require("utils.request_utils")
|
2025-07-21 19:57:50 +04:00
|
|
|
|
2025-06-26 21:59:37 +04:00
|
|
|
-- Read request body once and reuse it throughout the handler
|
|
|
|
|
ngx.req.read_body()
|
|
|
|
|
local body_data = ngx.req.get_body_data() or ""
|
|
|
|
|
|
2025-02-18 17:39:10 +04:00
|
|
|
-- Extract and validate path parameters
|
2025-07-28 21:16:56 +04:00
|
|
|
local chain, network, provider_type, err = request_utils.parse_url_path(ngx.var.uri)
|
|
|
|
|
if err then
|
|
|
|
|
ngx.log(ngx.ERR, err)
|
2025-02-18 17:39:10 +04:00
|
|
|
ngx.status = 400
|
2025-07-28 21:16:56 +04:00
|
|
|
ngx.say(err)
|
2025-02-18 17:39:10 +04:00
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- Get providers for the requested chain/network
|
2025-07-28 21:16:56 +04:00
|
|
|
local chain_network_key = request_utils.get_chain_network_key(chain, network)
|
2025-02-18 17:39:10 +04:00
|
|
|
local providers_str = ngx.shared.providers:get(chain_network_key)
|
|
|
|
|
|
|
|
|
|
if not providers_str then
|
|
|
|
|
ngx.log(ngx.ERR, "No providers found for ", chain_network_key)
|
|
|
|
|
ngx.status = 404
|
|
|
|
|
ngx.say("No providers available for this chain/network")
|
|
|
|
|
return
|
|
|
|
|
end
|
2025-06-26 21:59:37 +04:00
|
|
|
|
|
|
|
|
-- Safely decode providers JSON with error handling
|
|
|
|
|
local ok, providers = pcall(json.decode, providers_str)
|
|
|
|
|
if not ok then
|
|
|
|
|
ngx.log(ngx.ERR, "Invalid providers JSON for ", chain_network_key, ": ", providers)
|
|
|
|
|
ngx.status = 500
|
|
|
|
|
ngx.say("Internal server error: invalid providers configuration")
|
|
|
|
|
return
|
|
|
|
|
end
|
2025-02-18 17:39:10 +04:00
|
|
|
|
2025-06-26 16:41:44 +04:00
|
|
|
-- Check cache with unified function (handles all cache operations)
|
|
|
|
|
local cache_info = cache.check_cache(chain, network, body_data)
|
|
|
|
|
if cache_info.cached_response then
|
|
|
|
|
ngx.header["Content-Type"] = "application/json"
|
2025-08-20 21:36:44 +04:00
|
|
|
if cache_info.cache_status then
|
|
|
|
|
ngx.header["X-Cache-Status"] = cache_info.cache_status
|
|
|
|
|
end
|
2025-09-02 13:25:54 +04:00
|
|
|
if cache_info.cache_level then
|
|
|
|
|
ngx.header["X-Cache-Level"] = cache_info.cache_level
|
|
|
|
|
end
|
2025-06-26 16:41:44 +04:00
|
|
|
ngx.say(cache_info.cached_response)
|
|
|
|
|
return
|
2025-06-25 21:26:02 +04:00
|
|
|
end
|
|
|
|
|
|
2025-02-18 17:39:10 +04:00
|
|
|
if #providers == 0 then
|
|
|
|
|
ngx.log(ngx.ERR, "No providers found for ", chain_network_key)
|
|
|
|
|
ngx.status = 404
|
|
|
|
|
ngx.say("No providers available for this chain/network")
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
2025-07-21 19:57:50 +04:00
|
|
|
-- Filter providers by provider_type if specified
|
2025-07-28 21:16:56 +04:00
|
|
|
local providers_to_try, tried_specific_provider = request_utils.filter_providers(providers, provider_type)
|
2025-07-21 19:57:50 +04:00
|
|
|
|
|
|
|
|
if #providers_to_try == 0 then
|
|
|
|
|
ngx.log(ngx.ERR, "No providers found for provider_type: ", provider_type or "none")
|
|
|
|
|
ngx.status = 404
|
|
|
|
|
ngx.say("No providers available for this provider type")
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
2025-06-27 14:37:03 +04:00
|
|
|
local success = false
|
2025-06-26 21:59:37 +04:00
|
|
|
|
2025-07-21 19:57:50 +04:00
|
|
|
for _, provider in ipairs(providers_to_try) do
|
|
|
|
|
local httpc = http.new()
|
|
|
|
|
|
2025-07-28 21:16:56 +04:00
|
|
|
-- Setup authentication and headers using request_utils
|
|
|
|
|
local base_headers = {
|
2025-07-21 19:57:50 +04:00
|
|
|
["Content-Type"] = "application/json"
|
|
|
|
|
}
|
2025-07-28 21:16:56 +04:00
|
|
|
local request_url, request_headers = request_utils.setup_auth(provider, provider.url, base_headers)
|
2025-02-18 17:39:10 +04:00
|
|
|
|
2025-07-21 19:57:50 +04:00
|
|
|
local res, err = httpc:request_uri(request_url, {
|
|
|
|
|
method = ngx.req.get_method(),
|
|
|
|
|
body = body_data,
|
|
|
|
|
headers = request_headers,
|
|
|
|
|
ssl_verify = false,
|
|
|
|
|
options = { family = ngx.AF_INET }
|
|
|
|
|
})
|
2025-02-18 17:39:10 +04:00
|
|
|
|
2025-07-21 19:57:50 +04:00
|
|
|
if res then
|
|
|
|
|
local ok, decoded_response = pcall(json.decode, res.body)
|
|
|
|
|
local decoded = ok and decoded_response or nil
|
|
|
|
|
|
2025-07-28 21:16:56 +04:00
|
|
|
-- Check if we should retry with next provider using request_utils
|
|
|
|
|
if not request_utils.should_retry(res, decoded) then
|
2025-07-21 19:57:50 +04:00
|
|
|
-- Cache response if cacheable
|
|
|
|
|
if cache_info.cache_type then
|
|
|
|
|
cache.save_to_cache(cache_info, res.body)
|
2025-06-27 14:37:03 +04:00
|
|
|
end
|
|
|
|
|
|
2025-07-28 21:16:56 +04:00
|
|
|
-- Success! Manually set response, filtering out unwanted headers
|
|
|
|
|
ngx.status = res.status
|
|
|
|
|
|
|
|
|
|
-- Filter headers using request_utils
|
|
|
|
|
local filtered_headers = request_utils.filter_response_headers(res.headers)
|
|
|
|
|
for key, value in pairs(filtered_headers) do
|
|
|
|
|
ngx.header[key] = value
|
|
|
|
|
end
|
|
|
|
|
|
2025-08-20 21:36:44 +04:00
|
|
|
-- Set cache status header for non-cached responses
|
|
|
|
|
if cache_info.cache_status then
|
|
|
|
|
ngx.header["X-Cache-Status"] = cache_info.cache_status
|
|
|
|
|
else
|
|
|
|
|
-- Default to MISS if cache_status is not available
|
|
|
|
|
ngx.header["X-Cache-Status"] = "MISS"
|
|
|
|
|
end
|
|
|
|
|
|
2025-09-02 13:25:54 +04:00
|
|
|
-- Set cache level header for non-cached responses
|
|
|
|
|
if cache_info.cache_level then
|
|
|
|
|
ngx.header["X-Cache-Level"] = cache_info.cache_level
|
|
|
|
|
else
|
|
|
|
|
-- Default to MISS if cache_level is not available
|
|
|
|
|
ngx.header["X-Cache-Level"] = "MISS"
|
|
|
|
|
end
|
|
|
|
|
|
2025-07-28 21:16:56 +04:00
|
|
|
-- Set response body
|
|
|
|
|
ngx.say(res.body)
|
2025-07-21 19:57:50 +04:00
|
|
|
success = true
|
|
|
|
|
break
|
2025-06-27 14:37:03 +04:00
|
|
|
else
|
2025-07-21 19:57:50 +04:00
|
|
|
if res.status then
|
|
|
|
|
ngx.log(ngx.ERR, "Error status ", res.status, ", trying next provider")
|
|
|
|
|
elseif decoded and decoded.error then
|
|
|
|
|
ngx.log(ngx.ERR, "JSON-RPC error code ", decoded.error.code, ", trying next provider")
|
|
|
|
|
end
|
2025-06-26 21:59:37 +04:00
|
|
|
end
|
2025-07-21 19:57:50 +04:00
|
|
|
else
|
|
|
|
|
ngx.log(ngx.ERR, "HTTP request failed: ", err)
|
2025-06-26 21:59:37 +04:00
|
|
|
end
|
2025-02-18 17:39:10 +04:00
|
|
|
end
|
|
|
|
|
|
2025-06-27 14:37:03 +04:00
|
|
|
if not success then
|
|
|
|
|
if provider_type and provider_type ~= "" and not tried_specific_provider then
|
|
|
|
|
ngx.status = 404
|
|
|
|
|
ngx.say("Provider not found: " .. provider_type)
|
|
|
|
|
else
|
|
|
|
|
ngx.status = 502
|
|
|
|
|
ngx.say("All providers failed")
|
|
|
|
|
end
|
2025-02-20 17:21:04 +04:00
|
|
|
end
|