diff --git a/ivette/src/frama-c/server.js b/ivette/src/frama-c/server.js index 0f89e8c781740bacdaf3f5b88029f1815d7435e3..dcbaf7248a94cff3cc0d007bfef6f7a8a9781ba3 100644 --- a/ivette/src/frama-c/server.js +++ b/ivette/src/frama-c/server.js @@ -620,7 +620,7 @@ function off( id , callback ) } /** - @summary Hook on Signal (Custom React Hook) + @summary Hook on Signal (Custom React Hook). @param {string} id - the signal event that was listen to @param {function} callback - the callback to remove */ diff --git a/ivette/src/frama-c/states.js b/ivette/src/frama-c/states.js index b95864b220cc48ddf0b4b9dcec00740c64d86322..3b24fb098c6dc395347e57647e5abd06a3fd8ece 100644 --- a/ivette/src/frama-c/states.js +++ b/ivette/src/frama-c/states.js @@ -53,7 +53,6 @@ Server.onReady(() => { Server.onShutdown(() => { currentProject = undefined ; globalStates = {} ; - globalSync = {} ; Dome.emit(PROJECT); }); @@ -127,7 +126,8 @@ export function useState(id) // --- Synchronized States // -------------------------------------------------------------------------- -class Synchro { +// shared for all projects +class SyncState { constructor(id) { this.id = id ; @@ -167,16 +167,23 @@ class Synchro { } -const synchros = {} ; -function synchro(id) { - let s = synchros[id] ; - if (!s) s = synchros[id] = new Synchro(id); +// -------------------------------------------------------------------------- +// --- Synchronized States Registry +// -------------------------------------------------------------------------- + +const syncStates = {} ; + +function syncState(id) { + let s = syncStates[id] ; + if (!s) s = syncStates[id] = new SyncState(id); return s ; } -Server.onReady(() => _.forEach( synchros , (s) => { - if (!s.insync) s.update(); -})); +Server.onShutdown(() => syncStates = {}); + +// -------------------------------------------------------------------------- +// --- Synchronized State Hooks +// -------------------------------------------------------------------------- /** @summary Use Synchronized State (Custom React Hook). @@ -190,8 +197,8 @@ Server.onReady(() => _.forEach( synchros , (s) => { */ export function useSyncState(id) { - let s = synchro(id) ; - Dome.useUpdate( s.UPDATE ); + let s = syncState(id) ; + Dome.useUpdate( PROJECT, s.UPDATE ); Server.useSignal( s.signal , s.update ); return [ s.value() , s.setValue ]; } @@ -204,15 +211,116 @@ export function useSyncState(id) Synchronization with some (projectified) server value: - sends a `<id>.get` request to obtain the current value of the state; - listens to `<id>.sig` signal to stay in sync with server updates. - */ +*/ export function useSyncValue(id) { - let s = synchro(id) ; + let s = syncState(id) ; Dome.useUpdate( s.update ); - React.useEffect( s.effect ); + Server.useSignal( s.signal , s.update ); return s.value(); } +// -------------------------------------------------------------------------- +// --- Synchronized Arrays +// -------------------------------------------------------------------------- + +// one per project +class SyncArray +{ + + constructor(id) { + this.UPDATE = STATE + id ; + this.signal = id + '.sig' ; + this.fetch_rq = id + '.fetch' ; + this.reload_rq = id + '.reload' ; + this.index = {} ; + this.insync = false ; + this.fetch = this.fetch.bind(this); + this.reload = this.reload.bind(this); + Dome.on( PROJECT , this.fetch ); + } + + getItems() { + if (!this.insync && Server.isRunning()) this.fetch(); + return this.items; + } + + fetch() { + this.insync = true ; + Server.sendGET( this.fetch_rq ).then(({ + reload=false, removed=[], updated=[], pending=0 + }) => { + if (reload) this.index = {}; + removed.forEach((id) => { + delete this.index[id]; + }); + updated.forEach((item) => { + this.index[item.id] = item; + }); + if (pending>0) this.fetch(); + Dome.emit( this.UPDATE ); + }); + } + + reload() { + Server.sendSET( this.reload_rq ); + this.index = {}; + this.insync = false ; + Dome.emit( this.UPDATE ); + } + +} + +// -------------------------------------------------------------------------- +// --- Synchronized Arrays Registry +// -------------------------------------------------------------------------- + +const syncArrays = {} ; // Model by project & id + +function syncArray(id) { + const path = [ currentProject , id ] ; + let a = _.get( syncArray , path ); + if (!a) { + a = new SyncArray(id); + _.set( syncArrays , path , a ); + } + return a; +} + +Server.onShutdown(() => syncArrays = {}); + +// -------------------------------------------------------------------------- +// --- Synchronized Array Hooks +// -------------------------------------------------------------------------- + +/** + @summary Force a Synchronized Array to Reload. + @description + Sends the `<id>.reload` request to the server for + triggering a complete array reload. + */ +export function reloadArray(id) +{ + syncArray(id).reload(); +} + +/** + @summary Use Synchronized Array (Custom React Hook). + @parameter {string} id - name of the server array + @return {object} items indexed by their identifiers + @description + Synchronization with some (projectified) server array: + - sends `<id>.fetch` requests to obtain the updated entries; + - listens to `<id>.sig` signal to stay in sync with server updates. + */ +export function useSyncArray(id) +{ + let a = syncArray(id); + Dome.useUpdate( PROJECT , a.UPDATE ); + Server.useSignal( a.signal , a.fetch ); + return a.getItems() ; +} + // -------------------------------------------------------------------------- export default { @@ -220,6 +328,8 @@ export default { useState, useSyncState, useSyncValue, + useSyncArray, + reloadArray, PROJECT, STATE };