Move low-level network stuff to CURLWrapper.

This commit is contained in:
tastytea 2020-01-04 18:11:24 +01:00
parent d9c92d5273
commit a7a861351f
Signed by: tastytea
GPG Key ID: CFC39497F1B26E07
6 changed files with 208 additions and 112 deletions

92
include/curl_wrapper.hpp Normal file
View File

@ -0,0 +1,92 @@
/* This file is part of mastodonpp.
* Copyright © 2020 tastytea <tastytea@tastytea.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MASTODONPP_CURL_WRAPPER_HPP
#define MASTODONPP_CURL_WRAPPER_HPP
#include "curl/curl.h"
#include <string>
namespace mastodonpp
{
using std::string;
//! Internal use only.
extern bool curl_initialized;
/*!
* @brief Handles the details of network connections.
*
* @since 0.1.0
*
* @headerfile curl_wrapper.hpp mastodonpp/curl_wrapper.hpp
*/
class CURLWrapper
{
public:
/*!
* @brief Constructs a CURLWrapper object.
*
* The first construction of an CurlWrapper object will call
* `curl_global_init`, which is not thread-safe. For more information
* consult [curl_global_init(3)]
* (https://curl.haxx.se/libcurl/c/curl_global_init.html).
*
* @since 0.1.0
*/
CURLWrapper();
//! Copy constructor
CURLWrapper(const CURLWrapper &other) = default;
//! Move constructor
CURLWrapper(CURLWrapper &&other) noexcept = default;
//! Destructor
virtual ~CURLWrapper() noexcept;
//! Copy assignment operator
CURLWrapper& operator=(const CURLWrapper &other) = default;
//! Move assignment operator
CURLWrapper& operator=(CURLWrapper &&other) noexcept = default;
private:
CURL *_connection;
char _curl_buffer_error[CURL_ERROR_SIZE];
string _curl_buffer;
/*!
* @brief libcurl write callback function.
*
* @since 0.1.0
*/
static int writer(char *data, size_t size, size_t nmemb,
string *writerData);
/*!
* @brief Setup libcurl connection.
*
* @since 0.1.0
*/
void setup_curl();
};
} // namespace mastodonpp
#endif // MASTODONPP_CURL_WRAPPER_HPP

View File

@ -17,7 +17,7 @@
#ifndef MASTODONPP_INSTANCE_HPP
#define MASTODONPP_INSTANCE_HPP
#include <curl/curl.h>
#include "curl_wrapper.hpp"
#include <string>
@ -26,27 +26,19 @@ namespace mastodonpp
using std::string;
//! Internal use only.
extern bool curl_initialized;
/*!
* @brief Holds the access data of and the connection to an instance.
* @brief Holds the access data of an instance.
*
* @since 0.1.0
*
* @headerfile instance.hpp mastodonpp/instance.hpp
*/
class Instance
class Instance : public CURLWrapper
{
public:
/*!
* @brief Construct a new Instance object.
*
* The first construction of an Instance object will call
* `curl_global_init`, which is not thread-safe. For more information
* consult [curl_global_init(3)]
* (https://curl.haxx.se/libcurl/c/curl_global_init.html).
*
* @param instance The hostname of the instance.
* @param access_token Your access token.
*
@ -54,43 +46,9 @@ public:
*/
explicit Instance(string instance, string access_token);
//! Copy constructor
Instance(const Instance &other) = default;
//! Move constructor
Instance(Instance &&other) = default;
//! Destructor
virtual ~Instance();
//! Copy assignment operator
Instance& operator=(const Instance &other) = delete;
//! Move assignment operator
Instance& operator=(Instance &&other) = delete;
private:
const string _instance;
string _access_token;
CURL *_connection;
char _curl_buffer_error[CURL_ERROR_SIZE];
string _curl_buffer;
/*!
* @brief libcurl write callback function.
*
* @since 0.1.0
*/
static int writer(char *data, size_t size, size_t nmemb,
string *writerData);
/*!
* @brief Setup libcurl connection.
*
* @since 0.1.0
*/
void setup_curl();
};
} // namespace mastodonpp

View File

