Skip to content
Snippets Groups Projects
Commit aaf69ad4 authored by Nicolas Werner's avatar Nicolas Werner
Browse files

Use pimpl for boost::asio dependent client members

parent 1d5f0fe9
No related branches found
No related tags found
No related merge requests found
......@@ -89,11 +89,25 @@ struct ThumbOpts
std::string mxc_url;
};
struct ClientPrivate
{
boost::asio::io_service ios_;
//! Used to prevent the event loop from shutting down.
std::optional<boost::asio::io_context::work> work_{ios_};
//! Worker threads for the requests.
boost::thread_group thread_group_;
//! SSL context for requests.
boost::asio::ssl::context ssl_ctx_{boost::asio::ssl::context::sslv23_client};
//! All the active sessions will shutdown the connection.
boost::signals2::signal<void()> shutdown_signal;
};
//! The main object that the user will interact.
class Client : public std::enable_shared_from_this<Client>
{
public:
Client(const std::string &server = "", uint16_t port = 443);
~Client();
//! Wait for the client to close.
void close(bool force = false);
......@@ -124,7 +138,7 @@ public:
//! Generate a new transaction id.
std::string generate_txn_id() { return client::utils::random_token(32, false); }
//! Abort all active pending requests.
void shutdown() { shutdown_signal(); }
void shutdown() { p->shutdown_signal(); }
//! Remove all saved configuration.
void clear()
{
......@@ -355,16 +369,15 @@ private:
template<class Response>
std::shared_ptr<Session> create_session(HeadersCallback<Response> callback);
std::shared_ptr<Session> create_session(
std::function<void(const HeaderFields &,
const std::string &,
const boost::system::error_code &,
boost::beast::http::status)> type_erased_cb);
//! Setup http header with the access token if needed.
void setup_auth(Session *session, bool auth);
boost::asio::io_service ios_;
//! Used to prevent the event loop from shutting down.
std::optional<boost::asio::io_context::work> work_{ios_};
//! Worker threads for the requests.
boost::thread_group thread_group_;
//! SSL context for requests.
boost::asio::ssl::context ssl_ctx_{boost::asio::ssl::context::sslv23_client};
//! The homeserver to connect to.
std::string server_;
//! The access token that would be used for authentication.
......@@ -377,8 +390,8 @@ private:
std::string next_batch_token_;
//! The homeserver port to connect.
uint16_t port_ = 443;
//! All the active sessions will shutdown the connection.
boost::signals2::signal<void()> shutdown_signal;
std::unique_ptr<ClientPrivate> p;
};
}
}
......@@ -511,39 +524,8 @@ mtx::http::Client::create_session(HeadersCallback<Response> callback)
}
};
auto session = std::make_shared<Session>(
std::ref(ios_),
std::ref(ssl_ctx_),
server_,
port_,
client::utils::random_token(),
[type_erased_cb](
RequestID,
const boost::beast::http::response<boost::beast::http::string_body> &response,
const boost::system::error_code &err_code) {
const auto header = response.base();
if (err_code) {
return type_erased_cb(header, "", err_code, {});
}
// Decompress the response.
const auto body = client::utils::decompress(
boost::iostreams::array_source{response.body().data(), response.body().size()},
header["Content-Encoding"].to_string());
type_erased_cb(header, body, err_code, response.result());
},
[type_erased_cb](RequestID, const boost::system::error_code ec) {
type_erased_cb(std::nullopt, "", ec, {});
});
if (session)
shutdown_signal.connect(
boost::signals2::signal<void()>::slot_type(&Session::terminate, session.get())
.track_foreign(session));
return session;
return create_session(type_erased_cb);
}
template<class Payload, mtx::events::EventType Event>
......
......@@ -14,12 +14,56 @@ using namespace boost::beast;
Client::Client(const std::string &server, uint16_t port)
: server_{server}
, port_{port}
, p{new ClientPrivate}
{
using namespace boost::asio;
const auto threads_num = std::max(1U, std::thread::hardware_concurrency());
for (unsigned int i = 0; i < threads_num; ++i)
thread_group_.add_thread(new boost::thread([this]() { ios_.run(); }));
p->thread_group_.add_thread(new boost::thread([this]() { p->ios_.run(); }));
}
// call destuctor of work queue and ios first!
Client::~Client() { p.reset(); }
std::shared_ptr<Session>
Client::create_session(std::function<void(const HeaderFields &,
const std::string &,
const boost::system::error_code &,
boost::beast::http::status)> type_erased_cb)
{
auto session = std::make_shared<Session>(
std::ref(p->ios_),
std::ref(p->ssl_ctx_),
server_,
port_,
client::utils::random_token(),
[type_erased_cb](
RequestID,
const boost::beast::http::response<boost::beast::http::string_body> &response,
const boost::system::error_code &err_code) {
const auto header = response.base();
if (err_code) {
return type_erased_cb(header, "", err_code, {});
}
// Decompress the response.
const auto body = client::utils::decompress(
boost::iostreams::array_source{response.body().data(), response.body().size()},
header["Content-Encoding"].to_string());
type_erased_cb(header, body, err_code, response.result());
},
[type_erased_cb](RequestID, const boost::system::error_code ec) {
type_erased_cb(std::nullopt, "", ec, {});
});
if (session)
p->shutdown_signal.connect(
boost::signals2::signal<void()>::slot_type(&Session::terminate, session.get())
.track_foreign(session));
return session;
}
void
......@@ -50,16 +94,16 @@ Client::close(bool force)
// We close all open connections.
if (force) {
shutdown();
ios_.stop();
p->ios_.stop();
}
// Destroy work object. This allows the I/O thread to
// exit the event loop when there are no more pending
// asynchronous operations.
work_.reset();
p->work_.reset();
// Wait for the worker threads to exit.
thread_group_.join_all();
p->thread_group_.join_all();
}
void
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment