@@ -29,6 +29,8 @@ export class RemoteSession {
2929 this . networkFetchStatus = null ;
3030 this . cameraIds = new Set ( ) ;
3131 this . stateCache = { } ;
32+ this . progressCallbacks = new Set ( ) ;
33+ this . progressState = null ;
3234 // FIXME - remove when VTK>=9.5
3335 this . renderWindowIds = new Set ( ) ;
3436 this . renderWindowIdToInteractorId = new Map ( ) ;
@@ -116,6 +118,52 @@ export class RemoteSession {
116118 this . networkFetchStatus = fetchStatus ;
117119 }
118120
121+ /**
122+ * Register a callback to monitor download progress.
123+ *
124+ * @param {Function } callback
125+ * @returns {Function } cleanup function
126+ */
127+ addProgressCallback ( callback ) {
128+ if ( callback ) {
129+ this . progressCallbacks . add ( callback ) ;
130+ }
131+ return ( ) => {
132+ this . progressCallbacks . delete ( callback ) ;
133+ } ;
134+ }
135+
136+ emitProgress ( ) {
137+ if ( ! this . progressCallbacks . size || ! this . progressState ) {
138+ return ;
139+ }
140+ const { active, state, hash } = this . progressState ;
141+ const payload = {
142+ active,
143+ state : {
144+ current : state . current ,
145+ total : state . total ,
146+ } ,
147+ hash : {
148+ current : hash . current ,
149+ total : hash . total ,
150+ } ,
151+ } ;
152+ this . progressCallbacks . forEach ( ( cb ) => cb ( payload ) ) ;
153+ }
154+
155+ incrementProgress ( kind ) {
156+ if ( ! this . progressState ) {
157+ return ;
158+ }
159+ const bucket = this . progressState [ kind ] ;
160+ if ( ! bucket ) {
161+ return ;
162+ }
163+ bucket . current = Math . min ( bucket . current + 1 , bucket . total ) ;
164+ this . emitProgress ( ) ;
165+ }
166+
119167 /**
120168 * Free old blobs if they go beyond the allowed cache size in Bytes
121169 * starting with the older ones.
@@ -164,7 +212,9 @@ export class RemoteSession {
164212 */
165213 async fetchState ( vtkId ) {
166214 const serverState = await this . networkFetchState ( vtkId ) ;
167- return this . patchState ( serverState ) ;
215+ const patchedState = this . patchState ( serverState ) ;
216+ this . incrementProgress ( "state" ) ;
217+ return patchedState ;
168218 }
169219
170220 /**
@@ -221,17 +271,19 @@ export class RemoteSession {
221271 * @returns typed array matching blob content
222272 */
223273 async fetchHash ( hash ) {
274+ let array ;
224275 // pendingArray only filled via pushHash
225276 if ( this . pendingArrays [ hash ] ) {
226277 await this . pendingArrays [ hash ] ;
227278 this . hashesMTime [ hash ] = this . currentMTime ;
228279 delete this . pendingArrays [ hash ] ;
229- return ;
280+ } else {
281+ // regular network call
282+ array = await this . networkFetchHash ( hash ) ;
283+ this . sceneManager . registerBlob ( hash , array ) ;
284+ this . hashesMTime [ hash ] = this . currentMTime ;
230285 }
231- // regular network call
232- const array = await this . networkFetchHash ( hash ) ;
233- this . sceneManager . registerBlob ( hash , array ) ;
234- this . hashesMTime [ hash ] = this . currentMTime ;
286+ this . incrementProgress ( "hash" ) ;
235287 return array ;
236288 }
237289
@@ -274,8 +326,8 @@ export class RemoteSession {
274326
275327 try {
276328 const serverStatus = await this . networkFetchStatus ( vtkId ) ;
277- const pendingHashes = [ ] ;
278- const pendingStates = [ ] ;
329+ const hashesToFetch = [ ] ;
330+ const statesToFetch = [ ] ;
279331
280332 // Handle forcepush if any
281333 const resetIds = serverStatus . force_push || [ ] ;
@@ -286,18 +338,29 @@ export class RemoteSession {
286338 // Fetch any state that needs update
287339 serverStatus . ids . forEach ( ( [ vtkId , mtime ] ) => {
288340 if ( ! this . stateMTimes [ vtkId ] || this . stateMTimes [ vtkId ] < mtime ) {
289- pendingStates . push ( this . fetchState ( vtkId ) ) ;
341+ statesToFetch . push ( vtkId ) ;
290342 }
291343 } ) ;
292344
293345 // Fetch any blob that is missing
294346 serverStatus . hashes . forEach ( ( hash ) => {
295347 if ( ! this . hashesMTime [ hash ] ) {
296- pendingHashes . push ( this . fetchHash ( hash ) ) ;
348+ hashesToFetch . push ( hash ) ;
297349 }
298350 this . hashesMTime [ hash ] = this . currentMTime ;
299351 } ) ;
300352
353+ this . progressState = {
354+ active : ! ! ( statesToFetch . length + hashesToFetch . length ) ,
355+ state : { current : 0 , total : statesToFetch . length } ,
356+ hash : { current : 0 , total : hashesToFetch . length } ,
357+ } ;
358+ this . emitProgress ( ) ;
359+ const pendingStates = statesToFetch . map ( ( stateId ) =>
360+ this . fetchState ( stateId ) ,
361+ ) ;
362+ const pendingHashes = hashesToFetch . map ( ( hash ) => this . fetchHash ( hash ) ) ;
363+
301364 // Capture cameras
302365 serverStatus . cameras . forEach ( ( v ) => this . cameraIds . add ( Number ( v ) ) ) ;
303366
@@ -344,6 +407,11 @@ export class RemoteSession {
344407 } catch ( e ) {
345408 console . error ( "Error in update" , e ) ;
346409 } finally {
410+ if ( this . progressState ) {
411+ this . progressState . active = false ;
412+ this . emitProgress ( ) ;
413+ this . progressState = null ;
414+ }
347415 this . updateInProgress -- ;
348416 if ( this . updateInProgress ) {
349417 this . updateInProgress = 0 ;
0 commit comments