@opentap/runner-client 2.2.4-alpha.1.1 → 2.2.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.
@@ -1,5 +1,5 @@
1
1
  import { ComponentSettingsBase, ComponentSettingsIdentifier, ComponentSettingsListItem, DataGridControl, ErrorResponse, FileParameter, FileResponse, ListItemType, ProfileGroup, RepositoryPackageReference, RepositorySettingsPackageDefinition, SettingsTapPackage } from './DTOs';
2
- import { ConnectionOptions, RequestOptions, Subscription, SubscriptionOptions, Msg } from 'nats.ws';
2
+ import { ConnectionOptions, RequestOptions, Subscription, SubscriptionOptions } from 'nats.ws';
3
3
  export declare class BaseClient {
4
4
  private connection;
5
5
  private baseSubject;
@@ -52,20 +52,30 @@ export declare class BaseClient {
52
52
  */
53
53
  protected subscribe(subject: string, options: SubscriptionOptions): Subscription;
54
54
  /**
55
- * Send an object to the nats server with chunks.
56
- * @param subject The subject to request
57
- * @param payload (optional)
58
- * @param options (optional)
59
- * @returns Promise of an object
55
+ * Make a request to the runner with a chunked payload. The response will be received in chunks.
56
+ * @param subject The request subject.
57
+ * @param payload The request body which will be chunked
58
+ * @param options Optional request options
59
+ * @param rawResponse If true, the response will not be decoded
60
+ * @returns
60
61
  */
61
- protected sendChunked<T>(subject: string, payload?: any, options?: RequestOptions, rawResponse?: boolean): Promise<T>;
62
- receiveFile<T>(msg: Msg, rawResponse?: boolean, opts?: RequestOptions): Promise<T>;
62
+ protected sendChunked<T>(subject: string, payload: any, options?: RequestOptions, rawResponse?: boolean): Promise<T>;
63
63
  /**
64
- * Request an object to the nats server with chunks.
65
- * @param subject The subject to request
66
- * @param payload (optional)
67
- * @param options (optional)
68
- * @returns Promise of an object
64
+ * Receive a chunked file specified by a request response
65
+ * @param requestResponse Contains a reply subject and a file descriptor which can be used to download chunks
66
+ * @param rawResponse If true, the response should not be decoded
67
+ * @param opts Request options
68
+ * @returns
69
+ */
70
+ private downloadChunkedRequest;
71
+ /**
72
+ * Make a request to the runner whose response will be sent in chunked
73
+ * @param subject The request subject
74
+ * @param payload Optional request body
75
+ * @param options Optional request options
76
+ * @param rawResponse If true, the return value will not be decoded
77
+ * @param fullSubject If true, the base subject will not be prepended
78
+ * @returns
69
79
  */
70
80
  protected requestChunked<T>(subject: string, payload?: any, options?: RequestOptions, rawResponse?: boolean, fullSubject?: boolean): Promise<T>;
71
81
  /**
package/lib/BaseClient.js CHANGED
@@ -189,15 +189,16 @@ var BaseClient = /** @class */ (function () {
189
189
  return this.connection.subscribe(natsSubject, options);
190
190
  };
191
191
  /**
192
- * Send an object to the nats server with chunks.
193
- * @param subject The subject to request
194
- * @param payload (optional)
195
- * @param options (optional)
196
- * @returns Promise of an object
192
+ * Make a request to the runner with a chunked payload. The response will be received in chunks.
193
+ * @param subject The request subject.
194
+ * @param payload The request body which will be chunked
195
+ * @param options Optional request options
196
+ * @param rawResponse If true, the response will not be decoded
197
+ * @returns
197
198
  */
198
199
  BaseClient.prototype.sendChunked = function (subject, payload, options, rawResponse) {
199
200
  return __awaiter(this, void 0, void 0, function () {
200
- var stringCodec, data, headers, opts, fileDescriptor, msg, jsonCodec, response, error, getChunk, dataSubject, i;
201
+ var stringCodec, data, headers, opts, fileDescriptor, requestResponse, jsonCodec, response, error, getChunk, dataSubject, i;
201
202
  return __generator(this, function (_a) {
202
203
  switch (_a.label) {
203
204
  case 0:
@@ -220,46 +221,59 @@ var BaseClient = /** @class */ (function () {
220
221
  return [2 /*return*/, Promise.reject("".concat(subject, ": File is empty!"))];
221
222
  return [4 /*yield*/, this.connection.request(subject, stringCodec.encode(JSON.stringify(fileDescriptor)), opts)];
222
223
  case 1:
223
- msg = _a.sent();
224
- if (msg.data.length > 0) {
224
+ requestResponse = _a.sent();
225
+ if (requestResponse.data.length > 0) {
225
226
  jsonCodec = JSONCodec();
226
- response = jsonCodec.decode(msg.data);
227
+ response = jsonCodec.decode(requestResponse.data);
227
228
  if (this.isErrorResponse(response)) {
228
229
  error = ErrorResponse.fromJS(response);
229
230
  this.eventEmitter.emit(Events.ERROR, error);
230
231
  return [2 /*return*/, Promise.reject(error)];
231
232
  }
232
233
  }
233
- if (!msg.reply) {
234
+ // This should never happen. If it does happen, it likely means we are targetting an incompatible Runner version.
235
+ if (!requestResponse.reply) {
234
236
  return [2 /*return*/, Promise.reject('Send chunks: Runner did not return a reply subject.')];
235
237
  }
236
238
  getChunk = function (chunk) {
237
239
  var offset = chunk * fileDescriptor.chunkSize;
238
240
  return data.slice(offset, offset + fileDescriptor.chunkSize);
239
241
  };
240
- dataSubject = msg.reply;
242
+ dataSubject = requestResponse.reply;
241
243
  i = 0;
242
244
  _a.label = 2;
243
245
  case 2:
244
246
  if (!(i < fileDescriptor.numberOfChunks)) return [3 /*break*/, 5];
245
247
  return [4 /*yield*/, this.connection.request(dataSubject, getChunk(i), opts)];
246
248
  case 3:
247
- msg = _a.sent();
248
- dataSubject = msg.reply;
249
+ // The runner must acknowledge that it has received each chunk.
250
+ // Likewise, we must wait for the runner to acknowledge each chunk
251
+ // before sending the next one, because the acknowledge from the runner
252
+ // contains the subject where we should send the next chunk.
253
+ requestResponse = _a.sent();
254
+ dataSubject = requestResponse.reply;
249
255
  _a.label = 4;
250
256
  case 4:
251
257
  i++;
252
258
  return [3 /*break*/, 2];
253
259
  case 5:
254
- // Receive a response based on the last message
255
- return [2 /*return*/, this.receiveFile(msg, rawResponse, opts)];
260
+ // The response to any chunked request is itself a chunked response.
261
+ // The last acknowledge from the runner indicates the subject where the response can be downloaded from.
262
+ return [2 /*return*/, this.downloadChunkedRequest(requestResponse, rawResponse, opts)];
256
263
  }
257
264
  });
258
265
  });
259
266
  };
260
- BaseClient.prototype.receiveFile = function (msg, rawResponse, opts) {
267
+ /**
268
+ * Receive a chunked file specified by a request response
269
+ * @param requestResponse Contains a reply subject and a file descriptor which can be used to download chunks
270
+ * @param rawResponse If true, the response should not be decoded
271
+ * @param opts Request options
272
+ * @returns
273
+ */
274
+ BaseClient.prototype.downloadChunkedRequest = function (requestResponse, rawResponse, opts) {
261
275
  return __awaiter(this, void 0, void 0, function () {
262
- var jsonCodec, fdResponse, error, fd, dataSubject, result, k, i, j, resultCodec;
276
+ var jsonCodec, responseBody, error, fileDescriptor, dataSubject, result, bytesReceived, i, j, resultCodec;
263
277
  return __generator(this, function (_a) {
264
278
  switch (_a.label) {
265
279
  case 0:
@@ -268,41 +282,44 @@ var BaseClient = /** @class */ (function () {
268
282
  if (this.connection.isClosed())
269
283
  return [2 /*return*/, Promise.reject("Chunking: Connection has been closed! Please reconnect!")];
270
284
  jsonCodec = JSONCodec();
271
- fdResponse = jsonCodec.decode(msg.data);
272
- if (this.isErrorResponse(fdResponse)) {
273
- error = ErrorResponse.fromJS(fdResponse);
285
+ responseBody = jsonCodec.decode(requestResponse.data);
286
+ if (this.isErrorResponse(responseBody)) {
287
+ error = ErrorResponse.fromJS(responseBody);
274
288
  this.eventEmitter.emit(Events.ERROR, error);
275
289
  return [2 /*return*/, Promise.reject(error)];
276
290
  }
277
- fd = FileDescriptor.fromJS(fdResponse);
278
- if (!msg.reply || !fd || fd.numberOfChunks === 0) {
291
+ fileDescriptor = FileDescriptor.fromJS(responseBody);
292
+ if (!requestResponse.reply || !fileDescriptor || fileDescriptor.numberOfChunks === 0) {
279
293
  return [2 /*return*/, Promise.reject('Chunking: Response payload does not indicate a chunked response.')];
280
294
  }
281
- dataSubject = msg.reply;
282
- result = new Uint8Array(fd.fileSize);
283
- k = 0;
295
+ dataSubject = requestResponse.reply;
296
+ result = new Uint8Array(fileDescriptor.fileSize);
297
+ bytesReceived = 0;
284
298
  i = 0;
285
299
  _a.label = 1;
286
300
  case 1:
287
- if (!(i < fd.numberOfChunks)) return [3 /*break*/, 4];
301
+ if (!(i < fileDescriptor.numberOfChunks)) return [3 /*break*/, 4];
288
302
  return [4 /*yield*/, this.connection.request(dataSubject, Empty, opts)];
289
303
  case 2:
290
- msg = _a.sent();
291
- dataSubject = msg.reply;
292
- for (j = 0; j < msg.data.length; j++) {
293
- result[k++] = msg.data[j];
304
+ // Send a request with an empty payload to acknowledge that we received the previous chunk
305
+ // The response body contains the current chunk.
306
+ // The reply subject of the response indicates where we can get the next chunk
307
+ requestResponse = _a.sent();
308
+ dataSubject = requestResponse.reply;
309
+ for (j = 0; j < requestResponse.data.length; j++) {
310
+ result[bytesReceived++] = requestResponse.data[j];
294
311
  }
295
312
  _a.label = 3;
296
313
  case 3:
297
314
  i++;
298
315
  return [3 /*break*/, 1];
299
316
  case 4:
300
- // Send an empty message to acknowledge the final chunk was received
317
+ // Send an empty message to acknowledge that the final chunk was received
301
318
  this.connection.publish(dataSubject, Empty);
302
- if (k !== fd.fileSize) {
303
- return [2 /*return*/, Promise.reject("Unexpected repsonse size. Got ".concat(k, " bytes, but expected ").concat(fd.fileSize, "."))];
319
+ if (bytesReceived !== fileDescriptor.fileSize) {
320
+ return [2 /*return*/, Promise.reject("Unexpected repsonse size. Got ".concat(bytesReceived, " bytes, but expected ").concat(fileDescriptor.fileSize, "."))];
304
321
  }
305
- // Avoid decoding the response if the expected response is bytearray
322
+ // The runner skips the encoding step if the return type is a byte array, so we must also skip the decoding step in this case.
306
323
  if (rawResponse)
307
324
  return [2 /*return*/, Promise.resolve(result)];
308
325
  resultCodec = JSONCodec();
@@ -312,15 +329,17 @@ var BaseClient = /** @class */ (function () {
312
329
  });
313
330
  };
314
331
  /**
315
- * Request an object to the nats server with chunks.
316
- * @param subject The subject to request
317
- * @param payload (optional)
318
- * @param options (optional)
319
- * @returns Promise of an object
332
+ * Make a request to the runner whose response will be sent in chunked
333
+ * @param subject The request subject
334
+ * @param payload Optional request body
335
+ * @param options Optional request options
336
+ * @param rawResponse If true, the return value will not be decoded
337
+ * @param fullSubject If true, the base subject will not be prepended
338
+ * @returns
320
339
  */
321
340
  BaseClient.prototype.requestChunked = function (subject, payload, options, rawResponse, fullSubject) {
322
341
  return __awaiter(this, void 0, void 0, function () {
323
- var data, stringCodec, headers, opts, msg;
342
+ var data, stringCodec, headers, opts, requestResponse;
324
343
  return __generator(this, function (_a) {
325
344
  switch (_a.label) {
326
345
  case 0:
@@ -342,8 +361,8 @@ var BaseClient = /** @class */ (function () {
342
361
  opts = __assign(__assign({}, options), { timeout: this.timeout, headers: headers });
343
362
  return [4 /*yield*/, this.connection.request(subject, data, opts)];
344
363
  case 1:
345
- msg = _a.sent();
346
- return [2 /*return*/, this.receiveFile(msg, rawResponse, opts)];
364
+ requestResponse = _a.sent();
365
+ return [2 /*return*/, this.downloadChunkedRequest(requestResponse, rawResponse, opts)];
347
366
  }
348
367
  });
349
368
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opentap/runner-client",
3
- "version": "2.2.4-alpha.1.1",
3
+ "version": "2.2.4",
4
4
  "description": "This is the web client for the OpenTAP Runner.",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",