RigsofRods
Soft-body Physics Simulation
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 
30 using namespace RoR;
31 
32 #ifdef USE_CURL
33 # include <curl/curl.h>
34 # include <curl/easy.h>
35 
36 static 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 
42 static 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  {
56  ScriptEventArgs* args = new ScriptEventArgs;
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 
71 bool 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
GameContext.h
Game state manager and message-queue provider.
RoR::ScriptEventArgs
Args for eventCallbackEx() queued via MSG_SIM_SCRIPT_EVENT_TRIGGERED See descriptions at enum RoR::sc...
Definition: ScriptEvents.h:101
RoR::GetUrlAsString
bool GetUrlAsString(const std::string &url, CURLcode &curl_result, long &response_code, std::string &response_payload)
Definition: CurlHelpers.cpp:71
RoR::CurlTaskContext::ctc_msg_progress
MsgType ctc_msg_progress
Definition: CurlHelpers.h:39
format
Truck file format(technical spec)
RoR::CurlTaskContext::ctc_msg_failure
MsgType ctc_msg_failure
Sent on failure; Payload: RoR::ScriptEventArgs (see 'gameplay/ScriptEvents.h') with args for RoR::SE_...
Definition: CurlHelpers.h:41
RoR::GetUrlAsStringMQ
bool GetUrlAsStringMQ(CurlTaskContext task)
Definition: CurlHelpers.cpp:106
RoR::ASTHREADSTATUS_CURLSTRING_SUCCESS
@ ASTHREADSTATUS_CURLSTRING_SUCCESS
Args of RoR::SE_ANGELSCRIPT_THREAD_STATUS: arg#1 type, arg#2 HTTP code, arg#3 CURLcode,...
Definition: ScriptEvents.h:81
CurlHelpers.h
RoR::GameContext::PushMessage
void PushMessage(Message m)
Doesn't guarantee order! Use ChainMessage() if order matters.
Definition: GameContext.cpp:66
Application.h
Central state/object manager and communications hub.
RoR::App::GetGameContext
GameContext * GetGameContext()
Definition: Application.cpp:279
RoRVersion.h
ROR_VERSION_STRING
const char *const ROR_VERSION_STRING
RoR::CurlTaskContext::ctc_old_perc
double ctc_old_perc
Definition: CurlHelpers.h:43
RoR::CurlTaskContext::ctc_url
std::string ctc_url
Definition: CurlHelpers.h:37
RoR::MSG_INVALID
@ MSG_INVALID
Definition: Application.h:76
RoR::ScriptEventArgs::arg5ex
std::string arg5ex
Definition: ScriptEvents.h:110
RoR::CurlTaskContext::ctc_displayname
std::string ctc_displayname
Definition: CurlHelpers.h:36
RoR::Message
Unified game event system - all requests and state changes are reported using a message.
Definition: GameContext.h:51
ScriptEvents.h
RoR::ScriptEventArgs::arg2ex
int arg2ex
Definition: ScriptEvents.h:107
RoR::CurlTaskContext
Definition: CurlHelpers.h:34
RoR::ASTHREADSTATUS_CURLSTRING_PROGRESS
@ ASTHREADSTATUS_CURLSTRING_PROGRESS
Args of RoR::SE_ANGELSCRIPT_THREAD_STATUS: arg#1 type, arg#2 percentage, arg#3 unused,...
Definition: ScriptEvents.h:80
CurlStringWriteFunc
static size_t CurlStringWriteFunc(void *ptr, size_t size, size_t nmemb, std::string *data)
Definition: CurlHelpers.cpp:36
RoR
Definition: AppContext.h:36
CurlProgressFunc
static size_t CurlProgressFunc(void *ptr, double filesize_B, double downloaded_B)
Definition: CurlHelpers.cpp:42
RoR::ScriptEventArgs::arg1
int arg1
Definition: ScriptEvents.h:105
RoR::ASTHREADSTATUS_CURLSTRING_FAILURE
@ ASTHREADSTATUS_CURLSTRING_FAILURE
Args of RoR::SE_ANGELSCRIPT_THREAD_STATUS: arg#1 type, arg#2 HTTP code, arg#3 CURLcode,...
Definition: ScriptEvents.h:82
RoR::ScriptEventArgs::arg3ex
int arg3ex
Definition: ScriptEvents.h:108