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

This commit is contained in:
tastytea 2020-01-09 18:50:59 +01:00
commit 746d57fbc6
Signed by: tastytea
GPG Key ID: CFC39497F1B26E07
13 changed files with 332 additions and 28 deletions

View File

@ -1,6 +1,6 @@
# -*- fill-column: 1000 -*-
kind: pipeline
name: build x86_64
name: Build x86_64
volumes:
- name: debian-package-cache
@ -83,3 +83,116 @@ steps:
from_secret: email_password
when:
status: [ changed, failure ]
---
kind: pipeline
name: Packages x86_64
volumes:
- name: debian-package-cache
host:
path: /var/cache/debian-package-cache
- name: centos-package-cache
host:
path: /var/cache/centos-package-cache
trigger:
event:
- tag
steps:
- name: Debian buster
image: debian:buster-slim
pull: always
environment:
CXX: g++-8
CXXFLAGS: -pipe -O2
DEBIAN_FRONTEND: noninteractive
LANG: C.utf8
commands:
- 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 lsb-release
- apt-get install -qq libcurl4-openssl-dev
- rm -rf build && mkdir -p build && cd build
- cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=/usr -DWITH_DEB=YES ..
- make
- make install DESTDIR=install
- make package
- cp -v libmastodon-cpp_${DRONE_TAG}-0_amd64_buster.deb ..
volumes:
- name: debian-package-cache
path: /var/cache/apt/archives
- name: Ubuntu bionic
image: ubuntu:bionic
pull: always
environment:
CXX: g++-7
CXXFLAGS: -pipe -O2
DEBIAN_FRONTEND: noninteractive
LANG: C.utf8
commands:
- 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 lsb-release
- apt-get install -qq libcurl4-openssl-dev
- rm -rf build && mkdir -p build && cd build
- cmake -G "Unix Makefiles" -SCMAKE_INSTALL_PREFIX=/usr -DWITH_DEB=YES ..
- make
- make install DESTDIR=install
- make package
- cp -v libmastodon-cpp_${DRONE_TAG}-0_amd64_bionic.deb ..
volumes:
- name: debian-package-cache
path: /var/cache/apt/archives
- name: CentOS 8
image: centos:8
pull: always
environment:
CXX: g++
CXXFLAGS: -pipe -O2
LANG: C.utf8
commands:
- sed -i 's/keepcache=0/keepcache=1/' /etc/yum.conf
- yum install -qy gcc-c++ cmake rpm-build redhat-lsb-core
- yum install -qy libcurl-devel
- rm -rf build && mkdir -p build && cd build
- cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=/usr -DWITH_RPM=YES ..
- make
- make install DESTDIR=install
- make package
- cp -v libmastodonpp-${DRONE_TAG}-0.x86_64.centos8.rpm ..
- name: gitea_release
image: plugins/gitea-release
pull: always
settings:
base_url: https://schlomp.space
api_key:
from_secret: gitea_token
title: ${DRONE_TAG}
prerelease: true
files:
- libmastodonpp_${DRONE_TAG}-0_buster_amd64.deb
- libmastodonpp_${DRONE_TAG}-0_bionic_amd64.deb
- libmastodonpp-${DRONE_TAG}-0.x86_64.centos8.rpm
checksum:
- sha512
- name: notification
image: drillster/drone-email
pull: always
settings:
host: cryptoparty-celle.de
from: drone@tzend.de
username:
from_secret: email_username
password:
from_secret: email_password
when:
status: [ changed, failure ]

View File

@ -20,8 +20,8 @@ list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
# Project build options.
option(WITH_TESTS "Compile tests." NO)
option(WITH_EXAMPLES "Compile examples." NO)
# option(WITH_DEB "Prepare for the building of .deb packages." NO)
# option(WITH_RPM "Prepare for the building of .rpm packages." NO)
option(WITH_DEB "Prepare for the building of .deb packages." NO)
option(WITH_RPM "Prepare for the building of .rpm packages." NO)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
@ -48,4 +48,4 @@ if(WITH_EXAMPLES)
add_subdirectory(examples)
endif()
# include(cmake/packages.cmake)
include(cmake/packages.cmake)

View File

