azure-kusto-ingest 4.0.5 → 5.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/README.md +15 -2
- package/{source → dist-esm/src}/abstractKustoClient.js +0 -0
- package/{source → dist-esm/src}/columnMappings.js +0 -0
- package/dist-esm/src/descriptors.js +64 -0
- package/{source → dist-esm/src}/errors.js +0 -0
- package/dist-esm/src/fileDescriptor.browser.js +44 -0
- package/dist-esm/src/fileDescriptor.js +81 -0
- package/{index.js → dist-esm/src/index.js} +12 -10
- package/dist-esm/src/ingestClient.browser.js +43 -0
- package/dist-esm/src/ingestClient.js +45 -0
- package/dist-esm/src/ingestClientBase.js +47 -0
- package/{source → dist-esm/src}/ingestionBlobInfo.js +1 -5
- package/{source → dist-esm/src}/ingestionProperties.js +0 -0
- package/{source → dist-esm/src}/managedStreamingIngestClient.js +36 -38
- package/dist-esm/src/resourceManager.js +142 -0
- package/dist-esm/src/retry.js +37 -0
- package/{source → dist-esm/src}/status.js +0 -0
- package/dist-esm/src/statusQ.js +119 -0
- package/dist-esm/src/streamUtils.browser.js +22 -0
- package/{source → dist-esm/src}/streamUtils.js +24 -19
- package/dist-esm/src/streamingIngestClient.browser.js +42 -0
- package/dist-esm/src/streamingIngestClient.js +51 -0
- package/dist-esm/tsconfig.tsbuildinfo +1 -0
- package/package.json +35 -20
- package/{source → types/src}/abstractKustoClient.d.ts +4 -5
- package/{source → types/src}/columnMappings.d.ts +1 -0
- package/types/src/descriptors.d.ts +39 -0
- package/{source → types/src}/errors.d.ts +1 -0
- package/types/src/fileDescriptor.browser.d.ts +16 -0
- package/types/src/fileDescriptor.d.ts +29 -0
- package/{index.d.ts → types/src/index.d.ts} +13 -11
- package/types/src/ingestClient.browser.d.ts +19 -0
- package/types/src/ingestClient.d.ts +21 -0
- package/types/src/ingestClientBase.d.ts +14 -0
- package/{source → types/src}/ingestionBlobInfo.d.ts +2 -2
- package/{source → types/src}/ingestionProperties.d.ts +1 -0
- package/{source → types/src}/managedStreamingIngestClient.d.ts +12 -4
- package/{source → types/src}/resourceManager.d.ts +7 -5
- package/{source → types/src}/retry.d.ts +1 -0
- package/{source → types/src}/status.d.ts +1 -0
- package/{source → types/src}/statusQ.d.ts +1 -0
- package/types/src/streamUtils.browser.d.ts +7 -0
- package/types/src/streamUtils.d.ts +8 -0
- package/types/src/streamingIngestClient.browser.d.ts +21 -0
- package/types/src/streamingIngestClient.d.ts +23 -0
- package/example.js +0 -128
- package/source/descriptors.d.ts +0 -37
- package/source/descriptors.js +0 -125
- package/source/ingestClient.d.ts +0 -19
- package/source/ingestClient.js +0 -104
- package/source/resourceManager.js +0 -158
- package/source/retry.js +0 -48
- package/source/statusQ.js +0 -138
- package/source/streamUtils.d.ts +0 -6
- package/source/streamingIngestClient.d.ts +0 -15
- package/source/streamingIngestClient.js +0 -52
- package/tsconfig.tsbuildinfo +0 -1
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) Microsoft Corporation.
|
|
3
|
+
// Licensed under the MIT License.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.ResourceManager = exports.IngestClientResources = exports.ResourceURI = void 0;
|
|
6
|
+
const azure_kusto_data_1 = require("azure-kusto-data");
|
|
7
|
+
const retry_1 = require("./retry");
|
|
8
|
+
const storage_blob_1 = require("@azure/storage-blob");
|
|
9
|
+
const ATTEMPT_COUNT = 4;
|
|
10
|
+
class ResourceURI {
|
|
11
|
+
constructor(uri) {
|
|
12
|
+
this.uri = uri;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.ResourceURI = ResourceURI;
|
|
16
|
+
class IngestClientResources {
|
|
17
|
+
constructor(securedReadyForAggregationQueues = null, failedIngestionsQueues = null, successfulIngestionsQueues = null, containers = null) {
|
|
18
|
+
this.securedReadyForAggregationQueues = securedReadyForAggregationQueues;
|
|
19
|
+
this.failedIngestionsQueues = failedIngestionsQueues;
|
|
20
|
+
this.successfulIngestionsQueues = successfulIngestionsQueues;
|
|
21
|
+
this.containers = containers;
|
|
22
|
+
}
|
|
23
|
+
valid() {
|
|
24
|
+
const resources = [this.securedReadyForAggregationQueues, this.failedIngestionsQueues, this.failedIngestionsQueues, this.containers];
|
|
25
|
+
return resources.reduce((prev, current) => !!(prev && current), true);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.IngestClientResources = IngestClientResources;
|
|
29
|
+
class ResourceManager {
|
|
30
|
+
constructor(kustoClient, isBrowser = false) {
|
|
31
|
+
this.kustoClient = kustoClient;
|
|
32
|
+
this.isBrowser = isBrowser;
|
|
33
|
+
this.baseSleepTimeSecs = 1;
|
|
34
|
+
this.baseJitterSecs = 1;
|
|
35
|
+
this.refreshPeriod = azure_kusto_data_1.TimeUtils.toMilliseconds(1, 0, 0);
|
|
36
|
+
this.ingestClientResources = null;
|
|
37
|
+
this.ingestClientResourcesLastUpdate = null;
|
|
38
|
+
this.authorizationContext = null;
|
|
39
|
+
this.authorizationContextLastUpdate = null;
|
|
40
|
+
}
|
|
41
|
+
async refreshIngestClientResources() {
|
|
42
|
+
const now = Date.now();
|
|
43
|
+
if (!this.ingestClientResources ||
|
|
44
|
+
!this.ingestClientResourcesLastUpdate ||
|
|
45
|
+
this.ingestClientResourcesLastUpdate + this.refreshPeriod <= now ||
|
|
46
|
+
!this.ingestClientResources.valid()) {
|
|
47
|
+
this.ingestClientResources = await this.getIngestClientResourcesFromService();
|
|
48
|
+
this.ingestClientResourcesLastUpdate = now;
|
|
49
|
+
}
|
|
50
|
+
return this.ingestClientResources;
|
|
51
|
+
}
|
|
52
|
+
async getIngestClientResourcesFromService() {
|
|
53
|
+
const retry = new retry_1.ExponentialRetry(ATTEMPT_COUNT, this.baseSleepTimeSecs, this.baseJitterSecs);
|
|
54
|
+
while (retry.shouldTry()) {
|
|
55
|
+
try {
|
|
56
|
+
const cmd = `.get ingestion resources ${this.isBrowser ? `with (EnableBlobCors='true', EnableQueueCors='true', EnableTableCors='true')` : ""}`;
|
|
57
|
+
const response = await this.kustoClient.execute("NetDefaultDB", cmd);
|
|
58
|
+
const table = response.primaryResults[0];
|
|
59
|
+
return new IngestClientResources(this.getResourceByName(table, "SecuredReadyForAggregationQueue"), this.getResourceByName(table, "FailedIngestionsQueue"), this.getResourceByName(table, "SuccessfulIngestionsQueue"), this.getResourceByName(table, "TempStorage"));
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
if (!(error instanceof azure_kusto_data_1.KustoDataErrors.ThrottlingError)) {
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
await retry.backoff();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
throw new Error(`Failed to get ingestion resources from server - the request was throttled ${ATTEMPT_COUNT} times.`);
|
|
69
|
+
}
|
|
70
|
+
getResourceByName(table, resourceName) {
|
|
71
|
+
const result = [];
|
|
72
|
+
for (const row of table.rows()) {
|
|
73
|
+
const typedRow = row;
|
|
74
|
+
if (typedRow.ResourceTypeName === resourceName) {
|
|
75
|
+
result.push(new ResourceURI(typedRow.StorageRoot));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
async refreshAuthorizationContext() {
|
|
81
|
+
var _a;
|
|
82
|
+
const now = Date.now();
|
|
83
|
+
if (!((_a = this.authorizationContext) === null || _a === void 0 ? void 0 : _a.trim()) || !this.authorizationContextLastUpdate || this.authorizationContextLastUpdate + this.refreshPeriod <= now) {
|
|
84
|
+
this.authorizationContext = await this.getAuthorizationContextFromService();
|
|
85
|
+
this.authorizationContextLastUpdate = now;
|
|
86
|
+
if (this.authorizationContext == null) {
|
|
87
|
+
throw new Error("Authorization context can't be null");
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return this.authorizationContext;
|
|
91
|
+
}
|
|
92
|
+
async getAuthorizationContextFromService() {
|
|
93
|
+
const retry = new retry_1.ExponentialRetry(ATTEMPT_COUNT, this.baseSleepTimeSecs, this.baseJitterSecs);
|
|
94
|
+
while (retry.shouldTry()) {
|
|
95
|
+
try {
|
|
96
|
+
const response = await this.kustoClient.execute("NetDefaultDB", ".get kusto identity token");
|
|
97
|
+
const next = response.primaryResults[0].rows().next();
|
|
98
|
+
if (next.done) {
|
|
99
|
+
throw new Error("Failed to get authorization context - got empty results");
|
|
100
|
+
}
|
|
101
|
+
return next.value.toJSON().AuthorizationContext;
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
if (!(error instanceof azure_kusto_data_1.KustoDataErrors.ThrottlingError)) {
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
await retry.backoff();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
throw new Error(`Failed to get identity token from server - the request was throttled ${ATTEMPT_COUNT} times.`);
|
|
111
|
+
}
|
|
112
|
+
async getIngestionQueues() {
|
|
113
|
+
return (await this.refreshIngestClientResources()).securedReadyForAggregationQueues;
|
|
114
|
+
}
|
|
115
|
+
async getFailedIngestionsQueues() {
|
|
116
|
+
return (await this.refreshIngestClientResources()).failedIngestionsQueues;
|
|
117
|
+
}
|
|
118
|
+
async getSuccessfulIngestionsQueues() {
|
|
119
|
+
return (await this.refreshIngestClientResources()).successfulIngestionsQueues;
|
|
120
|
+
}
|
|
121
|
+
async getContainers() {
|
|
122
|
+
return (await this.refreshIngestClientResources()).containers;
|
|
123
|
+
}
|
|
124
|
+
async getAuthorizationContext() {
|
|
125
|
+
return this.refreshAuthorizationContext();
|
|
126
|
+
}
|
|
127
|
+
async getBlockBlobClient(blobName) {
|
|
128
|
+
const containers = await this.getContainers();
|
|
129
|
+
if (containers == null) {
|
|
130
|
+
throw new Error("Failed to get containers");
|
|
131
|
+
}
|
|
132
|
+
const container = containers[Math.floor(Math.random() * containers.length)];
|
|
133
|
+
const containerClient = new storage_blob_1.ContainerClient(container.uri);
|
|
134
|
+
return containerClient.getBlockBlobClient(blobName);
|
|
135
|
+
}
|
|
136
|
+
close() {
|
|
137
|
+
this.kustoClient.close();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
exports.ResourceManager = ResourceManager;
|
|
141
|
+
exports.default = ResourceManager;
|
|
142
|
+
//# sourceMappingURL=resourceManager.js.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) Microsoft Corporation.
|
|
3
|
+
// Licensed under the MIT License.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.ExponentialRetry = exports.sleep = void 0;
|
|
6
|
+
const sleep = (ms) => {
|
|
7
|
+
return new Promise((resolve) => {
|
|
8
|
+
setTimeout(resolve, ms);
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
exports.sleep = sleep;
|
|
12
|
+
class ExponentialRetry {
|
|
13
|
+
constructor(attemptCount, sleepBaseSecs, maxJitterSecs) {
|
|
14
|
+
this.attemptCount = attemptCount;
|
|
15
|
+
this.sleepBaseSecs = sleepBaseSecs;
|
|
16
|
+
this.maxJitterSecs = maxJitterSecs;
|
|
17
|
+
this.currentAttempt = 0;
|
|
18
|
+
}
|
|
19
|
+
async backoff() {
|
|
20
|
+
if (!this.shouldTry()) {
|
|
21
|
+
throw new Error("Max retries exceeded");
|
|
22
|
+
}
|
|
23
|
+
this.currentAttempt++;
|
|
24
|
+
if (!this.shouldTry()) {
|
|
25
|
+
// This was the last retry - no need to sleep
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const base = this.sleepBaseSecs * Math.pow(2, this.currentAttempt - 1);
|
|
29
|
+
const jitter = Math.floor(this.maxJitterSecs * Math.random());
|
|
30
|
+
await (0, exports.sleep)(1000 * (base + jitter));
|
|
31
|
+
}
|
|
32
|
+
shouldTry() {
|
|
33
|
+
return this.currentAttempt < this.attemptCount;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.ExponentialRetry = ExponentialRetry;
|
|
37
|
+
//# sourceMappingURL=retry.js.map
|
|
File without changes
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) Microsoft Corporation.
|
|
3
|
+
// Licensed under the MIT License.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.StatusQueue = void 0;
|
|
6
|
+
const storage_queue_1 = require("@azure/storage-queue");
|
|
7
|
+
class QueueDetails {
|
|
8
|
+
constructor(name, service) {
|
|
9
|
+
this.name = name;
|
|
10
|
+
this.service = service;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
const shuffle = (a) => {
|
|
14
|
+
for (let i = a.length - 1; i > 0; i--) {
|
|
15
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
16
|
+
const temp = a[j];
|
|
17
|
+
a[j] = a[i];
|
|
18
|
+
a[i] = temp;
|
|
19
|
+
}
|
|
20
|
+
return a;
|
|
21
|
+
};
|
|
22
|
+
class StatusQueue {
|
|
23
|
+
constructor(getQueuesFunc, messageCls) {
|
|
24
|
+
this.getQueuesFunc = getQueuesFunc;
|
|
25
|
+
this.messageCls = messageCls;
|
|
26
|
+
}
|
|
27
|
+
_getQServices(queuesDetails) {
|
|
28
|
+
return queuesDetails.map((q) => {
|
|
29
|
+
const fullUri = q.uri;
|
|
30
|
+
if (!fullUri) {
|
|
31
|
+
throw new Error("Empty or null connection string");
|
|
32
|
+
}
|
|
33
|
+
// chop off sas
|
|
34
|
+
const indexOfSas = q.uri.indexOf("?");
|
|
35
|
+
const name = indexOfSas > 0 ? q.uri.substring(0, indexOfSas) : q.uri;
|
|
36
|
+
return new QueueDetails(name, new storage_queue_1.QueueClient(fullUri));
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
async isEmpty() {
|
|
40
|
+
const result = await this.peek(1, { raw: true });
|
|
41
|
+
return !result || result.length === 0;
|
|
42
|
+
}
|
|
43
|
+
decodeContent(content) {
|
|
44
|
+
return Buffer.from(content, "base64").toString("ascii");
|
|
45
|
+
}
|
|
46
|
+
deserializeMessage(m) {
|
|
47
|
+
return new this.messageCls(this.decodeContent(m.messageText), null, null);
|
|
48
|
+
}
|
|
49
|
+
async _peek(qs, n, options) {
|
|
50
|
+
const result = [];
|
|
51
|
+
const nonEmptyQs = [];
|
|
52
|
+
for (const q of qs) {
|
|
53
|
+
const response = await q.service.peekMessages();
|
|
54
|
+
const messages = response.peekedMessageItems;
|
|
55
|
+
if (messages && messages.length > 0) {
|
|
56
|
+
nonEmptyQs.push(q);
|
|
57
|
+
}
|
|
58
|
+
for (const m of messages) {
|
|
59
|
+
if (m && Object.keys(m).length > 0) {
|
|
60
|
+
result.push(options && options.raw ? m : this.deserializeMessage(m));
|
|
61
|
+
if (result.length === n) {
|
|
62
|
+
return { done: true, nonEmptyQs, result };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return { done: nonEmptyQs.length === 0, nonEmptyQs, result };
|
|
68
|
+
}
|
|
69
|
+
async peek(n = 1, options = null) {
|
|
70
|
+
const queues = await this.getQueuesFunc();
|
|
71
|
+
const qServices = shuffle(this._getQServices(queues));
|
|
72
|
+
const perQ = qServices.length > 1 ? Math.floor(n / qServices.length) : qServices.length;
|
|
73
|
+
// First, iterate evenly and randomly on status queues
|
|
74
|
+
const partial = await this._peek(qServices, perQ, options);
|
|
75
|
+
if (partial.done) {
|
|
76
|
+
return partial.result;
|
|
77
|
+
}
|
|
78
|
+
const messagesLeftToPeek = n - partial.result.length;
|
|
79
|
+
// In case queues are uneven, iterate again. This time, request for all n messages and trim
|
|
80
|
+
return (await this._peek(partial.nonEmptyQs, messagesLeftToPeek, options)).result;
|
|
81
|
+
}
|
|
82
|
+
async _pop(qs, n, options) {
|
|
83
|
+
const nonEmptyQs = [];
|
|
84
|
+
const result = [];
|
|
85
|
+
for (const q of qs) {
|
|
86
|
+
const response = await q.service.receiveMessages({ numOfMessages: n });
|
|
87
|
+
const messages = response.receivedMessageItems;
|
|
88
|
+
for (const m of messages) {
|
|
89
|
+
if (m && Object.keys(m).length > 0) {
|
|
90
|
+
result.push(options && options.raw ? m : this.deserializeMessage(m));
|
|
91
|
+
if (!(options && !options.remove)) {
|
|
92
|
+
await q.service.deleteMessage(m.messageId, m.popReceipt);
|
|
93
|
+
}
|
|
94
|
+
if (result.length === n) {
|
|
95
|
+
return { done: true, nonEmptyQs, result };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return { done: nonEmptyQs.length === 0, nonEmptyQs, result };
|
|
101
|
+
}
|
|
102
|
+
async pop(n = 1, options = null) {
|
|
103
|
+
var _a;
|
|
104
|
+
const queues = await this.getQueuesFunc();
|
|
105
|
+
const qServices = shuffle(this._getQServices(queues));
|
|
106
|
+
const perQ = qServices.length > 1 ? Math.floor(n / qServices.length) : qServices.length;
|
|
107
|
+
// First, iterate evenly and randomly on status queues
|
|
108
|
+
const partial = await this._pop(qServices, perQ, options);
|
|
109
|
+
if (partial.done) {
|
|
110
|
+
return partial.result;
|
|
111
|
+
}
|
|
112
|
+
const messagesLeftToPop = n - partial.result.length;
|
|
113
|
+
// In case queues are uneven, iterate again. This time, request for all n messages and trim
|
|
114
|
+
const final = await this._pop((_a = partial.result.nonEmptyQs) !== null && _a !== void 0 ? _a : [], messagesLeftToPop, options);
|
|
115
|
+
return partial.result.concat(final.result);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
exports.StatusQueue = StatusQueue;
|
|
119
|
+
//# sourceMappingURL=statusQ.js.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) Microsoft Corporation.
|
|
3
|
+
// Licensed under the MIT License.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.tryStreamToArray = exports.tryFileToBuffer = exports.fileToStream = void 0;
|
|
6
|
+
const descriptors_1 = require("./descriptors");
|
|
7
|
+
const fileToStream = async (file) => {
|
|
8
|
+
const streamFs = await file.file.arrayBuffer();
|
|
9
|
+
const compressionType = file.zipped ? descriptors_1.CompressionType.GZIP : descriptors_1.CompressionType.None;
|
|
10
|
+
return new descriptors_1.StreamDescriptor(streamFs, file.sourceId, compressionType);
|
|
11
|
+
};
|
|
12
|
+
exports.fileToStream = fileToStream;
|
|
13
|
+
const tryFileToBuffer = async (file) => {
|
|
14
|
+
return await (0, exports.fileToStream)(file);
|
|
15
|
+
};
|
|
16
|
+
exports.tryFileToBuffer = tryFileToBuffer;
|
|
17
|
+
// NOT USED
|
|
18
|
+
const tryStreamToArray = async (stream) => {
|
|
19
|
+
return Promise.resolve(stream);
|
|
20
|
+
};
|
|
21
|
+
exports.tryStreamToArray = tryStreamToArray;
|
|
22
|
+
//# sourceMappingURL=streamUtils.browser.js.map
|
|
@@ -1,31 +1,34 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// Copyright (c) Microsoft Corporation.
|
|
3
3
|
// Licensed under the MIT License.
|
|
4
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
5
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
6
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
7
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
8
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
9
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
10
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
11
|
-
});
|
|
12
|
-
};
|
|
13
4
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
14
5
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
6
|
};
|
|
16
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.tryStreamToArray = exports.
|
|
8
|
+
exports.tryStreamToArray = exports.tryFileToBuffer = exports.fileToStream = void 0;
|
|
18
9
|
const descriptors_1 = require("./descriptors");
|
|
19
10
|
const fs_1 = __importDefault(require("fs"));
|
|
20
11
|
const stream_1 = require("stream");
|
|
21
12
|
const stream_array_1 = __importDefault(require("stream-array"));
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const streamFs = fs_1.default.createReadStream(fileDescriptor.
|
|
13
|
+
// Returns fs.ReadStream for node and NodeJS.ReadableStream in browser
|
|
14
|
+
const fileToStream = (fileDescriptor) => {
|
|
15
|
+
const streamFs = fs_1.default.createReadStream(fileDescriptor.file);
|
|
25
16
|
const compressionType = fileDescriptor.zipped ? descriptors_1.CompressionType.GZIP : descriptors_1.CompressionType.None;
|
|
26
|
-
return new descriptors_1.StreamDescriptor(streamFs, fileDescriptor.sourceId, compressionType);
|
|
17
|
+
return Promise.resolve(new descriptors_1.StreamDescriptor(streamFs, fileDescriptor.sourceId, compressionType));
|
|
27
18
|
};
|
|
28
19
|
exports.fileToStream = fileToStream;
|
|
20
|
+
// Used in managed streaming where we buffer the file to memory for retries
|
|
21
|
+
const tryFileToBuffer = async (fileDescriptor) => {
|
|
22
|
+
try {
|
|
23
|
+
const buffer = fs_1.default.readFileSync(fileDescriptor.file);
|
|
24
|
+
const compressionType = fileDescriptor.zipped ? descriptors_1.CompressionType.GZIP : descriptors_1.CompressionType.None;
|
|
25
|
+
return new descriptors_1.StreamDescriptor(buffer, fileDescriptor.sourceId, compressionType);
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
return await (0, exports.fileToStream)(fileDescriptor);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
exports.tryFileToBuffer = tryFileToBuffer;
|
|
29
32
|
const mergeStreams = (...streams) => {
|
|
30
33
|
let pass = new stream_1.PassThrough();
|
|
31
34
|
let waiting = streams.length;
|
|
@@ -35,9 +38,11 @@ const mergeStreams = (...streams) => {
|
|
|
35
38
|
}
|
|
36
39
|
return pass;
|
|
37
40
|
};
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
const tryStreamToArray = async (stream, maxBufferSize) => {
|
|
42
|
+
if (stream instanceof Buffer) {
|
|
43
|
+
return stream;
|
|
44
|
+
}
|
|
45
|
+
return await new Promise((resolve, reject) => {
|
|
41
46
|
const result = [];
|
|
42
47
|
const endListener = () => resolve(Buffer.concat(result));
|
|
43
48
|
const dataHandler = (chunk) => {
|
|
@@ -46,7 +51,7 @@ const tryStreamToArray = (stream, maxBufferSize) => __awaiter(void 0, void 0, vo
|
|
|
46
51
|
if (result.reduce((sum, b) => sum + b.length, 0) > maxBufferSize) {
|
|
47
52
|
stream.removeListener("data", dataHandler);
|
|
48
53
|
stream.removeListener("end", endListener);
|
|
49
|
-
resolve(
|
|
54
|
+
resolve(mergeStreams((0, stream_array_1.default)(result), stream));
|
|
50
55
|
}
|
|
51
56
|
}
|
|
52
57
|
catch (e) {
|
|
@@ -56,6 +61,6 @@ const tryStreamToArray = (stream, maxBufferSize) => __awaiter(void 0, void 0, vo
|
|
|
56
61
|
stream.on("data", dataHandler);
|
|
57
62
|
stream.on("end", endListener);
|
|
58
63
|
});
|
|
59
|
-
}
|
|
64
|
+
};
|
|
60
65
|
exports.tryStreamToArray = tryStreamToArray;
|
|
61
66
|
//# sourceMappingURL=streamUtils.js.map
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) Microsoft Corporation.
|
|
3
|
+
// Licensed under the MIT License.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
const descriptors_1 = require("./descriptors");
|
|
6
|
+
const fileDescriptor_browser_1 = require("./fileDescriptor.browser");
|
|
7
|
+
const abstractKustoClient_1 = require("./abstractKustoClient");
|
|
8
|
+
const azure_kusto_data_1 = require("azure-kusto-data");
|
|
9
|
+
const streamUtils_browser_1 = require("./streamUtils.browser");
|
|
10
|
+
class KustoStreamingIngestClient extends abstractKustoClient_1.AbstractKustoClient {
|
|
11
|
+
constructor(kcsb, defaultProps) {
|
|
12
|
+
super(defaultProps);
|
|
13
|
+
this.kustoClient = new azure_kusto_data_1.Client(kcsb);
|
|
14
|
+
this.defaultDatabase = this.kustoClient.defaultDatabase;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Use Readable for Node.js and ArrayBuffer in browser
|
|
18
|
+
*/
|
|
19
|
+
async ingestFromStream(stream, ingestionProperties, clientRequestId) {
|
|
20
|
+
var _a;
|
|
21
|
+
this.ensureOpen();
|
|
22
|
+
const props = this._getMergedProps(ingestionProperties);
|
|
23
|
+
const descriptor = stream instanceof descriptors_1.StreamDescriptor ? stream : new descriptors_1.StreamDescriptor(stream);
|
|
24
|
+
return await this.kustoClient.executeStreamingIngest(props.database, props.table, descriptor.stream, props.format, (_a = props.ingestionMappingReference) !== null && _a !== void 0 ? _a : null, clientRequestId);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Use string for Node.js and Blob in browser
|
|
28
|
+
*/
|
|
29
|
+
async ingestFromFile(file, ingestionProperties) {
|
|
30
|
+
this.ensureOpen();
|
|
31
|
+
const descriptor = file instanceof fileDescriptor_browser_1.FileDescriptor ? file : new fileDescriptor_browser_1.FileDescriptor(file);
|
|
32
|
+
return this.ingestFromStream(await (0, streamUtils_browser_1.tryFileToBuffer)(descriptor), ingestionProperties);
|
|
33
|
+
}
|
|
34
|
+
close() {
|
|
35
|
+
if (!this._isClosed) {
|
|
36
|
+
this.kustoClient.close();
|
|
37
|
+
}
|
|
38
|
+
super.close();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
exports.default = KustoStreamingIngestClient;
|
|
42
|
+
//# sourceMappingURL=streamingIngestClient.browser.js.map
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) Microsoft Corporation.
|
|
3
|
+
// Licensed under the MIT License.
|
|
4
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
5
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
6
|
+
};
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
const descriptors_1 = require("./descriptors");
|
|
9
|
+
const fileDescriptor_1 = require("./fileDescriptor");
|
|
10
|
+
const zlib_1 = __importDefault(require("zlib"));
|
|
11
|
+
const abstractKustoClient_1 = require("./abstractKustoClient");
|
|
12
|
+
const azure_kusto_data_1 = require("azure-kusto-data");
|
|
13
|
+
const streamUtils_1 = require("./streamUtils");
|
|
14
|
+
class KustoStreamingIngestClient extends abstractKustoClient_1.AbstractKustoClient {
|
|
15
|
+
constructor(kcsb, defaultProps) {
|
|
16
|
+
super(defaultProps);
|
|
17
|
+
this.kustoClient = new azure_kusto_data_1.Client(kcsb);
|
|
18
|
+
this.defaultDatabase = this.kustoClient.defaultDatabase;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Use Readable for Node.js and ArrayBuffer in browser
|
|
22
|
+
*/
|
|
23
|
+
async ingestFromStream(stream, ingestionProperties, clientRequestId) {
|
|
24
|
+
var _a;
|
|
25
|
+
this.ensureOpen();
|
|
26
|
+
const props = this._getMergedProps(ingestionProperties);
|
|
27
|
+
const descriptor = stream instanceof descriptors_1.StreamDescriptor ? stream : new descriptors_1.StreamDescriptor(stream);
|
|
28
|
+
const compressedStream = descriptor.compressionType === descriptors_1.CompressionType.None
|
|
29
|
+
? !(descriptor.stream instanceof ArrayBuffer)
|
|
30
|
+
? descriptor.stream.pipe(zlib_1.default.createGzip())
|
|
31
|
+
: descriptor.stream
|
|
32
|
+
: descriptor.stream;
|
|
33
|
+
return await this.kustoClient.executeStreamingIngest(props.database, props.table, compressedStream, props.format, (_a = props.ingestionMappingReference) !== null && _a !== void 0 ? _a : null, clientRequestId);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Use string for Node.js and Blob in browser
|
|
37
|
+
*/
|
|
38
|
+
async ingestFromFile(file, ingestionProperties) {
|
|
39
|
+
this.ensureOpen();
|
|
40
|
+
const descriptor = file instanceof fileDescriptor_1.FileDescriptor ? file : new fileDescriptor_1.FileDescriptor(file);
|
|
41
|
+
return this.ingestFromStream(await (0, streamUtils_1.fileToStream)(descriptor), ingestionProperties);
|
|
42
|
+
}
|
|
43
|
+
close() {
|
|
44
|
+
if (!this._isClosed) {
|
|
45
|
+
this.kustoClient.close();
|
|
46
|
+
}
|
|
47
|
+
super.close();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
exports.default = KustoStreamingIngestClient;
|
|
51
|
+
//# sourceMappingURL=streamingIngestClient.js.map
|