src/api/transport/impl/ws/ws_session.cpp¶
Namespaces¶
| Name |
|---|
| sgns |
| sgns::api |
Source code¶
#include "api/transport/impl/ws/ws_session.hpp"
#include <boost/asio/dispatch.hpp>
#include <boost/config.hpp>
#include <cstring>
#include "outcome/outcome.hpp"
namespace sgns::api {
WsSession::WsSession(Context &context, Configuration config, SessionId id)
: strand_(boost::asio::make_strand(context)),
socket_(strand_),
config_{config},
stream_(socket_),
id_(id) {}
void WsSession::start() {
boost::asio::dispatch(stream_.get_executor(),
boost::asio::bind_executor(stream_.get_executor(),
std::bind(&WsSession::onRun,
shared_from_this())));
}
void WsSession::stop() {
boost::system::error_code ec;
stream_.close(boost::beast::websocket::close_reason(), ec);
boost::ignore_unused(ec);
notifyOnClose(id_, type());
}
void WsSession::handleRequest(std::string_view data) {
processRequest(data, shared_from_this());
}
void WsSession::asyncRead() {
stream_.async_read(rbuffer_,
boost::asio::bind_executor(stream_.get_executor(),
std::bind(&WsSession::onRead,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
}
void WsSession::asyncWrite() {
stream_.async_write(wbuffer_.data(),
boost::asio::bind_executor(stream_.get_executor(),
std::bind(&WsSession::onWrite,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
}
sgns::api::Session::SessionId WsSession::id() const {
return id_;
}
void WsSession::respond(std::string_view response) {
boost::asio::buffer_copy(
wbuffer_.prepare(response.size()),
boost::asio::const_buffer(response.data(), response.size()));
wbuffer_.commit(response.size());
stream_.text(true);
asyncWrite();
}
void WsSession::onRun() {
// Set suggested timeout settings for the websocket
stream_.set_option(boost::beast::websocket::stream_base::timeout::suggested(
boost::beast::role_type::server));
// Set a decorator to change the Server of the handshake
stream_.set_option(boost::beast::websocket::stream_base::decorator(
[](boost::beast::websocket::response_type& res) {
res.set(boost::beast::http::field::server,
std::string(BOOST_BEAST_VERSION_STRING)
+ " websocket-server-async");
}));
// Accept the websocket handshake
stream_.async_accept(boost::asio::bind_executor(stream_.get_executor(),
std::bind(&WsSession::onAccept,
shared_from_this(),
std::placeholders::_1)));
}
void WsSession::onAccept(boost::system::error_code ec) {
if (ec) {
auto error_message = (ec == WsError::closed) ? "connection was closed"
: "unknown error occurred";
reportError(ec, error_message);
stop();
return;
}
asyncRead();
};
void WsSession::onRead(boost::system::error_code ec,
std::size_t bytes_transferred) {
if (ec) {
auto error_message = (ec == WsError::closed) ? "connection was closed"
: "unknown error occurred";
reportError(ec, error_message);
stop();
return;
}
handleRequest(
{static_cast<char *>(rbuffer_.data().data()), bytes_transferred});
rbuffer_.consume(bytes_transferred);
}
void WsSession::onWrite(boost::system::error_code ec,
std::size_t bytes_transferred) {
if (ec) {
reportError(ec, "failed to write message");
return stop();
}
wbuffer_.consume(bytes_transferred);
asyncRead();
}
void WsSession::reportError(boost::system::error_code ec,
std::string_view message) {
logger_->error("error occured: {}, code: {}", message, ec.message());
}
} // namespace sgns::api
Updated on 2026-03-04 at 13:10:44 -0800