libshv-js 3.11.0 → 3.12.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/package.json +7 -7
- package/src/rpcmessage.ts +4 -1
- package/src/rpcvalue.ts +3 -1
- package/src/ws-client.ts +195 -104
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "libshv-js",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.12.0",
|
|
4
4
|
"description": "Typescript implementation of libshv",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
@@ -31,12 +31,12 @@
|
|
|
31
31
|
"zod": "^3.25.67"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@typescript-eslint/parser": "^8.
|
|
35
|
-
"eslint": "^9.
|
|
36
|
-
"eslint-config-xo": "^0.
|
|
34
|
+
"@typescript-eslint/parser": "^8.35.0",
|
|
35
|
+
"eslint": "^9.29.0",
|
|
36
|
+
"eslint-config-xo": "^0.47.0",
|
|
37
37
|
"eslint-formatter-unix": "^8.40.0",
|
|
38
|
-
"eslint-plugin-unicorn": "^
|
|
39
|
-
"typescript": "^5.8.
|
|
40
|
-
"typescript-eslint": "^8.
|
|
38
|
+
"eslint-plugin-unicorn": "^59.0.1",
|
|
39
|
+
"typescript": "^5.8.3",
|
|
40
|
+
"typescript-eslint": "^8.35.0"
|
|
41
41
|
}
|
|
42
42
|
}
|
package/src/rpcmessage.ts
CHANGED
|
@@ -9,6 +9,7 @@ export const RPC_MESSAGE_PARAMS = 1;
|
|
|
9
9
|
export const RPC_MESSAGE_RESULT = 2;
|
|
10
10
|
export const RPC_MESSAGE_ERROR = 3;
|
|
11
11
|
export const RPC_MESSAGE_DELAY = 4;
|
|
12
|
+
export const RPC_MESSAGE_ABORT = 5;
|
|
12
13
|
|
|
13
14
|
export const ERROR_CODE = 1;
|
|
14
15
|
export const ERROR_MESSAGE = 2;
|
|
@@ -46,7 +47,9 @@ const RpcRequestMetaZod = z.metamap({
|
|
|
46
47
|
|
|
47
48
|
const RpcRequestValueZod = z.imap({
|
|
48
49
|
[RPC_MESSAGE_PARAMS]: z.rpcvalue().optional(),
|
|
49
|
-
})
|
|
50
|
+
}).or(z.imap({
|
|
51
|
+
[RPC_MESSAGE_ABORT]: z.boolean(),
|
|
52
|
+
}));
|
|
50
53
|
|
|
51
54
|
const RpcResponseMetaZod = z.metamap({
|
|
52
55
|
[RPC_MESSAGE_CALLER_IDS]: z.int().or(z.array(z.int())).optional(),
|
package/src/rpcvalue.ts
CHANGED
|
@@ -137,7 +137,9 @@ const makeMap = <T extends Record<string, RpcValue> = Record<string, RpcValue>,
|
|
|
137
137
|
});
|
|
138
138
|
|
|
139
139
|
class RpcValueWithMetaData<MetaSchema extends MetaMap = MetaMap, ValueSchema extends RpcValueType = RpcValueType> {
|
|
140
|
-
constructor(public meta: MetaSchema, public value: ValueSchema) {
|
|
140
|
+
constructor(public meta: MetaSchema, public value: ValueSchema) {
|
|
141
|
+
/* nothing */
|
|
142
|
+
}
|
|
141
143
|
}
|
|
142
144
|
|
|
143
145
|
export type RpcValue = RpcValueType | RpcValueWithMetaData;
|
package/src/ws-client.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {ChainPackReader, CHAINPACK_PROTOCOL_TYPE, ChainPackWriter, toChainPack} from './chainpack';
|
|
2
2
|
import {type CponReader, CPON_PROTOCOL_TYPE, toCpon} from './cpon';
|
|
3
|
-
import {ERROR_MESSAGE, ErrorCode, ERROR_CODE, RpcMessageZod, type RpcMessage, isSignal, isRequest, type RpcRequest, isResponse, ERROR_DATA, type ErrorMap, RPC_MESSAGE_METHOD, RPC_MESSAGE_SHV_PATH, RPC_MESSAGE_REQUEST_ID, RPC_MESSAGE_PARAMS, RPC_MESSAGE_ERROR, RPC_MESSAGE_RESULT, RPC_MESSAGE_CALLER_IDS, RpcResponseValue, RPC_MESSAGE_DELAY} from './rpcmessage';
|
|
3
|
+
import {ERROR_MESSAGE, ErrorCode, ERROR_CODE, RpcMessageZod, type RpcMessage, isSignal, isRequest, type RpcRequest, isResponse, ERROR_DATA, type ErrorMap, RPC_MESSAGE_METHOD, RPC_MESSAGE_SHV_PATH, RPC_MESSAGE_REQUEST_ID, RPC_MESSAGE_PARAMS, RPC_MESSAGE_ERROR, RPC_MESSAGE_RESULT, RPC_MESSAGE_CALLER_IDS, RpcResponseValue, RPC_MESSAGE_DELAY, RPC_MESSAGE_ABORT, RpcSignal, RpcResponse} from './rpcmessage';
|
|
4
4
|
import {type RpcValue, type Null, type Int, type IMap, type ShvMap, makeMap, makeIMap, RpcValueWithMetaData, makeMetaMap, Double} from './rpcvalue';
|
|
5
5
|
|
|
6
6
|
const DEFAULT_TIMEOUT = 5000;
|
|
@@ -50,6 +50,16 @@ type WsClientOptionsCommon = {
|
|
|
50
50
|
wsUri: string;
|
|
51
51
|
};
|
|
52
52
|
|
|
53
|
+
export class RequestHandler {
|
|
54
|
+
constructor(public options: {
|
|
55
|
+
result: Promise<RpcValue>;
|
|
56
|
+
onAbort?: () => void;
|
|
57
|
+
onProgressQuery?: () => number | Promise<number>;
|
|
58
|
+
}) {
|
|
59
|
+
/* nothing */
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
53
63
|
type WsClientOptionsLogin = WsClientOptionsCommon & {
|
|
54
64
|
mountPoint?: string;
|
|
55
65
|
login: Login;
|
|
@@ -58,7 +68,7 @@ type WsClientOptionsLogin = WsClientOptionsCommon & {
|
|
|
58
68
|
onConnected: () => void;
|
|
59
69
|
onConnectionFailure: (error: Error) => void;
|
|
60
70
|
onDisconnected: () => void;
|
|
61
|
-
onRequest: (shvPath: string, method: string, param: RpcValue, delay: (progress: number) => void) => RpcValue | Promise<RpcValue
|
|
71
|
+
onRequest: (shvPath: string, method: string, param: RpcValue, delay: (progress: number) => void) => RpcValue | Promise<RpcValue> | RequestHandler;
|
|
62
72
|
};
|
|
63
73
|
|
|
64
74
|
type WsClientOptionsWorkflows = WsClientOptionsCommon & {
|
|
@@ -137,13 +147,30 @@ export const UserIDRequired = createErrorClass(ErrorCode.UserIDRequired);
|
|
|
137
147
|
export const NotImplemented = createErrorClass(ErrorCode.NotImplemented);
|
|
138
148
|
/* eslint-enable @typescript-eslint/naming-convention */
|
|
139
149
|
|
|
150
|
+
const makeTimeout = (ms: number, resolve: RpcResponseResolver) => globalThis.setTimeout(() => {
|
|
151
|
+
resolve(new MethodCallTimeout(makeIMap({
|
|
152
|
+
[ERROR_CODE]: ErrorCode.MethodCallTimeout,
|
|
153
|
+
[ERROR_MESSAGE]: `Shv call timeout after: ${ms} msec.`,
|
|
154
|
+
[ERROR_DATA]: undefined,
|
|
155
|
+
})));
|
|
156
|
+
}, ms);
|
|
157
|
+
|
|
158
|
+
class RpcRequestPromise<Result> extends Promise<Result> {
|
|
159
|
+
constructor(executor: (resolve: (value: Result | PromiseLike<Result>) => void, reject: (reason?: unknown) => void) => void, public readonly abort: () => void, public readonly progressQuery: () => void) {
|
|
160
|
+
super(executor);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
140
164
|
class WsClient {
|
|
141
165
|
private requestId = 1;
|
|
142
166
|
private pingTimerId: ReturnType<typeof globalThis.setInterval> | undefined = undefined;
|
|
143
167
|
private rpcHandlers: Array<{
|
|
144
168
|
resolve: RpcResponseResolver;
|
|
169
|
+
delayCallback?: (progress: number) => void;
|
|
145
170
|
timeout_handle: ReturnType<typeof globalThis.setTimeout>;
|
|
146
171
|
}> = [];
|
|
172
|
+
private requestHandlers: RequestHandler[] = [];
|
|
173
|
+
private abortedRequests = new Set<number>();
|
|
147
174
|
private readonly subscriptions: Subscription[] = [];
|
|
148
175
|
private readonly websocket: WebSocket;
|
|
149
176
|
private readonly options: WsClientOptions;
|
|
@@ -160,105 +187,166 @@ class WsClient {
|
|
|
160
187
|
this.websocket = new WebSocket(options.wsUri);
|
|
161
188
|
this.websocket.binaryType = 'arraybuffer';
|
|
162
189
|
|
|
163
|
-
|
|
164
|
-
const
|
|
190
|
+
const handleSignal = (signal: RpcSignal) => {
|
|
191
|
+
for (const sub of this.subscriptions) {
|
|
192
|
+
const shvPath = signal.meta[RPC_MESSAGE_SHV_PATH];
|
|
193
|
+
const method = signal.meta[RPC_MESSAGE_METHOD];
|
|
165
194
|
|
|
166
|
-
|
|
167
|
-
|
|
195
|
+
if (shvPath.startsWith(sub.path) && method === sub.method) {
|
|
196
|
+
sub.callback(shvPath, method, signal.value[RPC_MESSAGE_PARAMS]);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
const handleRequest = async (request: RpcRequest) => {
|
|
202
|
+
if ('onRequest' in this.options) {
|
|
203
|
+
const requestId = request.meta[RPC_MESSAGE_REQUEST_ID];
|
|
204
|
+
const respond = (value: RpcResponseValue) => {
|
|
205
|
+
this.sendRpcMessage(new RpcValueWithMetaData(
|
|
206
|
+
makeMetaMap({
|
|
207
|
+
[RPC_MESSAGE_CALLER_IDS]: request.meta[RPC_MESSAGE_CALLER_IDS],
|
|
208
|
+
[RPC_MESSAGE_REQUEST_ID]: requestId,
|
|
209
|
+
}),
|
|
210
|
+
value,
|
|
211
|
+
));
|
|
212
|
+
};
|
|
168
213
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
214
|
+
const sendDelay = (progress: number) => {
|
|
215
|
+
respond(makeIMap({
|
|
216
|
+
[RPC_MESSAGE_DELAY]: new Double(progress),
|
|
217
|
+
}));
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
if (RPC_MESSAGE_ABORT in request.value) {
|
|
221
|
+
const requestHandler = this.requestHandlers[requestId];
|
|
173
222
|
|
|
174
|
-
if (
|
|
175
|
-
|
|
223
|
+
if (request.value[RPC_MESSAGE_ABORT] === true && requestHandler?.options.onAbort !== undefined) {
|
|
224
|
+
this.abortedRequests.add(requestId);
|
|
225
|
+
requestHandler.options.onAbort();
|
|
176
226
|
}
|
|
227
|
+
|
|
228
|
+
if (request.value[RPC_MESSAGE_ABORT] === false && requestHandler?.options.onProgressQuery !== undefined) {
|
|
229
|
+
const progress = requestHandler.options.onProgressQuery();
|
|
230
|
+
sendDelay(progress instanceof Promise ? await progress : progress);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return;
|
|
177
234
|
}
|
|
178
|
-
} else if (isRequest(rpcMsg)) {
|
|
179
|
-
if ('onRequest' in this.options) {
|
|
180
|
-
const respond = (value: RpcResponseValue) => {
|
|
181
|
-
this.sendRpcMessage(new RpcValueWithMetaData(
|
|
182
|
-
makeMetaMap({
|
|
183
|
-
[RPC_MESSAGE_CALLER_IDS]: rpcMsg.meta[RPC_MESSAGE_CALLER_IDS],
|
|
184
|
-
[RPC_MESSAGE_REQUEST_ID]: rpcMsg.meta[RPC_MESSAGE_REQUEST_ID],
|
|
185
|
-
}),
|
|
186
|
-
value,
|
|
187
|
-
));
|
|
188
|
-
};
|
|
189
235
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
236
|
+
try {
|
|
237
|
+
let result = this.options.onRequest(request.meta[RPC_MESSAGE_SHV_PATH], request.meta[RPC_MESSAGE_METHOD], request.value[RPC_MESSAGE_PARAMS], sendDelay);
|
|
238
|
+
if (result instanceof RequestHandler) {
|
|
239
|
+
this.requestHandlers[requestId] = result;
|
|
240
|
+
result = result.options.result;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const resultOrError = makeIMap({
|
|
244
|
+
[RPC_MESSAGE_RESULT]: result instanceof Promise ? await result : result,
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
if (!this.abortedRequests.has(requestId)) {
|
|
248
|
+
respond(resultOrError);
|
|
249
|
+
} else {
|
|
250
|
+
this.abortedRequests.delete(requestId);
|
|
251
|
+
}
|
|
196
252
|
|
|
197
|
-
|
|
253
|
+
if (requestId in this.requestHandlers) {
|
|
254
|
+
// eslint-disable-next-line @typescript-eslint/no-array-delete
|
|
255
|
+
delete this.requestHandlers[requestId];
|
|
256
|
+
}
|
|
257
|
+
} catch (error: unknown) {
|
|
258
|
+
const sendError = (error: RpcError) => {
|
|
198
259
|
respond(makeIMap({
|
|
199
|
-
[
|
|
260
|
+
[RPC_MESSAGE_ERROR]: error.err_info,
|
|
200
261
|
}));
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
sendError(new InternalError(error.message));
|
|
214
|
-
break;
|
|
215
|
-
default:
|
|
216
|
-
sendError(new InternalError('Unknown error'));
|
|
217
|
-
break;
|
|
218
|
-
}
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
switch (true) {
|
|
265
|
+
case error instanceof RpcError:
|
|
266
|
+
sendError(error);
|
|
267
|
+
break;
|
|
268
|
+
case error instanceof Error:
|
|
269
|
+
sendError(new InternalError(error.message));
|
|
270
|
+
break;
|
|
271
|
+
default:
|
|
272
|
+
sendError(new InternalError('Unknown error'));
|
|
273
|
+
break;
|
|
219
274
|
}
|
|
220
275
|
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
case ErrorCode.MethodCallTimeout: return MethodCallTimeout;
|
|
239
|
-
case ErrorCode.MethodCallCancelled: return MethodCallCancelled;
|
|
240
|
-
case ErrorCode.MethodCallException: return MethodCallException;
|
|
241
|
-
case ErrorCode.Unknown: return Unknown;
|
|
242
|
-
case ErrorCode.LoginRequired: return LoginRequired;
|
|
243
|
-
case ErrorCode.UserIDRequired: return UserIDRequired;
|
|
244
|
-
case ErrorCode.NotImplemented: return NotImplemented;
|
|
245
|
-
default: return Unknown;
|
|
246
|
-
}
|
|
247
|
-
})();
|
|
248
|
-
|
|
249
|
-
return new ErrorTypeCtor(rpcMsg.value[RPC_MESSAGE_ERROR]);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
if (RPC_MESSAGE_RESULT in rpcMsg.value) {
|
|
253
|
-
return rpcMsg.value[RPC_MESSAGE_RESULT];
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// If both result and error are missing, the result is implicitly Null.
|
|
257
|
-
// https://silicon-heaven.github.io/shv-doc/rpcmessage.html#response
|
|
258
|
-
})());
|
|
259
|
-
// eslint-disable-next-line @typescript-eslint/no-array-delete
|
|
260
|
-
delete this.rpcHandlers[Number(requestId)];
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
const handleResponse = (response: RpcResponse) => {
|
|
280
|
+
const requestId = response.meta[RPC_MESSAGE_REQUEST_ID];
|
|
281
|
+
|
|
282
|
+
if (this.rpcHandlers[Number(requestId)] !== undefined) {
|
|
283
|
+
const handler = this.rpcHandlers[Number(requestId)];
|
|
284
|
+
clearTimeout(handler.timeout_handle);
|
|
285
|
+
|
|
286
|
+
if (RPC_MESSAGE_DELAY in response.value) {
|
|
287
|
+
if (handler.delayCallback !== undefined) {
|
|
288
|
+
handler.delayCallback(response.value[RPC_MESSAGE_DELAY].value);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
handler.timeout_handle = makeTimeout(this.timeout, handler.resolve);
|
|
292
|
+
return;
|
|
261
293
|
}
|
|
294
|
+
|
|
295
|
+
handler.resolve((() => {
|
|
296
|
+
if (RPC_MESSAGE_ERROR in response.value) {
|
|
297
|
+
const code = response.value[RPC_MESSAGE_ERROR][ERROR_CODE] as unknown;
|
|
298
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
299
|
+
const ErrorTypeCtor = (() => {
|
|
300
|
+
switch (code) {
|
|
301
|
+
case ErrorCode.InvalidRequest: return InvalidRequest;
|
|
302
|
+
case ErrorCode.MethodNotFound: return MethodNotFound;
|
|
303
|
+
case ErrorCode.InvalidParams: return InvalidParams;
|
|
304
|
+
case ErrorCode.InternalError: return InternalError;
|
|
305
|
+
case ErrorCode.ParseError: return ParseError;
|
|
306
|
+
case ErrorCode.MethodCallTimeout: return MethodCallTimeout;
|
|
307
|
+
case ErrorCode.MethodCallCancelled: return MethodCallCancelled;
|
|
308
|
+
case ErrorCode.MethodCallException: return MethodCallException;
|
|
309
|
+
case ErrorCode.Unknown: return Unknown;
|
|
310
|
+
case ErrorCode.LoginRequired: return LoginRequired;
|
|
311
|
+
case ErrorCode.UserIDRequired: return UserIDRequired;
|
|
312
|
+
case ErrorCode.NotImplemented: return NotImplemented;
|
|
313
|
+
default: return Unknown;
|
|
314
|
+
}
|
|
315
|
+
})();
|
|
316
|
+
|
|
317
|
+
return new ErrorTypeCtor(response.value[RPC_MESSAGE_ERROR]);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (RPC_MESSAGE_RESULT in response.value) {
|
|
321
|
+
return response.value[RPC_MESSAGE_RESULT];
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// At this point, the RpcResponse either has:
|
|
325
|
+
// - no keys, which means that the response has an implicit Null result.
|
|
326
|
+
// - has some unknown keys, in which case we will produce an error for the client.
|
|
327
|
+
// https://silicon-heaven.github.io/shv-doc/rpcmessage.html#response
|
|
328
|
+
const rpcMessageKeys = Object.keys(response.value);
|
|
329
|
+
if (rpcMessageKeys.length !== 0) {
|
|
330
|
+
return new NotImplemented(`Got an RpcResponse with unsupported keys: ${rpcMessageKeys.join(' ')}`);
|
|
331
|
+
}
|
|
332
|
+
})());
|
|
333
|
+
// eslint-disable-next-line @typescript-eslint/no-array-delete
|
|
334
|
+
delete this.rpcHandlers[Number(requestId)];
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
this.websocket.addEventListener('message', async (evt: MessageEvent<ArrayBuffer>) => {
|
|
339
|
+
const rpcVal = dataToRpcValue(evt.data);
|
|
340
|
+
|
|
341
|
+
const rpcMsg = RpcMessageZod.parse(rpcVal);
|
|
342
|
+
this.logDebug(`message received: ${toCpon(rpcMsg)}`);
|
|
343
|
+
|
|
344
|
+
if (isSignal(rpcMsg)) {
|
|
345
|
+
handleSignal(rpcMsg);
|
|
346
|
+
} else if (isRequest(rpcMsg)) {
|
|
347
|
+
await handleRequest(rpcMsg);
|
|
348
|
+
} else if (isResponse(rpcMsg)) {
|
|
349
|
+
handleResponse(rpcMsg);
|
|
262
350
|
}
|
|
263
351
|
});
|
|
264
352
|
|
|
@@ -274,31 +362,34 @@ class WsClient {
|
|
|
274
362
|
}
|
|
275
363
|
}
|
|
276
364
|
|
|
277
|
-
callRpcMethod(shvPath: '.broker/currentClient', method: 'accessGrantForMethodCall', params: [string, string]):
|
|
278
|
-
callRpcMethod(shvPath: string | undefined, method: 'dir', params?: RpcValue):
|
|
279
|
-
callRpcMethod(shvPath: string | undefined, method: 'ls', params?: RpcValue):
|
|
280
|
-
callRpcMethod(shvPath: string | undefined, method: string, params?: RpcValue):
|
|
281
|
-
callRpcMethod(shvPath: string | undefined, method: string, params?: RpcValue):
|
|
365
|
+
callRpcMethod(shvPath: '.broker/currentClient', method: 'accessGrantForMethodCall', params: [string, string], delayCallback?: (progress: number) => void): RpcRequestPromise<ResultOrError<string>>;
|
|
366
|
+
callRpcMethod(shvPath: string | undefined, method: 'dir', params?: RpcValue, delayCallback?: (progress: number) => void): RpcRequestPromise<ResultOrError<DirResult>>;
|
|
367
|
+
callRpcMethod(shvPath: string | undefined, method: 'ls', params?: RpcValue, delayCallback?: (progress: number) => void): RpcRequestPromise<ResultOrError<LsResult>>;
|
|
368
|
+
callRpcMethod(shvPath: string | undefined, method: string, params?: RpcValue, delayCallback?: (progress: number) => void): RpcRequestPromise<ResultOrError>;
|
|
369
|
+
callRpcMethod(shvPath: string | undefined, method: string, params?: RpcValue, delayCallback?: (progress: number) => void): RpcRequestPromise<ResultOrError> {
|
|
282
370
|
const rqId = this.requestId++;
|
|
283
|
-
const
|
|
371
|
+
const makeRq = (value: IMap) => new RpcValueWithMetaData(makeMetaMap({
|
|
284
372
|
[RPC_MESSAGE_CALLER_IDS]: undefined,
|
|
285
373
|
[RPC_MESSAGE_REQUEST_ID]: rqId,
|
|
286
374
|
[RPC_MESSAGE_METHOD]: method ?? '',
|
|
287
375
|
[RPC_MESSAGE_SHV_PATH]: shvPath ?? '',
|
|
288
|
-
}),
|
|
376
|
+
}), value);
|
|
377
|
+
const rq: RpcRequest = makeRq(makeIMap({
|
|
289
378
|
[RPC_MESSAGE_PARAMS]: params,
|
|
290
379
|
}));
|
|
291
380
|
|
|
292
381
|
this.sendRpcMessage(rq);
|
|
293
382
|
|
|
294
|
-
const promise = new
|
|
295
|
-
this.rpcHandlers[rqId] = {resolve, timeout_handle:
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
383
|
+
const promise = new RpcRequestPromise<ResultOrError>(resolve => {
|
|
384
|
+
this.rpcHandlers[rqId] = {resolve, timeout_handle: makeTimeout(this.timeout, resolve), delayCallback};
|
|
385
|
+
}, () => {
|
|
386
|
+
this.sendRpcMessage(makeRq(makeIMap({
|
|
387
|
+
[RPC_MESSAGE_ABORT]: true,
|
|
388
|
+
})));
|
|
389
|
+
}, () => {
|
|
390
|
+
this.sendRpcMessage(makeRq(makeIMap({
|
|
391
|
+
[RPC_MESSAGE_ABORT]: false,
|
|
392
|
+
})));
|
|
302
393
|
});
|
|
303
394
|
|
|
304
395
|
return promise;
|