This repository has been archived by the owner on Dec 18, 2018. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding MsgPack hub protocol to TS client
- Loading branch information
Pawel Kadluczka
committed
Aug 7, 2017
1 parent
90916d1
commit e853651
Showing
12 changed files
with
334 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
103 changes: 103 additions & 0 deletions
103
client-ts/Microsoft.AspNetCore.SignalR.Client.TS.Tests/MessagePackHubProtocol.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import { MessagePackHubProtocol } from "../Microsoft.AspNetCore.SignalR.Client.TS/MessagePackHubProtocol" | ||
import { MessageType, InvocationMessage, CompletionMessage, ResultMessage } from "../Microsoft.AspnetCore.SignalR.Client.TS/IHubProtocol" | ||
|
||
describe("MessageHubProtocol", () => { | ||
it("can write/read Invocation message", () => { | ||
let invocation = <InvocationMessage>{ | ||
type: MessageType.Invocation, | ||
invocationId: "123", | ||
target: "myMethod", | ||
nonblocking: true, | ||
arguments: [42, true, "test", ["x1", "y2"], null] | ||
}; | ||
|
||
let protocol = new MessagePackHubProtocol(); | ||
var parsedMessages = protocol.parseMessages(protocol.writeMessage(invocation)); | ||
expect(parsedMessages).toEqual([invocation]); | ||
}); | ||
|
||
([ | ||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, | ||
0x94, 0x03, 0xa3, 0x61, 0x62, 0x63, 0x01, 0xa3, 0x45, 0x72, 0x72], | ||
{ | ||
type: MessageType.Completion, | ||
invocationId: "abc", | ||
error: "Err", | ||
result: null | ||
} as CompletionMessage ], | ||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, | ||
0x94, 0x03, 0xa3, 0x61, 0x62, 0x63, 0x03, 0xa2, 0x4f, 0x4b ], | ||
{ | ||
type: MessageType.Completion, | ||
invocationId: "abc", | ||
error: null, | ||
result: "OK" | ||
} as CompletionMessage ], | ||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, | ||
0x93, 0x03, 0xa3, 0x61, 0x62, 0x63, 0x02 ], | ||
{ | ||
type: MessageType.Completion, | ||
invocationId: "abc", | ||
error: null, | ||
result: null | ||
} as CompletionMessage ] | ||
] as [[number[], CompletionMessage]]).forEach(([payload, expected_message]) => | ||
it("can read Completion message", () => { | ||
let messages = new MessagePackHubProtocol().parseMessages(new Uint8Array(payload).buffer); | ||
expect(messages).toEqual([expected_message]); | ||
})); | ||
|
||
([ | ||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, | ||
0x93, 0x02, 0xa3, 0x61, 0x62, 0x63, 0x08 ], | ||
{ | ||
type: MessageType.Result, | ||
invocationId: "abc", | ||
item: 8 | ||
} as ResultMessage ] | ||
] as [[number[], CompletionMessage]]).forEach(([payload, expected_message]) => | ||
it("can read Result message", () => { | ||
let messages = new MessagePackHubProtocol().parseMessages(new Uint8Array(payload).buffer); | ||
expect(messages).toEqual([expected_message]); | ||
})); | ||
|
||
([ | ||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ], new Error("Invalid payload.") ], | ||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x90 ], new Error("Invalid payload.") ], | ||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc2 ], new Error("Invalid payload.") ], | ||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x91, 0x05 ], new Error("Invalid message type.") ], | ||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x91, 0xa1, 0x78 ], new Error("Invalid message type.") ], | ||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x91, 0x01 ], new Error("Invalid payload for Invocation message.") ], | ||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x91, 0x02 ], new Error("Invalid payload for stream Result message.") ], | ||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x92, 0x03, 0xa0 ], new Error("Invalid payload for Completion message.") ], | ||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x94, 0x03, 0xa0, 0x02, 0x00 ], new Error("Invalid payload for Completion message.") ], | ||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x93, 0x03, 0xa0, 0x01 ], new Error("Invalid payload for Completion message.") ], | ||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x93, 0x03, 0xa0, 0x03 ], new Error("Invalid payload for Completion message.") ] | ||
] as [[number[], Error]]).forEach(([payload, expected_error]) => | ||
it("throws for invalid messages", () => { | ||
expect(() => new MessagePackHubProtocol().parseMessages(new Uint8Array(payload).buffer)) | ||
.toThrow(expected_error); | ||
})); | ||
|
||
it("can read multiple messages", () => { | ||
let payload = [ | ||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, | ||
0x93, 0x02, 0xa3, 0x61, 0x62, 0x63, 0x08, | ||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, | ||
0x94, 0x03, 0xa3, 0x61, 0x62, 0x63, 0x03, 0xa2, 0x4f, 0x4b ]; | ||
let messages = new MessagePackHubProtocol().parseMessages(new Uint8Array(payload).buffer); | ||
expect(messages).toEqual([ | ||
{ | ||
type: MessageType.Result, | ||
invocationId: "abc", | ||
item: 8 | ||
} as ResultMessage, | ||
{ | ||
type: MessageType.Completion, | ||
invocationId: "abc", | ||
error: null, | ||
result: "OK" | ||
} as CompletionMessage | ||
]); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
117 changes: 117 additions & 0 deletions
117
client-ts/Microsoft.AspNetCore.SignalR.Client.TS/MessagePackHubProtocol.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
import { IHubProtocol, MessageType, HubMessage, InvocationMessage, ResultMessage, CompletionMessage } from "./IHubProtocol"; | ||
import { BinaryMessageFormat } from "./Formatters" | ||
|
||
var msgpack = require("msgpack-lite"); | ||
|
||
export class MessagePackHubProtocol implements IHubProtocol { | ||
name(): string { | ||
return "messagepack"; | ||
} | ||
|
||
parseMessages(input: ArrayBuffer): HubMessage[] { | ||
return BinaryMessageFormat.parse(input).map(m => this.parseMessage(m)); | ||
} | ||
|
||
private parseMessage(input: Uint8Array): HubMessage { | ||
if (input.length == 0) { | ||
throw new Error("Invalid payload."); | ||
} | ||
|
||
let properties = msgpack.decode(input); | ||
if (properties.length == 0 || !(properties instanceof Array)) { | ||
throw new Error("Invalid payload."); | ||
} | ||
|
||
let messageType = properties[0] as MessageType; | ||
switch (messageType) { | ||
case MessageType.Invocation: | ||
return this.createInvocationMessage(properties); | ||
case MessageType.Result: | ||
return this.createStreamItemMessage(properties); | ||
case MessageType.Completion: | ||
return this.createCompletionMessage(properties); | ||
default: | ||
throw new Error("Invalid message type."); | ||
} | ||
} | ||
|
||
private createInvocationMessage(properties: any[]): InvocationMessage { | ||
if (properties.length != 5) { | ||
throw new Error("Invalid payload for Invocation message."); | ||
} | ||
|
||
return { | ||
type: MessageType.Invocation, | ||
invocationId: properties[1], | ||
nonblocking: properties[2], | ||
target: properties[3], | ||
arguments: properties[4] | ||
} as InvocationMessage; | ||
} | ||
|
||
private createStreamItemMessage(properties: any[]): ResultMessage { | ||
if (properties.length != 3) { | ||
throw new Error("Invalid payload for stream Result message."); | ||
} | ||
|
||
return { | ||
type: MessageType.Result, | ||
invocationId: properties[1], | ||
item: properties[2] | ||
} as ResultMessage; | ||
} | ||
|
||
private createCompletionMessage(properties: any[]): CompletionMessage { | ||
if (properties.length < 3) { | ||
throw new Error("Invalid payload for Completion message."); | ||
} | ||
|
||
const errorResult = 1; | ||
const voidResult = 2; | ||
const nonVoidResult = 3; | ||
|
||
let resultKind = properties[2]; | ||
|
||
if ((resultKind === voidResult && properties.length != 3) || | ||
(resultKind !== voidResult && properties.length != 4)) { | ||
throw new Error("Invalid payload for Completion message."); | ||
} | ||
|
||
let completionMessage = { | ||
type: MessageType.Completion, | ||
invocationId: properties[1], | ||
error: null as string, | ||
result: null as any | ||
}; | ||
|
||
switch (resultKind) { | ||
case errorResult: | ||
completionMessage.error = properties[3]; | ||
break; | ||
case nonVoidResult: | ||
completionMessage.result = properties[3]; | ||
break; | ||
} | ||
|
||
return completionMessage as ResultMessage; | ||
} | ||
|
||
writeMessage(message: HubMessage): ArrayBuffer { | ||
switch (message.type) { | ||
case MessageType.Invocation: | ||
return this.writeInvocation(message as InvocationMessage); | ||
case MessageType.Result: | ||
case MessageType.Completion: | ||
throw new Error(`Writing messages of type '${message.type}' is not supported.`); | ||
default: | ||
throw new Error("Invalid message type."); | ||
} | ||
} | ||
|
||
private writeInvocation(invocationMessage: InvocationMessage): ArrayBuffer { | ||
let payload = msgpack.encode([ MessageType.Invocation, invocationMessage.invocationId, | ||
invocationMessage.nonblocking, invocationMessage.target, invocationMessage.arguments]); | ||
|
||
return BinaryMessageFormat.write(payload); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.