From 70daed535a4bdbd936bbf912155543c5c2fb59f8 Mon Sep 17 00:00:00 2001 From: "Helgevold Consulting, LLC" Date: Tue, 14 Apr 2020 00:58:03 -0400 Subject: [PATCH] Allow access to msgpack configuration options (#20438) --- .../src/MessagePackHubProtocol.ts | 33 ++++++++++++++----- .../src/MessagePackOptions.ts | 23 +++++++++++++ .../ts/signalr-protocol-msgpack/src/index.ts | 2 ++ .../tests/MessagePackHubProtocol.test.ts | 28 ++++++++++++++++ 4 files changed, 78 insertions(+), 8 deletions(-) create mode 100644 src/SignalR/clients/ts/signalr-protocol-msgpack/src/MessagePackOptions.ts diff --git a/src/SignalR/clients/ts/signalr-protocol-msgpack/src/MessagePackHubProtocol.ts b/src/SignalR/clients/ts/signalr-protocol-msgpack/src/MessagePackHubProtocol.ts index edf8d8dc72..97b872bf27 100644 --- a/src/SignalR/clients/ts/signalr-protocol-msgpack/src/MessagePackHubProtocol.ts +++ b/src/SignalR/clients/ts/signalr-protocol-msgpack/src/MessagePackHubProtocol.ts @@ -4,6 +4,8 @@ import { Buffer } from "buffer"; import * as msgpack5 from "msgpack5"; +import { MessagePackOptions } from "./MessagePackOptions"; + import { CancelInvocationMessage, CompletionMessage, HubMessage, IHubProtocol, ILogger, InvocationMessage, LogLevel, MessageHeaders, MessageType, NullLogger, StreamInvocationMessage, StreamItemMessage, TransferFormat, @@ -32,6 +34,21 @@ export class MessagePackHubProtocol implements IHubProtocol { private readonly voidResult = 2; private readonly nonVoidResult = 3; + private readonly messagePackOptions?: any; + + /** + * + * @param messagePackOptions MessagePack options passed to msgpack5 + */ + constructor(messagePackOptions?: MessagePackOptions) { + if (messagePackOptions) { + this.messagePackOptions = { + ...messagePackOptions, + compatibilityMode: false, + }; + } + } + /** Creates an array of HubMessage objects from the specified serialized representation. * * @param {ArrayBuffer | Buffer} input An ArrayBuffer or Buffer containing the serialized representation. @@ -90,7 +107,7 @@ export class MessagePackHubProtocol implements IHubProtocol { throw new Error("Invalid payload."); } - const msgpack = msgpack5(); + const msgpack = msgpack5(this.messagePackOptions); const properties = msgpack.decode(Buffer.from(input)); if (properties.length === 0 || !(properties instanceof Array)) { throw new Error("Invalid payload."); @@ -220,35 +237,35 @@ export class MessagePackHubProtocol implements IHubProtocol { } private writeInvocation(invocationMessage: InvocationMessage): ArrayBuffer { - const msgpack = msgpack5(); + const msgpack = msgpack5(this.messagePackOptions); let payload: any; if (invocationMessage.streamIds) { payload = msgpack.encode([MessageType.Invocation, invocationMessage.headers || {}, invocationMessage.invocationId || null, invocationMessage.target, invocationMessage.arguments, invocationMessage.streamIds]); } else { payload = msgpack.encode([MessageType.Invocation, invocationMessage.headers || {}, invocationMessage.invocationId || null, - invocationMessage.target, invocationMessage.arguments]); + invocationMessage.target, invocationMessage.arguments]); } return BinaryMessageFormat.write(payload.slice()); } private writeStreamInvocation(streamInvocationMessage: StreamInvocationMessage): ArrayBuffer { - const msgpack = msgpack5(); + const msgpack = msgpack5(this.messagePackOptions); let payload: any; if (streamInvocationMessage.streamIds) { payload = msgpack.encode([MessageType.StreamInvocation, streamInvocationMessage.headers || {}, streamInvocationMessage.invocationId, streamInvocationMessage.target, streamInvocationMessage.arguments, streamInvocationMessage.streamIds]); } else { payload = msgpack.encode([MessageType.StreamInvocation, streamInvocationMessage.headers || {}, streamInvocationMessage.invocationId, - streamInvocationMessage.target, streamInvocationMessage.arguments]); + streamInvocationMessage.target, streamInvocationMessage.arguments]); } return BinaryMessageFormat.write(payload.slice()); } private writeStreamItem(streamItemMessage: StreamItemMessage): ArrayBuffer { - const msgpack = msgpack5(); + const msgpack = msgpack5(this.messagePackOptions); const payload = msgpack.encode([MessageType.StreamItem, streamItemMessage.headers || {}, streamItemMessage.invocationId, streamItemMessage.item]); @@ -256,7 +273,7 @@ export class MessagePackHubProtocol implements IHubProtocol { } private writeCompletion(completionMessage: CompletionMessage): ArrayBuffer { - const msgpack = msgpack5(); + const msgpack = msgpack5(this.messagePackOptions); const resultKind = completionMessage.error ? this.errorResult : completionMessage.result ? this.nonVoidResult : this.voidResult; let payload: any; @@ -276,7 +293,7 @@ export class MessagePackHubProtocol implements IHubProtocol { } private writeCancelInvocation(cancelInvocationMessage: CancelInvocationMessage): ArrayBuffer { - const msgpack = msgpack5(); + const msgpack = msgpack5(this.messagePackOptions); const payload = msgpack.encode([MessageType.CancelInvocation, cancelInvocationMessage.headers || {}, cancelInvocationMessage.invocationId]); return BinaryMessageFormat.write(payload.slice()); diff --git a/src/SignalR/clients/ts/signalr-protocol-msgpack/src/MessagePackOptions.ts b/src/SignalR/clients/ts/signalr-protocol-msgpack/src/MessagePackOptions.ts new file mode 100644 index 0000000000..5c6cede95d --- /dev/null +++ b/src/SignalR/clients/ts/signalr-protocol-msgpack/src/MessagePackOptions.ts @@ -0,0 +1,23 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +/** + * MessagePack Options per: + * {@link https://github.com/mcollina/msgpack5#msgpackoptionsobj Msgpack5 Options Object} + */ +export interface MessagePackOptions { + /** + * @name sortKeys Force a determinate key order + */ + sortKeys?: boolean; + + /** + * @name disableTimestampEncoding Disable the encoding of Dates into the timestamp extension type + */ + disableTimestampEncoding?: boolean; + + /** + * @name forceFloat64 Force floats to be encoded as 64-bit floats + */ + forceFloat64?: boolean; +} diff --git a/src/SignalR/clients/ts/signalr-protocol-msgpack/src/index.ts b/src/SignalR/clients/ts/signalr-protocol-msgpack/src/index.ts index 55745ddf7c..dbd681bcc8 100644 --- a/src/SignalR/clients/ts/signalr-protocol-msgpack/src/index.ts +++ b/src/SignalR/clients/ts/signalr-protocol-msgpack/src/index.ts @@ -6,3 +6,5 @@ export const VERSION = "0.0.0-DEV_BUILD"; export { MessagePackHubProtocol } from "./MessagePackHubProtocol"; + +export { MessagePackOptions } from "./MessagePackOptions"; diff --git a/src/SignalR/clients/ts/signalr-protocol-msgpack/tests/MessagePackHubProtocol.test.ts b/src/SignalR/clients/ts/signalr-protocol-msgpack/tests/MessagePackHubProtocol.test.ts index abc72712d1..c5674da9fc 100644 --- a/src/SignalR/clients/ts/signalr-protocol-msgpack/tests/MessagePackHubProtocol.test.ts +++ b/src/SignalR/clients/ts/signalr-protocol-msgpack/tests/MessagePackHubProtocol.test.ts @@ -217,4 +217,32 @@ describe("MessagePackHubProtocol", () => { const buffer = new MessagePackHubProtocol().writeMessage({ type: MessageType.CancelInvocation, invocationId: "abc" }); expect(new Uint8Array(buffer)).toEqual(payload); }); + + it("will preserve double precision if forceFloat64 is set", () => { + const invocation = { + arguments: [Number(0.005)], + headers: {}, + invocationId: "123", + streamIds: [], + target: "myMethod", + type: MessageType.Invocation, + } as InvocationMessage; + + const protocol = new MessagePackHubProtocol({ forceFloat64: true }); + const parsedMessages = protocol.parseMessages(protocol.writeMessage(invocation), NullLogger.instance); + expect(parsedMessages[0]).toEqual({ + arguments: [0.005], + headers: {}, + invocationId: "123", + streamIds: [], + target: "myMethod", + type: 1, + }); + }); + + it("will force compatibilityMode to false", () => { + const options: any = { compatibilityMode: true }; + const protocol: any = new MessagePackHubProtocol(options); + expect(protocol.messagePackOptions.compatibilityMode).toBe(false); + }); });