@@ -13,50 +13,62 @@ struct Model {
1313 messages : Vec < String > ,
1414 input_text : String ,
1515 web_socket : WebSocket ,
16+ web_socket_reconnector : Option < StreamHandle > ,
1617}
1718
1819// ------ ------
1920// Init
2021// ------ ------
2122
2223fn init ( _: Url , orders : & mut impl Orders < Msg > ) -> Model {
23- let web_socket = WebSocket :: builder ( WS_URL , orders)
24- . on_open ( || log ! ( "WebSocket connection is open now" ) )
25- . on_message ( Msg :: MessageReceived )
26- . on_close ( Msg :: WebSocketClosed )
27- . on_error ( || log ! ( "Error" ) )
28- . build_and_open ( )
29- . unwrap ( ) ;
30-
3124 Model {
3225 sent_messages_count : 0 ,
3326 messages : Vec :: new ( ) ,
3427 input_text : String :: new ( ) ,
35- web_socket,
28+ web_socket : create_websocket ( orders) ,
29+ web_socket_reconnector : None ,
3630 }
3731}
3832
33+ fn create_websocket ( orders : & impl Orders < Msg > ) -> WebSocket {
34+ WebSocket :: builder ( WS_URL , orders)
35+ . on_open ( || Msg :: WebSocketOpened )
36+ . on_message ( Msg :: MessageReceived )
37+ . on_close ( Msg :: WebSocketClosed )
38+ . on_error ( || Msg :: WebSocketFailed )
39+ . build_and_open ( )
40+ . unwrap ( )
41+ }
42+
3943// ------ ------
4044// Update
4145// ------ ------
4246
4347enum Msg {
48+ WebSocketOpened ,
4449 MessageReceived ( WebSocketMessage ) ,
4550 CloseWebSocket ,
4651 WebSocketClosed ( CloseEvent ) ,
52+ WebSocketFailed ,
53+ ReconnectWebSocket ( usize ) ,
4754 InputTextChanged ( String ) ,
4855 SendMessage ( shared:: ClientMessage ) ,
4956}
5057
51- fn update ( msg : Msg , mut model : & mut Model , _ : & mut impl Orders < Msg > ) {
58+ fn update ( msg : Msg , mut model : & mut Model , orders : & mut impl Orders < Msg > ) {
5259 match msg {
60+ Msg :: WebSocketOpened => {
61+ model. web_socket_reconnector = None ;
62+ log ! ( "WebSocket connection is open now" ) ;
63+ }
5364 Msg :: MessageReceived ( message) => {
5465 log ! ( "Client received a message" ) ;
5566 model
5667 . messages
5768 . push ( message. json :: < shared:: ServerMessage > ( ) . unwrap ( ) . text ) ;
5869 }
5970 Msg :: CloseWebSocket => {
71+ model. web_socket_reconnector = None ;
6072 model
6173 . web_socket
6274 . close ( None , Some ( "user clicked Close button" ) )
@@ -69,6 +81,25 @@ fn update(msg: Msg, mut model: &mut Model, _: &mut impl Orders<Msg>) {
6981 log ! ( "Code:" , close_event. code( ) ) ;
7082 log ! ( "Reason:" , close_event. reason( ) ) ;
7183 log ! ( "==================" ) ;
84+
85+ // Chrome doesn't invoke `on_error` when the connection is lost.
86+ if !close_event. was_clean ( ) && model. web_socket_reconnector . is_none ( ) {
87+ model. web_socket_reconnector = Some (
88+ orders. stream_with_handle ( streams:: backoff ( None , Msg :: ReconnectWebSocket ) ) ,
89+ ) ;
90+ }
91+ }
92+ Msg :: WebSocketFailed => {
93+ log ! ( "WebSocket failed" ) ;
94+ if model. web_socket_reconnector . is_none ( ) {
95+ model. web_socket_reconnector = Some (
96+ orders. stream_with_handle ( streams:: backoff ( None , Msg :: ReconnectWebSocket ) ) ,
97+ ) ;
98+ }
99+ }
100+ Msg :: ReconnectWebSocket ( retries) => {
101+ log ! ( "Reconnect attempt:" , retries) ;
102+ model. web_socket = create_websocket ( orders) ;
72103 }
73104 Msg :: InputTextChanged ( input_text) => {
74105 model. input_text = input_text;
0 commit comments