11import { mountLayout } from "idom-client-react" ;
2+ import { unmountComponentAtNode } from "react-dom" ;
3+
4+ const maxReconnectTimeout = 45 ;
5+ const initialReconnectTimeoutRange = 5 ;
26
37const userPackages = import ( "./user-packages.js" ) . then ( ( module ) => {
48 for ( const pkgName in module . default ) {
@@ -8,23 +12,6 @@ const userPackages = import("./user-packages.js").then((module) => {
812 }
913} ) ;
1014
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-
2815function defaultWebSocketEndpoint ( ) {
2916 const uri = document . location . hostname + ":" + document . location . port ;
3017 const url = ( uri + document . location . pathname ) . split ( "/" ) . slice ( 0 , - 1 ) ;
@@ -40,3 +27,71 @@ function defaultWebSocketEndpoint() {
4027
4128 return protocol + "//" + url . join ( "/" ) + window . location . search ;
4229}
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