Крашит игру, когда много запросов в Lua скрипте

sadik~

Известный
Автор темы
152
56
Версия MoonLoader
.027.0-preview
Пишу Lua скрипт, он шлёт события на сервер через HTTP. Всё вроде норм, но если в чате начинается жёсткий спам (например семейные новости), то игра просто крашится.


Есть ощущение, что я как-то криво сделал асинхронность. Использую effil.thread и requests. Когда запросов много — что-то ломается.


Вот куски кода::
local function http_post(url, body)
    local request_thread = effil.thread(function(url, body, timeout)
        local requests = require 'requests'
        local result, response = pcall(requests.request, "POST", url, {
            headers = {
                ["Content-Type"] = "application/json",
                ["Content-Length"] = tostring(#body)
            },
            data = body,
            timeout = timeout
        })
        
        if result then
            return {
                success = true,
                code = response.status_code,
                text = response.text,
                headers = response.headers
            }
        else
            return {
                success = false,
                error = response
            }
        end
    end)(url, body, HTTP_TIMEOUT_MS/1000)
    
    lua_thread.create(function()
        while true do
            local status, err = request_thread:status()
            if not err then
                if status == 'completed' then
                    local result = request_thread:get()
                    if result.success then
                        -- обработка ответа
                    else
                        print("HTTP request failed: "..tostring(result.error))
                    end
                    return
                elseif status == 'canceled' then
                    return
                end
            else
                print("Thread error: "..tostring(err))
                return
            end
            wait(0)
        end
    end)
end


А вызываю так::
local function notifyServer(payload)
    payload.version = VERSION
    local json_payload = json.encode(payload)
    http_post(SERVER_URL, json_payload)
end


Как лучше сделать асинхронку, чтобы игра не лагала и не падала?
 

kyrtion

Известный
1,321
485
попробуй извлекать обновленный effil в гитхаб и requests
1. effil-v1.2-0-lua5.1-Win-x64.zip или effil-v1.2-0-lua5.1-Win-x86.zip (надо потестить, т.к. игра под x32, а в оперативке x64...)
2. https://github.com/JakobGreen/lua-requests/blob/master/src/requests.lua
и смотри в requests что там требует/поменялось библиотеки
lua-requests/rocks /lua-requests-1.2-2.rockspec:
dependencies = {
  "lua >= 5.1",
  "luasocket",
  "md5",
  "lua-cjson",
  "xml",
  "luasec >= 0.5.1, < 0.8-1"
}
если ничего не поменялось, то:
Lua:
--- @diagnostic disable: lowercase-global

local effil = require('effil')
local encoding = require('encoding')
encoding.default = 'CP1251'
local u8 = encoding.UTF8

--- @param method 'GET'|'POST'
--- @param body { url: string, headers: table?, data: string|table }
--- @param callback fun(status_code: string|nil, res: string|table|nil, err: string|nil)
function asyncHttpRequest(method, body, callback)
  local url = u8(body.url)
  body.url = url
  body.headers = body.headers or {}
  body.headers['content-type'] = body.headers['content-type'] or 'application/x-www-form-urlencoded'

  local function createRequest(_method, _url, _body)
    local requests = require('requests')
    local success, response = pcall(requests.request, _method, _url, _body)
    if success then
      response.json, response.xml = nil, nil -- хз почему решили отказаться от этих
      return true, response
    else
      return false, response
    end
  end

  local function httpBuildData(data)
    local function valueToUrlEncode(str)
      str = str:gsub('([^%w])', function(с) return string.format('%%%02X', string.byte(с)) end)
      return str
    end
    local t = {}
    for k, v in pairs(data) do
      v = valueToUrlEncode(u8(tostring(v)))
      table.insert(t, string.format('%s=%s', k, v))
    end
    return u8(table.concat(t, '&'))
  end

  if type(body) == 'table' and type(body.data) == 'table' then
    body.data = httpBuildData(body.data)
  end

  local thread = effil.thread(createRequest)(method, url, body)

  lua_thread.create(function()
    wait(0)
    while true do
      local status, err = thread:status()
      if not status or err then
        return callback(nil, nil, err)
      end
      if status == 'completed' or status == 'canceled' then
        local success, response = thread:get()
        if success then
          if response and type(response.text) == 'string' and response.text:len() ~= 0 then
            response.text = u8:decode(response.text)
          end
          local result_json, json = pcall(decodeJson, response.text)
          return callback(response.status_code, result_json and json or response.text, nil)
        else
          return callback(nil, nil, response)
        end
      end
      wait(10)
    end
  end)
end

sampRegisterChatCommand('testurl', function(arg)
  local body = {
    url = 'https://formtester.goodbytes.be/post.php',
    data = {
      nick = 'kyrtion',
      server = sampGetCurrentServerName(),
      info = 'че сказать, хз',
      time = os.clock()
    },
  }
  asyncHttpRequest('POST', body, function(...)
    print(encodeJson({ ... }))
  end)
end)

-- example:
-- https://httpbin.org/get
-- https://httpbin.org/post
-- https://httpbin.org/response-headers
-- https://formtester.goodbytes.be/post.php
Если в body не указано content-type, автоматически вставит application/x-www-form-urlencoded
 
Последнее редактирование:
  • Нравится
Реакции: sadik~