@@ -41,38 +41,66 @@ const openWebSocket = (currentLocation: Location) => {
41
41
}
42
42
}
43
43
44
+ // https://exponentialbackoffcalculator.com
45
+ const backoffMs = ( n : number ) => Math . min ( 100 * Math . pow ( 2 , n ) , 10000 ) ;
46
+
44
47
export const websocketMiddleware = ( window : Window ) : Middleware => store => {
45
- const socket = openWebSocket ( window . location ) ;
48
+ let socket : WebSocket | null = null ;
49
+ let wasConnected = false ;
50
+ let reconnectAttempt = 0 ;
46
51
47
- if ( socket ) {
48
- socket . addEventListener ( 'open' , ( ) => {
49
- store . dispatch ( websocketConnected ( ) ) ;
50
- } ) ;
52
+ const connect = ( ) => {
53
+ socket = openWebSocket ( window . location ) ;
51
54
52
- socket . addEventListener ( 'close' , ( ) => {
53
- store . dispatch ( websocketDisconnected ( ) ) ;
54
- } ) ;
55
+ if ( socket ) {
56
+ socket . addEventListener ( 'open' , ( ) => {
57
+ store . dispatch ( websocketConnected ( ) ) ;
55
58
56
- socket . addEventListener ( 'error' , ( ) => {
57
- // We cannot get detailed information about the failure
58
- // https://stackoverflow.com/a/31003057/155423
59
- const error = 'Generic WebSocket Error' ;
60
- store . dispatch ( websocketError ( error ) ) ;
61
- reportWebSocketError ( error ) ;
62
- } ) ;
59
+ wasConnected = true ;
60
+ } ) ;
63
61
64
- // TODO: reconnect on error? (if ever connected? if < n failures?)
62
+ socket . addEventListener ( 'close' , ( event ) => {
63
+ store . dispatch ( websocketDisconnected ( ) ) ;
65
64
66
- socket . addEventListener ( 'message' , ( event ) => {
67
- try {
68
- const rawMessage = JSON . parse ( event . data ) ;
69
- const message = WSMessageResponse . parse ( rawMessage ) ;
70
- store . dispatch ( message ) ;
71
- } catch ( e ) {
72
- console . log ( 'Unable to parse WebSocket message' , event . data , e ) ;
73
- }
74
- } ) ;
75
- }
65
+ // Reconnect if we've previously connected
66
+ if ( wasConnected && ! event . wasClean ) {
67
+ wasConnected = false ;
68
+ reconnectAttempt = 0 ;
69
+ reconnect ( ) ;
70
+ }
71
+ } ) ;
72
+
73
+ socket . addEventListener ( 'error' , ( ) => {
74
+ // We cannot get detailed information about the failure
75
+ // https://stackoverflow.com/a/31003057/155423
76
+ const error = 'Generic WebSocket Error' ;
77
+ store . dispatch ( websocketError ( error ) ) ;
78
+ reportWebSocketError ( error ) ;
79
+ } ) ;
80
+
81
+ socket . addEventListener ( 'message' , ( event ) => {
82
+ try {
83
+ const rawMessage = JSON . parse ( event . data ) ;
84
+ const message = WSMessageResponse . parse ( rawMessage ) ;
85
+ store . dispatch ( message ) ;
86
+ } catch ( e ) {
87
+ console . log ( 'Unable to parse WebSocket message' , event . data , e ) ;
88
+ }
89
+ } ) ;
90
+ }
91
+ } ;
92
+
93
+ const reconnect = ( ) => {
94
+ if ( socket && socket . readyState == socket . OPEN ) { return ; }
95
+
96
+ connect ( ) ;
97
+
98
+ const delay = backoffMs ( reconnectAttempt ) ;
99
+ reconnectAttempt += 1 ;
100
+ setTimeout ( reconnect , delay ) ;
101
+ } ;
102
+
103
+ connect ( ) ;
76
104
77
105
return next => action => {
78
106
if ( socket && socket . readyState == socket . OPEN && sendActionOnWebsocket ( action ) ) {
0 commit comments