• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
13 websocket_session::
websocket_session(tcp::socket && socket,boost::shared_ptr<shared_state> const & state)14 websocket_session(
15     tcp::socket&& socket,
16     boost::shared_ptr<shared_state> const& state)
17     : ws_(std::move(socket))
18     , state_(state)
19 {
20 }
21 
22 websocket_session::
~websocket_session()23 ~websocket_session()
24 {
25     // Remove this session from the list of active sessions
26     state_->leave(this);
27 }
28 
29 void
30 websocket_session::
fail(beast::error_code ec,char const * what)31 fail(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 
41 void
42 websocket_session::
on_accept(beast::error_code ec)43 on_accept(beast::error_code ec)
44 {
45     // Handle the error, if any
46     if(ec)
47         return fail(ec, "accept");
48 
49     // Add this session to the list of active sessions
50     state_->join(this);
51 
52     // Read a message
53     ws_.async_read(
54         buffer_,
55         beast::bind_front_handler(
56             &websocket_session::on_read,
57             shared_from_this()));
58 }
59 
60 void
61 websocket_session::
on_read(beast::error_code ec,std::size_t)62 on_read(beast::error_code ec, std::size_t)
63 {
64     // Handle the error, if any
65     if(ec)
66         return fail(ec, "read");
67 
68     // Send to all connections
69     state_->send(beast::buffers_to_string(buffer_.data()));
70 
71     // Clear the buffer
72     buffer_.consume(buffer_.size());
73 
74     // Read another message
75     ws_.async_read(
76         buffer_,
77         beast::bind_front_handler(
78             &websocket_session::on_read,
79             shared_from_this()));
80 }
81 
82 void
83 websocket_session::
send(boost::shared_ptr<std::string const> const & ss)84 send(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         ws_.get_executor(),
92         beast::bind_front_handler(
93             &websocket_session::on_send,
94             shared_from_this(),
95             ss));
96 }
97 
98 void
99 websocket_session::
on_send(boost::shared_ptr<std::string const> const & ss)100 on_send(boost::shared_ptr<std::string const> const& ss)
101 {
102     // Always add to queue
103     queue_.push_back(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         net::buffer(*queue_.front()),
112         beast::bind_front_handler(
113             &websocket_session::on_write,
114             shared_from_this()));
115 }
116 
117 void
118 websocket_session::
on_write(beast::error_code ec,std::size_t)119 on_write(beast::error_code ec, std::size_t)
120 {
121     // Handle the error, if any
122     if(ec)
123         return fail(ec, "write");
124 
125     // Remove the string from the queue
126     queue_.erase(queue_.begin());
127 
128     // Send the next message if any
129     if(! queue_.empty())
130         ws_.async_write(
131             net::buffer(*queue_.front()),
132             beast::bind_front_handler(
133                 &websocket_session::on_write,
134                 shared_from_this()));
135 }
136