Add HTTP API for Lua
Also fix a bug with Requests where any connection that took longer to finish than 15 seconds would be killed. Should have used CURLOPT_CONNECTTIMEOUT instead of CURLOPT_TIMEOUT when specifying the timeout, oops.
This commit is contained in:
parent
4d52531889
commit
fe87203eb4
@ -201,7 +201,7 @@ namespace http
|
||||
curl_easy_setopt(easy, CURLOPT_ERRORBUFFER, error_buffer);
|
||||
error_buffer[0] = 0;
|
||||
|
||||
curl_easy_setopt(easy, CURLOPT_TIMEOUT, timeout);
|
||||
curl_easy_setopt(easy, CURLOPT_CONNECTTIMEOUT, timeout);
|
||||
curl_easy_setopt(easy, CURLOPT_HTTPHEADER, headers);
|
||||
curl_easy_setopt(easy, CURLOPT_URL, uri.c_str());
|
||||
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "client/SaveFile.h"
|
||||
#include "client/SaveInfo.h"
|
||||
#include "client/Client.h"
|
||||
#include "client/http/Request.h"
|
||||
|
||||
#include "graphics/Graphics.h"
|
||||
#include "graphics/Renderer.h"
|
||||
@ -152,6 +153,9 @@ LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m):
|
||||
initFileSystemAPI();
|
||||
initPlatformAPI();
|
||||
initEventAPI();
|
||||
#ifndef NOHTTP
|
||||
initHttpAPI();
|
||||
#endif
|
||||
|
||||
//Old TPT API
|
||||
int currentElementMeta, currentElement;
|
||||
@ -3686,6 +3690,204 @@ int LuaScriptInterface::event_getmodifiers(lua_State * l)
|
||||
return 1;
|
||||
}
|
||||
|
||||
class RequestHandle
|
||||
{
|
||||
http::Request *request;
|
||||
bool dead;
|
||||
|
||||
public:
|
||||
RequestHandle(ByteString &uri, std::map<ByteString, ByteString> &post_data, std::map<ByteString, ByteString> &headers)
|
||||
{
|
||||
dead = false;
|
||||
request = new http::Request(uri);
|
||||
for (auto &header : headers)
|
||||
{
|
||||
request->AddHeader(header.first, header.second);
|
||||
}
|
||||
request->AddPostData(post_data);
|
||||
request->Start();
|
||||
}
|
||||
|
||||
~RequestHandle()
|
||||
{
|
||||
if (!Dead())
|
||||
{
|
||||
Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
bool Dead() const
|
||||
{
|
||||
return dead;
|
||||
}
|
||||
|
||||
bool Done() const
|
||||
{
|
||||
return dead || request->CheckDone();
|
||||
}
|
||||
|
||||
bool Running() const
|
||||
{
|
||||
return !dead && request->CheckStarted();
|
||||
}
|
||||
|
||||
void Progress(int *total, int *done)
|
||||
{
|
||||
if (!dead)
|
||||
{
|
||||
request->CheckProgress(total, done);
|
||||
}
|
||||
}
|
||||
|
||||
void Cancel()
|
||||
{
|
||||
if (!dead)
|
||||
{
|
||||
request->Cancel();
|
||||
dead = true;
|
||||
}
|
||||
}
|
||||
|
||||
ByteString Finish(int *status_out)
|
||||
{
|
||||
ByteString data;
|
||||
if (!dead)
|
||||
{
|
||||
if (request->CheckDone())
|
||||
{
|
||||
data = request->Finish(status_out);
|
||||
dead = true;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
};
|
||||
|
||||
static int http_request_gc(lua_State *l)
|
||||
{
|
||||
auto *rh = (RequestHandle *)luaL_checkudata(l, 1, "HTTPRequest");
|
||||
rh->~RequestHandle();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int http_request_status(lua_State *l)
|
||||
{
|
||||
auto *rh = (RequestHandle *)luaL_checkudata(l, 1, "HTTPRequest");
|
||||
if (rh->Dead())
|
||||
{
|
||||
lua_pushliteral(l, "dead");
|
||||
}
|
||||
else if (rh->Done())
|
||||
{
|
||||
lua_pushliteral(l, "done");
|
||||
}
|
||||
else if (rh->Running())
|
||||
{
|
||||
lua_pushliteral(l, "running");
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pushliteral(l, "queued");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int http_request_progress(lua_State *l)
|
||||
{
|
||||
auto *rh = (RequestHandle *)luaL_checkudata(l, 1, "HTTPRequest");
|
||||
if (!rh->Dead())
|
||||
{
|
||||
int total, done;
|
||||
rh->Progress(&total, &done);
|
||||
lua_pushinteger(l, total);
|
||||
lua_pushinteger(l, done);
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int http_request_cancel(lua_State *l)
|
||||
{
|
||||
auto *rh = (RequestHandle *)luaL_checkudata(l, 1, "HTTPRequest");
|
||||
if (!rh->Dead())
|
||||
{
|
||||
rh->Cancel();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int http_request_finish(lua_State *l)
|
||||
{
|
||||
auto *rh = (RequestHandle *)luaL_checkudata(l, 1, "HTTPRequest");
|
||||
if (!rh->Dead())
|
||||
{
|
||||
int status_out;
|
||||
ByteString data = rh->Finish(&status_out);
|
||||
lua_pushlstring(l, data.c_str(), data.size());
|
||||
lua_pushinteger(l, status_out);
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int http_request(lua_State *l)
|
||||
{
|
||||
ByteString uri(luaL_checkstring(l, 1));
|
||||
std::map<ByteString, ByteString> post_data;
|
||||
if (lua_istable(l, 2))
|
||||
{
|
||||
lua_pushnil(l);
|
||||
while (lua_next(l, 2))
|
||||
{
|
||||
lua_pushvalue(l, -2);
|
||||
post_data.emplace(lua_tostring(l, -1), lua_tostring(l, -2));
|
||||
lua_pop(l, 2);
|
||||
}
|
||||
}
|
||||
std::map<ByteString, ByteString> headers;
|
||||
if (lua_istable(l, 3))
|
||||
{
|
||||
lua_pushnil(l);
|
||||
while (lua_next(l, 3))
|
||||
{
|
||||
lua_pushvalue(l, -2);
|
||||
headers.emplace(lua_tostring(l, -1), lua_tostring(l, -2));
|
||||
lua_pop(l, 2);
|
||||
}
|
||||
}
|
||||
auto *rh = (RequestHandle *)lua_newuserdata(l, sizeof(RequestHandle));
|
||||
if (!rh)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
new(rh) RequestHandle(uri, post_data, headers);
|
||||
luaL_newmetatable(l, "HTTPRequest");
|
||||
lua_setmetatable(l, -2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void LuaScriptInterface::initHttpAPI()
|
||||
{
|
||||
luaL_newmetatable(l, "HTTPRequest");
|
||||
lua_pushcfunction(l, http_request_gc);
|
||||
lua_setfield(l, -2, "__gc");
|
||||
lua_newtable(l);
|
||||
lua_pushcfunction(l, http_request_status);
|
||||
lua_setfield(l, -2, "status");
|
||||
lua_pushcfunction(l, http_request_progress);
|
||||
lua_setfield(l, -2, "progress");
|
||||
lua_pushcfunction(l, http_request_cancel);
|
||||
lua_setfield(l, -2, "cancel");
|
||||
lua_pushcfunction(l, http_request_finish);
|
||||
lua_setfield(l, -2, "finish");
|
||||
lua_setfield(l, -2, "__index");
|
||||
struct luaL_Reg httpAPIMethods [] = {
|
||||
{"request", http_request},
|
||||
{NULL, NULL}
|
||||
};
|
||||
luaL_register(l, "http", httpAPIMethods);
|
||||
}
|
||||
|
||||
bool LuaScriptInterface::HandleEvent(LuaEvents::EventTypes eventType, Event * event)
|
||||
{
|
||||
return LuaEvents::HandleEvent(this, event, ByteString::Build("tptevents-", eventType));
|
||||
@ -3792,7 +3994,6 @@ int strlcmp(const char* a, const char* b, int len)
|
||||
|
||||
String highlight(String command)
|
||||
{
|
||||
#define CMP(X) (String(wstart, len) == X)
|
||||
StringBuilder result;
|
||||
int pos = 0;
|
||||
String::value_type const*raw = command.c_str();
|
||||
@ -3806,12 +4007,14 @@ String highlight(String command)
|
||||
String::value_type const* wstart = raw+pos;
|
||||
while((w = wstart[len]) && ((w >= 'A' && w <= 'Z') || (w >= 'a' && w <= 'z') || (w >= '0' && w <= '9') || w == '_'))
|
||||
len++;
|
||||
#define CMP(X) (String(wstart, len) == X)
|
||||
if(CMP("and") || CMP("break") || CMP("do") || CMP("else") || CMP("elseif") || CMP("end") || CMP("for") || CMP("function") || CMP("if") || CMP("in") || CMP("local") || CMP("not") || CMP("or") || CMP("repeat") || CMP("return") || CMP("then") || CMP("until") || CMP("while"))
|
||||
result << "\x0F\xB5\x89\x01" << String(wstart, len) << "\bw";
|
||||
else if(CMP("false") || CMP("nil") || CMP("true"))
|
||||
result << "\x0F\xCB\x4B\x16" << String(wstart, len) << "\bw";
|
||||
else
|
||||
result << "\x0F\x2A\xA1\x98" << String(wstart, len) << "\bw";
|
||||
#undef CMP
|
||||
pos += len;
|
||||
}
|
||||
else if((c >= '0' && c <= '9') || (c == '.' && raw[pos + 1] >= '0' && raw[pos + 1] <= '9'))
|
||||
|
@ -180,6 +180,8 @@ class LuaScriptInterface: public CommandInterface
|
||||
static int event_unregister(lua_State * l);
|
||||
static int event_getmodifiers(lua_State * l);
|
||||
|
||||
void initHttpAPI();
|
||||
|
||||
std::vector<LuaSmartRef> lua_el_func_v, lua_gr_func_v, lua_cd_func_v;
|
||||
std::vector<int> lua_el_mode_v;
|
||||
|
||||
|
Reference in New Issue
Block a user