@ -12,15 +12,15 @@
:uri-catch: https://github.com/catchorg/Catch2
:uri-dpkg: https://packages.qa.debian.org/dpkg
:uri-rpm-build: http://www.rpm.org
:uri-curl: https://curl.haxx.se/
:uri-libcurl: https://curl.haxx.se/libcurl/
*{project}* is a C++ wrapper for the Mastodon API. It replaces
link:{uri-mastodon-cpp}[mastodon-cpp].
We aim to create a library that is comfortable, yet minimal. All API endpoints
from Mastodon and Pleroma are stored in `enum class`es, to counteract typos and
from Mastodon and Pleroma are stored in ``enum class``es, to counteract typos and
make your life easier. The network-facing code is built on
link:{uri-curl}[libcurl], a mature and stable library that is available on
link:{uri-libcurl}[libcurl], a mature and stable library that is available on
virtually every operating system. The library does not parse the responses
itself, but returns to you the raw data, because we know everyone has their
favorite JSON library and we don't want to impose our choice on you!
@ -84,12 +84,12 @@ link:{uri-reference}/examples.html[More examples] are included in the reference.
* Tested OS: Linux
* 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] (at least: 7.32)
* link:{uri-libcurl}[libcurl] (at least: 7.32)
* Optional
** Documentation: link:{uri-doxygen}[Doxygen] (tested: 1.8)
** Tests: link:{uri-catch}[Catch] (tested: 2.5 / 1.2)
// ** DEB package: link:{uri-dpkg}[dpkg] (tested: 1.18)
// ** RPM package: link:{uri-rpm-build}[rpm-build] (tested: 4.11)
** DEB package: link:{uri-dpkg}[dpkg] (tested: 1.18)
** RPM package: link:{uri-rpm-build}[rpm-build] (tested: 4.11)
==== Get sourcecode

60
cmake/packages.cmake Normal file
View File

@ -0,0 +1,60 @@
include(GNUInstallDirs)
set(CPACK_PACKAGE_NAME ${PROJECT_NAME})
set(CPACK_PACKAGE_VERSION_MAJOR ${${PROJECT_NAME}_VERSION_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${${PROJECT_NAME}_VERSION_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${${PROJECT_NAME}_VERSION_PATCH})
set(CPACK_PACKAGE_VERSION ${${PROJECT_NAME}_VERSION})
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PROJECT_DESCRIPTION}")
set(CPACK_PACKAGE_CONTACT "tastytea <tastytea@tastytea.de>")
set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
set(CPACK_RESOURCE_FILE_README "${PROJECT_SOURCE_DIR}/README.adoc")
execute_process(COMMAND uname -m
OUTPUT_VARIABLE CPACK_PACKAGE_ARCHITECTURE OUTPUT_STRIP_TRAILING_WHITESPACE)
set(CPACK_PACKAGE_FILE_NAME
"${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}_${CPACK_PACKAGE_ARCHITECTURE}")
set(CPACK_GENERATOR "TGZ")
if(WITH_DEB)
set(CPACK_PACKAGE_NAME "lib${PROJECT_NAME}")
set(CPACK_GENERATOR "DEB")
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE
"https://schlomp.space/tastytea/${PROJECT_NAME}")
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
execute_process(COMMAND dpkg --print-architecture
OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE
OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND lsb_release --codename --short
OUTPUT_VARIABLE DEBIAN_CODENAME
OUTPUT_STRIP_TRAILING_WHITESPACE)
set(CPACK_PACKAGE_FILE_NAME
"${CPACK_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}-0_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}_${DEBIAN_CODENAME}")
endif()
if(WITH_RPM)
set(CPACK_PACKAGE_NAME "lib${PROJECT_NAME}")
set(CPACK_GENERATOR "RPM")
set(CPACK_RPM_PACKAGE_LICENSE "AGPL-3")
set(CPACK_RPM_PACKAGE_URL "https://schlomp.space/tastytea/${PROJECT_NAME}")
set(CPACK_RPM_PACKAGE_REQUIRES "libcurl >= 7.32")
list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/cmake"
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/pkgconfig")
set(CPACK_PACKAGE_FILE_NAME
"${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-0.${CPACK_PACKAGE_ARCHITECTURE}")
execute_process(COMMAND lsb_release --id --short
OUTPUT_VARIABLE OS
OUTPUT_STRIP_TRAILING_WHITESPACE)
if("${OS}" STREQUAL "CentOS")
execute_process(COMMAND rpm -E %{rhel}
OUTPUT_VARIABLE OS_RELEASE
OUTPUT_STRIP_TRAILING_WHITESPACE)
set(CPACK_PACKAGE_FILE_NAME
"${CPACK_PACKAGE_FILE_NAME}.centos${OS_RELEASE}")
endif()
endif()
include(CPack)

