Merge branch 'develop' into main
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
commit
d4ed04f0cd
24
.drone.yml
24
.drone.yml
|
@ -13,7 +13,7 @@ trigger:
|
|||
- tag
|
||||
|
||||
steps:
|
||||
- name: GCC 8 on Debian buster
|
||||
- name: GCC 8 / clang 7
|
||||
image: debian:buster-slim
|
||||
pull: always
|
||||
environment:
|
||||
|
@ -25,10 +25,16 @@ steps:
|
|||
- rm /etc/apt/apt.conf.d/docker-clean
|
||||
- alias apt-get='rm -f /var/cache/apt/archives/lock && apt-get'
|
||||
- apt-get update -q
|
||||
- apt-get install -qq build-essential cmake
|
||||
- apt-get install -qq build-essential cmake clang
|
||||
- apt-get install -qq catch libcurl4-openssl-dev
|
||||
- rm -rf build && mkdir -p build && cd build
|
||||
- cmake -G "Unix Makefiles" -DWITH_TESTS=YES ..
|
||||
- cmake -G "Unix Makefiles" -DWITH_TESTS=YES -DWITH_EXAMPLES=YES ..
|
||||
- make VERBOSE=1
|
||||
- make install DESTDIR=install
|
||||
- cd tests && ctest -V
|
||||
- cd ../../
|
||||
- rm -rf build && mkdir -p build && cd build
|
||||
- CXX="clang++" cmake -G "Unix Makefiles" -DWITH_TESTS=YES -DWITH_EXAMPLES=YES ..
|
||||
- make VERBOSE=1
|
||||
- make install DESTDIR=install
|
||||
- cd tests && ctest -V
|
||||
|
@ -36,7 +42,7 @@ steps:
|
|||
- name: debian-package-cache
|
||||
path: /var/cache/apt/archives
|
||||
|
||||
- name: GCC 7 on Ubuntu bionic
|
||||
- name: GCC 7 / clang 6
|
||||
image: ubuntu:bionic
|
||||
pull: always
|
||||
environment:
|
||||
|
@ -48,10 +54,16 @@ steps:
|
|||
- rm /etc/apt/apt.conf.d/docker-clean
|
||||
- alias apt-get='rm -f /var/cache/apt/archives/lock && apt-get'
|
||||
- apt-get update -q
|
||||
- apt-get install -qq build-essential cmake
|
||||
- apt-get install -qq build-essential cmake clang
|
||||
- apt-get install -qq catch libcurl4-openssl-dev
|
||||
- rm -rf build && mkdir -p build && cd build
|
||||
- cmake -G "Unix Makefiles" -DWITH_TESTS=YES ..
|
||||
- cmake -G "Unix Makefiles" -DWITH_TESTS=YES -DWITH_EXAMPLES=YES ..
|
||||
- make VERBOSE=1
|
||||
- make install DESTDIR=install
|
||||
- cd tests && ctest -V
|
||||
- cd ../../
|
||||
- rm -rf build && mkdir -p build && cd build
|
||||
- CXX="clang++" cmake -G "Unix Makefiles" -DWITH_TESTS=YES -DWITH_EXAMPLES=YES ..
|
||||
- make VERBOSE=1
|
||||
- make install DESTDIR=install
|
||||
- cd tests && ctest -V
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
:uri-mastodon-cpp: https://schlomp.space/tastytea/mastodon-cpp
|
||||
:uri-reference: https://doc.schlomp.space/{project}/
|
||||
:uri-gcc: https://gcc.gnu.org/
|
||||
:uti-clang: https://clang.llvm.org/
|
||||
:uri-cmake: https://cmake.org/
|
||||
:uri-doxygen: http://www.doxygen.nl/
|
||||
:uri-catch: https://github.com/catchorg/Catch2
|
||||
|
@ -39,7 +40,7 @@ Have a look at the link:{uri-reference}[reference].
|
|||
==== Dependencies
|
||||
|
||||
* Tested OS: Linux
|
||||
* C++ compiler (tested: link:{uri-gcc}[GCC] 7/8/9)
|
||||
* C++ compiler (tested: link:{uri-gcc}[GCC] 7/8/9, link:{uri-lang}[clang] 6/7)
|
||||
* link:{uri-cmake}[CMake] (at least: 3.9)
|
||||
* link:{uri-curl}[curl] (tested: 7.66 / 7.58)
|
||||
* Optional
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
// Print information about an instance (/api/v1/instance).
|
||||
|
||||
#include <mastodonpp.hpp>
|
||||
#include "mastodonpp.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
|
|
@ -24,12 +24,16 @@
|
|||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <variant>
|
||||
|
||||
namespace mastodonpp
|
||||
{
|
||||
|
||||
using std::string;
|
||||
using std::string_view;
|
||||
using std::variant;
|
||||
|
||||
using endpoint_variant = variant<API::endpoint_type,string>;
|
||||
|
||||
/*!
|
||||
* @brief Represents a connection to an instance. Used for requests.
|
||||
|
@ -51,25 +55,43 @@ public:
|
|||
explicit Connection(Instance &instance);
|
||||
|
||||
/*!
|
||||
* @brief Make a HTTP GET call.
|
||||
* @brief Make a HTTP GET call with parameters.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* auto answer{connection.get(mastodonpp::API::v1::accounts_id_followers,
|
||||
* {
|
||||
* {"id", "12"},
|
||||
* {"limit", "10"}
|
||||
* })};
|
||||
* @endcode
|
||||
*
|
||||
* @param endpoint Endpoint as API::endpoint_type or `std::string`.
|
||||
* @param parameters A map of parameters.
|
||||
*
|
||||
* @param endpoint Endpoint as API::endpoint_type, for example:
|
||||
* `mastodonpp::API::v1::instance`.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
[[nodiscard]]
|
||||
answer_type get(const API::endpoint_type &endpoint);
|
||||
answer_type get(const endpoint_variant &endpoint,
|
||||
const parametermap ¶meters);
|
||||
|
||||
/*!
|
||||
* @brief Make a HTTP GET call.
|
||||
* Example:
|
||||
* @code
|
||||
* auto answer{connection.get("/api/v1/instance")};
|
||||
* @endcode
|
||||
*
|
||||
* @param endpoint Endpoint as string, for example: "/api/v1/instance".
|
||||
* @param endpoint Endpoint as API::endpoint_type or `std::string`.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
[[nodiscard]]
|
||||
answer_type get(const string_view &endpoint);
|
||||
inline answer_type get(const endpoint_variant &endpoint)
|
||||
{
|
||||
return get(endpoint, {});
|
||||
}
|
||||
|
||||
private:
|
||||
Instance &_instance;
|
||||
|
|
|
@ -114,15 +114,32 @@ public:
|
|||
CURLWrapper& operator=(CURLWrapper &&other) noexcept = default;
|
||||
|
||||
/*!
|
||||
* @brief Make a request.
|
||||
* @brief Returns pointer to the CURL easy handle.
|
||||
*
|
||||
* @param method The HTTP method.
|
||||
* @param uri The full URI.
|
||||
* You can use this handle to set or modify curl options. For more
|
||||
* information consult [curl_easy_setopt(3)]
|
||||
* (https://curl.haxx.se/libcurl/c/curl_easy_setopt.html).
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
inline CURL *get_curl_easy_handle()
|
||||
{
|
||||
return _connection;
|
||||
}
|
||||
|
||||
protected:
|
||||
/*!
|
||||
* @brief Make a HTTP request.
|
||||
*
|
||||
* @param method The HTTP method.
|
||||
* @param uri The full URI.
|
||||
* @param parameters A map of parameters.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
[[nodiscard]]
|
||||
answer_type make_request(const http_method &method, const string_view &uri);
|
||||
answer_type make_request(const http_method &method, string uri,
|
||||
const parametermap ¶meters);
|
||||
|
||||
private:
|
||||
CURL *_connection;
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
*
|
||||
* Or compile your code with `g++ $(pkg-config --cflags --libs mastodonpp)`.
|
||||
*
|
||||
* @subsection Example
|
||||
* @subsection example Example
|
||||
*
|
||||
* @code
|
||||
* #include <mastodonpp/mastodonpp.hpp>
|
||||
|
@ -67,27 +67,36 @@
|
|||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @subsection input Input
|
||||
*
|
||||
* All text input is expected to be UTF-8.
|
||||
*
|
||||
* @section exceptions Exceptions
|
||||
*
|
||||
* Any unrecoverable libcurl error will be thrown as a
|
||||
* mastodonpp::CURLException. Network errors will **not** be thrown, but
|
||||
* reported via the return value.
|
||||
*
|
||||
* @section thread_safety Thread safety
|
||||
*
|
||||
* The first time you construct an @link mastodonpp::Instance Instance @endlink
|
||||
* or @link mastodonpp::Connection Connection @endlink, [curl_global_init()]
|
||||
* (https://curl.haxx.se/libcurl/c/curl_global_init.html) is called. When the
|
||||
* last @link mastodonpp::Instance Instance @endlink or @link
|
||||
* mastodonpp::Connection Connection @endlink is destroyed,
|
||||
* [curl_global_cleanup()]
|
||||
* (https://curl.haxx.se/libcurl/c/curl_global_cleanup.html) is called. Both
|
||||
* are not thread safe.
|
||||
*
|
||||
* @example example01_instance_info.cpp
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @brief C++ wrapper for the Mastodon %API.
|
||||
*
|
||||
* All text input is expected to be UTF-8.
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
namespace mastodonpp
|
||||
{
|
||||
|
||||
|
||||
|
||||
} // namespace mastodonpp
|
||||
{} // namespace mastodonpp
|
||||
|
||||
#endif // MASTODONPP_HPP
|
||||
|
|
|
@ -4,7 +4,7 @@ find_package(CURL REQUIRED)
|
|||
|
||||
# Write version in header.
|
||||
configure_file ("version.hpp.in"
|
||||
"${PROJECT_BINARY_DIR}/version.hpp" @ONLY)
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/version.hpp" @ONLY)
|
||||
|
||||
add_library(${PROJECT_NAME})
|
||||
|
||||
|
@ -19,7 +19,7 @@ set_target_properties(${PROJECT_NAME} PROPERTIES
|
|||
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
"$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/src>" # version.hpp
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>" # version.hpp
|
||||
PUBLIC
|
||||
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
|
||||
|
|
|
@ -31,7 +31,7 @@ const map<API::endpoint_type,string_view> API::_endpoint_map
|
|||
{v1::accounts, "/api/v1/accounts"},
|
||||
{v1::accounts_verify_credentials, "/api/v1/accounts/verify/credentials"},
|
||||
{v1::accounts_update_credentials, "/api/v1/accounts/update/credentials"},
|
||||
{v1::accounts_id, "/api/v1/accounts/id"},
|
||||
{v1::accounts_id, "/api/v1/accounts/<ID>"},
|
||||
{v1::accounts_id_statuses, "/api/v1/accounts/<ID>/statuses"},
|
||||
{v1::accounts_id_followers, "/api/v1/accounts/<ID>/followers"},
|
||||
{v1::accounts_id_following, "/api/v1/accounts/<ID>/following"},
|
||||
|
|
|
@ -19,21 +19,27 @@
|
|||
namespace mastodonpp
|
||||
{
|
||||
|
||||
using std::holds_alternative;
|
||||
|
||||
Connection::Connection(Instance &instance)
|
||||
: _instance{instance}
|
||||
, _baseuri{instance.get_baseuri()}
|
||||
{}
|
||||
|
||||
answer_type Connection::get(const API::endpoint_type &endpoint)
|
||||
answer_type Connection::get(const endpoint_variant &endpoint,
|
||||
const parametermap ¶meters)
|
||||
{
|
||||
return make_request(
|
||||
http_method::GET,
|
||||
string(_baseuri).append(API{endpoint}.to_string_view()));
|
||||
}
|
||||
string uri{[&]
|
||||
{
|
||||
if (holds_alternative<API::endpoint_type>(endpoint))
|
||||
{
|
||||
return string(_baseuri).append(
|
||||
API{std::get<API::endpoint_type>(endpoint)}.to_string_view());
|
||||
}
|
||||
|
||||
answer_type Connection::get(const string_view &endpoint)
|
||||
{
|
||||
return make_request(http_method::GET, string(_baseuri).append(endpoint));
|
||||
return std::get<string>(endpoint);
|
||||
}()};
|
||||
return make_request(http_method::GET, uri, parameters);
|
||||
}
|
||||
|
||||
} // namespace mastodonpp
|
||||
|
|
|
@ -17,16 +17,26 @@
|
|||
#include "curl_wrapper.hpp"
|
||||
#include "exceptions.hpp"
|
||||
#include "log.hpp"
|
||||
#include "version.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
namespace mastodonpp
|
||||
{
|
||||
|
||||
using std::get;
|
||||
using std::holds_alternative;
|
||||
using std::any_of;
|
||||
using std::array;
|
||||
using std::atomic;
|
||||
using std::uint8_t;
|
||||
using std::uint16_t;
|
||||
|
||||
static uint16_t curlwrapper_instances{0};
|
||||
static atomic<uint16_t> curlwrapper_instances{0};
|
||||
|
||||
CURLWrapper::CURLWrapper()
|
||||
: _curl_buffer_error{}
|
||||
|
@ -53,11 +63,9 @@ CURLWrapper::~CURLWrapper() noexcept
|
|||
}
|
||||
}
|
||||
|
||||
answer_type CURLWrapper::make_request(const http_method &method,
|
||||
const string_view &uri)
|
||||
answer_type CURLWrapper::make_request(const http_method &method, string uri,
|
||||
const parametermap ¶meters)
|
||||
{
|
||||
debuglog << "Making request to: " << uri << '\n';
|
||||
|
||||
CURLcode code;
|
||||
switch (method)
|
||||
{
|
||||
|
@ -65,6 +73,52 @@ answer_type CURLWrapper::make_request(const http_method &method,
|
|||
{
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
|
||||
code = curl_easy_setopt(_connection, CURLOPT_HTTPGET, 1L);
|
||||
|
||||
for (const auto ¶m : parameters)
|
||||
{
|
||||
static constexpr array replace_in_uri
|
||||
{
|
||||
"id", "nickname", "nickname_or_id",
|
||||
"hashtag", "permission_group"
|
||||
};
|
||||
if (any_of(replace_in_uri.begin(), replace_in_uri.end(),
|
||||
[¶m](const auto &s) { return s == param.first; }))
|
||||
{
|
||||
const auto pos{uri.find('<')};
|
||||
if (pos != string::npos)
|
||||
{
|
||||
uri.replace(pos, param.first.size() + 2,
|
||||
get<string>(param.second));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
static bool first{true};
|
||||
if (first)
|
||||
{
|
||||
uri.append("?");
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
uri.append("&");
|
||||
}
|
||||
if (holds_alternative<string>(param.second))
|
||||
{
|
||||
uri.append(param.first + '=' + get<string>(param.second));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto &arg : get<vector<string>>(param.second))
|
||||
{
|
||||
uri.append(param.first + "[]=" + arg);
|
||||
if (arg != *get<vector<string>>(param.second).rbegin())
|
||||
{
|
||||
uri.append("&");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case http_method::POST:
|
||||
|
@ -97,6 +151,7 @@ answer_type CURLWrapper::make_request(const http_method &method,
|
|||
throw CURLException{code, "Failed to set HTTP method",
|
||||
_curl_buffer_error};
|
||||
}
|
||||
debuglog << "Making request to: " << uri << '\n';
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
|
||||
code = curl_easy_setopt(_connection, CURLOPT_URL, uri.data());
|
||||
|
@ -180,6 +235,25 @@ void CURLWrapper::setup_curl()
|
|||
throw CURLException{code, "Failed to set write data",
|
||||
_curl_buffer_error};
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
|
||||
code = curl_easy_setopt(_connection, CURLOPT_USERAGENT,
|
||||
string("mastorss/").append(version).c_str());
|
||||
if (code != CURLE_OK)
|
||||
{
|
||||
throw CURLException{code, "Failed to set User-Agent",
|
||||
_curl_buffer_error};
|
||||
}
|
||||
|
||||
// The next 2 only fail if HTTP is not supported.
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
|
||||
code = curl_easy_setopt(_connection, CURLOPT_FOLLOWLOCATION, 1L);
|
||||
if (code != CURLE_OK)
|
||||
{
|
||||
throw CURLException{code, "HTTP is not supported.", _curl_buffer_error};
|
||||
}
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
|
||||
curl_easy_setopt(_connection, CURLOPT_MAXREDIRS, 10L);
|
||||
}
|
||||
|
||||
} // namespace mastodonpp
|
||||
|
|
|
@ -40,7 +40,7 @@ uint64_t Instance::get_max_chars()
|
|||
{
|
||||
debuglog << "Querying " << _hostname << " for max_toot_chars…\n";
|
||||
const auto answer{make_request(http_method::GET,
|
||||
_baseuri + "/api/v1/instance")};
|
||||
_baseuri + "/api/v1/instance", {})};
|
||||
if (!answer)
|
||||
{
|
||||
debuglog << "Could not get instance info.\n";
|
||||
|
|
|
@ -31,7 +31,7 @@ constexpr auto shorten_filename(const string_view &filename)
|
|||
{
|
||||
for (const string_view &dir : {"/src/", "/include/"})
|
||||
{
|
||||
auto pos{filename.rfind("/src/")};
|
||||
const auto pos{filename.rfind(dir)};
|
||||
if (pos != string_view::npos)
|
||||
{
|
||||
return filename.substr(pos + dir.size());
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace mastodonpp
|
|||
|
||||
using std::string_view;
|
||||
|
||||
static constexpr string_view version = "@PROJECT_VERSION@";
|
||||
static constexpr string_view version{"@PROJECT_VERSION@"};
|
||||
|
||||
} // namespace mastodonpp
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user