-- capture_async_http.lua
-- Положи этот файл в папку скриптов и загрузи раньше остальных, чтобы подмена сработала.
-- Защита от повторной подмены
if rawget(_G, "__asyncHttpRequest_wrapped") then
print("asyncHttpRequest уже обёрнут.")
return
end
-- Сохранить оригинал
local orig_asyncHttpRequest = rawget(_G, "asyncHttpRequest")
if not orig_asyncHttpRequest then
-- Если в текущей среде asyncHttpRequest нет — предупреждаем, но не падаем.
print("ВНИМАНИЕ: asyncHttpRequest не найден в глобальной области. Перехват невозможен.")
-- Поместим маркер, чтобы не пытаться снова
_G["__asyncHttpRequest_wrapped"] = true
-- Инициализируем пустой контейнер для совместимости API
_G.__captured_http = _G.__captured_http or { by_url = {}, by_id = {} }
-- публичные функции
_G.get_captured = function(k)
return _G.__captured_http.by_url[k] or _G.__captured_http.by_id[k]
end
_G.pop_captured = function(k)
local v = _G.get_captured(k)
if _G.__captured_http.by_url[k] then _G.__captured_http.by_url[k] = nil end
if _G.__captured_http.by_id[k] then _G.__captured_http.by_id[k] = nil end
return v
end
_G.clear_captured = function() _G.__captured_http.by_url = {}; _G.__captured_http.by_id = {} end
return
end
-- инициализация контейнера хранения
_G.__captured_http = _G.__captured_http or { by_url = {}, by_id = {} }
-- Вспомогательная функция для сохранения (с ограничением размера списка)
local function save_response(key_table, key, response)
if not key or key == "" then return end
key_table[key] = key_table[key] or {}
-- сохраняем объект (можно копировать поля, но сохраним ссылку)
table.insert(key_table[key], response)
-- ограничение: сохранять не более N записей на ключ
local MAX_PER_KEY = 10
if #key_table[key] > MAX_PER_KEY then
-- удалить самый старый
table.remove(key_table[key], 1)
end
end
-- Создаём обёртку
local function make_wrapped(orig)
return function(method, url, callback, headers, ...)
-- Подготовка: допустим, аргументы совпадают с описанными (method, url, callback, headers)
-- Создадим обёрнутый callback, который сохраняет response, потом вызывает оригинальный callback
local function wrapped_callback(...)
-- Попробуем получить response (в большинстве реализаций это один аргумент)
local response = select(1, ...)
-- Сохраняем копию: лучше хранить минимально необходимые поля
local snapshot = nil
if type(response) == "table" then
snapshot = {
text = response.text,
status = response.status,
headers = response.headers,
url = response.url or url
}
else
snapshot = { raw = response, url = url }
end
-- Сохраняем по URL
pcall(save_response, _G.__captured_http.by_url, url, snapshot)
-- Если response содержит id (или оригинал возвращает id), попробуем сохранить по id ниже.
-- Но здесь id часто возвращается синхронно как return-value оригинальной функции.
-- Дополнительно: если response.id существует, сохраним по нему.
if type(response) == "table" and response.id ~= nil then
pcall(save_response, _G.__captured_http.by_id, tostring(response.id), snapshot)
end
-- Вызвать исходный callback (если он был)
if type(callback) == "function" then
local ok, err = pcall(callback, ...)
if not ok then
-- не ломаем цепочку — логируем ошибку, но продолжаем
print("Ошибка в оригинальном callback-е asyncHttpRequest:", tostring(err))
end
end
end
-- Вызов оригинала: может вернуть request-id или nil
local ok, ret = pcall(orig, method, url, wrapped_callback, headers, ...)
if not ok then
print("Ошибка при вызове оригинального asyncHttpRequest:", tostring(ret))
return nil
end
-- Если оригинал возвращает id (например строку/число) — сохраним привязку id -> url
if ret ~= nil then
local id_str = tostring(ret)
-- пометим, что запрос с таким id ожидается; сохраним пустой список, он заполнится в wrapped_callback, если response содержит id
_G.__captured_http.by_id[id_str] = _G.__captured_http.by_id[id_str] or {}
-- сохраняем связь id->url (как дополнительный элемент)
table.insert(_G.__captured_http.by_id[id_str], { meta = { url = url, returned_id = ret } })
end
return ret
end
end
-- Подменяем только один раз
_G["__asyncHttpRequest_wrapped"] = true
_G["__orig_asyncHttpRequest"] = orig_asyncHttpRequest
-- Выполняем замену
asyncHttpRequest = make_wrapped(orig_asyncHttpRequest)
-- Публичный API для получения / очистки перехваченных данных
_G.get_captured = function(key)
if key == nil then
return nil
end
local by_url = _G.__captured_http.by_url[key]
if by_url then return by_url end
local by_id = _G.__captured_http.by_id[key]
if by_id then return by_id end
return nil
end
_G.pop_captured = function(key)
if key == nil then return nil end
local v = _G.get_captured(key)
if v then
if _G.__captured_http.by_url[key] then _G.__captured_http.by_url[key] = nil end
if _G.__captured_http.by_id[key] then _G.__captured_http.by_id[key] = nil end
end
return v
end
_G.clear_captured = function()
_G.__captured_http.by_url = {}
_G.__captured_http.by_id = {}
end
-- Утилита печати перехваченных (для отладки)
_G.print_captured = function(key)
local v = _G.get_captured(key)
if not v then
print("Нет захваченных данных для:", tostring(key))
return
end
for i, item in ipairs(v) do
if type(item) == "table" then
print(string.format("[%d] url=%s status=%s text_len=%d", i, tostring(item.url), tostring(item.status), type(item.text)=="string" and #item.text or 0))
else
print(string.format("[%d] %s", i, tostring(item)))
end
end
end
print("asyncHttpRequest успешно обёрнут — ответы будут сохраняться в _G.__captured_http (by_url / by_id).")