Add support for onProgress and downloadFile to NETWORK:HttpRequest()
This commit is contained in:
+16
-15
@@ -2486,21 +2486,22 @@
|
|||||||
<Enum name='HttpErrorCode'>
|
<Enum name='HttpErrorCode'>
|
||||||
<EnumValue name=''HttpErrorCode_Blocked'' value='0'/>
|
<EnumValue name=''HttpErrorCode_Blocked'' value='0'/>
|
||||||
<EnumValue name=''HttpErrorCode_UnknownError'' value='1'/>
|
<EnumValue name=''HttpErrorCode_UnknownError'' value='1'/>
|
||||||
<EnumValue name=''HttpErrorCode_CannotConnect'' value='2'/>
|
<EnumValue name=''HttpErrorCode_FileError'' value='2'/>
|
||||||
<EnumValue name=''HttpErrorCode_Timeout'' value='3'/>
|
<EnumValue name=''HttpErrorCode_CannotConnect'' value='3'/>
|
||||||
<EnumValue name=''HttpErrorCode_Gzip'' value='4'/>
|
<EnumValue name=''HttpErrorCode_Timeout'' value='4'/>
|
||||||
<EnumValue name=''HttpErrorCode_UrlMalformed'' value='5'/>
|
<EnumValue name=''HttpErrorCode_Gzip'' value='5'/>
|
||||||
<EnumValue name=''HttpErrorCode_CannotCreateSocket'' value='6'/>
|
<EnumValue name=''HttpErrorCode_UrlMalformed'' value='6'/>
|
||||||
<EnumValue name=''HttpErrorCode_SendError'' value='7'/>
|
<EnumValue name=''HttpErrorCode_CannotCreateSocket'' value='7'/>
|
||||||
<EnumValue name=''HttpErrorCode_ReadError'' value='8'/>
|
<EnumValue name=''HttpErrorCode_SendError'' value='8'/>
|
||||||
<EnumValue name=''HttpErrorCode_CannotReadStatusLine'' value='9'/>
|
<EnumValue name=''HttpErrorCode_ReadError'' value='9'/>
|
||||||
<EnumValue name=''HttpErrorCode_MissingStatus'' value='10'/>
|
<EnumValue name=''HttpErrorCode_CannotReadStatusLine'' value='10'/>
|
||||||
<EnumValue name=''HttpErrorCode_HeaderParsingError'' value='11'/>
|
<EnumValue name=''HttpErrorCode_MissingStatus'' value='11'/>
|
||||||
<EnumValue name=''HttpErrorCode_MissingLocation'' value='12'/>
|
<EnumValue name=''HttpErrorCode_HeaderParsingError'' value='12'/>
|
||||||
<EnumValue name=''HttpErrorCode_TooManyRedirects'' value='13'/>
|
<EnumValue name=''HttpErrorCode_MissingLocation'' value='13'/>
|
||||||
<EnumValue name=''HttpErrorCode_ChunkReadError'' value='14'/>
|
<EnumValue name=''HttpErrorCode_TooManyRedirects'' value='14'/>
|
||||||
<EnumValue name=''HttpErrorCode_CannotReadBody'' value='15'/>
|
<EnumValue name=''HttpErrorCode_ChunkReadError'' value='15'/>
|
||||||
<EnumValue name=''HttpErrorCode_Cancelled'' value='16'/>
|
<EnumValue name=''HttpErrorCode_CannotReadBody'' value='16'/>
|
||||||
|
<EnumValue name=''HttpErrorCode_Cancelled'' value='17'/>
|
||||||
</Enum>
|
</Enum>
|
||||||
<Enum name='ImageCacheMode'>
|
<Enum name='ImageCacheMode'>
|
||||||
<EnumValue name=''ImageCacheMode_Off'' value='0'/>
|
<EnumValue name=''ImageCacheMode_Off'' value='0'/>
|
||||||
|
|||||||
@@ -3562,16 +3562,20 @@ end
|
|||||||
<pre><code>
|
<pre><code>
|
||||||
NETWORK:HttpRequest{
|
NETWORK:HttpRequest{
|
||||||
url="https://api.example.com",
|
url="https://api.example.com",
|
||||||
method="GET", -- default: "GET"
|
method="GET", -- default: "GET"
|
||||||
body="", -- default: ""
|
body="", -- default: ""
|
||||||
multipartBoundary="", -- default: ""
|
multipartBoundary="", -- default: ""
|
||||||
headers={ -- default: {}
|
headers={ -- default: {}
|
||||||
["Accept-Language"]="en-US",
|
["Accept-Language"]="en-US",
|
||||||
["Cookie"]="sessionId=42",
|
["Cookie"]="sessionId=42",
|
||||||
},
|
},
|
||||||
connectTimeout=3, -- default: 60
|
connectTimeout=3, -- default: 60
|
||||||
transferTimeout=10, -- default: 1800
|
transferTimeout=10, -- default: 1800
|
||||||
onResponse=function(response) -- default: no callback
|
downloadFile="", -- default: no download file
|
||||||
|
onProgress=function(currentBytes, totalBytes) -- default: no callback
|
||||||
|
...
|
||||||
|
end,
|
||||||
|
onResponse=function(response) -- default: no callback
|
||||||
...
|
...
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
@@ -3598,6 +3602,9 @@ NETWORK:HttpRequest{
|
|||||||
errorMessage="access to https://api.example.com is not allowed",
|
errorMessage="access to https://api.example.com is not allowed",
|
||||||
}
|
}
|
||||||
</code></pre>
|
</code></pre>
|
||||||
|
If the <code>downloadFile</code> parameter is set, the response body is not accumulated in memory, but written to <code>/Downloads/${downloadFile}</code>.
|
||||||
|
The file is available in the <code>onResponse</code> callback where it can be unzipped/copied to another location using <code>FILEMAN:Unzip()</code>/<code>FILEMAN:Copy()</code> respectively.
|
||||||
|
The file is deleted once the callback returns.
|
||||||
</Function>
|
</Function>
|
||||||
<Function name='UrlEncode' return='string' arguments='string value'>
|
<Function name='UrlEncode' return='string' arguments='string value'>
|
||||||
Returns the URL encoded representation of <code>value</code>.
|
Returns the URL encoded representation of <code>value</code>.
|
||||||
|
|||||||
-1
@@ -149,5 +149,4 @@ set(IXWEBSOCKET_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/IXWebSocket-11.3.2")
|
|||||||
target_include_directories(ixwebsocket PUBLIC
|
target_include_directories(ixwebsocket PUBLIC
|
||||||
"zlib"
|
"zlib"
|
||||||
$<BUILD_INTERFACE:${IXWEBSOCKET_INCLUDE_DIRS}/>
|
$<BUILD_INTERFACE:${IXWEBSOCKET_INCLUDE_DIRS}/>
|
||||||
$<INSTALL_INTERFACE:include/ixwebsocket>
|
|
||||||
)
|
)
|
||||||
|
|||||||
+182
-18
@@ -1,16 +1,22 @@
|
|||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "NetworkManager.h"
|
#include "NetworkManager.h"
|
||||||
#include "LuaManager.h"
|
#include "LuaManager.h"
|
||||||
|
#include "ProductInfo.h"
|
||||||
|
#include "RageFile.h"
|
||||||
|
#include "RageFileManager.h"
|
||||||
#include "RageLog.h"
|
#include "RageLog.h"
|
||||||
#include "RageUtil.h"
|
#include "RageUtil.h"
|
||||||
#include "StdString.h"
|
#include "StdString.h"
|
||||||
|
#include "ver.h"
|
||||||
|
|
||||||
#include <ixwebsocket/IXHttpClient.h>
|
#include <ixwebsocket/IXHttpClient.h>
|
||||||
#include <ixwebsocket/IXNetSystem.h>
|
#include <ixwebsocket/IXNetSystem.h>
|
||||||
#include <ixwebsocket/IXUrlParser.h>
|
#include <ixwebsocket/IXUrlParser.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <climits>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <sstream>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -23,6 +29,7 @@ Preference<RString> NetworkManager::httpAllowHosts("HttpAllowHosts", "", nullptr
|
|||||||
static const char *HttpErrorCodeNames[] = {
|
static const char *HttpErrorCodeNames[] = {
|
||||||
"Blocked",
|
"Blocked",
|
||||||
"UnknownError",
|
"UnknownError",
|
||||||
|
"FileError",
|
||||||
"CannotConnect",
|
"CannotConnect",
|
||||||
"Timeout",
|
"Timeout",
|
||||||
"Gzip",
|
"Gzip",
|
||||||
@@ -43,7 +50,7 @@ XToString(HttpErrorCode);
|
|||||||
StringToX(HttpErrorCode);
|
StringToX(HttpErrorCode);
|
||||||
LuaXType(HttpErrorCode);
|
LuaXType(HttpErrorCode);
|
||||||
|
|
||||||
NetworkManager::NetworkManager() : httpClient(true)
|
NetworkManager::NetworkManager() : httpClient(true), downloadClient(true)
|
||||||
{
|
{
|
||||||
ix::initNetSystem();
|
ix::initNetSystem();
|
||||||
|
|
||||||
@@ -54,6 +61,8 @@ NetworkManager::NetworkManager() : httpClient(true)
|
|||||||
lua_setglobal(L, "NETWORK");
|
lua_setglobal(L, "NETWORK");
|
||||||
LUA->Release(L);
|
LUA->Release(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->ClearDownloads();
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkManager::~NetworkManager()
|
NetworkManager::~NetworkManager()
|
||||||
@@ -97,24 +106,75 @@ bool NetworkManager::IsUrlAllowed(const std::string& url)
|
|||||||
|
|
||||||
HttpRequestFuturePtr NetworkManager::HttpRequest(const HttpRequestArgs& args)
|
HttpRequestFuturePtr NetworkManager::HttpRequest(const HttpRequestArgs& args)
|
||||||
{
|
{
|
||||||
ix::HttpRequestArgsPtr req = this->httpClient.createRequest(args.url, args.method);
|
auto &client = args.downloadFile.empty() ? this->httpClient : this->downloadClient;
|
||||||
|
auto downloadFile = std::make_shared<RageFile>();
|
||||||
|
std::string downloadFilename;
|
||||||
|
|
||||||
|
ix::HttpRequestArgsPtr req = client.createRequest(args.url, args.method);
|
||||||
req->body = args.body;
|
req->body = args.body;
|
||||||
req->multipartBoundary = args.multipartBoundary;
|
req->multipartBoundary = args.multipartBoundary;
|
||||||
|
|
||||||
|
req->extraHeaders["User-Agent"] = this->GetUserAgent();
|
||||||
for (const auto& entry : args.headers)
|
for (const auto& entry : args.headers)
|
||||||
{
|
{
|
||||||
req->extraHeaders[entry.first] = entry.second;
|
req->extraHeaders[entry.first] = entry.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.connectTimeout > 0) {
|
if (!args.downloadFile.empty())
|
||||||
|
{
|
||||||
|
downloadFilename = std::string("/Downloads/") + args.downloadFile;
|
||||||
|
if (!downloadFile->Open(downloadFilename, RageFile::WRITE | RageFile::STREAMED))
|
||||||
|
{
|
||||||
|
req->cancel = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
req->onChunkCallback = [args, downloadFile, req](const std::string& data) {
|
||||||
|
if (downloadFile->Write(data.c_str(), data.size()) < 0)
|
||||||
|
{
|
||||||
|
req->cancel = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Don't timeout downloads by default. This value might be
|
||||||
|
// overwritten below if a value is specified in the request.
|
||||||
|
req->transferTimeout = INT_MAX;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.connectTimeout > 0)
|
||||||
req->connectTimeout = args.connectTimeout;
|
req->connectTimeout = args.connectTimeout;
|
||||||
}
|
|
||||||
|
|
||||||
if (args.transferTimeout > 0) {
|
if (args.transferTimeout > 0)
|
||||||
req->transferTimeout = args.transferTimeout;
|
req->transferTimeout = args.transferTimeout;
|
||||||
}
|
|
||||||
|
|
||||||
this->httpClient.performRequest(req, args.onResponse);
|
if (args.onProgress)
|
||||||
|
req->onProgressCallback = args.onProgress;
|
||||||
|
|
||||||
|
client.performRequest(req, [args, downloadFile, downloadFilename](const ix::HttpResponsePtr& response) {
|
||||||
|
if (downloadFile->IsOpen())
|
||||||
|
{
|
||||||
|
RString error = downloadFile->GetError();
|
||||||
|
downloadFile->Close();
|
||||||
|
|
||||||
|
if (!error.empty())
|
||||||
|
{
|
||||||
|
std::string errorMessage = "could not write to " + downloadFile->GetPath() + ": " + error;
|
||||||
|
if (args.onFileError)
|
||||||
|
args.onFileError(errorMessage);
|
||||||
|
|
||||||
|
FILEMAN->Remove(downloadFilename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.onResponse)
|
||||||
|
args.onResponse(response);
|
||||||
|
|
||||||
|
if (!args.downloadFile.empty())
|
||||||
|
{
|
||||||
|
FILEMAN->Remove(downloadFilename);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return std::make_shared<HttpRequestFuture>(req);
|
return std::make_shared<HttpRequestFuture>(req);
|
||||||
}
|
}
|
||||||
@@ -129,7 +189,28 @@ std::string NetworkManager::EncodeQueryParameters(const std::unordered_map<std::
|
|||||||
return this->httpClient.serializeHttpParameters(query);
|
return this->httpClient.serializeHttpParameters(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
int HttpRequestFuture::collect(lua_State *L)
|
std::string NetworkManager::GetUserAgent()
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << PRODUCT_FAMILY << "/" << product_version;
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkManager::ClearDownloads()
|
||||||
|
{
|
||||||
|
vector<RString> files;
|
||||||
|
FILEMAN->GetDirListing("/Downloads/*", files, false, true);
|
||||||
|
|
||||||
|
for (const auto& file : files)
|
||||||
|
{
|
||||||
|
if (FILEMAN->IsADirectory(file))
|
||||||
|
FILEMAN->DeleteRecursive(file + "/");
|
||||||
|
else
|
||||||
|
FILEMAN->Remove(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int HttpRequestFuture::Collect(lua_State *L)
|
||||||
{
|
{
|
||||||
void *udata = luaL_checkudata(L, 1, "HttpRequestFuture");
|
void *udata = luaL_checkudata(L, 1, "HttpRequestFuture");
|
||||||
auto futptr = static_cast<HttpRequestFuturePtr*>(udata);
|
auto futptr = static_cast<HttpRequestFuturePtr*>(udata);
|
||||||
@@ -152,7 +233,7 @@ int HttpRequestFuture::Cancel(lua_State *L)
|
|||||||
static void registerHttpRequestMetatable(lua_State *L)
|
static void registerHttpRequestMetatable(lua_State *L)
|
||||||
{
|
{
|
||||||
const luaL_Reg HttpRequest_meta[] = {
|
const luaL_Reg HttpRequest_meta[] = {
|
||||||
{"__gc", HttpRequestFuture::collect},
|
{"__gc", HttpRequestFuture::Collect},
|
||||||
{"Cancel", HttpRequestFuture::Cancel},
|
{"Cancel", HttpRequestFuture::Cancel},
|
||||||
{NULL, NULL},
|
{NULL, NULL},
|
||||||
};
|
};
|
||||||
@@ -183,6 +264,8 @@ public:
|
|||||||
luaL_checktype(L, 1, LUA_TTABLE);
|
luaL_checktype(L, 1, LUA_TTABLE);
|
||||||
|
|
||||||
HttpRequestArgs args;
|
HttpRequestArgs args;
|
||||||
|
int onProgressRef = LUA_NOREF;
|
||||||
|
int onResponseRef = LUA_NOREF;
|
||||||
|
|
||||||
lua_getfield(L, 1, "url");
|
lua_getfield(L, 1, "url");
|
||||||
if (lua_isnil(L, -1))
|
if (lua_isnil(L, -1))
|
||||||
@@ -311,9 +394,44 @@ public:
|
|||||||
}
|
}
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
|
|
||||||
int onResponseRef = LUA_NOREF;
|
lua_getfield(L, 1, "downloadFile");
|
||||||
|
if (!lua_isnil(L, -1))
|
||||||
|
{
|
||||||
|
if (lua_isstring(L, -1))
|
||||||
|
{
|
||||||
|
args.downloadFile = lua_tostring(L, -1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
luaL_error(L, "downloadFile must be a string");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
lua_getfield(L, 1, "onProgress");
|
||||||
|
if (!lua_isnil(L, -1))
|
||||||
|
{
|
||||||
|
if (lua_isfunction(L, -1))
|
||||||
|
{
|
||||||
|
lua_pushvalue(L, -1);
|
||||||
|
onProgressRef = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||||
|
|
||||||
|
args.onProgress = [onProgressRef](int current, int total)
|
||||||
|
{
|
||||||
|
Lua *L = LUA->Get();
|
||||||
|
handleProgress(L, current, total, onProgressRef);
|
||||||
|
LUA->Release(L);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
luaL_error(L, "onProgress must be a function");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
// do this as the last check, so we don't leak lua references on error
|
|
||||||
lua_getfield(L, 1, "onResponse");
|
lua_getfield(L, 1, "onResponse");
|
||||||
if (!lua_isnil(L, -1))
|
if (!lua_isnil(L, -1))
|
||||||
{
|
{
|
||||||
@@ -321,21 +439,39 @@ public:
|
|||||||
{
|
{
|
||||||
lua_pushvalue(L, -1);
|
lua_pushvalue(L, -1);
|
||||||
onResponseRef = luaL_ref(L, LUA_REGISTRYINDEX);
|
onResponseRef = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||||
|
|
||||||
args.onResponse = [onResponseRef](const ix::HttpResponsePtr& response)
|
|
||||||
{
|
|
||||||
Lua *L = LUA->Get();
|
|
||||||
handleHttpResponse(L, response, onResponseRef);
|
|
||||||
LUA->Release(L);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
luaL_unref(L, LUA_REGISTRYINDEX, onProgressRef);
|
||||||
luaL_error(L, "onResponse must be a function");
|
luaL_error(L, "onResponse must be a function");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
args.onFileError = [onProgressRef, onResponseRef](const std::string& errorMessage)
|
||||||
|
{
|
||||||
|
Lua *L = LUA->Get();
|
||||||
|
|
||||||
|
luaL_unref(L, LUA_REGISTRYINDEX, onProgressRef);
|
||||||
|
|
||||||
|
if (onResponseRef != LUA_NOREF)
|
||||||
|
handleFileError(L, errorMessage, onResponseRef);
|
||||||
|
|
||||||
|
LUA->Release(L);
|
||||||
|
};
|
||||||
|
|
||||||
|
args.onResponse = [onProgressRef, onResponseRef](const ix::HttpResponsePtr& response)
|
||||||
|
{
|
||||||
|
Lua *L = LUA->Get();
|
||||||
|
|
||||||
|
luaL_unref(L, LUA_REGISTRYINDEX, onProgressRef);
|
||||||
|
|
||||||
|
if (onResponseRef != LUA_NOREF)
|
||||||
|
handleHttpResponse(L, response, onResponseRef);
|
||||||
|
|
||||||
|
LUA->Release(L);
|
||||||
|
};
|
||||||
|
|
||||||
if (p->IsUrlAllowed(args.url))
|
if (p->IsUrlAllowed(args.url))
|
||||||
{
|
{
|
||||||
auto fut = p->HttpRequest(args);
|
auto fut = p->HttpRequest(args);
|
||||||
@@ -349,6 +485,7 @@ public:
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG->Warn("blocked access to %s", args.url.c_str());
|
LOG->Warn("blocked access to %s", args.url.c_str());
|
||||||
|
luaL_unref(L, LUA_REGISTRYINDEX, onProgressRef);
|
||||||
if (onResponseRef != LUA_NOREF)
|
if (onResponseRef != LUA_NOREF)
|
||||||
{
|
{
|
||||||
handleUrlForbidden(L, args.url, onResponseRef);
|
handleUrlForbidden(L, args.url, onResponseRef);
|
||||||
@@ -431,6 +568,23 @@ private:
|
|||||||
LuaHelpers::RunScriptOnStack(L, error, 1, 0, true);
|
LuaHelpers::RunScriptOnStack(L, error, 1, 0, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handleFileError(Lua *L, const std::string& errorMessage, int onResponseRef)
|
||||||
|
{
|
||||||
|
lua_rawgeti(L, LUA_REGISTRYINDEX, onResponseRef);
|
||||||
|
luaL_unref(L, LUA_REGISTRYINDEX, onResponseRef);
|
||||||
|
|
||||||
|
lua_newtable(L);
|
||||||
|
|
||||||
|
LuaHelpers::Push(L, HttpErrorCode_FileError);
|
||||||
|
lua_setfield(L, -2, "error");
|
||||||
|
|
||||||
|
lua_pushstring(L, errorMessage.c_str());
|
||||||
|
lua_setfield(L, -2, "errorMessage");
|
||||||
|
|
||||||
|
RString error = "Lua error in HTTP response handler: ";
|
||||||
|
LuaHelpers::RunScriptOnStack(L, error, 1, 0, true);
|
||||||
|
}
|
||||||
|
|
||||||
static void handleHttpResponse(Lua *L, const ix::HttpResponsePtr& response, int onResponseRef)
|
static void handleHttpResponse(Lua *L, const ix::HttpResponsePtr& response, int onResponseRef)
|
||||||
{
|
{
|
||||||
lua_rawgeti(L, LUA_REGISTRYINDEX, onResponseRef);
|
lua_rawgeti(L, LUA_REGISTRYINDEX, onResponseRef);
|
||||||
@@ -493,6 +647,16 @@ private:
|
|||||||
RString error = "Lua error in HTTP response handler: ";
|
RString error = "Lua error in HTTP response handler: ";
|
||||||
LuaHelpers::RunScriptOnStack(L, error, 1, 0, true);
|
LuaHelpers::RunScriptOnStack(L, error, 1, 0, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handleProgress(Lua *L, int current, int total, int onProgressRef)
|
||||||
|
{
|
||||||
|
lua_rawgeti(L, LUA_REGISTRYINDEX, onProgressRef);
|
||||||
|
lua_pushinteger(L, current);
|
||||||
|
lua_pushinteger(L, total);
|
||||||
|
|
||||||
|
RString error = "Lua error in HTTP progress handler: ";
|
||||||
|
LuaHelpers::RunScriptOnStack(L, error, 2, 0, true);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
LUA_REGISTER_CLASS(NetworkManager)
|
LUA_REGISTER_CLASS(NetworkManager)
|
||||||
|
|||||||
+13
-3
@@ -4,8 +4,10 @@
|
|||||||
#include "Preference.h"
|
#include "Preference.h"
|
||||||
#include "StdString.h"
|
#include "StdString.h"
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
@@ -21,6 +23,7 @@ enum HttpErrorCode
|
|||||||
{
|
{
|
||||||
HttpErrorCode_Blocked,
|
HttpErrorCode_Blocked,
|
||||||
HttpErrorCode_UnknownError,
|
HttpErrorCode_UnknownError,
|
||||||
|
HttpErrorCode_FileError,
|
||||||
|
|
||||||
// from IXWebSocket
|
// from IXWebSocket
|
||||||
HttpErrorCode_CannotConnect,
|
HttpErrorCode_CannotConnect,
|
||||||
@@ -44,7 +47,7 @@ enum HttpErrorCode
|
|||||||
};
|
};
|
||||||
const RString& HttpErrorCodeToString(HttpErrorCode dc);
|
const RString& HttpErrorCodeToString(HttpErrorCode dc);
|
||||||
HttpErrorCode StringToHttpErrorCode(const RString& sDC);
|
HttpErrorCode StringToHttpErrorCode(const RString& sDC);
|
||||||
LuaDeclareType( HttpErrorCode );
|
LuaDeclareType(HttpErrorCode);
|
||||||
|
|
||||||
struct HttpRequestArgs
|
struct HttpRequestArgs
|
||||||
{
|
{
|
||||||
@@ -55,7 +58,10 @@ struct HttpRequestArgs
|
|||||||
std::unordered_map<std::string, std::string> headers;
|
std::unordered_map<std::string, std::string> headers;
|
||||||
int connectTimeout = -1;
|
int connectTimeout = -1;
|
||||||
int transferTimeout = -1;
|
int transferTimeout = -1;
|
||||||
std::function<void(const ix::HttpResponsePtr& response)> onResponse = [](const ix::HttpResponsePtr& response) {};
|
std::string downloadFile;
|
||||||
|
std::function<bool(int current, int total)> onProgress;
|
||||||
|
std::function<void(const ix::HttpResponsePtr& response)> onResponse;
|
||||||
|
std::function<void(const std::string& errorMessage)> onFileError;
|
||||||
};
|
};
|
||||||
|
|
||||||
class HttpRequestFuture
|
class HttpRequestFuture
|
||||||
@@ -63,7 +69,7 @@ class HttpRequestFuture
|
|||||||
public:
|
public:
|
||||||
HttpRequestFuture(ix::HttpRequestArgsPtr& args) : args(args) {};
|
HttpRequestFuture(ix::HttpRequestArgsPtr& args) : args(args) {};
|
||||||
|
|
||||||
static int collect(lua_State *L);
|
static int Collect(lua_State *L);
|
||||||
static int Cancel(lua_State *L);
|
static int Cancel(lua_State *L);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -87,7 +93,11 @@ public:
|
|||||||
void PushSelf(lua_State *L);
|
void PushSelf(lua_State *L);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::string GetUserAgent();
|
||||||
|
void ClearDownloads();
|
||||||
|
|
||||||
ix::HttpClient httpClient;
|
ix::HttpClient httpClient;
|
||||||
|
ix::HttpClient downloadClient;
|
||||||
|
|
||||||
static Preference<bool> httpEnabled;
|
static Preference<bool> httpEnabled;
|
||||||
static Preference<RString> httpAllowHosts;
|
static Preference<RString> httpAllowHosts;
|
||||||
|
|||||||
@@ -354,6 +354,7 @@ void ArchHooks::MountUserFilesystems( const RString &sDirOfExecutable )
|
|||||||
FILEMAN->Mount( "dir", ssprintf("%s/" PRODUCT_ID "/CDTitles", dir), "/CDTitles" );
|
FILEMAN->Mount( "dir", ssprintf("%s/" PRODUCT_ID "/CDTitles", dir), "/CDTitles" );
|
||||||
FILEMAN->Mount( "dir", ssprintf("%s/" PRODUCT_ID "/Characters", dir), "/Characters" );
|
FILEMAN->Mount( "dir", ssprintf("%s/" PRODUCT_ID "/Characters", dir), "/Characters" );
|
||||||
FILEMAN->Mount( "dir", ssprintf("%s/" PRODUCT_ID "/Courses", dir), "/Courses" );
|
FILEMAN->Mount( "dir", ssprintf("%s/" PRODUCT_ID "/Courses", dir), "/Courses" );
|
||||||
|
FILEMAN->Mount( "dir", ssprintf("%s/" PRODUCT_ID "/Downloads", dir), "/Downloads" );
|
||||||
FILEMAN->Mount( "dir", ssprintf("%s/" PRODUCT_ID "/NoteSkins", dir), "/NoteSkins" );
|
FILEMAN->Mount( "dir", ssprintf("%s/" PRODUCT_ID "/NoteSkins", dir), "/NoteSkins" );
|
||||||
FILEMAN->Mount( "dir", ssprintf("%s/" PRODUCT_ID "/Packages", dir), "/Packages" );
|
FILEMAN->Mount( "dir", ssprintf("%s/" PRODUCT_ID "/Packages", dir), "/Packages" );
|
||||||
FILEMAN->Mount( "dir", ssprintf("%s/" PRODUCT_ID "/Songs", dir), "/Songs" );
|
FILEMAN->Mount( "dir", ssprintf("%s/" PRODUCT_ID "/Songs", dir), "/Songs" );
|
||||||
|
|||||||
@@ -403,6 +403,7 @@ void ArchHooks::MountUserFilesystems( const RString &sDirOfExecutable )
|
|||||||
FILEMAN->Mount( "dir", sUserDataPath + "/CDTitles", "/CDTitles" );
|
FILEMAN->Mount( "dir", sUserDataPath + "/CDTitles", "/CDTitles" );
|
||||||
FILEMAN->Mount( "dir", sUserDataPath + "/Characters", "/Characters" );
|
FILEMAN->Mount( "dir", sUserDataPath + "/Characters", "/Characters" );
|
||||||
FILEMAN->Mount( "dir", sUserDataPath + "/Courses", "/Courses" );
|
FILEMAN->Mount( "dir", sUserDataPath + "/Courses", "/Courses" );
|
||||||
|
FILEMAN->Mount( "dir", sUserDataPath + "/Downloads", "/Downloads" );
|
||||||
FILEMAN->Mount( "dir", sUserDataPath + "/Logs", "/Logs" );
|
FILEMAN->Mount( "dir", sUserDataPath + "/Logs", "/Logs" );
|
||||||
FILEMAN->Mount( "dir", sUserDataPath + "/NoteSkins", "/NoteSkins" );
|
FILEMAN->Mount( "dir", sUserDataPath + "/NoteSkins", "/NoteSkins" );
|
||||||
FILEMAN->Mount( "dir", sUserDataPath + "/Packages", "/Packages" );
|
FILEMAN->Mount( "dir", sUserDataPath + "/Packages", "/Packages" );
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ void ArchHooks::MountUserFilesystems( const RString &sDirOfExecutable )
|
|||||||
FILEMAN->Mount( "dir", sAppDataDir + "/CDTitles", "/CDTitles" );
|
FILEMAN->Mount( "dir", sAppDataDir + "/CDTitles", "/CDTitles" );
|
||||||
FILEMAN->Mount( "dir", sAppDataDir + "/Characters", "/Characters" );
|
FILEMAN->Mount( "dir", sAppDataDir + "/Characters", "/Characters" );
|
||||||
FILEMAN->Mount( "dir", sAppDataDir + "/Courses", "/Courses" );
|
FILEMAN->Mount( "dir", sAppDataDir + "/Courses", "/Courses" );
|
||||||
|
FILEMAN->Mount( "dir", sAppDataDir + "/Downloads", "/Downloads" );
|
||||||
FILEMAN->Mount( "dir", sAppDataDir + "/Logs", "/Logs" );
|
FILEMAN->Mount( "dir", sAppDataDir + "/Logs", "/Logs" );
|
||||||
FILEMAN->Mount( "dir", sAppDataDir + "/NoteSkins", "/NoteSkins" );
|
FILEMAN->Mount( "dir", sAppDataDir + "/NoteSkins", "/NoteSkins" );
|
||||||
FILEMAN->Mount( "dir", sAppDataDir + "/Packages", "/Packages" );
|
FILEMAN->Mount( "dir", sAppDataDir + "/Packages", "/Packages" );
|
||||||
|
|||||||
Reference in New Issue
Block a user