@ -18,6 +18,7 @@
#define MASTODONPP_REQUEST_HPP
#include "api.hpp"
#include "curl_wrapper.hpp"
#include "instance.hpp"
#include "return_types.hpp"
@ -35,7 +36,7 @@ using std::string;
*
* @headerfile request.hpp mastodonpp/request.hpp
*/
class Request
class Request : public CURLWrapper
{
public:
/*!
@ -50,11 +51,24 @@ public:
/*!
* @brief Make a HTTP GET call.
*
* @param endpoint Endpoint as API::endpoint_type, for example:
* `mastodonpp::API::v1::instance`.
*
* @since 0.1.0
*/
[[nodiscard]]
answer_type get(API::endpoint_type endpoint) const;
/*!
* @brief Make a HTTP GET call.
*
* @param endpoint Endpoint as string, for example: "/api/v1/instance".
*
* @since 0.1.0
*/
[[nodiscard]]
answer_type get(string endpoint) const;
private:
Instance &_instance;
};

90
src/curl_wrapper.cpp Normal file
View File

@ -0,0 +1,90 @@
/* This file is part of mastodonpp.
* Copyright © 2020 tastytea <tastytea@tastytea.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "curl_wrapper.hpp"
#include "exceptions.hpp"
namespace mastodonpp
{
bool curl_initialized{false};
CURLWrapper::CURLWrapper()
: _curl_buffer_error{}
{
if (!curl_initialized)
{
curl_global_init(CURL_GLOBAL_ALL); // NOLINT(hicpp-signed-bitwise)
curl_initialized = true;
}
_connection = curl_easy_init();
setup_curl();
}
CURLWrapper::~CURLWrapper() noexcept
{
curl_easy_cleanup(_connection);
if (curl_initialized)
{
curl_global_cleanup();
curl_initialized = false;
}
}
int CURLWrapper::writer(char *data, size_t size, size_t nmemb, string *writerData)
{
if(writerData == nullptr)
{
return 0;
}
writerData->append(data, size*nmemb);
return static_cast<int>(size * nmemb);
}
void CURLWrapper::setup_curl()
{
if (_connection == nullptr)
{
throw CURLException{CURLE_FAILED_INIT, "Failed to initialize curl."};
}
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
CURLcode code{curl_easy_setopt(_connection, CURLOPT_ERRORBUFFER,
_curl_buffer_error)};
if (code != CURLE_OK)
{
throw CURLException{code, "Failed to set error buffer."};
}
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
code = curl_easy_setopt(_connection, CURLOPT_WRITEFUNCTION, writer);
if (code != CURLE_OK)
{
throw CURLException{code, "Failed to set writer", _curl_buffer_error};
}
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
code = curl_easy_setopt(_connection, CURLOPT_WRITEDATA, &_curl_buffer);
if (code != CURLE_OK)
{
throw CURLException{code, "Failed to set write data",
_curl_buffer_error};
}
}
} // namespace mastodonpp

View File

@ -15,7 +15,6 @@
*/
#include "instance.hpp"
#include "exceptions.hpp"
#include <utility>
@ -24,73 +23,9 @@ namespace mastodonpp
using std::move;
bool curl_initialized{false};
Instance::Instance(string instance, string access_token)
: _instance{move(instance)}
, _access_token{move(access_token)}
, _curl_buffer_error{}
{
if (!curl_initialized)
{
curl_global_init(CURL_GLOBAL_ALL); // NOLINT(hicpp-signed-bitwise)
curl_initialized = true;
}
_connection = curl_easy_init();
setup_curl();
}
Instance::~Instance()
{
curl_easy_cleanup(_connection);
if (curl_initialized)
{
curl_global_cleanup();
curl_initialized = false;
}
}
int Instance::writer(char *data, size_t size, size_t nmemb, string *writerData)
{
if(writerData == nullptr)
{
return 0;
}
writerData->append(data, size*nmemb);
return static_cast<int>(size * nmemb);
}
void Instance::setup_curl()
{
if (_connection == nullptr)
{
throw CURLException{CURLE_FAILED_INIT, "Failed to initialize curl."};
}
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
CURLcode code{curl_easy_setopt(_connection, CURLOPT_ERRORBUFFER,
_curl_buffer_error)};
if (code != CURLE_OK)
{
throw CURLException{code, "Failed to set error buffer."};
}
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
code = curl_easy_setopt(_connection, CURLOPT_WRITEFUNCTION, writer);
if (code != CURLE_OK)
{
throw CURLException{code, "Failed to set writer", _curl_buffer_error};
}
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
code = curl_easy_setopt(_connection, CURLOPT_WRITEDATA, &_curl_buffer);
if (code != CURLE_OK)
{
throw CURLException{code, "Failed to set write data",
_curl_buffer_error};
}
}
{}
} // namespace mastodonpp

View File

@ -30,4 +30,11 @@ answer_type Request::get(API::endpoint_type endpoint) const
return answer;
}
answer_type Request::get(string endpoint) const
{
answer_type answer;
answer.body = endpoint;
return answer;
}
} // namespace mastodonpp