summaryrefslogtreecommitdiffhomepage
path: root/websocket.h
diff options
context:
space:
mode:
Diffstat (limited to 'websocket.h')
-rw-r--r--websocket.h141
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();
+ }
+};
+