Ark Server API (ASA) - Wiki
Loading...
Searching...
No Matches
Requests.cpp
Go to the documentation of this file.
1#pragma once
2#define WIN32_LEAN_AND_MEAN
3#pragma warning(push)
4#pragma warning(disable: 4191)
5#include <Requests.h>
6
7#include "../IBaseApi.h"
8
9#include <sstream>
10
11#include <mutex>
12
13#include "fstream"
14#include "Poco/StreamCopier.h"
15#include "Poco/URI.h"
16#include "Poco/Exception.h"
17#include "Poco/SharedPtr.h"
18#include "Poco/Net/SSLManager.h"
19#include <Poco/Net/InvalidCertificateHandler.h>
20#include <Poco/Net/RejectCertificateHandler.h>
21#include "Poco/Net/HTTPSClientSession.h"
22#include "Poco/Net/HTTPRequest.h"
23#include "Poco/Net/HTTPResponse.h"
24#include <Poco/Path.h>
25#include <Poco/UTF8String.h>
26#include <Poco/NullStream.h>
27#include "Poco/Net/Context.h"
28#include "Poco/Net/PrivateKeyPassphraseHandler.h"
29#include "Poco/Net/HTTPSClientSession.h"
30#include "Poco/Net/HTTPRequest.h"
31#include "Poco/Net/HTTPResponse.h"
32
33namespace API
34{
36 {
37 public:
38 void WriteRequest(std::function<void(bool, std::string)> callback, bool success, std::string result);
39
41 const std::vector<std::string>& headers, const std::string& request_type);
42
43 std::string GetResponse(Poco::Net::HTTPClientSession* session, Poco::Net::HTTPResponse& response);
44
45 void Update();
46 private:
48 {
49 std::function<void(bool, std::string)> callback;
50 bool success;
51 std::string result;
52 };
53
56 };
57
59 : pimpl{ std::make_unique<impl>() }
60 {
61
62 Poco::Net::initializeSSL();
63 Poco::SharedPtr<Poco::Net::InvalidCertificateHandler> ptrCert = new Poco::Net::RejectCertificateHandler(false);
64
65 Poco::Net::Context::Ptr ptrContext = new Poco::Net::Context(Poco::Net::Context::TLS_CLIENT_USE, "", "", "", Poco::Net::Context::VERIFY_NONE, 9, false, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
66
67 Poco::Net::SSLManager::instance().initializeClient(0, ptrCert, ptrContext);
68
69 game_api->GetCommands()->AddOnTickCallback("RequestsUpdate", std::bind(&impl::Update, this->pimpl.get()));
70 }
71
73 {
74 Poco::Net::uninitializeSSL();
75 game_api->GetCommands()->RemoveOnTickCallback("RequestsUpdate");
76 }
77
79 {
80 static Requests instance;
81 return instance;
82 }
83
84 void Requests::impl::WriteRequest(std::function<void(bool, std::string)> callback, bool success, std::string result)
85 {
86 std::lock_guard<std::mutex> Guard(RequestMutex_);
87 RequestsVec_.push_back({ callback, success, result });
88 }
89
91 const std::vector<std::string>& headers, const std::string& request_type)
92 {
93 Poco::URI uri(url);
94
95 const std::string& path(uri.getPathAndQuery());
96
97 if (uri.getScheme() == "https")
98 session = new Poco::Net::HTTPSClientSession(uri.getHost(), uri.getPort());
99 else
100 session = new Poco::Net::HTTPClientSession(uri.getHost(), uri.getPort());
101
102 Poco::Net::HTTPRequest request(request_type, path, Poco::Net::HTTPMessage::HTTP_1_1);
103
104 if (!headers.empty())
105 {
106 for (const auto& header : headers)
107 {
108 const std::string& key = header.substr(0, header.find(":"));
109 const std::string& data = header.substr(header.find(":") + 1);
110
111 request.add(key, data);
112 }
113 }
114
115 return request;
116 }
117
118 std::string Requests::impl::GetResponse(Poco::Net::HTTPClientSession* session, Poco::Net::HTTPResponse& response)
119 {
120 std::string result = "";
121
122 std::istream& rs = session->receiveResponse(response);
123
124 if (response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK)
125 {
126 std::ostringstream oss;
127 Poco::StreamCopier::copyStream(rs, oss);
128 result = oss.str();
129 }
130 else
131 {
132 Poco::NullOutputStream null;
133 Poco::StreamCopier::copyStream(rs, null);
134 result = std::to_string(response.getStatus()) + " " + response.getReason();
135 }
136
137 return result;
138 }
139
140 bool Requests::CreateGetRequest(const std::string& url, const std::function<void(bool, std::string)>& callback,
141 std::vector<std::string> headers)
142 {
143 std::thread([this, url, callback, headers]
144 {
145 std::string Result = "";
146 Poco::Net::HTTPResponse response(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
147 Poco::Net::HTTPClientSession* session = nullptr;
148
149 try
150 {
151 Poco::Net::HTTPRequest&& request = pimpl->ConstructRequest(url, session, headers, Poco::Net::HTTPRequest::HTTP_GET);
152
153 session->sendRequest(request);
154 Result = pimpl->GetResponse(session, response);
155 }
156 catch (const Poco::Exception& exc)
157 {
158 Log::GetLog()->error(exc.displayText());
159 }
160
161 const bool success = (int)response.getStatus() >= 200
162 && (int)response.getStatus() < 300;
163
164 pimpl->WriteRequest(callback, success, Result);
165 delete session;
166 session = nullptr;
167 }
168 ).detach();
169
170 return true;
171 }
172
173 bool Requests::CreatePostRequest(const std::string& url, const std::function<void(bool, std::string)>& callback,
174 const std::string& post_data, std::vector<std::string> headers)
175 {
176 std::thread([this, url, callback, post_data, headers]
177 {
178 std::string Result = "";
179 Poco::Net::HTTPResponse response(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
180 Poco::Net::HTTPClientSession* session = nullptr;
181
182 try
183 {
184 Poco::Net::HTTPRequest&& request = pimpl->ConstructRequest(url, session, headers, Poco::Net::HTTPRequest::HTTP_POST);
185
186 request.setContentType("application/x-www-form-urlencoded");
187 request.setContentLength(post_data.length());
188
189 std::ostream& OutputStream = session->sendRequest(request);
190 OutputStream << post_data;
191
192 Result = pimpl->GetResponse(session, response);
193 }
194 catch (const Poco::Exception& exc)
195 {
196 Log::GetLog()->error(exc.displayText());
197 }
198
199 const bool success = (int)response.getStatus() >= 200
200 && (int)response.getStatus() < 300;
201
202 pimpl->WriteRequest(callback, success, Result);
203 delete session;
204 session = nullptr;
205 }
206 ).detach();
207
208 return true;
209 }
210
211 bool Requests::CreatePostRequest(const std::string& url, const std::function<void(bool, std::string)>& callback,
212 const std::string& post_data, const std::string& content_type, std::vector<std::string> headers)
213 {
214 std::thread([this, url, callback, post_data, content_type, headers]
215 {
216 std::string Result = "";
217 Poco::Net::HTTPResponse response(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
218 Poco::Net::HTTPClientSession* session = nullptr;
219
220 try
221 {
222 Poco::Net::HTTPRequest&& request = pimpl->ConstructRequest(url, session, headers, Poco::Net::HTTPRequest::HTTP_POST);
223
224 request.setContentType(content_type);
225 request.setContentLength(post_data.length());
226
227 std::ostream& OutputStream = session->sendRequest(request);
228 OutputStream << post_data;
229
230 Result = pimpl->GetResponse(session, response);
231 }
232 catch (const Poco::Exception& exc)
233 {
234 Log::GetLog()->error(exc.displayText());
235 }
236
237 const bool success = (int)response.getStatus() >= 200
238 && (int)response.getStatus() < 300;
239
240 pimpl->WriteRequest(callback, success, Result);
241 delete session;
242 session = nullptr;
243 }
244 ).detach();
245
246 return true;
247 }
248
249 bool Requests::CreatePostRequest(const std::string& url, const std::function<void(bool, std::string)>& callback,
250 const std::vector<std::string>& post_ids,
251 const std::vector<std::string>& post_data, std::vector<std::string> headers)
252 {
253 if (post_ids.size() != post_data.size())
254 return false;
255
256 std::thread([this, url, callback, post_ids, post_data, headers]
257 {
258 std::string Result = "";
259 Poco::Net::HTTPResponse response(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
260 Poco::Net::HTTPClientSession* session = nullptr;
261
262 try
263 {
264 Poco::Net::HTTPRequest&& request = pimpl->ConstructRequest(url, session, headers, Poco::Net::HTTPRequest::HTTP_POST);
265
266 std::string body;
267
268 for (size_t i = 0; i < post_ids.size(); ++i)
269 {
270 const std::string& id = post_ids[i];
271 const std::string& data = post_data[i];
272
273 body += fmt::format("{}={}&", Poco::UTF8::escape(id), Poco::UTF8::escape(data));
274 }
275
276 body.pop_back(); // Remove last '&'
277
278 request.setContentType("application/x-www-form-urlencoded");
279 request.setContentLength(body.size());
280
281 std::ostream& OutputStream = session->sendRequest(request);
282 OutputStream << body;
283
284 Result = pimpl->GetResponse(session, response);
285 }
286 catch (const Poco::Exception& exc)
287 {
288 Log::GetLog()->error(exc.displayText());
289 }
290
291 const bool success = (int)response.getStatus() >= 200
292 && (int)response.getStatus() < 300;
293
294 pimpl->WriteRequest(callback, success, Result);
295 delete session;
296 session = nullptr;
297 }
298 ).detach();
299
300 return true;
301 }
302
303 bool Requests::CreateDeleteRequest(const std::string& url, const std::function<void(bool, std::string)>& callback,
304 std::vector<std::string> headers)
305 {
306 std::thread([this, url, callback, headers]
307 {
308 std::string Result = "";
309 Poco::Net::HTTPResponse response(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
310 Poco::Net::HTTPClientSession* session = nullptr;
311
312 try
313 {
314 Poco::Net::HTTPRequest&& request = pimpl->ConstructRequest(url, session, headers, Poco::Net::HTTPRequest::HTTP_DELETE);
315
316 session->sendRequest(request);
317 Result = pimpl->GetResponse(session, response);
318 }
319 catch (const Poco::Exception& exc)
320 {
321 Log::GetLog()->error(exc.displayText());
322 }
323
324 const bool success = (int)response.getStatus() >= 200
325 && (int)response.getStatus() < 300;
326
327 pimpl->WriteRequest(callback, success, Result);
328 delete session;
329 session = nullptr;
330 }
331 ).detach();
332
333 return true;
334 }
335
336 bool Requests::DownloadFile(const std::string& url, const std::string& localPath, std::vector<std::string> headers)
337 {
338 Poco::Net::HTTPResponse response(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
339 Poco::Net::HTTPClientSession* session = nullptr;
340
341 try
342 {
343 Poco::Net::initializeSSL();
344 Poco::SharedPtr<Poco::Net::InvalidCertificateHandler> ptrCert = new Poco::Net::RejectCertificateHandler(false);
345
346 Poco::Net::Context::Ptr ptrContext = new Poco::Net::Context(Poco::Net::Context::TLS_CLIENT_USE, "", "", "", Poco::Net::Context::VERIFY_NONE, 9, false, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
347
348 Poco::Net::SSLManager::instance().initializeClient(0, ptrCert, ptrContext);
349
350 Poco::URI uri(url);
351
352 const std::string& path(uri.getPathAndQuery());
353
354 if (uri.getScheme() == "https")
355 session = new Poco::Net::HTTPSClientSession(uri.getHost(), uri.getPort());
356 else
357 session = new Poco::Net::HTTPClientSession(uri.getHost(), uri.getPort());
358
359 Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, path, Poco::Net::HTTPMessage::HTTP_1_1);
360
361 session->sendRequest(request);
362 std::istream& rs = session->receiveResponse(response);
363 if (response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK)
364 {
365 std::ofstream outFile(localPath, std::ios::binary);
366 if (!outFile)
367 {
368 Log::GetLog()->error("Writing the file '{}' failed", localPath);
369 delete session;
370 session = nullptr;
371 return false;
372 }
373
374 Poco::StreamCopier::copyStream(rs, outFile);
375 }
376 else
377 {
378 Log::GetLog()->error("Requested file '{}' failed with error: '{}'", url, response.getReason());
379 Poco::NullOutputStream null;
380 Poco::StreamCopier::copyStream(rs, null);
381 delete session;
382 session = nullptr;
383 return false;
384 }
385 }
386 catch (const Poco::Exception& exc)
387 {
388 Log::GetLog()->error(exc.displayText());
389
390 delete session;
391 session = nullptr;
392 return false;
393 }
394
395 delete session;
396 session = nullptr;
397 return true;
398 }
399
401 {
402 if (RequestsVec_.empty())
403 return;
404
405 RequestMutex_.lock();
406 std::vector<RequestData> requests_temp = std::move(RequestsVec_);
407 RequestMutex_.unlock();
408
409 for (const auto& request : requests_temp) { request.callback(request.success, request.result); }
410 }
411} // namespace API
std::mutex RequestMutex_
Definition Requests.cpp:55
void WriteRequest(std::function< void(bool, std::string)> callback, bool success, std::string result)
Definition Requests.cpp:84
std::string GetResponse(Poco::Net::HTTPClientSession *session, Poco::Net::HTTPResponse &response)
Definition Requests.cpp:118
Poco::Net::HTTPRequest ConstructRequest(const std::string &url, Poco::Net::HTTPClientSession *&session, const std::vector< std::string > &headers, const std::string &request_type)
Definition Requests.cpp:90
std::vector< RequestData > RequestsVec_
Definition Requests.cpp:54
ARK_API bool CreateGetRequest(const std::string &url, const std::function< void(bool, std::string)> &callback, std::vector< std::string > headers={})
Creates an async GET Request that runs in another thread but calls the callback from the main thread.
Definition Requests.cpp:140
ARK_API bool CreatePostRequest(const std::string &url, const std::function< void(bool, std::string)> &callback, const std::vector< std::string > &post_ids, const std::vector< std::string > &post_data, std::vector< std::string > headers={})
Creates an async POST Request that runs in another thread but calls the callback from the main thread...
Definition Requests.cpp:249
ARK_API bool CreateDeleteRequest(const std::string &url, const std::function< void(bool, std::string)> &callback, std::vector< std::string > headers={})
Creates an async DELETE Request that runs in another thread but calls the callback from the main thre...
Definition Requests.cpp:303
ARK_API bool CreatePostRequest(const std::string &url, const std::function< void(bool, std::string)> &callback, const std::string &post_data, std::vector< std::string > headers={})
Creates an async POST Request with application/x-www-form-urlencoded content type that runs in anothe...
Definition Requests.cpp:173
static ARK_API Requests & Get()
Definition Requests.cpp:78
ARK_API bool CreatePostRequest(const std::string &url, const std::function< void(bool, std::string)> &callback, const std::string &post_data, const std::string &content_type, std::vector< std::string > headers={})
Creates an async POST Request that runs in another thread but calls the callback from the main thread...
Definition Requests.cpp:211
Definition IBaseApi.h:9
Definition json.hpp:4518
std::function< void(bool, std::string)> callback
Definition Requests.cpp:49