@azure/service-bus
Version:
Azure Service Bus SDK for JavaScript
163 lines • 6.87 kB
JavaScript
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import { message } from "rhea-promise";
import isBuffer from "is-buffer";
import { Buffer } from "buffer";
import { logErrorStackTrace, logger } from "./log";
/** @internal */
export const dataSectionTypeCode = 0x75;
/** @internal */
export const sequenceSectionTypeCode = 0x76;
/** @internal */
export const valueSectionTypeCode = 0x77;
/**
* The default data transformer that will be used by the Azure SDK.
* @internal
*/
export const defaultDataTransformer = {
/**
* A function that takes the body property from an EventData object
* and returns an encoded body (some form of AMQP type).
*
* @param body - The AMQP message body
* @returns The encoded AMQP message body as an AMQP Data type
* (data section in rhea terms). Section object with following properties:
* - typecode: 117 (0x75)
* - content: The given AMQP message body as a Buffer.
* - multiple: true | undefined.
*/
encode(body, bodyType) {
let result;
if (bodyType === "value") {
// TODO: Expose value_section from `rhea` similar to the data_section and sequence_section. Right now there isn't a way to create a value section officially.
result = message.data_section(body);
result.typecode = valueSectionTypeCode;
}
else if (bodyType === "sequence") {
result = message.sequence_section(body);
}
else if (isBuffer(body) || body instanceof Uint8Array) {
result = message.data_section(body);
}
else {
// string, undefined, null, boolean, array, object, number should end up here
// coercing undefined to null as that will ensure that null value will be given to the
// customer on receive.
if (body === undefined)
body = null; // tslint:disable-line
try {
const bodyStr = JSON.stringify(body);
result = message.data_section(Buffer.from(bodyStr, "utf8"));
}
catch (err) {
const msg = `An error occurred while executing JSON.stringify() on the given body ` +
body +
`${err ? err.stack : JSON.stringify(err)}`;
logger.warning("[encode] " + msg);
logErrorStackTrace(logger, err);
throw new Error(msg);
}
}
return result;
},
/**
* A function that takes the body property from an AMQP message
* (an AMQP Data type (data section in rhea terms)) and returns the decoded message body.
* If it cannot decode the body then it returns the body
* as-is.
*
* NOTE: Use this to decode a message body when you know that the entire contents are _only_ contained
* in the 'data' section of the message (for instance, messages from the $mgmt link). Otherwise
* use 'defaultDataTransformer.decodeWithType', which can handle data coming from separate sections
* of the AMQP mesage.
*
* @param body - The AMQP message body
* @param skipParsingBodyAsJson - Boolean to skip running JSON.parse() on message body content.
* @returns decoded body or the given body as-is.
*/
decode(body, skipParsingBodyAsJson) {
let actualContent = body;
if (isRheaAmqpSection(body)) {
actualContent = body.content;
}
return skipParsingBodyAsJson ? actualContent : tryToJsonDecode(actualContent);
},
/**
* A function that takes the body property from an AMQP message, which can come from either
* the 'data', 'value' or 'sequence' sections of an AMQP message.
*
* If the body is not a JSON string the the raw contents will be returned, along with the bodyType
* indicating which part of the AMQP message the body was decoded from.
*
* @param body - The AMQP message body as received from rhea.
* @param skipParsingBodyAsJson - Boolean to skip running JSON.parse() on message body.
* @returns The decoded/raw body and the body type.
*/
decodeWithType(body, skipParsingBodyAsJson) {
try {
if (isRheaAmqpSection(body)) {
switch (body.typecode) {
case dataSectionTypeCode:
return {
body: skipParsingBodyAsJson ? body.content : tryToJsonDecode(body.content),
bodyType: "data",
};
case sequenceSectionTypeCode:
// typecode:
// handle sequences
return { body: body.content, bodyType: "sequence" };
case valueSectionTypeCode:
// value
return { body: body.content, bodyType: "value" };
}
}
else {
// not sure - we have to try to infer the proper bodyType and content
if (isBuffer(body)) {
// This indicates that we are getting the AMQP described type. Let us try decoding it.
return { body: skipParsingBodyAsJson ? body : tryToJsonDecode(body), bodyType: "data" };
}
else {
return { body: body, bodyType: "value" };
}
}
}
catch (err) {
logger.verbose("[decode] An error occurred while decoding the received message body. The error is: %O", err);
throw err;
}
},
};
/** @internal */
export function isRheaAmqpSection(possibleSection) {
return (possibleSection != null &&
typeof possibleSection.typecode === "number" &&
(possibleSection.typecode === dataSectionTypeCode ||
possibleSection.typecode === valueSectionTypeCode ||
possibleSection.typecode === sequenceSectionTypeCode));
}
/**
* Attempts to decode 'body' as a JSON string. If it fails it returns body
* verbatim.
*
* @param body - An AMQP message body.
* @returns A JSON decoded object, or body if body was not a JSON string.
*
* @internal
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function tryToJsonDecode(body) {
let processedBody = body;
try {
// Trying to stringify and JSON.parse() anything else will fail flat and we shall return
// the original type back
const bodyStr = processedBody.toString("utf8");
processedBody = JSON.parse(bodyStr);
}
catch (err) {
logger.verbose("[decode] An error occurred while trying JSON.parse() on the received body. " +
"The error is %O", err);
}
return processedBody;
}
//# sourceMappingURL=dataTransformer.js.map