@opentap/runner-client 2.3.2-alpha.1.1 → 2.3.2-alpha.1.5
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/lib/BaseClient.d.ts +10 -11
- package/lib/BaseClient.js +89 -118
- package/lib/RunnerClient.js +1 -1
- package/lib/SessionClient.js +3 -1
- package/package.json +1 -1
package/lib/BaseClient.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { ComponentSettingsBase, ComponentSettingsIdentifier, ComponentSettingsListItem, DataGridControl, ErrorResponse, FileParameter, FileResponse, ListItemType, ProfileGroup, RepositoryPackageReference, RepositorySettingsPackageDefinition, SettingsTapPackage } from './DTOs';
|
|
2
|
-
import { ConnectionOptions,
|
|
2
|
+
import { ConnectionOptions, Subscription, SubscriptionOptions, PublishOptions } from 'nats.ws';
|
|
3
|
+
interface BaseClientRequestOptions {
|
|
4
|
+
options?: PublishOptions;
|
|
5
|
+
rawResponse?: boolean;
|
|
6
|
+
fullSubject?: boolean;
|
|
7
|
+
timeout?: number;
|
|
8
|
+
}
|
|
3
9
|
export declare class BaseClient {
|
|
4
10
|
private connection;
|
|
5
11
|
private baseSubject;
|
|
@@ -9,7 +15,6 @@ export declare class BaseClient {
|
|
|
9
15
|
private _accessToken;
|
|
10
16
|
private _headers;
|
|
11
17
|
private _timeout;
|
|
12
|
-
private _chunkSize;
|
|
13
18
|
/** Get request access token */
|
|
14
19
|
get accessToken(): string;
|
|
15
20
|
/** Set request access token */
|
|
@@ -23,6 +28,7 @@ export declare class BaseClient {
|
|
|
23
28
|
/** Set timeout in milliseconds. Default is 40000 milliseconds */
|
|
24
29
|
set timeout(value: number);
|
|
25
30
|
constructor(baseSubject: string, options: ConnectionOptions);
|
|
31
|
+
private withTimeout;
|
|
26
32
|
/**
|
|
27
33
|
* Send a request to the nats server.
|
|
28
34
|
* @param subject The subject to request
|
|
@@ -30,7 +36,7 @@ export declare class BaseClient {
|
|
|
30
36
|
* @param options (optional)
|
|
31
37
|
* @returns Promise of an object
|
|
32
38
|
*/
|
|
33
|
-
protected request<T>(subject: string, payload?: any, options?:
|
|
39
|
+
protected request<T>(subject: string, payload?: any, options?: BaseClientRequestOptions): Promise<T>;
|
|
34
40
|
/**
|
|
35
41
|
* Handle the error
|
|
36
42
|
* @param error
|
|
@@ -50,14 +56,6 @@ export declare class BaseClient {
|
|
|
50
56
|
* @returns Subscription object
|
|
51
57
|
*/
|
|
52
58
|
protected subscribe(subject: string, options: SubscriptionOptions): Subscription;
|
|
53
|
-
/**
|
|
54
|
-
* Receive a chunked file specified by a request response
|
|
55
|
-
* @param requestResponse Contains a reply subject and a file descriptor which can be used to download chunks
|
|
56
|
-
* @param rawResponse If true, the response should not be decoded
|
|
57
|
-
* @param opts Request options
|
|
58
|
-
* @returns
|
|
59
|
-
*/
|
|
60
|
-
private downloadChunkedRequest;
|
|
61
59
|
protected encode(payload: any): Uint8Array;
|
|
62
60
|
/**
|
|
63
61
|
* Check if the the response is an error from the server.
|
|
@@ -246,3 +244,4 @@ export declare class BaseClient {
|
|
|
246
244
|
*/
|
|
247
245
|
downloadSettingsPackage(settingsTapPackage: SettingsTapPackage): Promise<FileResponse>;
|
|
248
246
|
}
|
|
247
|
+
export {};
|
package/lib/BaseClient.js
CHANGED
|
@@ -45,17 +45,8 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
45
45
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
46
46
|
}
|
|
47
47
|
};
|
|
48
|
-
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
49
|
-
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
50
|
-
if (ar || !(i in from)) {
|
|
51
|
-
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
52
|
-
ar[i] = from[i];
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return to.concat(ar || Array.prototype.slice.call(from));
|
|
56
|
-
};
|
|
57
48
|
import { ComponentSettingsBase, ComponentSettingsIdentifier, ComponentSettingsListItem, DataGridControl, ErrorResponse, FileDescriptor, ListItemType, ProfileGroup, } from './DTOs';
|
|
58
|
-
import { Empty, ErrorCode, JSONCodec,
|
|
49
|
+
import { Empty, ErrorCode, JSONCodec, StringCodec, connect, headers, } from 'nats.ws';
|
|
59
50
|
import { EventEmitter } from 'events';
|
|
60
51
|
var DEFAULT_TIMEOUT = 40000; // default timeout of 40 seconds
|
|
61
52
|
var Events;
|
|
@@ -66,7 +57,6 @@ var BaseClient = /** @class */ (function () {
|
|
|
66
57
|
function BaseClient(baseSubject, options) {
|
|
67
58
|
this.domainAccess = new Map();
|
|
68
59
|
this._headers = new Headers();
|
|
69
|
-
this._chunkSize = 512000;
|
|
70
60
|
this.baseSubject = baseSubject;
|
|
71
61
|
this.connectionOptions = __assign({}, options) || {};
|
|
72
62
|
this.connectionOptions.timeout = (options === null || options === void 0 ? void 0 : options.timeout) || DEFAULT_TIMEOUT;
|
|
@@ -108,6 +98,9 @@ var BaseClient = /** @class */ (function () {
|
|
|
108
98
|
enumerable: false,
|
|
109
99
|
configurable: true
|
|
110
100
|
});
|
|
101
|
+
BaseClient.prototype.withTimeout = function (promise, timeout) {
|
|
102
|
+
return Promise.race([promise, new Promise(function (_, reject) { return setTimeout(function () { return reject(new Error('Request timed out.')); }, timeout); })]);
|
|
103
|
+
};
|
|
111
104
|
/**
|
|
112
105
|
* Send a request to the nats server.
|
|
113
106
|
* @param subject The subject to request
|
|
@@ -115,74 +108,96 @@ var BaseClient = /** @class */ (function () {
|
|
|
115
108
|
* @param options (optional)
|
|
116
109
|
* @returns Promise of an object
|
|
117
110
|
*/
|
|
118
|
-
BaseClient.prototype.request = function (subject, payload, options
|
|
111
|
+
BaseClient.prototype.request = function (subject, payload, options) {
|
|
119
112
|
return __awaiter(this, void 0, void 0, function () {
|
|
120
|
-
var
|
|
113
|
+
var data, headers, replySubject, serverMaxPayload, requestId, opts, fileDescriptor, chunkNumber, subscription, getChunk, jsonCodec, responsePromise, chunk, i;
|
|
114
|
+
var _this = this;
|
|
121
115
|
return __generator(this, function (_a) {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
if (
|
|
152
|
-
|
|
153
|
-
case 3:
|
|
154
|
-
requestResponse = _a.sent();
|
|
155
|
-
dataSubject = requestResponse.reply;
|
|
156
|
-
_a.label = 4;
|
|
157
|
-
case 4:
|
|
158
|
-
i++;
|
|
159
|
-
return [3 /*break*/, 2];
|
|
160
|
-
case 5:
|
|
161
|
-
if (!(fileDescriptor.fileSize % fileDescriptor.chunkSize === 0)) return [3 /*break*/, 7];
|
|
162
|
-
return [4 /*yield*/, this.connection.request(dataSubject, Empty, opts)];
|
|
163
|
-
case 6:
|
|
164
|
-
requestResponse = _a.sent();
|
|
165
|
-
_a.label = 7;
|
|
166
|
-
case 7: return [4 /*yield*/, this.downloadChunkedRequest(requestResponse, rawResponse, opts)];
|
|
167
|
-
case 8:
|
|
168
|
-
result = _a.sent();
|
|
169
|
-
if (this.isErrorResponse(result)) {
|
|
170
|
-
error = ErrorResponse.fromJS(result);
|
|
171
|
-
this.eventEmitter.emit(Events.ERROR, error);
|
|
172
|
-
return [2 /*return*/, Promise.reject(error)];
|
|
173
|
-
}
|
|
174
|
-
return [2 /*return*/, result];
|
|
175
|
-
case 9:
|
|
176
|
-
ex_1 = _a.sent();
|
|
177
|
-
if (ex_1 instanceof NatsError) {
|
|
178
|
-
return [2 /*return*/, Promise.reject(this.natsErrorHandler(ex_1, originalSubject))];
|
|
116
|
+
// Prepend the base subject if the given subject does not start with that
|
|
117
|
+
if (!(options === null || options === void 0 ? void 0 : options.fullSubject)) {
|
|
118
|
+
subject = "".concat(this.baseSubject, ".Request.").concat(subject);
|
|
119
|
+
}
|
|
120
|
+
if (!this.connection)
|
|
121
|
+
return [2 /*return*/, Promise.reject("".concat(subject, ": Connection is down! Please try again!"))];
|
|
122
|
+
if (this.connection.isClosed())
|
|
123
|
+
return [2 /*return*/, Promise.reject("".concat(subject, ": Connection has been closed! Please reconnect!"))];
|
|
124
|
+
data = this.encode(payload);
|
|
125
|
+
headers = this.buildHeaders();
|
|
126
|
+
replySubject = crypto.randomUUID();
|
|
127
|
+
serverMaxPayload = 10;
|
|
128
|
+
headers.append('ChunkSize', serverMaxPayload.toString());
|
|
129
|
+
requestId = crypto.randomUUID();
|
|
130
|
+
headers.append('RequestId', requestId);
|
|
131
|
+
opts = __assign(__assign({}, options === null || options === void 0 ? void 0 : options.options), { headers: headers, reply: replySubject });
|
|
132
|
+
fileDescriptor = new FileDescriptor(data.length, serverMaxPayload);
|
|
133
|
+
chunkNumber = 1;
|
|
134
|
+
headers.set('ChunkNumber', chunkNumber.toString());
|
|
135
|
+
subscription = this.connection.subscribe(replySubject);
|
|
136
|
+
getChunk = function (chunk) {
|
|
137
|
+
var offset = chunk * fileDescriptor.chunkSize;
|
|
138
|
+
return data.slice(offset, offset + fileDescriptor.chunkSize);
|
|
139
|
+
};
|
|
140
|
+
jsonCodec = JSONCodec();
|
|
141
|
+
responsePromise = new Promise(function (resolve, reject) {
|
|
142
|
+
var messages = [];
|
|
143
|
+
subscription.callback = function (error, message) {
|
|
144
|
+
var _a;
|
|
145
|
+
if (error) {
|
|
146
|
+
reject(error);
|
|
179
147
|
}
|
|
180
|
-
|
|
181
|
-
|
|
148
|
+
messages.push(message);
|
|
149
|
+
if (message.data.length === 0 || message.data.length < serverMaxPayload) {
|
|
150
|
+
subscription.unsubscribe();
|
|
151
|
+
var finalMessage = messages[messages.length - 1];
|
|
152
|
+
var finalMessageNumber = (_a = finalMessage.headers) === null || _a === void 0 ? void 0 : _a.get('ChunkNumber');
|
|
153
|
+
if (!finalMessageNumber) {
|
|
154
|
+
return reject('Response is not a valid chunk.');
|
|
155
|
+
}
|
|
156
|
+
if (parseInt(finalMessageNumber) !== messages.length) {
|
|
157
|
+
return reject("Expected {finalMessageNumber} chunks, but received ".concat(messages.length, ". ") +
|
|
158
|
+
"The connection may have been interrupted.");
|
|
159
|
+
}
|
|
160
|
+
// Concatenate the payloads
|
|
161
|
+
var dataArrays = messages.map(function (m) { return m.data; });
|
|
162
|
+
var totalSize = dataArrays.reduce(function (total, current) { return total + current.length; }, 0);
|
|
163
|
+
var flattenedArray_1 = new Uint8Array(totalSize);
|
|
164
|
+
var k_1 = 0;
|
|
165
|
+
dataArrays.map(function (m) {
|
|
166
|
+
for (var i = 0; i < m.length; i++) {
|
|
167
|
+
flattenedArray_1[k_1++] = m[i];
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
return resolve(flattenedArray_1);
|
|
182
171
|
}
|
|
183
|
-
|
|
184
|
-
|
|
172
|
+
};
|
|
173
|
+
})
|
|
174
|
+
.then(function (byteArray) {
|
|
175
|
+
var response = (options === null || options === void 0 ? void 0 : options.rawResponse) ? byteArray : jsonCodec.decode(byteArray);
|
|
176
|
+
return _this.isErrorResponse(response) ? Promise.reject(ErrorResponse.fromJS(response)) : Promise.resolve(response);
|
|
177
|
+
})
|
|
178
|
+
.catch(function (err) {
|
|
179
|
+
return Promise.reject(_this.natsErrorHandler(err, subject));
|
|
180
|
+
});
|
|
181
|
+
chunk = getChunk(0);
|
|
182
|
+
this.connection.publish(subject, chunk, opts);
|
|
183
|
+
chunkNumber += 1;
|
|
184
|
+
for (i = 1; i < fileDescriptor.numberOfChunks; i++) {
|
|
185
|
+
headers.set('ChunkNumber', chunkNumber.toString());
|
|
186
|
+
chunk = getChunk(i);
|
|
187
|
+
this.connection.publish(subject, chunk, opts);
|
|
188
|
+
chunkNumber += 1;
|
|
189
|
+
}
|
|
190
|
+
// In the special case where the last published chunk was full, we need to publish
|
|
191
|
+
// an empty message
|
|
192
|
+
if (data.length > 0 && data.length % fileDescriptor.chunkSize === 0) {
|
|
193
|
+
headers.set('ChunkNumber', chunkNumber.toString());
|
|
194
|
+
this.connection.publish(subject, Empty, opts);
|
|
195
|
+
}
|
|
196
|
+
// Now that we have sent the terminating chunk, the result should arrive on our promise.
|
|
197
|
+
if (options === null || options === void 0 ? void 0 : options.timeout) {
|
|
198
|
+
return [2 /*return*/, this.withTimeout(responsePromise, options.timeout)];
|
|
185
199
|
}
|
|
200
|
+
return [2 /*return*/, responsePromise];
|
|
186
201
|
});
|
|
187
202
|
});
|
|
188
203
|
};
|
|
@@ -234,50 +249,6 @@ var BaseClient = /** @class */ (function () {
|
|
|
234
249
|
var natsSubject = "".concat(this.baseSubject, ".").concat(subject);
|
|
235
250
|
return this.connection.subscribe(natsSubject, options);
|
|
236
251
|
};
|
|
237
|
-
/**
|
|
238
|
-
* Receive a chunked file specified by a request response
|
|
239
|
-
* @param requestResponse Contains a reply subject and a file descriptor which can be used to download chunks
|
|
240
|
-
* @param rawResponse If true, the response should not be decoded
|
|
241
|
-
* @param opts Request options
|
|
242
|
-
* @returns
|
|
243
|
-
*/
|
|
244
|
-
BaseClient.prototype.downloadChunkedRequest = function (requestResponse, rawResponse, opts) {
|
|
245
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
246
|
-
var result, resultCodec;
|
|
247
|
-
return __generator(this, function (_a) {
|
|
248
|
-
switch (_a.label) {
|
|
249
|
-
case 0:
|
|
250
|
-
if (!this.connection)
|
|
251
|
-
return [2 /*return*/, Promise.reject('Chunking: Connection is down! Please try again!')];
|
|
252
|
-
if (this.connection.isClosed())
|
|
253
|
-
return [2 /*return*/, Promise.reject("Chunking: Connection has been closed! Please reconnect!")];
|
|
254
|
-
result = new Uint8Array([]);
|
|
255
|
-
_a.label = 1;
|
|
256
|
-
case 1:
|
|
257
|
-
result = new Uint8Array(__spreadArray(__spreadArray([], Array.from(result), true), Array.from(requestResponse.data), true));
|
|
258
|
-
// Acknowledge that the final chunk was received
|
|
259
|
-
if (requestResponse.data.length < this._chunkSize) {
|
|
260
|
-
this.connection.publish(requestResponse.reply, Empty, opts);
|
|
261
|
-
return [3 /*break*/, 4];
|
|
262
|
-
}
|
|
263
|
-
return [4 /*yield*/, this.connection.request(requestResponse.reply, Empty, opts)];
|
|
264
|
-
case 2:
|
|
265
|
-
requestResponse = _a.sent();
|
|
266
|
-
_a.label = 3;
|
|
267
|
-
case 3: return [3 /*break*/, 1];
|
|
268
|
-
case 4:
|
|
269
|
-
if (result.length !== 0) {
|
|
270
|
-
// 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.
|
|
271
|
-
if (rawResponse)
|
|
272
|
-
return [2 /*return*/, Promise.resolve(result)];
|
|
273
|
-
resultCodec = JSONCodec();
|
|
274
|
-
return [2 /*return*/, resultCodec.decode(result)];
|
|
275
|
-
}
|
|
276
|
-
return [2 /*return*/];
|
|
277
|
-
}
|
|
278
|
-
});
|
|
279
|
-
});
|
|
280
|
-
};
|
|
281
252
|
BaseClient.prototype.encode = function (payload) {
|
|
282
253
|
if (!payload) {
|
|
283
254
|
return Empty;
|
package/lib/RunnerClient.js
CHANGED
|
@@ -51,7 +51,7 @@ var RunnerClient = /** @class */ (function (_super) {
|
|
|
51
51
|
*/
|
|
52
52
|
RunnerClient.prototype.resolveImage = function (images, timeout) {
|
|
53
53
|
return (images === null || images === void 0 ? void 0 : images.length) > 0
|
|
54
|
-
? this.request('ResolveImage', images, { timeout: timeout
|
|
54
|
+
? this.request('ResolveImage', images, { timeout: timeout })
|
|
55
55
|
.then(function (imageJs) { return Image.fromJS(imageJs); })
|
|
56
56
|
.then(this.success())
|
|
57
57
|
.catch(this.error())
|
package/lib/SessionClient.js
CHANGED
|
@@ -218,7 +218,9 @@ var SessionClient = /** @class */ (function (_super) {
|
|
|
218
218
|
return Promise.reject('The source of the provided resource is not a nats subject.');
|
|
219
219
|
}
|
|
220
220
|
var subject = resource.source.slice(runnerResourcePrefix.length);
|
|
221
|
-
return this.request(subject, undefined,
|
|
221
|
+
return this.request(subject, undefined, { rawResponse: true, fullSubject: true })
|
|
222
|
+
.then(this.success())
|
|
223
|
+
.catch(this.error());
|
|
222
224
|
};
|
|
223
225
|
/**
|
|
224
226
|
* Load test plan using a test plan TapPackage from a repository
|