Revamped streams.

This commit is contained in:
tastytea 2019-04-10 02:25:55 +02:00
parent ccedfba4af
commit bde8d11706
Signed by: tastytea
GPG Key ID: CFC39497F1B26E07
7 changed files with 199 additions and 31 deletions

View File

@ -74,9 +74,11 @@ set_target_properties(mastodon-cpp PROPERTIES
)
if(WITH_EASY)
target_link_libraries(mastodon-cpp ${CURLPP_LIBRARIES} ${JSONCPP_LIBRARIES})
target_link_libraries(mastodon-cpp
${CURLPP_LIBRARIES} pthread ${JSONCPP_LIBRARIES})
else()
target_link_libraries(mastodon-cpp ${CURLPP_LIBRARIES})
target_link_libraries(mastodon-cpp
${CURLPP_LIBRARIES} pthread)
endif()
# Compile examples

View File

@ -0,0 +1,107 @@
/* This file is part of mastodon-cpp.
*/
// Don't compile this if the Easy-interface is turned off
#ifndef WITHOUT_EASY
#include <iostream>
#include <string>
#include <cstdint>
#include <mutex>
#include <chrono>
#include <vector>
#ifdef MASTODON_CPP
#include "mastodon-cpp.hpp"
#include "easy/all.hpp"
#else
#include <mastodon-cpp/mastodon-cpp.hpp>
#include <mastodon-cpp/easy/all.hpp>
#endif
using std::cout;
using std::cerr;
using std::endl;
using std::string;
using std::uint8_t;
using namespace Mastodon;
int main(int argc, char *argv[])
{
if (argc < 2)
{
std::cerr << "usage: " << argv[0] << " <instance>\n";
return 1;
}
// Construct a Mastodon::Easy object without authorization token.
Easy::API masto(argv[1], "");
// Prepare a pointer to the http object, to cancel the stream later.
std::unique_ptr<API::http> ptr;
// This variable is filled with the stream data.
string stream;
// Get the public timeline, the pointer is set here. The error detection is
// not very reliable at the moment, don't count on it.
uint8_t ret = masto.get_stream(API::v1::streaming_public, ptr, stream);
cout << "Return code: " << std::to_string(ret) << endl;
// Listen to the stream for 120 seconds.
for (uint8_t counter = 0; counter < 120; ++counter)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
// Acquire lock for the stream variable to avoid simultaneous access.
std::lock_guard<std::mutex> lock(ptr->get_mutex());
// Parse event stream into a vector.
std::vector<Easy::stream_event> events = Easy::parse_stream(stream);
// Clear the stream buffer.
stream.clear();
for (const Easy::stream_event &event : events)
{
// Print out some information about the events.
switch (event.type)
{
case Easy::event_type::Update:
{
Easy::Status status(event.data);
cout << "[" << status.created_at().strtime("%T") << "] ";
cout << "Status from: " << status.account().acct()
<< " (" << status.url() << ")\n";
break;
}
case Easy::event_type::Notification:
{
Easy::Notification notification(event.data);
cout << "Notification involving: "
<< notification.account().acct()
<< " (" << notification.id() << ")\n";
break;
}
case Easy::event_type::Delete:
{
cout << "Deleted: " << event.data << '\n';
break;
}
default:
{
cout << "Something undefined happened. 😱\n";
}
}
}
}
// Close connection.
ptr->cancel_stream();
return 0;
}
#else
#include <cstdio>
int main()
{
std::printf("mastodon-cpp was compiled without Easy support.\n");
return 255;
}
#endif // WITHOUT_EASY

View File

@ -21,9 +21,10 @@
using namespace Mastodon;
using std::cerr;
return_call API::get_stream(const Mastodon::API::v1 &call,
const parametermap &parameters,
std::unique_ptr<Mastodon::API::http> &ptr)
uint8_t API::get_stream(const Mastodon::API::v1 &call,
const parametermap &parameters,
std::unique_ptr<Mastodon::API::http> &ptr,
string &stream)
{
string strcall = "";
@ -46,7 +47,7 @@ return_call API::get_stream(const Mastodon::API::v1 &call,
break;
default:
ttdebug << "ERROR: Invalid call.\n";
return { 22, "Invalid argument", 0, "" };
return 22;
break;
}
@ -55,18 +56,19 @@ return_call API::get_stream(const Mastodon::API::v1 &call,
strcall += maptostr(parameters);
}
return get_stream(strcall, ptr);
return get_stream(strcall, ptr, stream);
}
return_call API::get_stream(const Mastodon::API::v1 &call,
std::unique_ptr<Mastodon::API::http> &ptr)
uint8_t API::get_stream(const Mastodon::API::v1 &call,
std::unique_ptr<Mastodon::API::http> &ptr,
string &stream)
{
parametermap p = {};
return get_stream(call, p, ptr);
return get_stream(call, {}, ptr, stream);
}
return_call API::get_stream(const std::string &call, std::unique_ptr<http> &ptr)
uint8_t API::get_stream(const std::string &call, std::unique_ptr<http> &ptr,
string &stream)
{
ptr = std::make_unique<http>(*this, _instance, _access_token);
return ptr->request(http_method::GET_STREAM, call);
return ptr->request_stream(call, stream);
}

View File

@ -70,7 +70,7 @@ const vector<Easy::stream_event> Easy::parse_stream(
else if (event.compare("delete") == 0)
type = event_type::Delete;
vec.push_back(stream_event(type, data));
vec.push_back({ type, data });
stream = match.suffix().str();
}

View File

