Add scriptapi interface to HTTPFetchRequest
This allows mods to perform both asynchronous and synchronous HTTP requests. For game mods, a special callback API is provided via minetest.http_fetch(<request>, <callback function>)master
parent
69b75d5fbb
commit
3e9499fca3
|
@ -112,3 +112,21 @@ function core.record_protection_violation(pos, name)
|
|||
end
|
||||
end
|
||||
|
||||
-- If built with cURL
|
||||
if core.http_fetch_async then
|
||||
core.http_requests = {}
|
||||
function core.http_fetch(req, callback)
|
||||
local handle = core.http_fetch_async(req)
|
||||
table.insert(core.http_requests, {handle = handle, callback = callback})
|
||||
end
|
||||
|
||||
core.register_globalstep(function()
|
||||
for i, req in ipairs(core.http_requests) do
|
||||
local res = core.http_fetch_async_get(req.handle)
|
||||
if res.code ~= 0 then
|
||||
table.remove(core.http_requests, i)
|
||||
req.callback(res)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
|
|
@ -2118,6 +2118,20 @@ These functions return the leftover itemstack.
|
|||
* `force_placement` is a boolean indicating whether nodes other than `air` and
|
||||
`ignore` are replaced by the schematic
|
||||
|
||||
### HTTP Requests:
|
||||
* `minetest.http_fetch(HTTPRequest req, callback)`
|
||||
* Performs given request asynchronously and calls callback upon completion
|
||||
* callback: `function(HTTPRequestResult res)`
|
||||
* `minetest.http_fetch_async(HTTPRequest req)`: returns handle
|
||||
* Performs given request asynchronously and returns handle for `minetest.http_fetch_async_get`
|
||||
* `minetest.http_fetch_async_get(handle)`: returns HTTPRequestResult
|
||||
* Return response data for given asynchronous HTTP request
|
||||
* `minetest.http_fetch_sync(HTTPRequest req)`: returns HTTPRequestResult
|
||||
* Blocking. Returns HTTP response data for given request directly.
|
||||
|
||||
If possible, do NOT use sychronous HTTP requests, they block the server thread.
|
||||
These functions only exist if minetest was built with cURL support.
|
||||
|
||||
### Misc.
|
||||
* `minetest.get_connected_players()`: returns list of `ObjectRefs`
|
||||
* `minetest.hash_node_position({x=,y=,z=})`: returns an 48-bit integer
|
||||
|
@ -3267,3 +3281,23 @@ Definition tables
|
|||
playername = "singleplayer"
|
||||
-- ^ Playername is optional, if specified spawns particle only on the player's client
|
||||
}
|
||||
|
||||
### `HTTPRequest` definition (`http_fetch`, `http_fetch_async`, `http_fetch_sync`)
|
||||
{
|
||||
url = "http://example.org",
|
||||
timeout = 10,
|
||||
-- ^ Timeout for connection in seconds
|
||||
post_data = "Post request data"
|
||||
-- ^ If supplied, a POST request is performed. Otherwise, performs GET request.
|
||||
}
|
||||
|
||||
### `HTTPRequestResult` definition (`http_fetch` callback, `http_fetch_async_get`)
|
||||
{
|
||||
succeeded = true,
|
||||
-- ^ If true, the request was succesful
|
||||
timeout = false,
|
||||
-- ^ If true, the request timed out
|
||||
code = 200,
|
||||
-- ^ HTTP status code
|
||||
data = "response"
|
||||
}
|
||||
|
|
|
@ -386,4 +386,13 @@ void setboolfield(lua_State *L, int table,
|
|||
lua_setfield(L, table, fieldname);
|
||||
}
|
||||
|
||||
void setstringfield(lua_State *L, int table,
|
||||
const char *fieldname, const char *value)
|
||||
{
|
||||
lua_pushstring(L, value);
|
||||
if(table < 0)
|
||||
table -= 1;
|
||||
lua_setfield(L, table, fieldname);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -69,6 +69,8 @@ void setfloatfield(lua_State *L, int table,
|
|||
const char *fieldname, float value);
|
||||
void setboolfield(lua_State *L, int table,
|
||||
const char *fieldname, bool value);
|
||||
void setstringfield(lua_State *L, int table,
|
||||
const char *fieldname, const char *value);
|
||||
|
||||
|
||||
v3f checkFloatPos (lua_State *L, int index);
|
||||
|
|
|
@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "cpp_api/s_async.h"
|
||||
#include "serialization.h"
|
||||
#include "json/json.h"
|
||||
#include "httpfetch.h"
|
||||
#include "debug.h"
|
||||
#include "porting.h"
|
||||
#include "log.h"
|
||||
|
@ -320,6 +321,99 @@ int ModApiUtil::l_decompress(lua_State *L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
#if USE_CURL
|
||||
void ModApiUtil::read_http_fetch_request(lua_State *L, HTTPFetchRequest &req)
|
||||
{
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
|
||||
req.caller = httpfetch_caller_alloc();
|
||||
getstringfield(L, 1, "url", req.url);
|
||||
req.post_data = getstringfield_default(L, 1, "post_data", "");
|
||||
lua_getfield(L, 1, "useragent");
|
||||
if (lua_isstring(L, -1))
|
||||
req.useragent = getstringfield_default(L, 1, "useragent", "");
|
||||
lua_pop(L, 1);
|
||||
req.multipart = getboolfield_default(L, 1, "multipart", false);
|
||||
req.timeout = getintfield_default(L, 1, "timeout", 1) * 1000;
|
||||
|
||||
lua_getfield(L, 1, "post_fields");
|
||||
if (lua_istable(L, 2)) {
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, 2) != 0)
|
||||
{
|
||||
req.post_fields[luaL_checkstring(L, -2)] = luaL_checkstring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, 1, "extra_headers");
|
||||
if (lua_istable(L, 2)) {
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, 2) != 0)
|
||||
{
|
||||
req.extra_headers.push_back(luaL_checkstring(L, -1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
void ModApiUtil::push_http_fetch_result(lua_State *L, HTTPFetchResult &res)
|
||||
{
|
||||
lua_newtable(L);
|
||||
setboolfield(L, -1, "succeeded", res.succeeded);
|
||||
setboolfield(L, -1, "timeout", res.timeout);
|
||||
setintfield(L, -1, "code", res.response_code);
|
||||
setstringfield(L, -1, "data", res.data.c_str());
|
||||
}
|
||||
|
||||
// http_fetch_async({url=, timeout=, post_data=})
|
||||
int ModApiUtil::l_http_fetch_async(lua_State *L)
|
||||
{
|
||||
NO_MAP_LOCK_REQUIRED;
|
||||
|
||||
HTTPFetchRequest req;
|
||||
read_http_fetch_request(L, req);
|
||||
|
||||
actionstream<<"Mod performs HTTP request with URL "<<req.url<<std::endl;
|
||||
httpfetch_async(req);
|
||||
|
||||
lua_pushnumber(L, req.caller);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// http_fetch_async_get(handle)
|
||||
int ModApiUtil::l_http_fetch_async_get(lua_State *L)
|
||||
{
|
||||
NO_MAP_LOCK_REQUIRED;
|
||||
|
||||
int handle = luaL_checknumber(L, 1);
|
||||
|
||||
HTTPFetchResult res;
|
||||
httpfetch_async_get(handle, res);
|
||||
|
||||
push_http_fetch_result(L, res);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// http_fetch_sync({url=, timeout=, post_data=})
|
||||
int ModApiUtil::l_http_fetch_sync(lua_State *L)
|
||||
{
|
||||
NO_MAP_LOCK_REQUIRED;
|
||||
|
||||
HTTPFetchRequest req;
|
||||
HTTPFetchResult res;
|
||||
read_http_fetch_request(L, req);
|
||||
|
||||
actionstream<<"Mod performs HTTP request with URL "<<req.url<<std::endl;
|
||||
httpfetch_sync(req, res);
|
||||
|
||||
push_http_fetch_result(L, res);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
void ModApiUtil::Initialize(lua_State *L, int top)
|
||||
{
|
||||
API_FCT(debug);
|
||||
|
@ -345,6 +439,12 @@ void ModApiUtil::Initialize(lua_State *L, int top)
|
|||
|
||||
API_FCT(compress);
|
||||
API_FCT(decompress);
|
||||
|
||||
#if USE_CURL
|
||||
API_FCT(http_fetch_async);
|
||||
API_FCT(http_fetch_async_get);
|
||||
API_FCT(http_fetch_sync);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ModApiUtil::InitializeAsync(AsyncEngine& engine)
|
||||
|
@ -367,5 +467,11 @@ void ModApiUtil::InitializeAsync(AsyncEngine& engine)
|
|||
|
||||
ASYNC_API_FCT(compress);
|
||||
ASYNC_API_FCT(decompress);
|
||||
|
||||
#if USE_CURL
|
||||
ASYNC_API_FCT(http_fetch_async);
|
||||
ASYNC_API_FCT(http_fetch_async_get);
|
||||
ASYNC_API_FCT(http_fetch_sync);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#define L_UTIL_H_
|
||||
|
||||
#include "lua_api/l_base.h"
|
||||
#include "config.h"
|
||||
|
||||
struct HTTPFetchRequest;
|
||||
struct HTTPFetchResult;
|
||||
class AsyncEngine;
|
||||
|
||||
class ModApiUtil : public ModApiBase {
|
||||
|
@ -87,6 +90,21 @@ private:
|
|||
// decompress(data, method, ...)
|
||||
static int l_decompress(lua_State *L);
|
||||
|
||||
#if USE_CURL
|
||||
// Helpers for HTTP fetch functions
|
||||
static void read_http_fetch_request(lua_State *L, HTTPFetchRequest &req);
|
||||
static void push_http_fetch_result(lua_State *L, HTTPFetchResult &res);
|
||||
|
||||
// http_fetch_async({url=, timeout=, post_data=})
|
||||
static int l_http_fetch_async(lua_State *L);
|
||||
|
||||
// http_fetch_async_get(handle)
|
||||
static int l_http_fetch_async_get(lua_State *L);
|
||||
|
||||
// http_fetch_sync({url=, timeout=, post_data=})
|
||||
static int l_http_fetch_sync(lua_State *L);
|
||||
#endif
|
||||
|
||||
public:
|
||||
static void Initialize(lua_State *L, int top);
|
||||
|
||||
|
|
Loading…
Reference in New Issue