libshv-js 7.2.0 → 8.0.0
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/dist/access.js +1 -5
- package/dist/chainpack.d.ts +3 -3
- package/dist/chainpack.js +28 -35
- package/dist/cpcontext.js +1 -5
- package/dist/cpon.d.ts +2 -2
- package/dist/cpon.js +31 -40
- package/dist/index.d.ts +9 -9
- package/dist/index.js +9 -25
- package/dist/json.d.ts +1 -1
- package/dist/json.js +19 -24
- package/dist/rpcmessage.d.ts +1 -1
- package/dist/rpcmessage.js +19 -25
- package/dist/rpcvalue.js +2 -17
- package/dist/shv-ri.js +1 -5
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +2 -7
- package/dist/ws-client.d.ts +3 -3
- package/dist/ws-client.js +153 -159
- package/package.json +2 -1
package/dist/ws-client.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const rpcmessage_1 = require("./rpcmessage");
|
|
8
|
-
const rpcvalue_1 = require("./rpcvalue");
|
|
9
|
-
const utils_1 = require("./utils");
|
|
1
|
+
import { accessLevelFromAccessString } from './access.js';
|
|
2
|
+
import { ChainPackReader, CHAINPACK_PROTOCOL_TYPE, ChainPackWriter, toChainPack } from './chainpack.js';
|
|
3
|
+
import { CPON_PROTOCOL_TYPE, toCpon } from './cpon.js';
|
|
4
|
+
import { ERROR_MESSAGE, ErrorCode, ERROR_CODE, isSignal, isRequest, isResponse, ERROR_DATA, RPC_MESSAGE_METHOD, RPC_MESSAGE_SHV_PATH, RPC_MESSAGE_REQUEST_ID, RPC_MESSAGE_PARAMS, RPC_MESSAGE_ERROR, RPC_MESSAGE_RESULT, RPC_MESSAGE_CALLER_IDS, RPC_MESSAGE_DELAY, RPC_MESSAGE_ABORT, RPC_MESSAGE_ACCESS_LEVEL, RPC_MESSAGE_USER_ID } from './rpcmessage.js';
|
|
5
|
+
import { makeMap, makeIMap, RpcValueWithMetaData, makeMetaMap, Double } from './rpcvalue.js';
|
|
6
|
+
import { resolveRI } from './utils.js';
|
|
10
7
|
const DEFAULT_TIMEOUT = 5000;
|
|
11
8
|
const DEFAULT_PING_INTERVAL = 30 * 1000;
|
|
12
9
|
const defaultParseMessage = (rpcVal) => {
|
|
@@ -15,13 +12,13 @@ const defaultParseMessage = (rpcVal) => {
|
|
|
15
12
|
return rpcMsg;
|
|
16
13
|
};
|
|
17
14
|
const dataToRpcValue = (buff) => {
|
|
18
|
-
const rd = new
|
|
15
|
+
const rd = new ChainPackReader(buff);
|
|
19
16
|
rd.readUIntData();
|
|
20
17
|
const proto = rd.ctx.getByte();
|
|
21
18
|
switch (proto) {
|
|
22
|
-
case
|
|
19
|
+
case CHAINPACK_PROTOCOL_TYPE:
|
|
23
20
|
break;
|
|
24
|
-
case
|
|
21
|
+
case CPON_PROTOCOL_TYPE:
|
|
25
22
|
throw new Error('CPON protocol type is not supported anymore');
|
|
26
23
|
default:
|
|
27
24
|
throw new Error(`Unsupported protocol type ${proto}`);
|
|
@@ -29,19 +26,16 @@ const dataToRpcValue = (buff) => {
|
|
|
29
26
|
const rpcVal = rd.read();
|
|
30
27
|
return rpcVal;
|
|
31
28
|
};
|
|
32
|
-
class RequestHandler {
|
|
29
|
+
export class RequestHandler {
|
|
33
30
|
options;
|
|
34
31
|
constructor(options) {
|
|
35
32
|
this.options = options;
|
|
36
33
|
// nothing
|
|
37
34
|
}
|
|
38
35
|
}
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
const validateDirParam = (param) => param === undefined || typeof param === 'string' || typeof param === 'boolean';
|
|
43
|
-
exports.validateDirParam = validateDirParam;
|
|
44
|
-
var DirFlags;
|
|
36
|
+
export const validateLsParam = (param) => param === undefined || typeof param === 'string';
|
|
37
|
+
export const validateDirParam = (param) => param === undefined || typeof param === 'string' || typeof param === 'boolean';
|
|
38
|
+
export var DirFlags;
|
|
45
39
|
(function (DirFlags) {
|
|
46
40
|
DirFlags[DirFlags["Reserved"] = 1] = "Reserved";
|
|
47
41
|
DirFlags[DirFlags["Getter"] = 2] = "Getter";
|
|
@@ -49,49 +43,49 @@ var DirFlags;
|
|
|
49
43
|
DirFlags[DirFlags["LargeResultHint"] = 8] = "LargeResultHint";
|
|
50
44
|
DirFlags[DirFlags["NotIdempotent"] = 16] = "NotIdempotent";
|
|
51
45
|
DirFlags[DirFlags["RequiresClientId"] = 32] = "RequiresClientId";
|
|
52
|
-
})(DirFlags || (
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
46
|
+
})(DirFlags || (DirFlags = {}));
|
|
47
|
+
export const DIR_NAME = 1;
|
|
48
|
+
export const DIR_FLAGS = 2;
|
|
49
|
+
export const DIR_PARAM = 3;
|
|
50
|
+
export const DIR_RESULT = 4;
|
|
51
|
+
export const DIR_ACCESS = 5;
|
|
52
|
+
export const DIR_SIGNALS = 6;
|
|
53
|
+
export const DIR_EXTRA = 63;
|
|
60
54
|
class RpcError extends Error {
|
|
61
55
|
err_info;
|
|
62
56
|
constructor(err_info) {
|
|
63
57
|
const errorCodeToMessage = (code) => {
|
|
64
58
|
switch (code) {
|
|
65
|
-
case
|
|
66
|
-
case
|
|
67
|
-
case
|
|
68
|
-
case
|
|
69
|
-
case
|
|
70
|
-
case
|
|
71
|
-
case
|
|
72
|
-
case
|
|
73
|
-
case
|
|
74
|
-
case
|
|
75
|
-
case
|
|
76
|
-
case
|
|
59
|
+
case ErrorCode.InvalidRequest: return 'InvalidRequest';
|
|
60
|
+
case ErrorCode.MethodNotFound: return 'MethodNotFound';
|
|
61
|
+
case ErrorCode.InvalidParams: return 'InvalidParams';
|
|
62
|
+
case ErrorCode.InternalError: return 'InternalError';
|
|
63
|
+
case ErrorCode.ParseError: return 'ParseError';
|
|
64
|
+
case ErrorCode.MethodCallTimeout: return 'MethodCallTimeout';
|
|
65
|
+
case ErrorCode.MethodCallCancelled: return 'MethodCallCancelled';
|
|
66
|
+
case ErrorCode.MethodCallException: return 'MethodCallException';
|
|
67
|
+
case ErrorCode.Unknown: return 'Unknown';
|
|
68
|
+
case ErrorCode.LoginRequired: return 'LoginRequired';
|
|
69
|
+
case ErrorCode.UserIDRequired: return 'UserIDRequired';
|
|
70
|
+
case ErrorCode.NotImplemented: return 'NotImplemented';
|
|
77
71
|
default: return 'Unknown RpcError';
|
|
78
72
|
}
|
|
79
73
|
};
|
|
80
|
-
super(err_info[
|
|
74
|
+
super(err_info[ERROR_MESSAGE] ?? `${errorCodeToMessage(err_info[ERROR_CODE])} (${err_info[ERROR_CODE]})`);
|
|
81
75
|
this.err_info = err_info;
|
|
82
76
|
}
|
|
83
77
|
data() {
|
|
84
|
-
return this.err_info[
|
|
78
|
+
return this.err_info[ERROR_DATA];
|
|
85
79
|
}
|
|
86
80
|
}
|
|
87
81
|
const makeErrInfo = (errInfoOrMsg, code) => {
|
|
88
82
|
if (typeof errInfoOrMsg === 'object') {
|
|
89
83
|
return errInfoOrMsg;
|
|
90
84
|
}
|
|
91
|
-
return
|
|
92
|
-
[
|
|
93
|
-
[
|
|
94
|
-
[
|
|
85
|
+
return makeIMap({
|
|
86
|
+
[ERROR_CODE]: code,
|
|
87
|
+
[ERROR_MESSAGE]: errInfoOrMsg,
|
|
88
|
+
[ERROR_DATA]: undefined,
|
|
95
89
|
});
|
|
96
90
|
};
|
|
97
91
|
const createErrorClass = (code) => class extends RpcError {
|
|
@@ -100,24 +94,24 @@ const createErrorClass = (code) => class extends RpcError {
|
|
|
100
94
|
}
|
|
101
95
|
};
|
|
102
96
|
/* eslint-disable @typescript-eslint/naming-convention -- We want class names like this */
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
97
|
+
export const InvalidRequest = createErrorClass(ErrorCode.InvalidRequest);
|
|
98
|
+
export const MethodNotFound = createErrorClass(ErrorCode.MethodNotFound);
|
|
99
|
+
export const InvalidParams = createErrorClass(ErrorCode.InvalidParams);
|
|
100
|
+
export const InternalError = createErrorClass(ErrorCode.InternalError);
|
|
101
|
+
export const ParseError = createErrorClass(ErrorCode.ParseError);
|
|
102
|
+
export const MethodCallTimeout = createErrorClass(ErrorCode.MethodCallTimeout);
|
|
103
|
+
export const MethodCallCancelled = createErrorClass(ErrorCode.MethodCallCancelled);
|
|
104
|
+
export const MethodCallException = createErrorClass(ErrorCode.MethodCallException);
|
|
105
|
+
export const Unknown = createErrorClass(ErrorCode.Unknown);
|
|
106
|
+
export const LoginRequired = createErrorClass(ErrorCode.LoginRequired);
|
|
107
|
+
export const UserIDRequired = createErrorClass(ErrorCode.UserIDRequired);
|
|
108
|
+
export const NotImplemented = createErrorClass(ErrorCode.NotImplemented);
|
|
115
109
|
/* eslint-enable @typescript-eslint/naming-convention */
|
|
116
110
|
const makeTimeout = (ms, resolve) => setTimeout(() => {
|
|
117
|
-
resolve(new
|
|
118
|
-
[
|
|
119
|
-
[
|
|
120
|
-
[
|
|
111
|
+
resolve(new MethodCallTimeout(makeIMap({
|
|
112
|
+
[ERROR_CODE]: ErrorCode.MethodCallTimeout,
|
|
113
|
+
[ERROR_MESSAGE]: `Shv call timeout after: ${ms} msec.`,
|
|
114
|
+
[ERROR_DATA]: undefined,
|
|
121
115
|
})));
|
|
122
116
|
}, ms);
|
|
123
117
|
class RpcRequestPromise extends Promise {
|
|
@@ -155,10 +149,10 @@ class WsClient {
|
|
|
155
149
|
this.websocket.binaryType = 'arraybuffer';
|
|
156
150
|
const handleSignal = (signal) => {
|
|
157
151
|
for (const sub of this.subscriptions) {
|
|
158
|
-
const shvPath = signal.meta[
|
|
159
|
-
const signalName = signal.meta[
|
|
152
|
+
const shvPath = signal.meta[RPC_MESSAGE_SHV_PATH];
|
|
153
|
+
const signalName = signal.meta[RPC_MESSAGE_METHOD];
|
|
160
154
|
if (shvPath.startsWith(sub.path) && signalName === sub.signal) {
|
|
161
|
-
sub.callback(shvPath, signalName, signal.value[
|
|
155
|
+
sub.callback(shvPath, signalName, signal.value[RPC_MESSAGE_PARAMS]);
|
|
162
156
|
}
|
|
163
157
|
}
|
|
164
158
|
};
|
|
@@ -167,40 +161,40 @@ class WsClient {
|
|
|
167
161
|
if (!('onRequest' in this.options)) {
|
|
168
162
|
return;
|
|
169
163
|
}
|
|
170
|
-
const requestId = request.meta[
|
|
164
|
+
const requestId = request.meta[RPC_MESSAGE_REQUEST_ID];
|
|
171
165
|
const respond = (value) => {
|
|
172
|
-
this.sendRpcMessage(new
|
|
173
|
-
[
|
|
174
|
-
[
|
|
166
|
+
this.sendRpcMessage(new RpcValueWithMetaData(makeMetaMap({
|
|
167
|
+
[RPC_MESSAGE_CALLER_IDS]: request.meta[RPC_MESSAGE_CALLER_IDS],
|
|
168
|
+
[RPC_MESSAGE_REQUEST_ID]: requestId,
|
|
175
169
|
}), value));
|
|
176
170
|
};
|
|
177
171
|
const sendDelay = (progress) => {
|
|
178
|
-
respond(
|
|
179
|
-
[
|
|
172
|
+
respond(makeIMap({
|
|
173
|
+
[RPC_MESSAGE_DELAY]: new Double(progress),
|
|
180
174
|
}));
|
|
181
175
|
};
|
|
182
176
|
// eslint-disable-next-line unicorn/no-computed-property-existence-check
|
|
183
|
-
if (
|
|
177
|
+
if (RPC_MESSAGE_ABORT in request.value) {
|
|
184
178
|
const requestHandler = this.requestHandlers.get(requestId);
|
|
185
|
-
if (request.value[
|
|
179
|
+
if (request.value[RPC_MESSAGE_ABORT]) {
|
|
186
180
|
this.abortedRequests.add(requestId);
|
|
187
181
|
if (requestHandler?.options.onAbort !== undefined) {
|
|
188
182
|
requestHandler.options.onAbort();
|
|
189
183
|
}
|
|
190
184
|
}
|
|
191
|
-
if (!request.value[
|
|
185
|
+
if (!request.value[RPC_MESSAGE_ABORT] && requestHandler?.options.onProgressQuery !== undefined) {
|
|
192
186
|
const progress = requestHandler.options.onProgressQuery();
|
|
193
187
|
sendDelay(progress instanceof Promise ? await progress : progress);
|
|
194
188
|
}
|
|
195
189
|
return;
|
|
196
190
|
}
|
|
197
191
|
try {
|
|
198
|
-
const shvPath = request.meta[
|
|
199
|
-
const methodName = request.meta[
|
|
192
|
+
const shvPath = request.meta[RPC_MESSAGE_SHV_PATH];
|
|
193
|
+
const methodName = request.meta[RPC_MESSAGE_METHOD];
|
|
200
194
|
const unhandledMethod = () => {
|
|
201
|
-
throw new
|
|
195
|
+
throw new MethodNotFound(`No such path '${shvPath}' or method '${methodName}' or insufficient access rights.`);
|
|
202
196
|
};
|
|
203
|
-
const accessLevel = request.meta[
|
|
197
|
+
const accessLevel = request.meta[RPC_MESSAGE_ACCESS_LEVEL];
|
|
204
198
|
if (accessLevel === undefined) {
|
|
205
199
|
unhandledMethod();
|
|
206
200
|
return;
|
|
@@ -211,34 +205,34 @@ class WsClient {
|
|
|
211
205
|
return;
|
|
212
206
|
}
|
|
213
207
|
const methodDefinition = (() => {
|
|
214
|
-
const dirEntry =
|
|
215
|
-
[
|
|
216
|
-
[
|
|
217
|
-
[
|
|
218
|
-
[
|
|
219
|
-
[
|
|
220
|
-
[
|
|
221
|
-
[
|
|
208
|
+
const dirEntry = makeIMap({
|
|
209
|
+
[DIR_NAME]: 'dir',
|
|
210
|
+
[DIR_FLAGS]: 0,
|
|
211
|
+
[DIR_PARAM]: 'DirParam',
|
|
212
|
+
[DIR_RESULT]: 'DirResult',
|
|
213
|
+
[DIR_ACCESS]: accessLevelFromAccessString('bws'),
|
|
214
|
+
[DIR_SIGNALS]: makeMap({}),
|
|
215
|
+
[DIR_EXTRA]: makeMap({}),
|
|
222
216
|
});
|
|
223
|
-
const lsEntry =
|
|
224
|
-
[
|
|
225
|
-
[
|
|
226
|
-
[
|
|
227
|
-
[
|
|
228
|
-
[
|
|
229
|
-
[
|
|
230
|
-
[
|
|
217
|
+
const lsEntry = makeIMap({
|
|
218
|
+
[DIR_NAME]: 'ls',
|
|
219
|
+
[DIR_FLAGS]: 0,
|
|
220
|
+
[DIR_PARAM]: 'LsParam',
|
|
221
|
+
[DIR_RESULT]: 'LsResult',
|
|
222
|
+
[DIR_ACCESS]: accessLevelFromAccessString('bws'),
|
|
223
|
+
[DIR_SIGNALS]: makeMap({}),
|
|
224
|
+
[DIR_EXTRA]: makeMap({}),
|
|
231
225
|
});
|
|
232
226
|
switch (methodName) {
|
|
233
227
|
case 'dir':
|
|
234
228
|
return {
|
|
235
229
|
entry: dirEntry,
|
|
236
|
-
paramValidator:
|
|
230
|
+
paramValidator: validateDirParam,
|
|
237
231
|
handler(_shvPath, _method, param) {
|
|
238
232
|
const methodsResult = [dirEntry, lsEntry, ...methods.dirEntries.map(method => method.entry)];
|
|
239
233
|
switch (true) {
|
|
240
234
|
case typeof param === 'string':
|
|
241
|
-
return methodsResult.find(method => method[
|
|
235
|
+
return methodsResult.find(method => method[DIR_NAME] === param) ?? false;
|
|
242
236
|
case typeof param === 'boolean':
|
|
243
237
|
case param === undefined:
|
|
244
238
|
console.log('methodsResult', '=', methodsResult);
|
|
@@ -249,34 +243,34 @@ class WsClient {
|
|
|
249
243
|
case 'ls':
|
|
250
244
|
return {
|
|
251
245
|
entry: lsEntry,
|
|
252
|
-
paramValidator:
|
|
246
|
+
paramValidator: validateLsParam,
|
|
253
247
|
handler(shvPath) {
|
|
254
248
|
return methods.ls(shvPath);
|
|
255
249
|
},
|
|
256
250
|
};
|
|
257
251
|
default:
|
|
258
|
-
return methods.dirEntries.find(method => method.entry[
|
|
252
|
+
return methods.dirEntries.find(method => method.entry[DIR_NAME] === methodName);
|
|
259
253
|
}
|
|
260
254
|
})();
|
|
261
255
|
if (methodDefinition === undefined) {
|
|
262
256
|
unhandledMethod();
|
|
263
257
|
return;
|
|
264
258
|
}
|
|
265
|
-
if (accessLevel < methodDefinition.entry[
|
|
259
|
+
if (accessLevel < methodDefinition.entry[DIR_ACCESS]) {
|
|
266
260
|
unhandledMethod();
|
|
267
261
|
return;
|
|
268
262
|
}
|
|
269
|
-
const requestParam = request.value[
|
|
263
|
+
const requestParam = request.value[RPC_MESSAGE_PARAMS];
|
|
270
264
|
if (methodDefinition.paramValidator !== undefined && !methodDefinition.paramValidator(requestParam)) {
|
|
271
|
-
throw new
|
|
265
|
+
throw new InvalidParams(`Unexpected param '${shvPath}:${methodName}': ${toCpon(requestParam)}`);
|
|
272
266
|
}
|
|
273
267
|
let result = methodDefinition.handler(shvPath, methodName, requestParam, sendDelay);
|
|
274
268
|
if (result instanceof RequestHandler) {
|
|
275
269
|
this.requestHandlers.set(requestId, result);
|
|
276
270
|
result = result.options.result;
|
|
277
271
|
}
|
|
278
|
-
const resultOrError =
|
|
279
|
-
[
|
|
272
|
+
const resultOrError = makeIMap({
|
|
273
|
+
[RPC_MESSAGE_RESULT]: result instanceof Promise ? await result : result,
|
|
280
274
|
});
|
|
281
275
|
if (!this.abortedRequests.has(requestId)) {
|
|
282
276
|
respond(resultOrError);
|
|
@@ -290,8 +284,8 @@ class WsClient {
|
|
|
290
284
|
}
|
|
291
285
|
catch (error) {
|
|
292
286
|
const sendError = (error) => {
|
|
293
|
-
respond(
|
|
294
|
-
[
|
|
287
|
+
respond(makeIMap({
|
|
288
|
+
[RPC_MESSAGE_ERROR]: error.err_info,
|
|
295
289
|
}));
|
|
296
290
|
};
|
|
297
291
|
switch (true) {
|
|
@@ -299,54 +293,54 @@ class WsClient {
|
|
|
299
293
|
sendError(error);
|
|
300
294
|
break;
|
|
301
295
|
case error instanceof Error:
|
|
302
|
-
sendError(new
|
|
296
|
+
sendError(new InternalError(error.message));
|
|
303
297
|
break;
|
|
304
298
|
default:
|
|
305
|
-
sendError(new
|
|
299
|
+
sendError(new InternalError('Unknown error'));
|
|
306
300
|
break;
|
|
307
301
|
}
|
|
308
302
|
}
|
|
309
303
|
};
|
|
310
304
|
const handleResponse = (response) => {
|
|
311
|
-
const requestId = response.meta[
|
|
305
|
+
const requestId = response.meta[RPC_MESSAGE_REQUEST_ID];
|
|
312
306
|
if (this.rpcHandlers[requestId] !== undefined) {
|
|
313
307
|
const handler = this.rpcHandlers[requestId];
|
|
314
308
|
clearTimeout(handler.timeout_handle);
|
|
315
309
|
// eslint-disable-next-line unicorn/no-computed-property-existence-check
|
|
316
|
-
if (
|
|
310
|
+
if (RPC_MESSAGE_DELAY in response.value) {
|
|
317
311
|
if (handler.delayCallback !== undefined) {
|
|
318
|
-
handler.delayCallback(response.value[
|
|
312
|
+
handler.delayCallback(response.value[RPC_MESSAGE_DELAY].value);
|
|
319
313
|
}
|
|
320
314
|
handler.timeout_handle = makeTimeout(this.timeout, handler.resolve);
|
|
321
315
|
return;
|
|
322
316
|
}
|
|
323
317
|
handler.resolve((() => {
|
|
324
318
|
// eslint-disable-next-line unicorn/no-computed-property-existence-check
|
|
325
|
-
if (
|
|
326
|
-
const code = response.value[
|
|
319
|
+
if (RPC_MESSAGE_ERROR in response.value) {
|
|
320
|
+
const code = response.value[RPC_MESSAGE_ERROR][ERROR_CODE];
|
|
327
321
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
328
322
|
const ErrorTypeCtor = (() => {
|
|
329
323
|
switch (code) {
|
|
330
|
-
case
|
|
331
|
-
case
|
|
332
|
-
case
|
|
333
|
-
case
|
|
334
|
-
case
|
|
335
|
-
case
|
|
336
|
-
case
|
|
337
|
-
case
|
|
338
|
-
case
|
|
339
|
-
case
|
|
340
|
-
case
|
|
341
|
-
case
|
|
342
|
-
default: return
|
|
324
|
+
case ErrorCode.InvalidRequest: return InvalidRequest;
|
|
325
|
+
case ErrorCode.MethodNotFound: return MethodNotFound;
|
|
326
|
+
case ErrorCode.InvalidParams: return InvalidParams;
|
|
327
|
+
case ErrorCode.InternalError: return InternalError;
|
|
328
|
+
case ErrorCode.ParseError: return ParseError;
|
|
329
|
+
case ErrorCode.MethodCallTimeout: return MethodCallTimeout;
|
|
330
|
+
case ErrorCode.MethodCallCancelled: return MethodCallCancelled;
|
|
331
|
+
case ErrorCode.MethodCallException: return MethodCallException;
|
|
332
|
+
case ErrorCode.Unknown: return Unknown;
|
|
333
|
+
case ErrorCode.LoginRequired: return LoginRequired;
|
|
334
|
+
case ErrorCode.UserIDRequired: return UserIDRequired;
|
|
335
|
+
case ErrorCode.NotImplemented: return NotImplemented;
|
|
336
|
+
default: return Unknown;
|
|
343
337
|
}
|
|
344
338
|
})();
|
|
345
|
-
return new ErrorTypeCtor(response.value[
|
|
339
|
+
return new ErrorTypeCtor(response.value[RPC_MESSAGE_ERROR]);
|
|
346
340
|
}
|
|
347
341
|
// eslint-disable-next-line unicorn/no-computed-property-existence-check
|
|
348
|
-
if (
|
|
349
|
-
return response.value[
|
|
342
|
+
if (RPC_MESSAGE_RESULT in response.value) {
|
|
343
|
+
return response.value[RPC_MESSAGE_RESULT];
|
|
350
344
|
}
|
|
351
345
|
// At this point, the RpcResponse either has:
|
|
352
346
|
// - no keys, which means that the response has an implicit Null result.
|
|
@@ -354,7 +348,7 @@ class WsClient {
|
|
|
354
348
|
// https://silicon-heaven.github.io/shv-doc/rpcmessage.html#response
|
|
355
349
|
const rpcMessageKeys = Object.keys(response.value);
|
|
356
350
|
if (rpcMessageKeys.length !== 0) {
|
|
357
|
-
return new
|
|
351
|
+
return new NotImplemented(`Got an RpcResponse with unsupported keys: ${rpcMessageKeys.join(' ')}`);
|
|
358
352
|
}
|
|
359
353
|
})());
|
|
360
354
|
// eslint-disable-next-line @typescript-eslint/no-array-delete, @typescript-eslint/no-dynamic-delete
|
|
@@ -366,14 +360,14 @@ class WsClient {
|
|
|
366
360
|
const rpcVal = dataToRpcValue(evt.data);
|
|
367
361
|
const parseMessage = this.options.parseMessage ?? defaultParseMessage;
|
|
368
362
|
const rpcMsg = parseMessage(rpcVal);
|
|
369
|
-
this.logDebug(`message received: ${
|
|
370
|
-
if (
|
|
363
|
+
this.logDebug(`message received: ${toCpon(rpcMsg)}`);
|
|
364
|
+
if (isSignal(rpcMsg)) {
|
|
371
365
|
handleSignal(rpcMsg);
|
|
372
366
|
}
|
|
373
|
-
else if (
|
|
367
|
+
else if (isRequest(rpcMsg)) {
|
|
374
368
|
await handleRequest(rpcMsg);
|
|
375
369
|
}
|
|
376
|
-
else if (
|
|
370
|
+
else if (isResponse(rpcMsg)) {
|
|
377
371
|
handleResponse(rpcMsg);
|
|
378
372
|
}
|
|
379
373
|
});
|
|
@@ -433,10 +427,10 @@ class WsClient {
|
|
|
433
427
|
this.sendPing();
|
|
434
428
|
}, options.pingInterval ?? DEFAULT_PING_INTERVAL);
|
|
435
429
|
};
|
|
436
|
-
const makeLoginParams = (loginMap) =>
|
|
430
|
+
const makeLoginParams = (loginMap) => makeMap({
|
|
437
431
|
login: loginMap,
|
|
438
|
-
options:
|
|
439
|
-
device: typeof options.mountPoint === 'string' ?
|
|
432
|
+
options: makeMap({
|
|
433
|
+
device: typeof options.mountPoint === 'string' ? makeMap({ mountPoint: options.mountPoint }) : undefined,
|
|
440
434
|
}),
|
|
441
435
|
});
|
|
442
436
|
this.callRpcMethod(undefined, 'hello').then(response => {
|
|
@@ -447,13 +441,13 @@ class WsClient {
|
|
|
447
441
|
const makeLoginMap = () => {
|
|
448
442
|
switch (options.login.type) {
|
|
449
443
|
case 'PLAIN':
|
|
450
|
-
return
|
|
444
|
+
return makeMap({
|
|
451
445
|
password: options.login.password,
|
|
452
446
|
type: options.login.type,
|
|
453
447
|
user: options.login.user,
|
|
454
448
|
});
|
|
455
449
|
case 'TOKEN':
|
|
456
|
-
return
|
|
450
|
+
return makeMap({
|
|
457
451
|
token: options.login.token,
|
|
458
452
|
type: options.login.type,
|
|
459
453
|
});
|
|
@@ -473,19 +467,19 @@ class WsClient {
|
|
|
473
467
|
}
|
|
474
468
|
callRpcMethod(shvPath, method, params, options) {
|
|
475
469
|
const rqId = this.requestId++;
|
|
476
|
-
const makeRq = (value) => new
|
|
477
|
-
[
|
|
478
|
-
[
|
|
479
|
-
[
|
|
480
|
-
[
|
|
481
|
-
...(options?.requestUserId === true && { [
|
|
470
|
+
const makeRq = (value) => new RpcValueWithMetaData(makeMetaMap({
|
|
471
|
+
[RPC_MESSAGE_CALLER_IDS]: undefined,
|
|
472
|
+
[RPC_MESSAGE_REQUEST_ID]: rqId,
|
|
473
|
+
[RPC_MESSAGE_METHOD]: method ?? '',
|
|
474
|
+
[RPC_MESSAGE_SHV_PATH]: shvPath ?? '',
|
|
475
|
+
...(options?.requestUserId === true && { [RPC_MESSAGE_USER_ID]: '' }),
|
|
482
476
|
}), value);
|
|
483
477
|
// We will not add an explicit null as a param unless the user requests it. Receivers of RpcCalls should
|
|
484
478
|
// generally handle a missing param the same as if the param was Null.
|
|
485
479
|
const paramRaw = params !== undefined || (options?.explicitNullParam ?? false) ? {
|
|
486
|
-
[
|
|
480
|
+
[RPC_MESSAGE_PARAMS]: params,
|
|
487
481
|
} : {};
|
|
488
|
-
let rq = makeRq(
|
|
482
|
+
let rq = makeRq(makeIMap(paramRaw));
|
|
489
483
|
if (options?.beforeSendHook !== undefined) {
|
|
490
484
|
rq = options.beforeSendHook(rq);
|
|
491
485
|
}
|
|
@@ -493,12 +487,12 @@ class WsClient {
|
|
|
493
487
|
const promise = new RpcRequestPromise(resolve => {
|
|
494
488
|
this.rpcHandlers[rqId] = { resolve, timeout_handle: makeTimeout(this.timeout, resolve), delayCallback: options?.delayCallback };
|
|
495
489
|
}, () => {
|
|
496
|
-
this.sendRpcMessage(makeRq(
|
|
497
|
-
[
|
|
490
|
+
this.sendRpcMessage(makeRq(makeIMap({
|
|
491
|
+
[RPC_MESSAGE_ABORT]: true,
|
|
498
492
|
})));
|
|
499
493
|
}, () => {
|
|
500
|
-
this.sendRpcMessage(makeRq(
|
|
501
|
-
[
|
|
494
|
+
this.sendRpcMessage(makeRq(makeIMap({
|
|
495
|
+
[RPC_MESSAGE_ABORT]: false,
|
|
502
496
|
})));
|
|
503
497
|
});
|
|
504
498
|
return promise;
|
|
@@ -507,16 +501,16 @@ class WsClient {
|
|
|
507
501
|
if (this.websocket.readyState !== WebSocket.OPEN) {
|
|
508
502
|
return;
|
|
509
503
|
}
|
|
510
|
-
this.logDebug('sending rpc message:',
|
|
511
|
-
const msgData = new Uint8Array(
|
|
512
|
-
const wr = new
|
|
504
|
+
this.logDebug('sending rpc message:', toCpon(rpcMsg));
|
|
505
|
+
const msgData = new Uint8Array(toChainPack(rpcMsg));
|
|
506
|
+
const wr = new ChainPackWriter();
|
|
513
507
|
wr.writeUIntData(msgData.length + 1);
|
|
514
508
|
const dgram = new Uint8Array(wr.ctx.length + 1 + msgData.length);
|
|
515
509
|
let ix = 0;
|
|
516
510
|
for (let i = 0; i < wr.ctx.length; i++) {
|
|
517
511
|
dgram[ix++] = wr.ctx.data[i];
|
|
518
512
|
}
|
|
519
|
-
dgram[ix++] =
|
|
513
|
+
dgram[ix++] = CHAINPACK_PROTOCOL_TYPE;
|
|
520
514
|
for (const msgDatum of msgData) {
|
|
521
515
|
dgram[ix++] = msgDatum;
|
|
522
516
|
}
|
|
@@ -539,7 +533,7 @@ class WsClient {
|
|
|
539
533
|
return this.shvApiVersion;
|
|
540
534
|
}
|
|
541
535
|
async subscribe(subscriber, riGetter, callback) {
|
|
542
|
-
const ri = await
|
|
536
|
+
const ri = await resolveRI(riGetter);
|
|
543
537
|
const path = ri.path();
|
|
544
538
|
const signal = ri.signal();
|
|
545
539
|
if (this.subscriptions.some(val => val.subscriber === subscriber && val.path === path && val.signal === signal)) {
|
|
@@ -550,7 +544,7 @@ class WsClient {
|
|
|
550
544
|
if (this.subscriptions.every(val => !(val.path === path && val.signal === signal))) {
|
|
551
545
|
switch (await this.getShvApiVersion()) {
|
|
552
546
|
case ShvApiVersion.V2: {
|
|
553
|
-
const result = await this.callRpcMethod('.broker/app', 'subscribe',
|
|
547
|
+
const result = await this.callRpcMethod('.broker/app', 'subscribe', makeMap({ signal, path }));
|
|
554
548
|
if (result instanceof Error) {
|
|
555
549
|
this.logDebug(`Couldn't subscribe to ${path}, ${signal}`);
|
|
556
550
|
}
|
|
@@ -578,7 +572,7 @@ class WsClient {
|
|
|
578
572
|
});
|
|
579
573
|
}
|
|
580
574
|
async unsubscribe(subscriber, riGetter) {
|
|
581
|
-
const ri = await
|
|
575
|
+
const ri = await resolveRI(riGetter);
|
|
582
576
|
const path = ri.path();
|
|
583
577
|
const signal = ri.signal();
|
|
584
578
|
const idx = this.subscriptions.findIndex(val => val.subscriber === subscriber && val.path === path && val.signal === signal);
|
|
@@ -593,14 +587,14 @@ class WsClient {
|
|
|
593
587
|
}
|
|
594
588
|
switch (await this.getShvApiVersion()) {
|
|
595
589
|
case ShvApiVersion.V2: {
|
|
596
|
-
const result = await this.callRpcMethod('.broker/app', 'unsubscribe',
|
|
590
|
+
const result = await this.callRpcMethod('.broker/app', 'unsubscribe', makeMap({ signal, path }));
|
|
597
591
|
if (result instanceof Error) {
|
|
598
592
|
this.logDebug(`Couldn't unsubscribe ${path}, ${signal}`);
|
|
599
593
|
}
|
|
600
594
|
break;
|
|
601
595
|
}
|
|
602
596
|
case ShvApiVersion.V3: {
|
|
603
|
-
const result = await this.callRpcMethod('.broker/currentClient', 'unsubscribe',
|
|
597
|
+
const result = await this.callRpcMethod('.broker/currentClient', 'unsubscribe', makeMap({ ri: ri.asString(), ttl: undefined }));
|
|
604
598
|
if (result instanceof Error) {
|
|
605
599
|
this.logDebug(`Couldn't unsubscribe ${path}, ${signal}`);
|
|
606
600
|
}
|
|
@@ -629,4 +623,4 @@ class WsClient {
|
|
|
629
623
|
this.options.logDebug(...args);
|
|
630
624
|
}
|
|
631
625
|
}
|
|
632
|
-
|
|
626
|
+
export { WsClient };
|