@ -103,7 +103,11 @@ namespace Easy
*
* @since before 0.11.0
*/
typedef std::pair<event_type, string> stream_event;
typedef struct stream_event
{
event_type type = event_type::Undefined;
string data;
} stream_event;
/*!
* @brief Map of 'notification type' and 'push is requested or not'.

View File

@ -19,6 +19,7 @@
#include <list>
#include <cstring> // std::strncmp
#include <exception>
#include <thread>
#include <curlpp/Options.hpp>
#include <curlpp/Exception.hpp>
#include <curlpp/Infos.hpp>
@ -49,13 +50,43 @@ return_call API::http::request(const http_method &meth, const string &path)
return request(meth, path, curlpp::Forms());
}
return_call API::http::request(const http_method &meth,
const string &path,
return_call API::http::request(const http_method &meth, const string &path,
const curlpp::Forms &formdata)
{
string answer;
return request_common(meth, path, formdata, answer);
}
uint8_t API::http::request_stream(const string &path, string &stream)
{
static return_call ret;
_streamthread = std::thread(
[&]
{
ret = request_common(http_method::GET_STREAM, path,
curlpp::Forms(), stream);
});
// FIXME: Build reliable error detection.
std::this_thread::sleep_for(std::chrono::seconds(1));
if (!ret)
{
cancel_stream();
return ret.error_code;
}
else
{
return 0;
}
}
return_call API::http::request_common(const http_method &meth,
const string &path,
const curlpp::Forms &formdata,
string &answer)
{
using namespace std::placeholders; // _1, _2, _3
string answer;
ttdebug << "Path is: " << path << '\n';
try
@ -220,6 +251,7 @@ double API::http::callback_progress(double /* dltotal */, double /* dlnow */,
void API::http::cancel_stream()
{
_cancel_stream = true;
_streamthread.join();
}
std::mutex &API::http::get_mutex()

View File

@ -23,6 +23,8 @@
#include <array>
#include <mutex>
#include <ostream>
#include <thread>
#include <cstdint>
#include <curlpp/cURLpp.hpp>
#include <curlpp/Easy.hpp>
@ -36,6 +38,7 @@
#endif
using std::string;
using std::uint8_t;
/*!
* @example example01_get_public_timeline.cpp
@ -92,8 +95,8 @@ namespace Mastodon
/*!
* @brief HTTP Request.
*
* @param meth A method defined in http::method
* @param path The api call as string
* @param meth A method defined in http::method.
* @param path The API call as string.
* @param formdata The form data for PATCH and POST requests.
*
* @return @ref error "Error code". If the URL has permanently
@ -105,6 +108,16 @@ namespace Mastodon
const string &path,
const curlpp::Forms &formdata);
/*!
* @brief HTTP Request for streams.
*
* @param path The API call as string.
* @param stream The stream of data that is returned.
*
* @since 0.100.0
*/
uint8_t request_stream(const string &path, string &stream);
/*!
* @brief Get all headers in a string
*/
@ -140,7 +153,12 @@ namespace Mastodon
string _headers;
bool _cancel_stream;
std::mutex _mutex;
std::thread _streamthread;
return_call request_common(const http_method &meth,
const string &path,
const curlpp::Forms &formdata,
string &answer);
size_t callback_write(char* data, size_t size, size_t nmemb,
string *oss);
double callback_progress(double /* dltotal */, double /* dlnow */,
@ -467,7 +485,7 @@ namespace Mastodon
*
* @param call A call defined in Mastodon::API::v1
*
* @return @ref error "Error code".
* @return return_call
*
* @since 0.100.0
*/
@ -480,7 +498,7 @@ namespace Mastodon
* @param parameters A Mastodon::parametermap containing
* parameters
*
* @return @ref error "Error code".
* @return return_call
*/
const return_call get(const Mastodon::API::v1 &call,
const parametermap &parameters);
@ -494,7 +512,7 @@ namespace Mastodon
* @param parameters A Mastodon::parametermap containing
* parameters
*
* @return @ref error "Error code".
* @return return_call
*/
const return_call get(const Mastodon::API::v2 &call,
const parametermap &parameters);
@ -504,7 +522,7 @@ namespace Mastodon
*
* @param call String in the form `/api/v1/example`
*
* @return @ref error "Error code".
* @return return_call
*
* @since 0.100.0
*/
@ -523,9 +541,10 @@ namespace Mastodon
*
* @since 0.100.0
*/
return_call get_stream(const Mastodon::API::v1 &call,
const parametermap &parameters,
std::unique_ptr<Mastodon::API::http> &ptr);
uint8_t get_stream(const Mastodon::API::v1 &call,
const parametermap &parameters,
std::unique_ptr<Mastodon::API::http> &ptr,
string &stream);
/*!
* @brief Make a streaming GET request.
@ -538,8 +557,9 @@ namespace Mastodon
*
* @since 0.100.0
*/
return_call get_stream(const Mastodon::API::v1 &call,
std::unique_ptr<Mastodon::API::http> &ptr);
uint8_t get_stream(const Mastodon::API::v1 &call,
std::unique_ptr<Mastodon::API::http> &ptr,
string &stream);
/*!
* @brief Make a streaming GET request.
@ -552,8 +572,9 @@ namespace Mastodon
*
* @since 0.100.0
*/
return_call get_stream(const string &call,
std::unique_ptr<Mastodon::API::http> &ptr);
uint8_t get_stream(const string &call,
std::unique_ptr<Mastodon::API::http> &ptr,
string &stream);
/*!
* @brief Make a PATCH request.