diff --git a/loader/include/Geode/utils/web.hpp b/loader/include/Geode/utils/web.hpp index 73b53a8c..cd41bb5d 100644 --- a/loader/include/Geode/utils/web.hpp +++ b/loader/include/Geode/utils/web.hpp @@ -7,7 +7,7 @@ #include "general.hpp" #include -#include +#include namespace geode::utils::web { GEODE_DLL void openLinkInBrowser(std::string const& url); @@ -185,6 +185,10 @@ namespace geode::utils::web { * sets the content type to application/json. */ AsyncWebRequest& postFields(matjson::Value const& fields); + /** + * Specify a timeout, in seconds, in which the request will fail. + */ + AsyncWebRequest& timeout(std::chrono::seconds seconds); /** * Specify a callback to run if the download fails. The callback is * always ran in the GD thread, so interacting with UI is safe diff --git a/loader/src/utils/web.cpp b/loader/src/utils/web.cpp index c9cba70e..7734b546 100644 --- a/loader/src/utils/web.cpp +++ b/loader/src/utils/web.cpp @@ -204,6 +204,7 @@ public: bool m_sent = false; std::variant m_target; std::vector m_httpHeaders; + std::chrono::seconds m_timeoutSeconds; SentAsyncWebRequestHandle send(AsyncWebRequest&); }; @@ -241,7 +242,9 @@ SentAsyncWebRequest::Impl::Impl(SentAsyncWebRequest* self, AsyncWebRequest const if (req.m_impl->m_cancelled) m_cancelleds.push_back(req.m_impl->m_cancelled); if (req.m_impl->m_expect) m_expects.push_back(req.m_impl->m_expect); - std::thread([this]() { + auto timeoutSeconds = req.m_impl->m_timeoutSeconds; + + std::thread([this, timeoutSeconds]() { AWAIT_RESUME(); auto curl = curl_easy_init(); @@ -301,6 +304,11 @@ SentAsyncWebRequest::Impl::Impl(SentAsyncWebRequest* self, AsyncWebRequest const curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, m_postFields.size()); } + // Timeout + if (timeoutSeconds.count()) { + curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeoutSeconds.count()); + } + // Track progress curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0); // Follow redirects