Merge branch 'develop' into main
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
tastytea 2020-01-06 09:48:19 +01:00
commit 505a29bcb4
Signed by: tastytea
GPG Key ID: CFC39497F1B26E07
11 changed files with 182 additions and 53 deletions

View File

@ -0,0 +1,83 @@
/* This file is part of mastodonpp.
* Copyright © 2020 tastytea <tastytea@tastytea.de>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
// Print information about an instance (/api/v1/instance).
#include <mastodonpp.hpp>
#include <iostream>
#include <string>
#include <string_view>
#include <vector>
namespace masto = mastodonpp;
using std::cout;
using std::cerr;
using std::endl;
using std::to_string;
using std::string_view;
using std::vector;
int main(int argc, char *argv[])
{
const vector<string_view> args(argv, argv + argc);
if (args.size() <= 1)
{
cerr << "Usage: " << args[0] << " <instance hostname>\n";
return 1;
}
try
{
// Initialize an Instance.
masto::Instance instance{args[1], {}};
// Get maximum allowed characters per post.
const auto max_chars{instance.get_max_chars()};
cout << "Maximum characters per post: " << max_chars << "\n\n";
// Initialize a Connection.
masto::Connection connection{instance};
// Get information about the instance.
masto::answer_type answer{connection.get(masto::API::v1::instance)};
if (answer)
{
cout << answer << endl;
}
else
{
if (answer.curl_error_code == 0)
{
// If it is no libcurl error, it must be an HTTP error.
cerr << "HTTP status: " << answer.http_status << endl;
}
else
{
// Network errors like “Couldn't resolve host.”.
cerr << "libcurl error " << to_string(answer.curl_error_code)
<< ": " << answer.error_message << endl;
}
}
}
catch (const masto::CURLException &e)
{
// Only libcurl errors that are not network errors will be thrown.
// There went probably something wrong with the initialization.
cerr << e.what() << endl;
}
return 0;
}

View File

@ -302,7 +302,7 @@ public:
*
* @since 0.1.0
*/
explicit API();
explicit API(const endpoint_type &endpoint);
/*!
* @brief Convert #endpoint_type to `std::string_view`.
@ -310,14 +310,14 @@ public:
* @since 0.1.0
*/
[[nodiscard]]
inline string_view endpoint_to_string_view(const endpoint_type &endpoint)
const
inline string_view to_string_view() const
{
return _endpoint_map.at(endpoint).data();
return _endpoint_map.at(_endpoint).data();
}
private:
const map<endpoint_type,string_view> _endpoint_map;
const endpoint_type _endpoint;
static const map<endpoint_type,string_view> _endpoint_map;
};
} // namespace mastodonpp

View File

@ -74,7 +74,6 @@ public:
private:
Instance &_instance;
const string_view _baseuri;
const API _api;
};
} // namespace mastodonpp

View File

@ -59,7 +59,8 @@ public:
/*!
* @brief Initializes curl and sets up connection.
*
* Calls `curl_global_init`, which is not thread-safe. For more information
* The first time an instance of CURLWrapper is created, it calls
* `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).
*

View File

@ -50,7 +50,8 @@ public:
*
* @since 0.1.0
*/
explicit Instance(string hostname, string access_token);
explicit Instance(const string_view &hostname,
const string_view &access_token);
/*!
* @brief Returns the hostname.
@ -93,10 +94,7 @@ public:
* @since 0.1.0
*/
[[nodiscard]]
inline uint64_t get_max_chars() const
{
return _max_chars;
}
uint64_t get_max_chars();
private:
const string _hostname;

View File

