1//
2// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
3//
4// Distributed under the Boost Software License, Version 1.0. (See accompanying
5// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6//
7// Official repository: https://github.com/vinniefalco/CppCon2018
8//
9
10#include "websocket_session.hpp"
11#include <iostream>
12
13websocket_session::
14websocket_session(
15 tcp::socket&& socket,
16 boost::shared_ptr<shared_state> const& state)
17 : ws_(std::move(socket))
18 , state_(state)
19{
20}
21
22websocket_session::
23~websocket_session()
24{
25 // Remove this session from the list of active sessions
26 state_->leave(session: this);
27}
28
29void
30websocket_session::
31fail(beast::error_code ec, char const* what)
32{
33 // Don't report these
34 if( ec == net::error::operation_aborted ||
35 ec == websocket::error::closed)
36 return;
37
38 std::cerr << what << ": " << ec.message() << "\n";
39}
40
41void
42websocket_session::
43on_accept(beast::error_code ec)
44{
45 // Handle the error, if any
46 if(ec)
47 return fail(ec, what: "accept");
48
49 // Add this session to the list of active sessions
50 state_->join(session: this);
51
52 // Read a message
53 ws_.async_read(
54 buffer&: buffer_,
55 handler: beast::bind_front_handler(
56 handler: &websocket_session::on_read,
57 args: shared_from_this()));
58}
59
60void
61websocket_session::
62on_read(beast::error_code ec, std::size_t)
63{
64 // Handle the error, if any
65 if(ec)
66 return fail(ec, what: "read");
67
68 // Send to all connections
69 state_->send(message: beast::buffers_to_string(buffers: buffer_.data()));
70
71 // Clear the buffer
72 buffer_.consume(n: buffer_.size());
73
74 // Read another message
75 ws_.async_read(
76 buffer&: buffer_,
77 handler: beast::bind_front_handler(
78 handler: &websocket_session::on_read,
79 args: shared_from_this()));
80}
81
82void
83websocket_session::
84send(boost::shared_ptr<std::string const> const& ss)
85{
86 // Post our work to the strand, this ensures
87 // that the members of `this` will not be
88 // accessed concurrently.
89
90 net::post(
91 ex: ws_.get_executor(),
92 token: beast::bind_front_handler(
93 handler: &websocket_session::on_send,
94 args: shared_from_this(),
95 args: ss));
96}
97
98void
99websocket_session::
100on_send(boost::shared_ptr<std::string const> const& ss)
101{
102 // Always add to queue
103 queue_.push_back(x: ss);
104
105 // Are we already writing?
106 if(queue_.size() > 1)
107 return;
108
109 // We are not currently writing, so send this immediately
110 ws_.async_write(
111 bs: net::buffer(data: *queue_.front()),
112 handler: beast::bind_front_handler(
113 handler: &websocket_session::on_write,
114 args: shared_from_this()));
115}
116
117void
118websocket_session::
119on_write(beast::error_code ec, std::size_t)
120{
121 // Handle the error, if any
122 if(ec)
123 return fail(ec, what: "write");
124
125 // Remove the string from the queue
126 queue_.erase(position: queue_.begin());
127
128 // Send the next message if any
129 if(! queue_.empty())
130 ws_.async_write(
131 bs: net::buffer(data: *queue_.front()),
132 handler: beast::bind_front_handler(
133 handler: &websocket_session::on_write,
134 args: shared_from_this()));
135}
136

source code of boost/libs/beast/example/websocket/server/chat-multi/websocket_session.cpp