Rigs of Rods 2023.09
Soft-body Physics Simulation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Loading...
Searching...
No Matches
CurlHelpers.cpp
Go to the documentation of this file.
1/*
2 This source file is part of Rigs of Rods
3 Copyright 2005-2012 Pierre-Michel Ricordel
4 Copyright 2007-2012 Thomas Fischer
5 Copyright 2013-2023 Petr Ohlidal
6
7 For more information, see http://www.rigsofrods.org/
8
9 Rigs of Rods is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License version 3, as
11 published by the Free Software Foundation.
12
13 Rigs of Rods is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Rigs of Rods. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#include "Application.h"
23#include "CurlHelpers.h"
24#include "GameContext.h"
25#include "RoRVersion.h"
26#include "ScriptEvents.h"
27
28#include <fmt/format.h>
29
30using namespace RoR;
31
32#ifdef USE_CURL
33# include <curl/curl.h>
34# include <curl/easy.h>
35
36static size_t CurlStringWriteFunc(void *ptr, size_t size, size_t nmemb, std::string* data)
37{
38 data->append((char*)ptr, size * nmemb);
39 return size * nmemb;
40}
41
42static size_t CurlProgressFunc(void* ptr, double filesize_B, double downloaded_B)
43{
44 // Ensure that the file to be downloaded is not empty because that would cause a division by zero error later on
45 if (filesize_B <= 0.0)
46 {
47 return 0;
48 }
49
50 CurlTaskContext* context = (CurlTaskContext*)ptr;
51
52 double perc = (downloaded_B / filesize_B) * 100;
53
54 if (perc > context->ctc_old_perc && context->ctc_msg_progress != MSG_INVALID)
55 {
58 args->arg2ex = perc;
59 args->arg5ex = fmt::format("{} {}\n{}: {:.2f}{}\n{}: {:.2f}{}", "Downloading",
60 context->ctc_displayname, "File size", filesize_B/(1024 * 1024), "MB", "Downloaded", downloaded_B/(1024 * 1024), "MB");
61
63 }
64
65 context->ctc_old_perc = perc;
66
67 // If you don't return 0, the transfer will be aborted - see the documentation
68 return 0;
69}
70
71bool RoR::GetUrlAsString(const std::string& url, CURLcode& curl_result, long& response_code, std::string& response_payload)
72{
73 std::string response_header;
74 std::string user_agent = fmt::format("{}/{}", "Rigs of Rods Client", ROR_VERSION_STRING);
75
76 CURL *curl = curl_easy_init();
77 curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
78 curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
79#ifdef _WIN32
80 curl_easy_setopt(curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA);
81#endif // _WIN32
82 curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "gzip");
83 curl_easy_setopt(curl, CURLOPT_USERAGENT, user_agent.c_str());
84 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlStringWriteFunc);
85 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_payload);
86 curl_easy_setopt(curl, CURLOPT_HEADERDATA, &response_header);
87
88 curl_result = curl_easy_perform(curl);
89 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
90
91 curl_easy_cleanup(curl);
92 curl = nullptr;
93
94 if (curl_result != CURLE_OK || response_code != 200)
95 {
96 Ogre::LogManager::getSingleton().stream()
97 << "[RoR|CURL] Failed to retrieve url '"<<url<<"' as string;"
98 << " Error: '" << curl_easy_strerror(curl_result) << "'; HTTP status code: " << response_code;
99 response_payload = curl_easy_strerror(curl_result);
100 return false;
101 }
102
103 return true;
104}
105
107{
108 std::string data;
109 CURLcode curl_result = CURLE_OK;
110 long http_response = 0;
111 bool result = GetUrlAsString(task.ctc_url, /*out:*/curl_result, /*out:*/http_response, /*out:*/data);
112
113 if (!result && task.ctc_msg_failure != MSG_INVALID)
114 {
115 // `data` contains the `curl_easy_strerror()` message (already logged)
116 ScriptEventArgs* args = new ScriptEventArgs();
118 args->arg2ex = http_response;
119 args->arg3ex = curl_result;
120 args->arg5ex = data;
121
123 }
124 else if (result && task.ctc_msg_failure != MSG_INVALID)
125 {
126 // `data` contains the `CURL_WRITEDATA` payload.
127 ScriptEventArgs* args = new ScriptEventArgs();
129 args->arg2ex = http_response;
130 args->arg3ex = curl_result;
131 args->arg5ex = data;
132
134 }
135
136 return result;
137}
138
139#endif //USE_CURL
Central state/object manager and communications hub.
static size_t CurlStringWriteFunc(void *ptr, size_t size, size_t nmemb, std::string *data)
static size_t CurlProgressFunc(void *ptr, double filesize_B, double downloaded_B)
Game state manager and message-queue provider.
const char *const ROR_VERSION_STRING
void PushMessage(Message m)
Doesn't guarantee order! Use ChainMessage() if order matters.
@ MSG_INVALID
Definition Application.h:84
GameContext * GetGameContext()
bool GetUrlAsStringMQ(CurlTaskContext task)
@ ASTHREADSTATUS_CURLSTRING_PROGRESS
Args of RoR::SE_ANGELSCRIPT_THREAD_STATUS: arg#1 type, arg#2 percentage, arg#3 unused,...
@ ASTHREADSTATUS_CURLSTRING_FAILURE
Args of RoR::SE_ANGELSCRIPT_THREAD_STATUS: arg#1 type, arg#2 HTTP code, arg#3 CURLcode,...
@ ASTHREADSTATUS_CURLSTRING_SUCCESS
Args of RoR::SE_ANGELSCRIPT_THREAD_STATUS: arg#1 type, arg#2 HTTP code, arg#3 CURLcode,...
bool GetUrlAsString(const std::string &url, CURLcode &curl_result, long &response_code, std::string &response_payload)
std::string ctc_displayname
Definition CurlHelpers.h:36
std::string ctc_url
Definition CurlHelpers.h:37
MsgType ctc_msg_failure
Sent on failure; Payload: RoR::ScriptEventArgs (see 'gameplay/ScriptEvents.h') with args for RoR::SE_...
Definition CurlHelpers.h:41
Unified game event system - all requests and state changes are reported using a message.
Definition GameContext.h:52
Args for eventCallbackEx() queued via MSG_SIM_SCRIPT_EVENT_TRIGGERED See descriptions at enum RoR::sc...