77#define BOOST_ASIO_NO_DEPRECATED
88
99#include < boost/asio/ip/tcp.hpp>
10+ #include < boost/asio/strand.hpp>
1011#include < boost/asio/thread_pool.hpp>
1112#include < boost/beast/core.hpp>
1213#include < boost/beast/websocket.hpp>
@@ -87,41 +88,52 @@ class WebsocketEvergreenWireStream final : public EvergreenWireStream {
8788 }
8889
8990 absl::Status Send (SessionMessage message) override {
90-
91+ auto message_bytes = cppack::Pack ( std::move (message));
9192 concurrency::MutexLock lock (&mutex_);
9293 if (!status_.ok ()) {
9394 return status_;
9495 }
9596
97+ if (concurrency::Cancelled ()) {
98+ return absl::CancelledError (" Send cancelled" );
99+ }
100+
101+ while (send_pending_) {
102+ cv_.Wait (&mutex_);
103+ }
96104 send_pending_ = true ;
97- mutex_.Unlock ();
98- boost::system::error_code error;
99105 stream_.binary (true );
100- RunInAsioContext (
101- [this , &error, &message]() {
102- auto message_bytes = cppack::Pack (std::move (message));
103- stream_.write (asio::buffer (message_bytes), error);
104- },
105- {concurrency::OnCancel ()});
106+
107+ boost::system::error_code error;
108+ concurrency::PermanentEvent write_done;
109+ stream_.async_write (asio::buffer (message_bytes),
110+ [&error, &write_done, this ](
111+ const boost::system::error_code& ec, std::size_t ) {
112+ concurrency::MutexLock lock (&mutex_);
113+ error = ec;
114+ write_done.Notify ();
115+ send_pending_ = false ;
116+ cv_.SignalAll ();
117+ });
118+ mutex_.Unlock ();
119+ concurrency::Select ({write_done.OnEvent (), concurrency::OnCancel ()});
106120 mutex_.Lock ();
107- send_pending_ = false ;
108- last_send_status_ = absl::OkStatus ();
109121
122+ absl::Status status = absl::OkStatus ();
110123 if (concurrency::Cancelled ()) {
111- stream_.next_layer ().shutdown (asio::socket_base::shutdown_send);
124+ stream_.next_layer ().shutdown (asio::socket_base::shutdown_send, error );
112125 DLOG (INFO) << absl::StrFormat (" WESt %s Send cancelled" , id_);
113- last_send_status_ = absl::CancelledError (" Send cancelled" );
126+ status = absl::CancelledError (" Send cancelled" );
114127 }
115128
129+ // send_pending_ = false;
130+ // cv_.SignalAll();
116131 if (error) {
117- last_send_status_ = absl::InternalError (error.message ());
118- DLOG (INFO) << absl::StrFormat (" WESt %s Send failed: %v" , id_,
119- last_send_status_);
132+ status = absl::InternalError (error.message ());
133+ DLOG (INFO) << absl::StrFormat (" WESt %s Send failed: %v" , id_, status);
120134 }
121135
122- cv_.SignalAll ();
123-
124- return last_send_status_;
136+ return status;
125137 }
126138
127139 std::optional<SessionMessage> Receive () override {
@@ -135,6 +147,14 @@ class WebsocketEvergreenWireStream final : public EvergreenWireStream {
135147 return std::nullopt ;
136148 }
137149
150+ if (concurrency::Cancelled ()) {
151+ return std::nullopt ;
152+ }
153+
154+ while (recv_pending_) {
155+ cv_.Wait (&mutex_);
156+ }
157+
138158 recv_pending_ = true ;
139159 mutex_.Unlock ();
140160 boost::system::error_code error;
@@ -144,11 +164,23 @@ class WebsocketEvergreenWireStream final : public EvergreenWireStream {
144164 stream_.read (dynamic_buffer, error);
145165 },
146166 {concurrency::OnCancel ()});
167+
168+ if (concurrency::Cancelled ()) {
169+ stream_.next_layer ().shutdown (asio::socket_base::shutdown_receive,
170+ error);
171+ if (error && error != asio::error::not_connected) {
172+ LOG (ERROR) << absl::StrFormat (
173+ " WESt %s Cannot shut down receive on socket: %v" , id_,
174+ error.message ());
175+ }
176+ }
177+
147178 mutex_.Lock ();
148179 recv_pending_ = false ;
149180
181+ cv_.SignalAll ();
182+
150183 if (concurrency::Cancelled ()) {
151- stream_.next_layer ().shutdown (asio::socket_base::shutdown_receive);
152184 DLOG (INFO) << absl::StrFormat (" WESt %s Receive cancelled" , id_);
153185 return std::nullopt ;
154186 }
@@ -158,8 +190,6 @@ class WebsocketEvergreenWireStream final : public EvergreenWireStream {
158190 error.message ());
159191 return std::nullopt ;
160192 }
161-
162- cv_.SignalAll ();
163193 }
164194
165195 if (auto unpacked = cppack::Unpack<SessionMessage>(buffer); unpacked.ok ()) {
@@ -185,6 +215,7 @@ class WebsocketEvergreenWireStream final : public EvergreenWireStream {
185215 beast::http::field::server,
186216 " Action Engine / Evergreen Light 0.1.0 WebsocketEvergreenServer" );
187217 }));
218+ stream_.write_buffer_bytes (16 );
188219
189220 boost::system::error_code error;
190221
@@ -214,7 +245,7 @@ class WebsocketEvergreenWireStream final : public EvergreenWireStream {
214245 status_ = absl::InternalError (error.message ());
215246 }
216247 status_ = absl::CancelledError (" Cancelled" );
217- while (send_pending_ || recv_pending_ ) {
248+ while (send_pending_) {
218249 cv_.Wait (&mutex_);
219250 }
220251 stream_.next_layer ().wait (tcp::socket::wait_error, error);
@@ -235,7 +266,7 @@ class WebsocketEvergreenWireStream final : public EvergreenWireStream {
235266 }
236267 }
237268
238- absl::Status GetStatus () const override { return last_send_status_ ; }
269+ absl::Status GetStatus () const override { return status_ ; }
239270
240271 [[nodiscard]] std::string_view GetId () const override { return id_; }
241272
@@ -255,7 +286,6 @@ class WebsocketEvergreenWireStream final : public EvergreenWireStream {
255286 std::string id_;
256287
257288 absl::Status status_;
258- absl::Status last_send_status_;
259289
260290 mutable concurrency::Mutex mutex_;
261291 mutable concurrency::CondVar cv_ ABSL_GUARDED_BY (mutex_);
@@ -317,7 +347,8 @@ class WebsocketEvergreenServer {
317347 concurrency::MutexLock lock (&mutex_);
318348 main_loop_ = concurrency::NewTree ({}, [this ]() {
319349 while (!concurrency::Cancelled ()) {
320- tcp::socket socket{*GetDefaultAsioExecutionContext ()};
350+ tcp::socket socket{
351+ asio::make_strand (*GetDefaultAsioExecutionContext ())};
321352
322353 DLOG (INFO) << " WES waiting for connection." ;
323354 boost::system::error_code error;
@@ -499,6 +530,8 @@ MakeWebsocketEvergreenWireStream(std::string_view address = "127.0.0.1",
499530 return absl::CancelledError (" Cancelled" );
500531 }
501532
533+ ws_stream.write_buffer_bytes (16 );
534+
502535 if (prepare_stream) {
503536 if (auto status = std::move (prepare_stream)(&ws_stream); !status.ok ()) {
504537 return status;
0 commit comments