websocket_session.cpp 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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. #include "websocket_session.hpp"
  10. #include <iostream>
  11. websocket_session::
  12. websocket_session(
  13. tcp::socket&& socket,
  14. boost::shared_ptr<shared_state> const& state)
  15. : ws_(std::move(socket))
  16. , state_(state)
  17. {
  18. }
  19. websocket_session::
  20. ~websocket_session()
  21. {
  22. // Remove this session from the list of active sessions
  23. state_->leave(this);
  24. }
  25. void
  26. websocket_session::
  27. fail(beast::error_code ec, char const* what)
  28. {
  29. // Don't report these
  30. if( ec == net::error::operation_aborted ||
  31. ec == websocket::error::closed)
  32. return;
  33. std::cerr << what << ": " << ec.message() << "\n";
  34. }
  35. void
  36. websocket_session::
  37. on_accept(beast::error_code ec)
  38. {
  39. // Handle the error, if any
  40. if(ec)
  41. return fail(ec, "accept");
  42. // Add this session to the list of active sessions
  43. state_->join(this);
  44. // Read a message
  45. ws_.async_read(
  46. buffer_,
  47. beast::bind_front_handler(
  48. &websocket_session::on_read,
  49. shared_from_this()));
  50. }
  51. void
  52. websocket_session::
  53. on_read(beast::error_code ec, std::size_t)
  54. {
  55. // Handle the error, if any
  56. if(ec)
  57. return fail(ec, "read");
  58. // Send to all connections
  59. state_->send(beast::buffers_to_string(buffer_.data()));
  60. // Clear the buffer
  61. buffer_.consume(buffer_.size());
  62. // Read another message
  63. ws_.async_read(
  64. buffer_,
  65. beast::bind_front_handler(
  66. &websocket_session::on_read,
  67. shared_from_this()));
  68. }
  69. void
  70. websocket_session::
  71. send(boost::shared_ptr<std::string const> const& ss)
  72. {
  73. // Post our work to the strand, this ensures
  74. // that the members of `this` will not be
  75. // accessed concurrently.
  76. net::post(
  77. ws_.get_executor(),
  78. beast::bind_front_handler(
  79. &websocket_session::on_send,
  80. shared_from_this(),
  81. ss));
  82. }
  83. void
  84. websocket_session::
  85. on_send(boost::shared_ptr<std::string const> const& ss)
  86. {
  87. // Always add to queue
  88. queue_.push_back(ss);
  89. // Are we already writing?
  90. if(queue_.size() > 1)
  91. return;
  92. // We are not currently writing, so send this immediately
  93. ws_.async_write(
  94. net::buffer(*queue_.front()),
  95. beast::bind_front_handler(
  96. &websocket_session::on_write,
  97. shared_from_this()));
  98. }
  99. void
  100. websocket_session::
  101. on_write(beast::error_code ec, std::size_t)
  102. {
  103. // Handle the error, if any
  104. if(ec)
  105. return fail(ec, "write");
  106. // Remove the string from the queue
  107. queue_.erase(queue_.begin());
  108. // Send the next message if any
  109. if(! queue_.empty())
  110. ws_.async_write(
  111. net::buffer(*queue_.front()),
  112. beast::bind_front_handler(
  113. &websocket_session::on_write,
  114. shared_from_this()));
  115. }