19 #ifndef IRCCD_STREAM_HPP
20 #define IRCCD_STREAM_HPP
27 #include <irccd/sysconfig.hpp>
34 #include <system_error>
37 #include <boost/asio.hpp>
39 #if defined(IRCCD_HAVE_SSL)
40 # include <boost/asio/ssl.hpp>
63 using recv_handler = std::function<void (std::error_code, nlohmann::json)>;
110 template <
typename Socket>
113 boost::asio::streambuf input_{2048};
114 boost::asio::streambuf output_;
117 bool is_receiving_{
false};
118 bool is_sending_{
false};
121 void handle_recv(boost::system::error_code, std::size_t,
recv_handler);
122 void handle_send(boost::system::error_code, std::size_t,
send_handler);
132 template <
typename... Args>
170 template <typename Socket>
171 template <typename... Args>
173 : socket_(
std::forward<Args>(args)...)
177 template <
typename Socket>
183 template <
typename Socket>
189 template <
typename Socket>
195 is_receiving_ =
false;
198 if (code == boost::asio::error::not_found) {
199 handler(make_error_code(std::errc::argument_list_too_long),
nullptr);
202 if (code == boost::asio::error::eof || xfer == 0) {
203 handler(make_error_code(std::errc::connection_reset),
nullptr);
207 handler(std::move(code),
nullptr);
215 buffer = std::string(
216 boost::asio::buffers_begin(input_.data()),
217 boost::asio::buffers_begin(input_.data()) + xfer - 4
220 input_.consume(xfer);
221 }
catch (
const std::bad_alloc&) {
230 doc = nlohmann::json::parse(buffer);
231 }
catch (
const std::exception&) {
236 if (!doc.is_object())
239 handler(std::error_code(), std::move(doc));
242 template <
typename Socket>
243 inline void basic_socket_stream<Socket>::handle_send(boost::system::error_code code,
251 if (code == boost::asio::error::eof || xfer == 0) {
256 handler(std::move(code));
259 template <
typename Socket>
263 assert(!is_receiving_);
265 is_receiving_ =
true;
270 async_read_until(socket_, input_,
"\r\n\r\n", [
this, handler] (
auto code,
auto xfer) {
271 handle_recv(code, xfer, handler);
275 template <
typename Socket>
279 assert(!is_sending_);
284 assert(json.is_object());
287 std::ostream out(&output_);
293 async_write(socket_, output_, [
this, handler] (
auto code,
auto xfer) {
294 handle_send(code, xfer, handler);
312 #if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS)
326 #if defined(IRCCD_HAVE_SSL)
333 template <
typename Socket>
336 std::shared_ptr<boost::asio::ssl::context> context_;
348 tls_stream(boost::asio::io_context& service, std::shared_ptr<boost::asio::ssl::context> ctx);
351 template <
typename Socket>
354 , context_(
std::move(ctx))
363 #if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS)
Complete implementation for basic sockets.
Definition: stream.hpp:111
void send(const nlohmann::json &json, send_handler handler) override
Definition: stream.hpp:276
auto get_socket() const noexcept -> const Socket &
Definition: stream.hpp:178
void recv(recv_handler handler) override
Definition: stream.hpp:260
basic_socket_stream(Args &&... args)
Definition: stream.hpp:172
Abstract stream interface.
Definition: stream.hpp:58
std::function< void(std::error_code, nlohmann::json)> recv_handler
Read completion handler.
Definition: stream.hpp:63
virtual void send(const nlohmann::json &json, send_handler handler)=0
virtual void recv(recv_handler handler)=0
std::function< void(std::error_code)> send_handler
Write completion handler.
Definition: stream.hpp:68
virtual ~stream()=default
TLS/SSL streams.
Definition: stream.hpp:334
tls_stream(boost::asio::io_context &service, std::shared_ptr< boost::asio::ssl::context > ctx)
Definition: stream.hpp:352
auto make_error_code(bot_error::error e) noexcept -> std::error_code
Parent namespace.
Definition: acceptor.hpp:43