View File

@ -65,9 +65,13 @@ int main(int argc, char *argv[])
// Print new events every 2 seconds, for 10 seconds.
for (auto counter{0}; counter < 5; ++counter)
{
cout << "----------------------------------------" << endl;
sleep_for(2s);
cout << connection.get_new_stream_contents() << endl;
for (const auto &event : connection.get_new_events())
{
// Print typo of event and the beginning of the data.
cout << event.type << ": "
<< event.data.substr(0, 70) << "" << endl;
}
}
// Cancel the stream, …

View File

@ -99,6 +99,17 @@ struct answer_type
*/
friend std::ostream &operator <<(std::ostream &out,
const answer_type &answer);
/*!
* @brief Returns the value of a header field.
*
* Is only valid for as long as the answer_type is in scope.
*
* @param field Case insensitive, only ASCII.
*
* @since 0.1.0
*/
string_view get_header(string_view field) const;
};
} // namespace mastodonpp

View File

@ -25,6 +25,7 @@
#include <string>
#include <string_view>
#include <variant>
#include <vector>
namespace mastodonpp
{
@ -32,6 +33,7 @@ namespace mastodonpp
using std::string;
using std::string_view;
using std::variant;
using std::vector;
/*!
* @brief An endpoint. Either API::endpoint_type or `std::string_view`.
@ -40,6 +42,29 @@ using std::variant;
*/
using endpoint_variant = variant<API::endpoint_type,string_view>;
/*!
* @brief A stream event.
*
* @since 0.1.0
*
* @headerfile connection.hpp mastodonpp/connection.hpp
*/
struct event_type
{
/*!
* @brief The type of the event.
*
* Can be: update, notification, delete or filters_changed. For
* more information consult [the Mastodon documentation]
* (https://docs.joinmastodon.org/methods/timelines/streaming/
* #event-types-a-idevent-typesa).
*/
string type;
//! The payload.
string data;
};
/*!
* @brief Represents a connection to an instance. Used for requests.
*
@ -99,13 +124,6 @@ public:
return get(endpoint, {});
}
/*! @copydoc CURLWrapper::set_proxy(string_view)
*
* Sets also the proxy for the Instance you used to initialize this
* Connection.
*/
void set_proxy(string_view proxy);
/*!
* @brief Copy new stream contents and delete the original.
*
@ -113,10 +131,19 @@ public:
* that you are calling this function mid-transfer. You have to check the
* data integrity yourself.
*
* Using get_new_events() instead is recommended.
*
* @since 0.1.0
*/
string get_new_stream_contents();
/*!
* @brief Get new stream events.
*
* @since 0.1.0
*/
vector<event_type> get_new_events();
private:
Instance &_instance;
const string_view _baseuri;

View File

@ -53,7 +53,7 @@ enum class http_method
};
/*!
* @brief std::map of parameters for API calls.
* @brief std::map of parameters for %API calls.
*
* Example:
* @code

View File

@ -95,11 +95,35 @@ public:
[[nodiscard]]
uint64_t get_max_chars();
/*! @copydoc CURLWrapper::set_proxy(string_view)
*
* Sets also the proxy for all Connection%s that are initialized with this
* Instance afterwards.
*/
void set_proxy(const string_view proxy)
{
_proxy = proxy;
CURLWrapper::set_proxy(proxy);
}
/*!
* @brief Returns the proxy string that was previously set.
*
* Does not return the proxy if it was set from an environment variable.
*
* @since 0.1.0
*/
string_view get_proxy() const
{
return _proxy;
}
private:
const string _hostname;
const string _baseuri;
string _access_token;
uint64_t _max_chars;
string _proxy;
};
} // namespace mastodonpp