@ -70,7 +70,8 @@
* @section exceptions Exceptions
*
* Any unrecoverable libcurl error will be thrown as a
* mastodonpp::CURLException.
* mastodonpp::CURLException. Network errors will **not** be thrown, but
* reported via the return value.
*/
/*!

View File

@ -19,8 +19,11 @@
namespace mastodonpp
{
API::API()
: _endpoint_map
API::API(const endpoint_type &endpoint)
: _endpoint{endpoint}
{}
const map<API::endpoint_type,string_view> API::_endpoint_map
{
{v1::apps, "/api/v1/apps"},
{v1::apps_verify_credentials, "/api/v1/apps/verify/credentials"},
@ -238,7 +241,6 @@ API::API()
"/api/pleroma/pleroma/notification_settings"},
{pleroma::pleroma_healthcheck, "/api/pleroma/pleroma/healthcheck"},
{pleroma::pleroma_change_email, "/api/pleroma/pleroma/change_email"},
}
{}
};
} // namespace mastodonpp

View File

@ -22,14 +22,13 @@ namespace mastodonpp
Connection::Connection(Instance &instance)
: _instance{instance}
, _baseuri{instance.get_baseuri()}
, _api{}
{}
answer_type Connection::get(const API::endpoint_type &endpoint)
{
return make_request(
http_method::GET,
string(_baseuri).append(_api.endpoint_to_string_view(endpoint)));
string(_baseuri).append(API{endpoint}.to_string_view()));
}
answer_type Connection::get(const string_view &endpoint)

View File

@ -26,17 +26,31 @@ namespace mastodonpp
using std::uint8_t;
using std::uint16_t;
static uint16_t curlwrapper_instances{0};
CURLWrapper::CURLWrapper()
: _curl_buffer_error{}
{
if (curlwrapper_instances == 0)
{
curl_global_init(CURL_GLOBAL_ALL); // NOLINT(hicpp-signed-bitwise)
}
++curlwrapper_instances;
debuglog << "CURLWrapper instances: " << curlwrapper_instances << " (+1)\n";
_connection = curl_easy_init();
setup_curl();
}
CURLWrapper::~CURLWrapper() noexcept
{
curl_easy_cleanup(_connection);
--curlwrapper_instances;
debuglog << "CURLWrapper instances: " << curlwrapper_instances << " (-1)\n";
if (curlwrapper_instances == 0)
{
curl_global_cleanup();
}
}
answer_type CURLWrapper::make_request(const http_method &method,

View File

@ -18,46 +18,60 @@
#include "log.hpp"
#include "return_types.hpp"
#include <utility>
namespace mastodonpp
{
using std::move;
using std::stoull;
Instance::Instance(string hostname, string access_token)
: _hostname{move(hostname)}
Instance::Instance(const string_view &hostname, const string_view &access_token)
: _hostname{hostname}
, _baseuri{"https://" + _hostname}
, _access_token{move(access_token)}
, _max_chars{500}
, _access_token{access_token}
, _max_chars{0}
{}
uint64_t Instance::get_max_chars()
{
constexpr uint64_t default_max_chars{500};
if (_max_chars == 0)
{
try
{
debuglog << "Querying " << _hostname << " for max_toot_chars…\n";
const auto answer{make_request(http_method::GET,
_baseuri + "/api/v1/instance")};
if (answer)
if (!answer)
{
debuglog << "Could not get instance info.\n";
return default_max_chars;
}
_max_chars = [&answer]
{
debuglog << "Querying instance for max_toot_chars…\n";
auto &body{answer.body};
size_t pos_start{body.find("max_toot_chars")};
if (pos_start == string::npos)
{
debuglog << "max_toot_chars not found.";
return;
debuglog << "max_toot_chars not found.\n";
return default_max_chars;
}
pos_start = body.find(':', pos_start) + 1;
const size_t pos_end{body.find(',', pos_start)};
const auto max_toot_chars{body.substr(pos_start,
pos_end - pos_start)};
_max_chars = std::stoull(max_toot_chars);
return static_cast<uint64_t>(stoull(max_toot_chars));
}();
debuglog << "Set _max_chars to: " << _max_chars << '\n';
}
}
catch (const std::exception &e)
{
debuglog << "Unexpected exception: " << e.what() << '\n';
}
}
return _max_chars;
}
} // namespace mastodonpp

View File

@ -18,17 +18,35 @@
#define MASTODONPP_LOG_HPP
#include <iostream>
#include <string_view>
namespace mastodonpp
{
using std::cerr;
using std::string_view;
constexpr auto shorten_filename(const string_view &filename)
{
for (const string_view &dir : {"/src/", "/include/"})
{
auto pos{filename.rfind("/src/")};
if (pos != string_view::npos)
{
return filename.substr(pos + dir.size());
}
}
return filename;
}
#define commonlog cerr << '[' << shorten_filename(__FILE__) \
<< ':' << __LINE__ << ']'
#ifndef NDEBUG
#define debuglog cerr << "[" << __func__ << "():" << __LINE__ << "] DEBUG: "
#define debuglog commonlog << " DEBUG: "
#else
#define debuglog false && cerr
#endif
#define errorlog commonlog << " ERROR: "
} // namespace mastodonpp