Merge branch 'develop' into main
This commit is contained in:
commit
f2594d2c46
@ -31,9 +31,9 @@ This is still a work in progress; here is a rough overview of the features:
|
|||||||
|
|
||||||
* [x] `GET`, Streaming `GET`, `POST`, `PATCH`, `PUT` and `DELETE` requests.
|
* [x] `GET`, Streaming `GET`, `POST`, `PATCH`, `PUT` and `DELETE` requests.
|
||||||
* [x] Report maximum allowed character per post.
|
* [x] Report maximum allowed character per post.
|
||||||
* [ ] Comfortable access to pagination headers.
|
* [x] Comfortable access to pagination headers.
|
||||||
* [ ] Comfortable function to register a new “app” (get an access token).
|
* [x] Comfortable function to register a new “app” (get an access token).
|
||||||
* [ ] Report which mime types are allowed for posting statuses.
|
* [x] Report which mime types are allowed for posting statuses.
|
||||||
|
|
||||||
== Usage
|
== Usage
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ if(WITH_RPM)
|
|||||||
set(CPACK_GENERATOR "RPM")
|
set(CPACK_GENERATOR "RPM")
|
||||||
set(CPACK_RPM_PACKAGE_LICENSE "AGPL-3")
|
set(CPACK_RPM_PACKAGE_LICENSE "AGPL-3")
|
||||||
set(CPACK_RPM_PACKAGE_URL "https://schlomp.space/tastytea/${PROJECT_NAME}")
|
set(CPACK_RPM_PACKAGE_URL "https://schlomp.space/tastytea/${PROJECT_NAME}")
|
||||||
set(CPACK_RPM_PACKAGE_REQUIRES "libcurl >= 7.32")
|
set(CPACK_RPM_PACKAGE_REQUIRES "libcurl >= 7.56")
|
||||||
list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION
|
list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION
|
||||||
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/cmake"
|
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/cmake"
|
||||||
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
#ifndef MASTODONPP_CONNECTION_HPP
|
#ifndef MASTODONPP_CONNECTION_HPP
|
||||||
#define MASTODONPP_CONNECTION_HPP
|
#define MASTODONPP_CONNECTION_HPP
|
||||||
|
|
||||||
#include "answer.hpp"
|
|
||||||
#include "api.hpp"
|
#include "api.hpp"
|
||||||
#include "curl_wrapper.hpp"
|
#include "curl_wrapper.hpp"
|
||||||
#include "instance.hpp"
|
#include "instance.hpp"
|
||||||
|
#include "types.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
@ -17,28 +17,20 @@
|
|||||||
#ifndef MASTODONPP_CURL_WRAPPER_HPP
|
#ifndef MASTODONPP_CURL_WRAPPER_HPP
|
||||||
#define MASTODONPP_CURL_WRAPPER_HPP
|
#define MASTODONPP_CURL_WRAPPER_HPP
|
||||||
|
|
||||||
#include "answer.hpp"
|
#include "types.hpp"
|
||||||
|
|
||||||
#include "curl/curl.h"
|
#include "curl/curl.h"
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <utility>
|
|
||||||
#include <variant>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace mastodonpp
|
namespace mastodonpp
|
||||||
{
|
{
|
||||||
|
|
||||||
using std::map;
|
|
||||||
using std::mutex;
|
using std::mutex;
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::string_view;
|
using std::string_view;
|
||||||
using std::pair;
|
|
||||||
using std::variant;
|
|
||||||
using std::vector;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief The HTTP method.
|
* @brief The HTTP method.
|
||||||
@ -54,36 +46,6 @@ enum class http_method
|
|||||||
DELETE
|
DELETE
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief `std::map` of parameters for %API calls.
|
|
||||||
*
|
|
||||||
* Note that arrays always have to be specified as vectors, even if they have
|
|
||||||
* only 1 element. To send a file, use “<tt>\@file:</tt>” followed by the file
|
|
||||||
* name as value.
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
* @code
|
|
||||||
* parametermap parameters
|
|
||||||
* {
|
|
||||||
* {"poll[expires_in]", "86400"},
|
|
||||||
* {"poll[options]", vector<string_view>{"Yes", "No", "Maybe"}},
|
|
||||||
* {"status", "How is the weather?"}
|
|
||||||
* };
|
|
||||||
* @endcode
|
|
||||||
*
|
|
||||||
* @since 0.1.0
|
|
||||||
*/
|
|
||||||
using parametermap =
|
|
||||||
map<string_view, variant<string_view, vector<string_view>>>;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief A single parameter of a parametermap.
|
|
||||||
*
|
|
||||||
* @since 0.1.0
|
|
||||||
*/
|
|
||||||
using parameterpair =
|
|
||||||
pair<string_view, variant<string_view, vector<string_view>>>;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Handles the details of network connections.
|
* @brief Handles the details of network connections.
|
||||||
*
|
*
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
#define MASTODONPP_INSTANCE_HPP
|
#define MASTODONPP_INSTANCE_HPP
|
||||||
|
|
||||||
#include "curl_wrapper.hpp"
|
#include "curl_wrapper.hpp"
|
||||||
#include "answer.hpp"
|
#include "types.hpp"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -17,11 +17,11 @@
|
|||||||
#ifndef MASTODONPP_HPP
|
#ifndef MASTODONPP_HPP
|
||||||
#define MASTODONPP_HPP
|
#define MASTODONPP_HPP
|
||||||
|
|
||||||
#include "answer.hpp"
|
|
||||||
#include "api.hpp"
|
#include "api.hpp"
|
||||||
#include "connection.hpp"
|
#include "connection.hpp"
|
||||||
#include "exceptions.hpp"
|
#include "exceptions.hpp"
|
||||||
#include "instance.hpp"
|
#include "instance.hpp"
|
||||||
|
#include "types.hpp"
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @headerfile mastodonpp.hpp mastodonpp/mastodonpp.hpp
|
* @headerfile mastodonpp.hpp mastodonpp/mastodonpp.hpp
|
||||||
|
@ -14,22 +14,62 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef MASTODONPP_ANSWER_HPP
|
// Types that are used in more than one file.
|
||||||
#define MASTODONPP_ANSWER_HPP
|
|
||||||
|
#ifndef MASTODONPP_TYPES_HPP
|
||||||
|
#define MASTODONPP_TYPES_HPP
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <map>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <utility>
|
||||||
|
#include <variant>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace mastodonpp
|
namespace mastodonpp
|
||||||
{
|
{
|
||||||
|
|
||||||
using std::uint8_t;
|
using std::uint8_t;
|
||||||
using std::uint16_t;
|
using std::uint16_t;
|
||||||
|
using std::map;
|
||||||
using std::ostream;
|
using std::ostream;
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::string_view;
|
using std::string_view;
|
||||||
|
using std::pair;
|
||||||
|
using std::variant;
|
||||||
|
using std::vector;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief `std::map` of parameters for %API calls.
|
||||||
|
*
|
||||||
|
* Note that arrays always have to be specified as vectors, even if they have
|
||||||
|
* only 1 element. To send a file, use “<tt>\@file:</tt>” followed by the file
|
||||||
|
* name as value.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* @code
|
||||||
|
* parametermap parameters
|
||||||
|
* {
|
||||||
|
* {"poll[expires_in]", "86400"},
|
||||||
|
* {"poll[options]", vector<string_view>{"Yes", "No", "Maybe"}},
|
||||||
|
* {"status", "How is the weather?"}
|
||||||
|
* };
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* @since 0.1.0
|
||||||
|
*/
|
||||||
|
using parametermap =
|
||||||
|
map<string_view, variant<string_view, vector<string_view>>>;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief A single parameter of a parametermap.
|
||||||
|
*
|
||||||
|
* @since 0.1.0
|
||||||
|
*/
|
||||||
|
using parameterpair =
|
||||||
|
pair<string_view, variant<string_view, vector<string_view>>>;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Return type for Request%s.
|
* @brief Return type for Request%s.
|
||||||
@ -110,9 +150,48 @@ struct answer_type
|
|||||||
*
|
*
|
||||||
* @since 0.1.0
|
* @since 0.1.0
|
||||||
*/
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
string_view get_header(string_view field) const;
|
string_view get_header(string_view field) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Returns the parameters needed for the next entries.
|
||||||
|
*
|
||||||
|
* Parses the `Link` header.
|
||||||
|
*
|
||||||
|
* @since 0.3.0
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
inline parametermap next() const
|
||||||
|
{
|
||||||
|
return parse_pagination(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Returns the parameters needed for the previous entries.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Parses the `Link` header.
|
||||||
|
*
|
||||||
|
* @since 0.3.0
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
inline parametermap prev() const
|
||||||
|
{
|
||||||
|
return parse_pagination(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*!
|
||||||
|
* @brief Returns the parameters needed for the next or previous entries.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Parses the `Link` header.
|
||||||
|
*
|
||||||
|
* @since 0.3.0
|
||||||
|
*/
|
||||||
|
parametermap parse_pagination(bool next) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mastodonpp
|
} // namespace mastodonpp
|
||||||
|
|
||||||
#endif // MASTODONPP_ANSWER_HPP
|
#endif // MASTODONPP_TYPES_HPP
|
28
src/api.cpp
28
src/api.cpp
@ -38,7 +38,7 @@ const map<API::endpoint_type,string_view> API::_endpoint_map
|
|||||||
{v1::accounts_id_followers, "/api/v1/accounts/<ID>/followers"},
|
{v1::accounts_id_followers, "/api/v1/accounts/<ID>/followers"},
|
||||||
{v1::accounts_id_following, "/api/v1/accounts/<ID>/following"},
|
{v1::accounts_id_following, "/api/v1/accounts/<ID>/following"},
|
||||||
{v1::accounts_id_lists, "/api/v1/accounts/<ID>/lists"},
|
{v1::accounts_id_lists, "/api/v1/accounts/<ID>/lists"},
|
||||||
{v1::accounts_id_identity_proofs, "/api/v1/accounts/<ID>/identity/proofs"},
|
{v1::accounts_id_identity_proofs, "/api/v1/accounts/<ID>/identity_proofs"},
|
||||||
{v1::accounts_id_follow, "/api/v1/accounts/<ID>/follow"},
|
{v1::accounts_id_follow, "/api/v1/accounts/<ID>/follow"},
|
||||||
{v1::accounts_id_unfollow, "/api/v1/accounts/<ID>/unfollow"},
|
{v1::accounts_id_unfollow, "/api/v1/accounts/<ID>/unfollow"},
|
||||||
{v1::accounts_id_block, "/api/v1/accounts/<ID>/block"},
|
{v1::accounts_id_block, "/api/v1/accounts/<ID>/block"},
|
||||||
@ -58,23 +58,23 @@ const map<API::endpoint_type,string_view> API::_endpoint_map
|
|||||||
|
|
||||||
{v1::blocks, "/api/v1/blocks"},
|
{v1::blocks, "/api/v1/blocks"},
|
||||||
|
|
||||||
{v1::domain_blocks, "/api/v1/domain/blocks"},
|
{v1::domain_blocks, "/api/v1/domain_blocks"},
|
||||||
|
|
||||||
{v1::filters, "/api/v1/filters"},
|
{v1::filters, "/api/v1/filters"},
|
||||||
{v1::filters_id, "/api/v1/filters/<ID>"},
|
{v1::filters_id, "/api/v1/filters/<ID>"},
|
||||||
|
|
||||||
{v1::reports, "/api/v1/reports"},
|
{v1::reports, "/api/v1/reports"},
|
||||||
|
|
||||||
{v1::follow_requests, "/api/v1/follow/requests"},
|
{v1::follow_requests, "/api/v1/follow_requests"},
|
||||||
{v1::follow_requests_id_authorize,
|
{v1::follow_requests_id_authorize,
|
||||||
"/api/v1/follow/requests/<ID>/authorize"},
|
"/api/v1/follow_requests/<ID>/authorize"},
|
||||||
{v1::follow_requests_id_reject, "/api/v1/follow/requests/<ID>/reject"},
|
{v1::follow_requests_id_reject, "/api/v1/follow_requests/<ID>/reject"},
|
||||||
|
|
||||||
{v1::endorsements, "/api/v1/endorsements"},
|
{v1::endorsements, "/api/v1/endorsements"},
|
||||||
|
|
||||||
{v1::featured_tags, "/api/v1/featured/tags"},
|
{v1::featured_tags, "/api/v1/featured/tags"},
|
||||||
{v1::featured_tags_id, "/api/v1/featured/tags/<ID>"},
|
{v1::featured_tags_id, "/api/v1/featured_tags/<ID>"},
|
||||||
{v1::featured_tags_suggestions, "/api/v1/featured/tags/suggestions"},
|
{v1::featured_tags_suggestions, "/api/v1/featured_tags/suggestions"},
|
||||||
|
|
||||||
{v1::preferences, "/api/v1/preferences"},
|
{v1::preferences, "/api/v1/preferences"},
|
||||||
|
|
||||||
@ -84,8 +84,8 @@ const map<API::endpoint_type,string_view> API::_endpoint_map
|
|||||||
{v1::statuses, "/api/v1/statuses"},
|
{v1::statuses, "/api/v1/statuses"},
|
||||||
{v1::statuses_id, "/api/v1/statuses/<ID>"},
|
{v1::statuses_id, "/api/v1/statuses/<ID>"},
|
||||||
{v1::statuses_id_context, "/api/v1/statuses/<ID>/context"},
|
{v1::statuses_id_context, "/api/v1/statuses/<ID>/context"},
|
||||||
{v1::statuses_id_reblogged_by, "/api/v1/statuses/<ID>/reblogged/by"},
|
{v1::statuses_id_reblogged_by, "/api/v1/statuses/<ID>/reblogged_by"},
|
||||||
{v1::statuses_id_favourited_by, "/api/v1/statuses/<ID>/favourited/by"},
|
{v1::statuses_id_favourited_by, "/api/v1/statuses/<ID>/favourited_by"},
|
||||||
{v1::statuses_id_favourite, "/api/v1/statuses/<ID>/favourite"},
|
{v1::statuses_id_favourite, "/api/v1/statuses/<ID>/favourite"},
|
||||||
{v1::statuses_id_unfavourite, "/api/v1/statuses/<ID>/unfavourite"},
|
{v1::statuses_id_unfavourite, "/api/v1/statuses/<ID>/unfavourite"},
|
||||||
{v1::statuses_id_reblog, "/api/v1/statuses/<ID>/reblog"},
|
{v1::statuses_id_reblog, "/api/v1/statuses/<ID>/reblog"},
|
||||||
@ -103,13 +103,13 @@ const map<API::endpoint_type,string_view> API::_endpoint_map
|
|||||||
{v1::polls_id, "/api/v1/polls/<ID>"},
|
{v1::polls_id, "/api/v1/polls/<ID>"},
|
||||||
{v1::polls_id_votes, "/api/v1/polls/<ID>/votes"},
|
{v1::polls_id_votes, "/api/v1/polls/<ID>/votes"},
|
||||||
|
|
||||||
{v1::scheduled_statuses, "/api/v1/scheduled/statuses"},
|
{v1::scheduled_statuses, "/api/v1/scheduled_statuses"},
|
||||||
{v1::scheduled_statuses_id, "/api/v1/scheduled/statuses/<ID>"},
|
{v1::scheduled_statuses_id, "/api/v1/scheduled_statuses/<ID>"},
|
||||||
|
|
||||||
{v1::timelines_public, "/api/v1/timelines/public"},
|
{v1::timelines_public, "/api/v1/timelines/public"},
|
||||||
{v1::timelines_tag_hashtag, "/api/v1/timelines/tag/<HASHTAG>"},
|
{v1::timelines_tag_hashtag, "/api/v1/timelines/tag/<HASHTAG>"},
|
||||||
{v1::timelines_home, "/api/v1/timelines/home"},
|
{v1::timelines_home, "/api/v1/timelines/home"},
|
||||||
{v1::timelines_list_list_id, "/api/v1/timelines/list/list/<ID>"},
|
{v1::timelines_list_list_id, "/api/v1/timelines/list/<LIST_ID>"},
|
||||||
|
|
||||||
{v1::conversations, "/api/v1/conversations"},
|
{v1::conversations, "/api/v1/conversations"},
|
||||||
{v1::conversations_id, "/api/v1/conversations/<ID>"},
|
{v1::conversations_id, "/api/v1/conversations/<ID>"},
|
||||||
@ -150,7 +150,7 @@ const map<API::endpoint_type,string_view> API::_endpoint_map
|
|||||||
{v1::admin_accounts, "/api/v1/admin/accounts"},
|
{v1::admin_accounts, "/api/v1/admin/accounts"},
|
||||||
{v1::admin_accounts_id, "/api/v1/admin/accounts/<ID>"},
|
{v1::admin_accounts_id, "/api/v1/admin/accounts/<ID>"},
|
||||||
{v1::admin_accounts_account_id_action,
|
{v1::admin_accounts_account_id_action,
|
||||||
"/api/v1/admin/accounts/account/<ID>/action"},
|
"/api/v1/admin/accounts/<ACCOUNT_ID>/action"},
|
||||||
{v1::admin_accounts_id_approve, "/api/v1/admin/accounts/<ID>/approve"},
|
{v1::admin_accounts_id_approve, "/api/v1/admin/accounts/<ID>/approve"},
|
||||||
{v1::admin_accounts_id_reject, "/api/v1/admin/accounts/<ID>/reject"},
|
{v1::admin_accounts_id_reject, "/api/v1/admin/accounts/<ID>/reject"},
|
||||||
{v1::admin_accounts_id_enable, "/api/v1/admin/accounts/<ID>/enable"},
|
{v1::admin_accounts_id_enable, "/api/v1/admin/accounts/<ID>/enable"},
|
||||||
@ -159,7 +159,7 @@ const map<API::endpoint_type,string_view> API::_endpoint_map
|
|||||||
{v1::admin_reports, "/api/v1/admin/reports"},
|
{v1::admin_reports, "/api/v1/admin/reports"},
|
||||||
{v1::admin_reports_id, "/api/v1/admin/reports/<ID>"},
|
{v1::admin_reports_id, "/api/v1/admin/reports/<ID>"},
|
||||||
{v1::admin_reports_id_assign_to_self,
|
{v1::admin_reports_id_assign_to_self,
|
||||||
"/api/v1/admin/reports/<ID>/assign/to/self"},
|
"/api/v1/admin/reports/<ID>/assign_to_self"},
|
||||||
{v1::admin_reports_id_unassign, "/api/v1/admin/reports/<ID>/unassign"},
|
{v1::admin_reports_id_unassign, "/api/v1/admin/reports/<ID>/unassign"},
|
||||||
{v1::admin_reports_id_resolve, "/api/v1/admin/reports/<ID>/resolve"},
|
{v1::admin_reports_id_resolve, "/api/v1/admin/reports/<ID>/resolve"},
|
||||||
{v1::admin_reports_id_reopen, "/api/v1/admin/reports/<ID>/reopen"},
|
{v1::admin_reports_id_reopen, "/api/v1/admin/reports/<ID>/reopen"},
|
||||||
|
@ -353,8 +353,8 @@ bool CURLWrapper::replace_parameter_in_uri(string &uri,
|
|||||||
{
|
{
|
||||||
static constexpr array replace
|
static constexpr array replace
|
||||||
{
|
{
|
||||||
"id", "nickname", "nickname_or_id",
|
"id", "nickname", "nickname_or_id", "account_id",
|
||||||
"hashtag", "permission_group"
|
"list_id", "hashtag", "permission_group"
|
||||||
};
|
};
|
||||||
if (any_of(replace.begin(), replace.end(),
|
if (any_of(replace.begin(), replace.end(),
|
||||||
[¶meter](const auto &s) { return s == parameter.first; }))
|
[¶meter](const auto &s) { return s == parameter.first; }))
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "answer.hpp"
|
|
||||||
#include "instance.hpp"
|
#include "instance.hpp"
|
||||||
#include "log.hpp"
|
#include "log.hpp"
|
||||||
|
|
||||||
@ -54,19 +53,16 @@ uint64_t Instance::get_max_chars() noexcept
|
|||||||
|
|
||||||
_max_chars = [&answer]
|
_max_chars = [&answer]
|
||||||
{
|
{
|
||||||
auto &body{answer.body};
|
const regex re_chars{R"("max_toot_chars"\s*:\s*([^"]+))"};
|
||||||
size_t pos_start{body.find("max_toot_chars")};
|
smatch match;
|
||||||
if (pos_start == string::npos)
|
|
||||||
{
|
|
||||||
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,
|
if (regex_search(answer.body, match, re_chars))
|
||||||
pos_end - pos_start)};
|
{
|
||||||
return static_cast<uint64_t>(stoull(max_toot_chars));
|
return static_cast<uint64_t>(stoull(match[1].str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
debuglog << "max_toot_chars not found.\n";
|
||||||
|
return default_max_chars;
|
||||||
}();
|
}();
|
||||||
debuglog << "Set _max_chars to: " << _max_chars << '\n';
|
debuglog << "Set _max_chars to: " << _max_chars << '\n';
|
||||||
}
|
}
|
||||||
@ -81,7 +77,6 @@ uint64_t Instance::get_max_chars() noexcept
|
|||||||
|
|
||||||
answer_type Instance::get_nodeinfo()
|
answer_type Instance::get_nodeinfo()
|
||||||
{
|
{
|
||||||
debuglog << "Finding location of NodeInfo on " << _hostname << "…\n";
|
|
||||||
auto answer{make_request(http_method::GET,
|
auto answer{make_request(http_method::GET,
|
||||||
_baseuri + "/.well-known/nodeinfo", {})};
|
_baseuri + "/.well-known/nodeinfo", {})};
|
||||||
if (!answer)
|
if (!answer)
|
||||||
@ -90,15 +85,15 @@ answer_type Instance::get_nodeinfo()
|
|||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t pos{0};
|
|
||||||
vector<string> hrefs;
|
vector<string> hrefs;
|
||||||
constexpr string_view searchstring{R"("href":")"};
|
const regex re_href{R"("href"\s*:\s*"([^"]+)\")"};
|
||||||
while ((pos = answer.body.find(searchstring, pos)) != string::npos)
|
smatch match;
|
||||||
|
string body = answer.body;
|
||||||
|
while (regex_search(body, match, re_href))
|
||||||
{
|
{
|
||||||
pos += searchstring.size();
|
hrefs.push_back(match[1].str());
|
||||||
auto endpos{answer.body.find('"', pos)};
|
|
||||||
hrefs.push_back(answer.body.substr(pos, endpos - pos));
|
|
||||||
debuglog << "Found href: " << hrefs.back() << '\n';
|
debuglog << "Found href: " << hrefs.back() << '\n';
|
||||||
|
body = match.suffix();
|
||||||
}
|
}
|
||||||
sort(hrefs.begin(), hrefs.end()); // We assume they are sortable strings.
|
sort(hrefs.begin(), hrefs.end()); // We assume they are sortable strings.
|
||||||
debuglog << "Selecting href: " << hrefs.back() << '\n';
|
debuglog << "Selecting href: " << hrefs.back() << '\n';
|
||||||
@ -126,23 +121,23 @@ vector<string> Instance::get_post_formats() noexcept
|
|||||||
return _post_formats;
|
return _post_formats;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr string_view searchstring{R"("postFormats":[)"};
|
const regex re_allformats(R"("postFormats"\s*:\s*\[([^\]]+)\])");
|
||||||
auto pos{answer.body.find(searchstring)};
|
smatch match;
|
||||||
if (pos == string::npos)
|
if (!regex_search(answer.body, match, re_allformats))
|
||||||
{
|
{
|
||||||
debuglog << "Couldn't find metadata.postFormats.\n";
|
debuglog << "Couldn't find metadata.postFormats.\n";
|
||||||
_post_formats = {default_value};
|
_post_formats = {default_value};
|
||||||
return _post_formats;
|
return _post_formats;
|
||||||
}
|
}
|
||||||
pos += searchstring.size();
|
string allformats{match[1].str()};
|
||||||
auto endpos{answer.body.find("],", pos)};
|
debuglog << "Found postFormats: " << allformats << '\n';
|
||||||
string formats{answer.body.substr(pos, endpos - pos)};
|
|
||||||
debuglog << "Extracted postFormats: " << formats << '\n';
|
|
||||||
|
|
||||||
while ((pos = formats.find('"', 1)) != string::npos)
|
const regex re_format(R"(\s*"([^"]+)\"\s*,?)");
|
||||||
|
|
||||||
|
while (regex_search(allformats, match, re_format))
|
||||||
{
|
{
|
||||||
_post_formats.push_back(formats.substr(1, pos - 1));
|
_post_formats.push_back(match[1].str());
|
||||||
formats.erase(0, pos + 2); // 2 is the length of: ",
|
allformats = match.suffix();
|
||||||
debuglog << "Found postFormat: " << _post_formats.back() << '\n';
|
debuglog << "Found postFormat: " << _post_formats.back() << '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,8 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "answer.hpp"
|
#include "log.hpp"
|
||||||
|
#include "types.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
@ -60,4 +61,40 @@ string_view answer_type::get_header(const string_view field) const
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parametermap answer_type::parse_pagination(const bool next) const
|
||||||
|
{
|
||||||
|
const string_view link{get_header("Link")};
|
||||||
|
if (link.empty())
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto direction{next ? R"(rel="next")" : R"(rel="prev")"};
|
||||||
|
auto endpos{link.find(direction)};
|
||||||
|
endpos = link.rfind('>', endpos);
|
||||||
|
auto startpos{link.rfind('?', endpos) + 1};
|
||||||
|
const string_view paramstr{link.substr(startpos, endpos - startpos)};
|
||||||
|
debuglog << "Found parameters in Link header: " << paramstr << '\n';
|
||||||
|
|
||||||
|
startpos = 0;
|
||||||
|
parametermap parameters;
|
||||||
|
while ((endpos = paramstr.find('=', startpos)) != string_view::npos)
|
||||||
|
{
|
||||||
|
parameterpair param;
|
||||||
|
param.first = paramstr.substr(startpos, endpos - startpos);
|
||||||
|
startpos = endpos + 1;
|
||||||
|
endpos = paramstr.find('&', startpos);
|
||||||
|
param.second = paramstr.substr(startpos, endpos - startpos);
|
||||||
|
parameters.insert(param);
|
||||||
|
|
||||||
|
if (endpos == string_view::npos)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
startpos = endpos + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mastodonpp
|
} // namespace mastodonpp
|
Loading…
x
Reference in New Issue
Block a user