@kitware/wslink 2.5.0 → 2.5.4
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 +5 -4
- package/src/CompositeClosureHelper/index.js +5 -2
- package/src/WsLinkClient/index.d.ts +196 -0
- package/src/WsLinkClient/index.js +226 -0
- package/src/index.js +2 -0
- package/dist/wslink.mjs +0 -1474
- package/dist/wslink.umd.js +0 -1
package/package.json
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kitware/wslink",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.4",
|
|
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/
|
|
7
|
+
"url": "git+https://github.com/Kitware/wslink.git",
|
|
8
|
+
"directory": "js-lib"
|
|
8
9
|
},
|
|
9
10
|
"bugs": {
|
|
10
|
-
"url": "https://github.com/
|
|
11
|
+
"url": "https://github.com/Kitware/wslink/issues"
|
|
11
12
|
},
|
|
12
|
-
"homepage": "https://github.com/
|
|
13
|
+
"homepage": "https://github.com/Kitware/wslink#readme",
|
|
13
14
|
"main": "dist/wslink.umd.js",
|
|
14
15
|
"scripts": {
|
|
15
16
|
"format": "prettier src --write",
|
|
@@ -74,7 +74,7 @@ function destroy(publicAPI, model = {}) {
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
// ----------------------------------------------------------------------------
|
|
77
|
-
// Event handling: onXXX(callback), fireXXX(args...)
|
|
77
|
+
// Event handling: onXXX(callback), fireXXX(args...) or invokeXXX(args...)
|
|
78
78
|
// ----------------------------------------------------------------------------
|
|
79
79
|
|
|
80
80
|
function event(publicAPI, model, eventName, asynchronous = true) {
|
|
@@ -92,7 +92,7 @@ function event(publicAPI, model, eventName, asynchronous = true) {
|
|
|
92
92
|
return Object.freeze({ unsubscribe });
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
const triggerEvent = (...args) => {
|
|
96
96
|
if (model.deleted) {
|
|
97
97
|
console.log("instance deleted - can not call any method");
|
|
98
98
|
return;
|
|
@@ -117,6 +117,9 @@ function event(publicAPI, model, eventName, asynchronous = true) {
|
|
|
117
117
|
}
|
|
118
118
|
};
|
|
119
119
|
|
|
120
|
+
publicAPI[`fire${capitalize(eventName)}`] = triggerEvent;
|
|
121
|
+
publicAPI[`invoke${capitalize(eventName)}`] = triggerEvent;
|
|
122
|
+
|
|
120
123
|
publicAPI[`on${capitalize(eventName)}`] = (callback) => {
|
|
121
124
|
if (model.deleted) {
|
|
122
125
|
console.log("instance deleted - can not call any method");
|
|
@@ -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,226 @@
|
|
|
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
|
+
// Forward ready info as well
|
|
126
|
+
publicAPI.invokeConnectionReady(publicAPI);
|
|
127
|
+
|
|
128
|
+
resolve(publicAPI);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// error
|
|
132
|
+
model.smartConnect.onConnectionError((error) => {
|
|
133
|
+
publicAPI.invokeConnectionError(error);
|
|
134
|
+
reject(error);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// close
|
|
138
|
+
model.smartConnect.onConnectionClose((close) => {
|
|
139
|
+
publicAPI.invokeConnectionClose(close);
|
|
140
|
+
reject(close);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// Start connection
|
|
144
|
+
model.smartConnect.connect();
|
|
145
|
+
});
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
// --------------------------------------------------------------------------
|
|
149
|
+
|
|
150
|
+
publicAPI.disconnect = (timeout = 60) => {
|
|
151
|
+
if (model.connection) {
|
|
152
|
+
model.connection.destroy(timeout);
|
|
153
|
+
model.connection = null;
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// --------------------------------------------------------------------------
|
|
158
|
+
|
|
159
|
+
publicAPI.registerProtocol = (name, protocol) => {
|
|
160
|
+
model.remote[name] = busyWrap(
|
|
161
|
+
protocol(model.connection.getSession()),
|
|
162
|
+
updateBusy,
|
|
163
|
+
model.notBusyList
|
|
164
|
+
);
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
// --------------------------------------------------------------------------
|
|
168
|
+
|
|
169
|
+
publicAPI.unregisterProtocol = (name) => {
|
|
170
|
+
delete model.remote[name];
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// ----------------------------------------------------------------------------
|
|
175
|
+
// Object factory
|
|
176
|
+
// ----------------------------------------------------------------------------
|
|
177
|
+
|
|
178
|
+
const DEFAULT_VALUES = {
|
|
179
|
+
// protocols: null,
|
|
180
|
+
// connection: null,
|
|
181
|
+
// config: null,
|
|
182
|
+
notBusyList: [],
|
|
183
|
+
busyCount: 0,
|
|
184
|
+
timeoutId: 0,
|
|
185
|
+
notificationTimeout: 50,
|
|
186
|
+
// configDecorator: null,
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
// ----------------------------------------------------------------------------
|
|
190
|
+
|
|
191
|
+
export function extend(publicAPI, model, initialValues = {}) {
|
|
192
|
+
Object.assign(model, DEFAULT_VALUES, initialValues);
|
|
193
|
+
|
|
194
|
+
// Object methods
|
|
195
|
+
CompositeClosureHelper.set(publicAPI, model, [
|
|
196
|
+
"protocols",
|
|
197
|
+
"notBusyList",
|
|
198
|
+
"configDecorator",
|
|
199
|
+
]);
|
|
200
|
+
CompositeClosureHelper.get(publicAPI, model, [
|
|
201
|
+
"connection",
|
|
202
|
+
"config",
|
|
203
|
+
"remote",
|
|
204
|
+
"protocols",
|
|
205
|
+
"notBusyList",
|
|
206
|
+
"configDecorator",
|
|
207
|
+
]);
|
|
208
|
+
CompositeClosureHelper.event(publicAPI, model, "BusyChange");
|
|
209
|
+
CompositeClosureHelper.event(publicAPI, model, "ConnectionReady");
|
|
210
|
+
CompositeClosureHelper.event(publicAPI, model, "ConnectionError");
|
|
211
|
+
CompositeClosureHelper.event(publicAPI, model, "ConnectionClose");
|
|
212
|
+
|
|
213
|
+
// Object specific methods
|
|
214
|
+
vtkWSLinkClient(publicAPI, model);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// ----------------------------------------------------------------------------
|
|
218
|
+
|
|
219
|
+
export const newInstance = CompositeClosureHelper.newInstance(
|
|
220
|
+
extend,
|
|
221
|
+
"vtkWSLinkClient"
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
// ----------------------------------------------------------------------------
|
|
225
|
+
|
|
226
|
+
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
|
};
|