View File

@ -88,6 +88,14 @@
* (https://curl.haxx.se/libcurl/c/curl_global_cleanup.html) is called. Both
* are not thread safe.
*
* Do not make 2 requests with the same @link mastodonpp::Connection Connection
* @endlink at the same time. You can create as many @link
* mastodonpp::Connection Connection@endlink%s as you want from one @link
* mastodonpp::Instance Instance@endlink.
*
* If you are using libcurl with OpenSSL before 1.1.0, please read
* [libcurl-thread(3)](https://curl.haxx.se/libcurl/c/threadsafe.html).
*
* @example example01_instance_info.cpp
* @example example02_streaming.cpp
*/

View File

@ -16,9 +16,15 @@
#include "answer.hpp"
#include <algorithm>
#include <cctype>
namespace mastodonpp
{
using std::search;
using std::tolower;
answer_type::operator bool() const
{
return (curl_error_code == 0 && http_status == 200);
@ -35,4 +41,23 @@ std::ostream &operator <<(std::ostream &out, const answer_type &answer)
return out;
}
string_view answer_type::get_header(const string_view field) const
{
const string_view searchstring{string(field) += ':'};
auto it{search(headers.begin(), headers.end(),
searchstring.begin(), searchstring.end(),
[](unsigned char a, unsigned char b)
{ return tolower(a) == tolower(b); })};
if (it != headers.end())
{
auto pos{static_cast<size_t>(it - headers.begin())};
pos = headers.find(':', pos) + 2;
const auto endpos{headers.find('\n', pos)};
return string_view(&headers[pos], endpos - pos);
}
return {};
}
} // namespace mastodonpp

View File

@ -24,7 +24,13 @@ using std::holds_alternative;
Connection::Connection(Instance &instance)
: _instance{instance}
, _baseuri{instance.get_baseuri()}
{}
{
auto proxy{_instance.get_proxy()};
if (!proxy.empty())
{
CURLWrapper::set_proxy(proxy);
}
}
answer_type Connection::get(const endpoint_variant &endpoint,
const parametermap &parameters)
@ -36,18 +42,12 @@ answer_type Connection::get(const endpoint_variant &endpoint,
return string(_baseuri)
+= API{std::get<API::endpoint_type>(endpoint)}.to_string_view();
}
return string(std::get<string_view>(endpoint));
return string(_baseuri) += std::get<string_view>(endpoint);
}()};
return make_request(http_method::GET, uri, parameters);
}
void Connection::set_proxy(const string_view proxy)
{
CURLWrapper::set_proxy(proxy);
_instance.set_proxy(proxy);
}
string Connection::get_new_stream_contents()
{
buffer_mutex.lock();
@ -58,4 +58,33 @@ string Connection::get_new_stream_contents()
return buffer_copy;
}
vector<event_type> Connection::get_new_events()
{
buffer_mutex.lock();
auto &buffer{get_buffer()};
vector<event_type> events;
size_t pos{0};
while ((pos = buffer.find("event: ")) != string::npos)
{
const auto endpos{buffer.find("\n\n", pos)};
if (endpos == string::npos)
{
break;
}
event_type event;
pos += 7; // Length of "event: ".
event.type = buffer.substr(pos, buffer.find('\n', pos) - pos);
pos = buffer.find("data: ") + 6;
event.data = buffer.substr(pos, endpos - pos);
events.push_back(event);
buffer.erase(0, endpos);
}
buffer_mutex.unlock();
return events;
}
} // namespace mastodonpp

View File

@ -36,6 +36,7 @@ using std::atomic;
using std::uint8_t;
using std::uint16_t;
// No one will ever need more than 65535 connections. 😉
static atomic<uint16_t> curlwrapper_instances{0};
CURLWrapper::CURLWrapper()
@ -83,6 +84,8 @@ answer_type CURLWrapper::make_request(const http_method &method, string uri,
const parametermap &parameters)
{
_stream_cancelled = false;
_curl_buffer_headers.clear();
_curl_buffer_body.clear();
CURLcode code;
switch (method)