@kitware/wslink 2.5.0 → 2.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,15 +1,16 @@
1
1
  {
2
2
  "name": "@kitware/wslink",
3
- "version": "2.5.0",
3
+ "version": "2.5.3",
4
4
  "description": "Rpc and pub/sub between Python and JavaScript over WebSockets",
5
5
  "repository": {
6
6
  "type": "git",
7
- "url": "git+https://github.com/kitware/wslink.git"
7
+ "url": "git+https://github.com/Kitware/wslink.git",
8
+ "directory": "js-lib"
8
9
  },
9
10
  "bugs": {
10
- "url": "https://github.com/kitware/wslink/issues"
11
+ "url": "https://github.com/Kitware/wslink/issues"
11
12
  },
12
- "homepage": "https://github.com/kitware/wslink#readme",
13
+ "homepage": "https://github.com/Kitware/wslink#readme",
13
14
  "main": "dist/wslink.umd.js",
14
15
  "scripts": {
15
16
  "format": "prettier src --write",
@@ -0,0 +1,196 @@
1
+ export interface vtkSubscription {
2
+ unsubscribe(): void;
3
+ }
4
+
5
+ /**
6
+ * Bind optional dependency from WSLink to our current class.
7
+ * This is mandatory when using that class
8
+ *
9
+ * ```
10
+ * import SmartConnect from 'wslink/src/SmartConnect';
11
+ * import vtkWSLinkClient from '@kitware/vtk.js/IO/Core/WSLinkClient';
12
+ *
13
+ * vtkWSLinkClient.setSmartConnectClass(SmartConnect);
14
+ * ```
15
+ *
16
+ * @param smartConnectClass
17
+ */
18
+ export function setSmartConnectClass(smartConnectClass: object): void;
19
+
20
+ export interface vtkWSLinkClient {
21
+ /**
22
+ * Virtually increase work load to maybe keep isBusy() on
23
+ * while executing a synchronous task.
24
+ */
25
+ beginBusy(): void;
26
+
27
+ /**
28
+ * Virtually decreasing work load to maybe free isBusy()
29
+ * after executing a synchronous task. Other async calls
30
+ * could still keep the state as busy.
31
+ */
32
+ endBusy(): void;
33
+
34
+ /**
35
+ * Return the current state of busy.
36
+ * Do we still have pending calls?
37
+ */
38
+ isBusy(): boolean;
39
+
40
+ /**
41
+ * Return true if the client is currently connected to a server
42
+ */
43
+ isConnected(): boolean;
44
+
45
+ /**
46
+ * Initiate the connection with the server
47
+ * @param {Object} config
48
+ * @param {Function} [configDecorator] (default: null)
49
+ */
50
+ connect(
51
+ config: object,
52
+ configDecorator?: (config: object) => object,
53
+ ): Promise<vtkWSLinkClient>;
54
+
55
+ /**
56
+ * Disconnect from server
57
+ * @param {Number} timeout amount of second to wait before the server exit as well. If we want to avoid the server from quitting, `-1` should be provided. (default=60)
58
+ */
59
+ disconnect(timeout: number): void;
60
+
61
+ /**
62
+ * Register dynamically a protocol after being connected
63
+ *
64
+ * @param {String} name
65
+ * @param {Function} protocol
66
+ */
67
+ registerProtocol(name: string, protocol: (session: object) => object): void;
68
+
69
+ /**
70
+ * Remove a given protocol from the available list
71
+ *
72
+ * @param {String} name
73
+ */
74
+ unregisterProtocol(name: string): void;
75
+
76
+ // --- via macro --
77
+
78
+ /**
79
+ * Assign protocols to the client. Those will only be used at connect time and therefore needs to be set before being connected otherwise `registerProtocol` should be used instead.
80
+ * @returns {Boolean} true if the set method modified the object
81
+ */
82
+ setProtocols(protocols: Record<string, any>): boolean;
83
+
84
+ /**
85
+ * Get protocols that were either provided in `newInstance` or via its set
86
+ */
87
+ getProtocols(): Record<string, any>;
88
+
89
+ /**
90
+ * Update the list of methods that should be ignore from the busy state monitoring
91
+ * @returns {Boolean} true if the set method modified the object
92
+ */
93
+ setNotBusyList(methodList: [string]): boolean;
94
+
95
+ /**
96
+ * @returns {object} the current set of methods to ignore from busy state
97
+ */
98
+ getNotBusyList(): object;
99
+
100
+ /**
101
+ * Should the client auto listen to image stream topic by creating its imageStream object
102
+ * @param {Boolean} autoCreate (default: true)
103
+ * @returns {Boolean} true if the set method modified the object
104
+ */
105
+ setCreateImageStream(autoCreate: boolean): boolean;
106
+
107
+ /**
108
+ * @returns {Boolean} the autoCreate state for imageStream
109
+ */
110
+ getCreateImageStream(): boolean;
111
+
112
+ /**
113
+ * Set a config decorator to possibly alternate the config object that get received from the launcher.
114
+ * @param decorator function for config object
115
+ */
116
+ setConfigDecorator(decorator: (config: object) => object): boolean;
117
+
118
+ /**
119
+ * @returns {Function} configDecorator function if any was provided
120
+ */
121
+ getConfigDecorator(): (config: object) => object;
122
+
123
+ /**
124
+ *
125
+ */
126
+ getConnection(): any;
127
+
128
+ /**
129
+ *
130
+ */
131
+ getConfig(): object;
132
+
133
+ /**
134
+ *
135
+ */
136
+ getRemote(): Record<string, any>;
137
+
138
+ /**
139
+ *
140
+ */
141
+ getImageStream(): vtkImageStream;
142
+
143
+ /**
144
+ *
145
+ * @param callback
146
+ * @param priority
147
+ */
148
+ onBusyChange(callback: Function, priority: number): vtkSubscription;
149
+
150
+ /**
151
+ *
152
+ */
153
+ invokeBusyChange(): void;
154
+
155
+ onConnectionReady(callback: (httpReq: any) => void): vtkSubscription;
156
+ // invokeConnectionReady(): void
157
+
158
+ onConnectionError(callback: (httpReq: any) => void): vtkSubscription;
159
+ // invokeConnectionError(): void
160
+
161
+ onConnectionClose(callback: (httpReq: any) => void): vtkSubscription;
162
+ // invokeConnectionClose(): void
163
+ }
164
+
165
+ /**
166
+ * Method use to decorate a given object (publicAPI+model) with vtkWSLinkClient characteristics.
167
+ *
168
+ * @param publicAPI object on which methods will be bounds (public)
169
+ * @param model object on which data structure will be bounds (protected)
170
+ * @param {object} [initialValues] (default: {})
171
+ */
172
+ export function extend(
173
+ publicAPI: object,
174
+ model: object,
175
+ initialValues?: object,
176
+ ): void;
177
+
178
+ // ----------------------------------------------------------------------------
179
+
180
+ /**
181
+ * Method use to create a new instance of vtkWSLinkClient
182
+ * @param {object} [initialValues] for pre-setting some of its content
183
+ */
184
+ export function newInstance(initialValues?: object): vtkWSLinkClient;
185
+
186
+ /**
187
+ * vtkWSLinkClient is a WSLink client for talking to a server over WebSocket
188
+ */
189
+ export declare const vtkWSLinkClient: {
190
+ newInstance: typeof newInstance;
191
+ extend: typeof extend;
192
+ // static
193
+ setSmartConnectClass: typeof setSmartConnectClass;
194
+ };
195
+
196
+ export default vtkWSLinkClient;
@@ -0,0 +1,237 @@
1
+ import CompositeClosureHelper from "../CompositeClosureHelper";
2
+ // ----------------------------------------------------------------------------
3
+ // Dependency injection
4
+ // ----------------------------------------------------------------------------
5
+
6
+ let SMART_CONNECT_CLASS = null;
7
+
8
+ // ----------------------------------------------------------------------------
9
+
10
+ function setSmartConnectClass(klass) {
11
+ SMART_CONNECT_CLASS = klass;
12
+ }
13
+
14
+ // ----------------------------------------------------------------------------
15
+ // Busy feedback handling
16
+ // ----------------------------------------------------------------------------
17
+
18
+ function busy(fn, update) {
19
+ return (...args) =>
20
+ new Promise((resolve, reject) => {
21
+ update(1);
22
+ fn(...args).then(
23
+ (response) => {
24
+ update(-1);
25
+ resolve(response);
26
+ },
27
+ (error) => {
28
+ update(-1);
29
+ reject(error);
30
+ }
31
+ );
32
+ });
33
+ }
34
+
35
+ // ----------------------------------------------------------------------------
36
+
37
+ function busyWrap(methodMap, update, skipList = []) {
38
+ const busyContainer = {};
39
+ Object.keys(methodMap).forEach((methodName) => {
40
+ if (skipList.indexOf(methodName) === -1) {
41
+ busyContainer[methodName] = busy(methodMap[methodName], update);
42
+ } else {
43
+ busyContainer[methodName] = methodMap[methodName];
44
+ }
45
+ });
46
+ return busyContainer;
47
+ }
48
+
49
+ // ----------------------------------------------------------------------------
50
+ // vtkWSLinkClient
51
+ // ----------------------------------------------------------------------------
52
+
53
+ function vtkWSLinkClient(publicAPI, model) {
54
+ // --------------------------------------------------------------------------
55
+ // Internal methods
56
+ // --------------------------------------------------------------------------
57
+
58
+ function notifyBusy() {
59
+ publicAPI.invokeBusyChange(model.busyCount);
60
+ }
61
+
62
+ // --------------------------------------------------------------------------
63
+
64
+ function updateBusy(delta = 0) {
65
+ model.busyCount += delta;
66
+
67
+ // Clear any pending timeout
68
+ if (model.timeoutId) {
69
+ clearTimeout(model.timeoutId);
70
+ model.timeoutId = 0;
71
+ }
72
+
73
+ // Delay notification when idle
74
+ if (model.busyCount) {
75
+ notifyBusy();
76
+ } else {
77
+ model.timeoutId = setTimeout(notifyBusy, model.notificationTimeout);
78
+ }
79
+ }
80
+
81
+ // --------------------------------------------------------------------------
82
+ // Public methods
83
+ // --------------------------------------------------------------------------
84
+
85
+ publicAPI.beginBusy = () => updateBusy(+1);
86
+ publicAPI.endBusy = () => updateBusy(-1);
87
+ publicAPI.isBusy = () => !!model.busyCount;
88
+ publicAPI.isConnected = () => !!model.connection;
89
+
90
+ // --------------------------------------------------------------------------
91
+
92
+ publicAPI.connect = (config = {}, configDecorator = null) => {
93
+ if (!SMART_CONNECT_CLASS) {
94
+ return Promise.reject(new Error("Need to provide SmartConnect"));
95
+ }
96
+ if (model.connection) {
97
+ return Promise.reject(new Error("Need to disconnect first"));
98
+ }
99
+
100
+ model.config = config;
101
+ model.configDecorator = configDecorator || model.configDecorator;
102
+ return new Promise((resolve, reject) => {
103
+ model.smartConnect = SMART_CONNECT_CLASS.newInstance({
104
+ config,
105
+ configDecorator: model.configDecorator,
106
+ });
107
+
108
+ // ready
109
+ model.smartConnect.onConnectionReady((connection) => {
110
+ model.connection = connection;
111
+ model.remote = {};
112
+ model.config = model.smartConnect.getConfig();
113
+ const session = connection.getSession();
114
+
115
+ // Link remote API
116
+ model.protocols = model.protocols || {};
117
+ Object.keys(model.protocols).forEach((name) => {
118
+ model.remote[name] = busyWrap(
119
+ model.protocols[name](session),
120
+ updateBusy,
121
+ model.notBusyList
122
+ );
123
+ });
124
+
125
+ // Handle image stream if needed
126
+ if (model.createImageStream) {
127
+ model.imageStream = vtkImageStream.newInstance();
128
+ model.imageStream.connect(session);
129
+ }
130
+
131
+ // Forward ready info as well
132
+ publicAPI.invokeConnectionReady(publicAPI);
133
+
134
+ resolve(publicAPI);
135
+ });
136
+
137
+ // error
138
+ model.smartConnect.onConnectionError((error) => {
139
+ publicAPI.invokeConnectionError(error);
140
+ reject(error);
141
+ });
142
+
143
+ // close
144
+ model.smartConnect.onConnectionClose((close) => {
145
+ publicAPI.invokeConnectionClose(close);
146
+ reject(close);
147
+ });
148
+
149
+ // Start connection
150
+ model.smartConnect.connect();
151
+ });
152
+ };
153
+
154
+ // --------------------------------------------------------------------------
155
+
156
+ publicAPI.disconnect = (timeout = 60) => {
157
+ if (model.connection) {
158
+ model.connection.destroy(timeout);
159
+ model.connection = null;
160
+ }
161
+ };
162
+
163
+ // --------------------------------------------------------------------------
164
+
165
+ publicAPI.registerProtocol = (name, protocol) => {
166
+ model.remote[name] = busyWrap(
167
+ protocol(model.connection.getSession()),
168
+ updateBusy,
169
+ model.notBusyList
170
+ );
171
+ };
172
+
173
+ // --------------------------------------------------------------------------
174
+
175
+ publicAPI.unregisterProtocol = (name) => {
176
+ delete model.remote[name];
177
+ };
178
+ }
179
+
180
+ // ----------------------------------------------------------------------------
181
+ // Object factory
182
+ // ----------------------------------------------------------------------------
183
+
184
+ const DEFAULT_VALUES = {
185
+ // protocols: null,
186
+ // connection: null,
187
+ // config: null,
188
+ // imageStream
189
+ notBusyList: [],
190
+ busyCount: 0,
191
+ timeoutId: 0,
192
+ notificationTimeout: 50,
193
+ createImageStream: true,
194
+ // configDecorator: null,
195
+ };
196
+
197
+ // ----------------------------------------------------------------------------
198
+
199
+ export function extend(publicAPI, model, initialValues = {}) {
200
+ Object.assign(model, DEFAULT_VALUES, initialValues);
201
+
202
+ // Object methods
203
+ CompositeClosureHelper.set(publicAPI, model, [
204
+ "protocols",
205
+ "notBusyList",
206
+ "createImageStream",
207
+ "configDecorator",
208
+ ]);
209
+ CompositeClosureHelper.get(publicAPI, model, [
210
+ "connection",
211
+ "config",
212
+ "remote",
213
+ "imageStream",
214
+ "protocols",
215
+ "notBusyList",
216
+ "createImageStream",
217
+ "configDecorator",
218
+ ]);
219
+ CompositeClosureHelper.event(publicAPI, model, "BusyChange");
220
+ CompositeClosureHelper.event(publicAPI, model, "ConnectionReady");
221
+ CompositeClosureHelper.event(publicAPI, model, "ConnectionError");
222
+ CompositeClosureHelper.event(publicAPI, model, "ConnectionClose");
223
+
224
+ // Object specific methods
225
+ vtkWSLinkClient(publicAPI, model);
226
+ }
227
+
228
+ // ----------------------------------------------------------------------------
229
+
230
+ export const newInstance = CompositeClosureHelper.newInstance(
231
+ extend,
232
+ "vtkWSLinkClient"
233
+ );
234
+
235
+ // ----------------------------------------------------------------------------
236
+
237
+ export default { newInstance, extend, setSmartConnectClass };
package/src/index.js CHANGED
@@ -2,10 +2,12 @@ import CompositeClosureHelper from "./CompositeClosureHelper";
2
2
  import ProcessLauncher from "./ProcessLauncher";
3
3
  import SmartConnect from "./SmartConnect";
4
4
  import WebsocketConnection from "./WebsocketConnection";
5
+ import WsLinkClient from "./WsLinkClient";
5
6
 
6
7
  export {
7
8
  CompositeClosureHelper,
8
9
  ProcessLauncher,
9
10
  SmartConnect,
10
11
  WebsocketConnection,
12
+ WsLinkClient,
11
13
  };