botframework-streaming
Version:
Streaming library for the Microsoft Bot Framework
151 lines • 6.54 kB
JavaScript
"use strict";
/**
* @module botframework-streaming
*/
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PayloadAssembler = void 0;
const subscribableStream_1 = require("../subscribableStream");
const payloads_1 = require("../payloads");
const contentStream_1 = require("../contentStream");
/**
* Assembles payloads for streaming library.
*
* @internal
*/
class PayloadAssembler {
/**
* Initializes a new instance of the [PayloadAssembler](xref:botframework-streaming.PayloadAssembler) class.
*
* @param streamManager The [StreamManager](xref:botframework-streaming.StreamManager) managing the stream being assembled.
* @param params Parameters for a streaming assembler.
*/
constructor(streamManager, params) {
this.streamManager = streamManager;
this._byteOrderMark = 0xfeff;
this._utf = 'utf8';
if (params.header) {
this.id = params.header.id;
this.payloadType = params.header.payloadType;
this.contentLength = params.header.payloadLength;
this.end = params.header.end;
}
else {
this.id = params.id;
}
if (!this.id) {
throw Error('An ID must be supplied when creating an assembler.');
}
this._onCompleted = params.onCompleted;
}
/**
* Retrieves the assembler's payload as a stream.
*
* @returns A [SubscribableStream](xref:botframework-streaming.SubscribableStream) of the assembler's payload.
*/
getPayloadStream() {
if (!this.stream) {
this.stream = this.createPayloadStream();
}
return this.stream;
}
/**
* The action the assembler executes when new bytes are received on the incoming stream.
*
* @param header The stream's Header.
* @param stream The incoming stream being assembled.
* @param _contentLength The length of the stream, if finite.
*/
onReceive(header, stream, _contentLength) {
this.end = header.end;
if (header.payloadType === payloads_1.PayloadTypes.response || header.payloadType === payloads_1.PayloadTypes.request) {
this.process(stream).then().catch();
}
else if (header.end) {
stream.end();
}
}
/**
* Closes the assembler.
*/
close() {
this.streamManager.closeStream(this.id);
}
/**
* Creates a new [SubscribableStream](xref:botframework-streaming.SubscribableStream) instance.
*
* @returns The new stream ready for consumption.
*/
createPayloadStream() {
return new subscribableStream_1.SubscribableStream();
}
payloadFromJson(json) {
return JSON.parse(json.charCodeAt(0) === this._byteOrderMark ? json.slice(1) : json);
}
stripBOM(input) {
return input.charCodeAt(0) === this._byteOrderMark ? input.slice(1) : input;
}
process(stream) {
return __awaiter(this, void 0, void 0, function* () {
const streamData = stream.read(stream.length);
if (!streamData) {
return;
}
const streamDataAsString = streamData.toString(this._utf);
if (this.payloadType === payloads_1.PayloadTypes.request) {
yield this.processRequest(streamDataAsString);
}
else if (this.payloadType === payloads_1.PayloadTypes.response) {
yield this.processResponse(streamDataAsString);
}
});
}
processResponse(streamDataAsString) {
return __awaiter(this, void 0, void 0, function* () {
const responsePayload = this.payloadFromJson(this.stripBOM(streamDataAsString));
const receiveResponse = { streams: [], statusCode: responsePayload.statusCode };
yield this.processStreams(responsePayload, receiveResponse);
});
}
processRequest(streamDataAsString) {
return __awaiter(this, void 0, void 0, function* () {
const requestPayload = this.payloadFromJson(streamDataAsString);
const receiveRequest = { streams: [], path: requestPayload.path, verb: requestPayload.verb };
yield this.processStreams(requestPayload, receiveRequest);
});
}
processStreams(responsePayload, receiveResponse) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
(_a = responsePayload.streams) === null || _a === void 0 ? void 0 : _a.forEach((responseStream) => {
var _a;
// There was a bug in how streams were handled. In .NET, the StreamDescription definiton mapped the
// "type" JSON property to `contentType`, but in Typescript there was no mapping. This is a workaround
// to resolve this inconsistency.
//
// .NET code:
// https://github.com/microsoft/botbuilder-dotnet/blob/a79036ddf6625ec3fd68a6f7295886eb7831bc1c/libraries/Microsoft.Bot.Streaming/Payloads/Models/StreamDescription.cs#L28-L29
const contentType = (_a = responseStream.type) !== null && _a !== void 0 ? _a : responseStream.contentType;
const contentAssembler = this.streamManager.getPayloadAssembler(responseStream.id);
contentAssembler.payloadType = contentType;
contentAssembler.contentLength = responseStream.length;
receiveResponse.streams.push(new contentStream_1.ContentStream(responseStream.id, contentAssembler));
});
yield this._onCompleted(this.id, receiveResponse);
});
}
}
exports.PayloadAssembler = PayloadAssembler;
//# sourceMappingURL=payloadAssembler.js.map