@@ -46,6 +46,17 @@ namespace client
46
46
namespace details
47
47
{
48
48
49
+ // Helper function to build an error string from a Platform::Exception and a location.
50
+ static std::string build_error_msg (Platform::Exception ^exc, const std::string &location)
51
+ {
52
+ std::string msg (location);
53
+ msg.append (" : " );
54
+ msg.append (std::to_string (exc->HResult ));
55
+ msg.append (" : " );
56
+ msg.append (utility::conversions::utf16_to_utf8 (exc->Message ->Data ()));
57
+ return msg;
58
+ }
59
+
49
60
// This class is required by the implementation in order to function:
50
61
// The TypedEventHandler requires the message received and close handler to be a member of WinRT class.
51
62
ref class ReceiveContext sealed
@@ -59,13 +70,16 @@ ref class ReceiveContext sealed
59
70
60
71
private:
61
72
// Public members cannot have native types
62
- ReceiveContext (std::function<void (websocket_incoming_message &)> receive_handler, std::function<void ()> close_handler): m_receive_handler(receive_handler), m_close_handler(close_handler) {}
73
+ ReceiveContext (
74
+ std::function<void (websocket_incoming_message &)> receive_handler,
75
+ std::function<void (const websocket_exception &)> close_handler)
76
+ : m_receive_handler(std::move(receive_handler)), m_close_handler(std::move(close_handler)) {}
63
77
64
78
// Handler to be executed when a message has been received by the client
65
79
std::function<void (websocket_incoming_message &)> m_receive_handler;
66
80
67
81
// Handler to be executed when a close message has been received by the client
68
- std::function<void ()> m_close_handler;
82
+ std::function<void (const websocket_exception & )> m_close_handler;
69
83
};
70
84
71
85
class winrt_client : public _websocket_client_impl , public std ::enable_shared_from_this<winrt_client>
@@ -128,9 +142,9 @@ class winrt_client : public _websocket_client_impl, public std::enable_shared_fr
128
142
// Setting the tce outside the receive lock for better performance
129
143
tce.set (msg);
130
144
},
131
- [=]() // Close handler called upon receiving a close frame from the server.
145
+ [=](const websocket_exception &e)
132
146
{
133
- close_pending_tasks_with_error ();
147
+ close_pending_tasks_with_error (e );
134
148
m_close_tce.set ();
135
149
m_server_close_complete.set ();
136
150
});
@@ -150,19 +164,19 @@ class winrt_client : public _websocket_client_impl, public std::enable_shared_fr
150
164
}
151
165
else
152
166
{
153
- close_pending_tasks_with_error ();
167
+ close_pending_tasks_with_error (websocket_exception ( " websocket_client is being destroyed " ) );
154
168
}
155
169
}
156
170
157
- void close_pending_tasks_with_error ()
171
+ void close_pending_tasks_with_error (const websocket_exception &exc )
158
172
{
159
173
std::lock_guard<std::mutex> lock (m_receive_queue_lock);
160
174
m_client_closed = true ;
161
175
while (!m_receive_task_queue.empty ()) // There are tasks waiting to receive a message, signal them
162
176
{
163
177
auto tce = m_receive_task_queue.front ();
164
178
m_receive_task_queue.pop ();
165
- tce.set_exception (std::make_exception_ptr (websocket_exception ( " Websocket connection has been closed. " ) ));
179
+ tce.set_exception (std::make_exception_ptr (exc ));
166
180
}
167
181
}
168
182
@@ -195,10 +209,11 @@ class winrt_client : public _websocket_client_impl, public std::enable_shared_fr
195
209
result.get ();
196
210
m_messageWriter = ref new DataWriter (m_msg_websocket->OutputStream );
197
211
}
198
- catch (Platform::Exception^ ex )
212
+ catch (Platform::Exception^ e )
199
213
{
200
- close_pending_tasks_with_error ();
201
- return pplx::task_from_exception<void >(websocket_exception (ex->HResult ));
214
+ websocket_exception exc (e->HResult , build_error_msg (e, " ConnectAsync" ));
215
+ close_pending_tasks_with_error (exc);
216
+ return pplx::task_from_exception<void >(exc);
202
217
}
203
218
return pplx::task_from_result ();
204
219
});
@@ -436,10 +451,8 @@ class winrt_client : public _websocket_client_impl, public std::enable_shared_fr
436
451
// completed. The websocket_client destructor can wait on this event before proceeding.
437
452
Concurrency::event m_server_close_complete;
438
453
439
- // m_client_closed maintains the state of the client. It is set to true when:
440
- // 1. the client has not connected
441
- // 2. if it has received a close frame from the server.
442
- // We may want to keep an enum to maintain the client state in the future.
454
+ // Initially set to false, becomes true if a close frame is received from the server or
455
+ // if the underlying connection is aborted or terminated.
443
456
bool m_client_closed;
444
457
445
458
// When a message arrives, if there are tasks waiting for a message, signal the topmost one.
@@ -490,19 +503,15 @@ void ReceiveContext::OnReceive(MessageWebSocket^ sender, MessageWebSocketMessage
490
503
msg->set_length (len);
491
504
m_receive_handler (ws_incoming_message);
492
505
}
493
- catch (... )
506
+ catch (Platform::Exception ^e )
494
507
{
495
- // Swallow the exception for now. Following up on this with the WinRT team.
496
- // We can handle this more gracefully once we know the scenarios where DataReader operations can throw an exception:
497
- // When socket gets into a bad state
498
- // or only when we receive a valid message and message processing fails.
499
- // Tracking this on codeplex with : https://casablanca.codeplex.com/workitem/181
508
+ m_close_handler (websocket_exception (e->HResult , build_error_msg (e, " OnReceive" )));
500
509
}
501
510
}
502
511
503
512
void ReceiveContext::OnClosed (IWebSocket^ sender, WebSocketClosedEventArgs^ args)
504
513
{
505
- m_close_handler ();
514
+ m_close_handler (websocket_exception ( " close frame received from server " ) );
506
515
}
507
516
}
508
517
@@ -515,4 +524,4 @@ websocket_client::websocket_client(websocket_client_config config) :
515
524
{}
516
525
517
526
}}}
518
- #endif /* WINAPI_FAMILY == WINAPI_FAMILY_APP */
527
+ #endif
0 commit comments