diff options
Diffstat (limited to 'websocket.h')
-rw-r--r-- | websocket.h | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/websocket.h b/websocket.h new file mode 100644 index 0000000..d8d0262 --- /dev/null +++ b/websocket.h @@ -0,0 +1,141 @@ +#pragma once + +#include "error.h" + +#include <boost/asio/buffer.hpp> +#include <boost/beast/core.hpp> +#include <boost/beast/http.hpp> +#include <boost/beast/websocket.hpp> +#include <boost/beast/websocket/ssl.hpp> +#include <boost/beast/ssl/ssl_stream.hpp> +#include <boost/asio/buffers_iterator.hpp> +#include <boost/asio/dispatch.hpp> +#include <boost/asio/ssl/context.hpp> +#include <boost/beast/ssl.hpp> +#include <boost/asio/strand.hpp> +#include <boost/config.hpp> + +#include <algorithm> +#include <cstddef> +#include <cstdlib> +#include <filesystem> +#include <functional> +#include <iostream> +#include <memory> +#include <optional> +#include <string> +#include <thread> +#include <vector> + +namespace beast = boost::beast; // from <boost/beast.hpp> +namespace http = beast::http; // from <boost/beast/http.hpp> +namespace net = boost::asio; // from <boost/asio.hpp> +namespace ssl = boost::asio::ssl; // from <boost/asio/ssl.hpp> +namespace websocket = beast::websocket; +using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp> + +class websocket_session: public std::enable_shared_from_this<websocket_session> +{ + websocket::stream<beast::ssl_stream<beast::tcp_stream>> ws_; + beast::flat_buffer buffer_; + +public: + explicit websocket_session(beast::ssl_stream<beast::tcp_stream>&& stream) : + ws_(std::move(stream)) + { + } + + // Start the asynchronous accept operation + template<class Body, class Allocator> + void + do_accept(http::request<Body, http::basic_fields<Allocator>> req) + { + // Set suggested timeout settings for the websocket + ws_.set_option( + websocket::stream_base::timeout::suggested( + beast::role_type::server)); + + // Set a decorator to change the Server of the handshake + ws_.set_option(websocket::stream_base::decorator( + [](websocket::response_type& res) + { + res.set(http::field::server, + std::string{"Reichwein.IT Webserver"}); + })); + + // Accept the websocket handshake + ws_.async_accept( + req, + beast::bind_front_handler( + &websocket_session::on_accept, + shared_from_this())); + } + +private: + void + on_accept(beast::error_code ec) + { + if(ec) + return fail(ec, "accept"); + + // Read a message + do_read(); + } + + void + do_read() + { + // Read a message into our buffer + ws_.async_read( + buffer_, + beast::bind_front_handler( + &websocket_session::on_read, + shared_from_this())); + } + + void + on_read( + beast::error_code ec, + std::size_t bytes_transferred) + { + boost::ignore_unused(bytes_transferred); + + // This indicates that the websocket_session was closed + if(ec == websocket::error::closed) + return; + + if(ec) + fail(ec, "read"); + + // Echo the message + ws_.text(ws_.got_text()); + std::string data(boost::asio::buffers_begin(buffer_.data()), boost::asio::buffers_end(buffer_.data())); + static int count{}; + data += ": " + std::to_string(count++); + buffer_.consume(buffer_.size()); + boost::beast::ostream(buffer_) << data; + ws_.async_write( + buffer_.data(), + beast::bind_front_handler( + &websocket_session::on_write, + shared_from_this())); + } + + void + on_write( + beast::error_code ec, + std::size_t bytes_transferred) + { + boost::ignore_unused(bytes_transferred); + + if(ec) + return fail(ec, "write"); + + // Clear the buffer + buffer_.consume(buffer_.size()); + + // Do another read + do_read(); + } +}; + |