1
1
import { mountLayout } from "idom-client-react" ;
2
+ import { unmountComponentAtNode } from "react-dom" ;
3
+
4
+ const maxReconnectTimeout = 45 ;
5
+ const initialReconnectTimeoutRange = 5 ;
2
6
3
7
const userPackages = import ( "./user-packages.js" ) . then ( ( module ) => {
4
8
for ( const pkgName in module . default ) {
@@ -8,23 +12,6 @@ const userPackages = import("./user-packages.js").then((module) => {
8
12
}
9
13
} ) ;
10
14
11
- export function mountLayoutWithWebSocket ( element , endpoint , importSourceURL ) {
12
- const ws = new WebSocket ( endpoint || defaultWebSocketEndpoint ( ) ) ;
13
-
14
- function saveUpdateHook ( update ) {
15
- ws . onmessage = ( event ) => {
16
- const [ pathPrefix , patch ] = JSON . parse ( event . data ) ;
17
- update ( pathPrefix , patch ) ;
18
- } ;
19
- }
20
-
21
- function sendCallback ( event ) {
22
- ws . send ( JSON . stringify ( event ) ) ;
23
- }
24
-
25
- mountLayout ( element , saveUpdateHook , sendCallback , importSourceURL || "./" ) ;
26
- }
27
-
28
15
function defaultWebSocketEndpoint ( ) {
29
16
const uri = document . location . hostname + ":" + document . location . port ;
30
17
const url = ( uri + document . location . pathname ) . split ( "/" ) . slice ( 0 , - 1 ) ;
@@ -40,3 +27,71 @@ function defaultWebSocketEndpoint() {
40
27
41
28
return protocol + "//" + url . join ( "/" ) + window . location . search ;
42
29
}
30
+
31
+ export function mountLayoutWithWebSocket (
32
+ element ,
33
+ endpoint = defaultWebSocketEndpoint ( ) ,
34
+ importSourceURL = "./" ,
35
+ mountState = {
36
+ everMounted : false ,
37
+ reconnectAttempts : 0 ,
38
+ reconnectTimeoutRange : initialReconnectTimeoutRange ,
39
+ }
40
+ ) {
41
+ const socket = new WebSocket ( endpoint ) ;
42
+
43
+ let resolveUpdateHook = null ;
44
+ let rejectUpdateHook = null ;
45
+ const updateHookPromise = new Promise ( ( resolve , reject ) => {
46
+ resolveUpdateHook = resolve ;
47
+ rejectUpdateHook = reject ;
48
+ } ) ;
49
+
50
+ socket . onopen = ( event ) => {
51
+ console . log ( `Connected to ${ endpoint } ` ) ;
52
+ if ( mountState . everMounted ) {
53
+ unmountComponentAtNode ( element ) ;
54
+ }
55
+ mountLayout (
56
+ element ,
57
+ ( updateHook ) => resolveUpdateHook ( updateHook ) ,
58
+ ( event ) => socket . send ( JSON . stringify ( event ) ) ,
59
+ importSourceURL
60
+ ) ;
61
+ _setOpenMountState ( mountState ) ;
62
+ } ;
63
+
64
+ socket . onmessage = ( event ) => {
65
+ updateHookPromise . then ( ( update ) => {
66
+ const [ pathPrefix , patch ] = JSON . parse ( event . data ) ;
67
+ update ( pathPrefix , patch ) ;
68
+ } ) ;
69
+ } ;
70
+
71
+ socket . onclose = ( event ) => {
72
+ const reconnectTimeout = _nextReconnectTimeout ( mountState ) ;
73
+ console . log ( `Connection lost, reconnecting in ${ reconnectTimeout } seconds` ) ;
74
+ setTimeout ( function ( ) {
75
+ mountState . reconnectAttempts ++ ;
76
+ mountLayoutWithWebSocket ( element , endpoint , importSourceURL , mountState ) ;
77
+ } , reconnectTimeout * 1000 ) ;
78
+ } ;
79
+ }
80
+
81
+ function _setOpenMountState ( mountState ) {
82
+ mountState . everMounted = true ;
83
+ mountState . reconnectAttempts = 0 ;
84
+ mountState . reconnectTimeoutRange = initialReconnectTimeoutRange ;
85
+ }
86
+
87
+ function _nextReconnectTimeout ( mountState ) {
88
+ const timeout = Math . floor ( Math . random ( ) * mountState . reconnectTimeoutRange ) ;
89
+ mountState . reconnectTimeoutRange =
90
+ ( mountState . reconnectTimeoutRange + 5 ) % maxReconnectTimeout ;
91
+ if ( mountState . reconnectAttempts == 3 ) {
92
+ window . alert (
93
+ "Server connection was lost. Attempts to reconnect are being made in the background."
94
+ ) ;
95
+ }
96
+ return timeout ;
97
+ }
0 commit comments