UNPKG

@acransac/vtk.js

Version:

Visualization Toolkit for the Web

222 lines (179 loc) 6.42 kB
import macro from 'vtk.js/Sources/macro'; import vtkImageStream from 'vtk.js/Sources/IO/Core/ImageStream'; // ---------------------------------------------------------------------------- // Dependency injection // ---------------------------------------------------------------------------- let SMART_CONNECT_CLASS = null; // ---------------------------------------------------------------------------- function setSmartConnectClass(klass) { SMART_CONNECT_CLASS = klass; } // ---------------------------------------------------------------------------- // Busy feedback handling // ---------------------------------------------------------------------------- function busy(fn, update) { return (...args) => new Promise((resolve, reject) => { update(1); fn(...args).then( (response) => { update(-1); resolve(response); }, (error) => { update(-1); reject(error); } ); }); } // ---------------------------------------------------------------------------- function busyWrap(methodMap, update, skipList = []) { const busyContainer = {}; Object.keys(methodMap).forEach((methodName) => { if (skipList.indexOf(methodName) === -1) { busyContainer[methodName] = busy(methodMap[methodName], update); } else { busyContainer[methodName] = methodMap[methodName]; } }); return busyContainer; } // ---------------------------------------------------------------------------- // vtkWSLinkClient // ---------------------------------------------------------------------------- function vtkWSLinkClient(publicAPI, model) { // Set our className model.classHierarchy.push('vtkWSLinkClient'); // -------------------------------------------------------------------------- // Internal methods // -------------------------------------------------------------------------- function notifyBusy() { publicAPI.invokeBusyChange(model.busyCount); } // -------------------------------------------------------------------------- function updateBusy(delta = 0) { model.busyCount += delta; // Clear any pending timeout if (model.timeoutId) { clearTimeout(model.timeoutId); model.timeoutId = 0; } // Delay notification when idle if (model.busyCount) { notifyBusy(); } else { model.timeoutId = setTimeout(notifyBusy, model.notificationTimeout); } } // -------------------------------------------------------------------------- // Public methods // -------------------------------------------------------------------------- publicAPI.beginBusy = () => updateBusy(+1); publicAPI.endBusy = () => updateBusy(-1); publicAPI.isBusy = () => !!model.busyCount; publicAPI.isConnected = () => !!model.connection; // -------------------------------------------------------------------------- publicAPI.connect = (config = {}, configDecorator = null) => { if (!SMART_CONNECT_CLASS) { return Promise.reject(new Error('Need to provide SmartConnect')); } if (model.connection) { return Promise.reject(new Error('Need to disconnect first')); } model.config = config; model.configDecorator = configDecorator || model.configDecorator; return new Promise((resolve, reject) => { model.smartConnect = SMART_CONNECT_CLASS.newInstance({ config, configDecorator: model.configDecorator, }); // ready model.smartConnect.onConnectionReady((connection) => { model.connection = connection; model.remote = {}; model.config = model.smartConnect.getConfig(); const session = connection.getSession(); // Link remote API model.protocols = model.protocols || {}; Object.keys(model.protocols).forEach((name) => { model.remote[name] = busyWrap( model.protocols[name](session), updateBusy, model.notBusyList ); }); // Handle image stream if needed if (model.createImageStream) { model.imageStream = vtkImageStream.newInstance(); model.imageStream.connect(session); } // Forward ready info as well publicAPI.invokeConnectionReady(publicAPI); resolve(publicAPI); }); // error model.smartConnect.onConnectionError((error) => { publicAPI.invokeConnectionError(error); reject(error); }); // close model.smartConnect.onConnectionClose((close) => { publicAPI.invokeConnectionClose(close); reject(close); }); // Start connection model.smartConnect.connect(); }); }; // -------------------------------------------------------------------------- publicAPI.disconnect = (timeout = 60) => { if (model.connection) { model.connection.destroy(timeout); model.connection = null; } }; } // ---------------------------------------------------------------------------- // Object factory // ---------------------------------------------------------------------------- const DEFAULT_VALUES = { // protocols: null, // connection: null, // config: null, // imageStream notBusyList: [], busyCount: 0, timeoutId: 0, notificationTimeout: 50, createImageStream: true, // configDecorator: null, }; // ---------------------------------------------------------------------------- export function extend(publicAPI, model, initialValues = {}) { Object.assign(model, DEFAULT_VALUES, initialValues); // Object methods macro.obj(publicAPI, model); macro.setGet(publicAPI, model, [ 'protocols', 'notBusyList', 'createImageStream', 'configDecorator', ]); macro.get(publicAPI, model, [ 'connection', 'config', 'remote', 'imageStream', ]); macro.event(publicAPI, model, 'BusyChange'); macro.event(publicAPI, model, 'ConnectionReady'); macro.event(publicAPI, model, 'ConnectionError'); macro.event(publicAPI, model, 'ConnectionClose'); // Object specific methods vtkWSLinkClient(publicAPI, model); } // ---------------------------------------------------------------------------- export const newInstance = macro.newInstance(extend, 'vtkWSLinkClient'); // ---------------------------------------------------------------------------- export default { newInstance, extend, setSmartConnectClass };