Changing length prefixing to separator for JSON TS
This commit is contained in:
parent
5ad5f36f88
commit
e349329dc7
|
|
@ -1,13 +1,11 @@
|
||||||
import { TextMessageFormat, BinaryMessageFormat } from "../Microsoft.AspNetCore.SignalR.Client.TS/Formatters"
|
import { TextMessageFormat, BinaryMessageFormat } from "../Microsoft.AspNetCore.SignalR.Client.TS/Formatters"
|
||||||
|
|
||||||
describe("Text Message Formatter", () => {
|
describe("Text Message Formatter", () => {
|
||||||
it("should return empty array on empty input", () => {
|
|
||||||
let messages = TextMessageFormat.parse("");
|
|
||||||
expect(messages).toEqual([]);
|
|
||||||
});
|
|
||||||
([
|
([
|
||||||
["0:;", [""]],
|
["\u001e", [""]],
|
||||||
["5:Hello;", ["Hello"]],
|
["\u001e\u001e", ["", ""]],
|
||||||
|
["Hello\u001e", ["Hello"]],
|
||||||
|
["Hello,\u001eWorld!\u001e", ["Hello,", "World!"]],
|
||||||
] as [[string, string[]]]).forEach(([payload, expected_messages]) => {
|
] as [[string, string[]]]).forEach(([payload, expected_messages]) => {
|
||||||
it(`should parse '${payload}' correctly`, () => {
|
it(`should parse '${payload}' correctly`, () => {
|
||||||
let messages = TextMessageFormat.parse(payload);
|
let messages = TextMessageFormat.parse(payload);
|
||||||
|
|
@ -16,14 +14,9 @@ describe("Text Message Formatter", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
([
|
([
|
||||||
["ABC", new Error("Invalid length: 'ABC'")],
|
["", new Error("Message is incomplete.")],
|
||||||
["1:A;12ab34:", new Error("Invalid length: '12ab34'")],
|
["ABC", new Error("Message is incomplete.")],
|
||||||
["1:A;1:", new Error("Message is incomplete")],
|
["ABC\u001eXYZ", new Error("Message is incomplete.")],
|
||||||
["1:A;1:AB:", new Error("Message missing trailer character")],
|
|
||||||
["1:A;5:A", new Error("Message is incomplete")],
|
|
||||||
["1:A;5:AB", new Error("Message is incomplete")],
|
|
||||||
["1:A;5:ABCDE", new Error("Message is incomplete")],
|
|
||||||
["1:A;5:ABCDEF", new Error("Message missing trailer character")],
|
|
||||||
] as [[string, Error]]).forEach(([payload, expected_error]) => {
|
] as [[string, Error]]).forEach(([payload, expected_error]) => {
|
||||||
it(`should fail to parse '${payload}'`, () => {
|
it(`should fail to parse '${payload}'`, () => {
|
||||||
expect(() => TextMessageFormat.parse(payload)).toThrow(expected_error);
|
expect(() => TextMessageFormat.parse(payload)).toThrow(expected_error);
|
||||||
|
|
|
||||||
|
|
@ -1,68 +1,19 @@
|
||||||
|
|
||||||
function splitAt(input: string, searchString: string, position: number): [string, number] {
|
|
||||||
let index = input.indexOf(searchString, position);
|
|
||||||
if (index < 0) {
|
|
||||||
return [input.substr(position), input.length];
|
|
||||||
}
|
|
||||||
let left = input.substring(position, index);
|
|
||||||
return [left, index + searchString.length];
|
|
||||||
}
|
|
||||||
|
|
||||||
export namespace TextMessageFormat {
|
export namespace TextMessageFormat {
|
||||||
const LengthRegex = /^[0-9]+$/;
|
|
||||||
|
|
||||||
function hasSpace(input: string, offset: number, length: number): boolean {
|
const RecordSeparator = String.fromCharCode(0x1e);
|
||||||
let requiredLength = offset + length;
|
|
||||||
return input.length >= requiredLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseMessage(input: string, position: number): [number, string] {
|
|
||||||
var offset = position;
|
|
||||||
|
|
||||||
// Read the length
|
|
||||||
var [lenStr, offset] = splitAt(input, ":", offset);
|
|
||||||
|
|
||||||
// parseInt is too leniant, we need a strict check to see if the string is an int
|
|
||||||
|
|
||||||
if (!LengthRegex.test(lenStr)) {
|
|
||||||
throw new Error(`Invalid length: '${lenStr}'`);
|
|
||||||
}
|
|
||||||
let length = Number.parseInt(lenStr);
|
|
||||||
|
|
||||||
// Required space is: (";") + length (payload len)
|
|
||||||
if (!hasSpace(input, offset, 1 + length)) {
|
|
||||||
throw new Error("Message is incomplete");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the payload
|
|
||||||
var payload = input.substr(offset, length);
|
|
||||||
offset += length;
|
|
||||||
|
|
||||||
// Verify the final trailing character
|
|
||||||
if (input[offset] != ';') {
|
|
||||||
throw new Error("Message missing trailer character");
|
|
||||||
}
|
|
||||||
offset += 1;
|
|
||||||
|
|
||||||
return [offset, payload];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function write(output: string): string {
|
export function write(output: string): string {
|
||||||
return `${output.length}:${output};`;
|
return `${output}${RecordSeparator}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parse(input: string): string[] {
|
export function parse(input: string): string[] {
|
||||||
if (input.length == 0) {
|
if (!input.endsWith(RecordSeparator)) {
|
||||||
return []
|
throw new Error("Message is incomplete.");
|
||||||
}
|
}
|
||||||
|
|
||||||
let messages = [];
|
let messages = input.split(RecordSeparator);
|
||||||
var offset = 0;
|
messages.pop();
|
||||||
while (offset < input.length) {
|
|
||||||
let message;
|
|
||||||
[offset, message] = parseMessage(input, offset);
|
|
||||||
messages.push(message);
|
|
||||||
}
|
|
||||||
return messages;
|
return messages;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ describe('hubConnection', () => {
|
||||||
eachTransportAndProtocol((transportType, protocol) => {
|
eachTransportAndProtocol((transportType, protocol) => {
|
||||||
describe(`${protocol.name} over ${signalR.TransportType[transportType]} transport`, () => {
|
describe(`${protocol.name} over ${signalR.TransportType[transportType]} transport`, () => {
|
||||||
it(`can invoke server method and receive result`, done => {
|
it(`can invoke server method and receive result`, done => {
|
||||||
const message = "Hi";
|
const message = "你好,世界!";
|
||||||
let hubConnection = new signalR.HubConnection(
|
let hubConnection = new signalR.HubConnection(
|
||||||
new signalR.HttpConnection(TESTHUBENDPOINT_URL, { transport: transportType }), protocol);
|
new signalR.HttpConnection(TESTHUBENDPOINT_URL, { transport: transportType }), protocol);
|
||||||
hubConnection.onClosed = error => {
|
hubConnection.onClosed = error => {
|
||||||
|
|
@ -122,7 +122,7 @@ describe('hubConnection', () => {
|
||||||
it(`can receive server calls`, done => {
|
it(`can receive server calls`, done => {
|
||||||
let client = new signalR.HubConnection(
|
let client = new signalR.HubConnection(
|
||||||
new signalR.HttpConnection(TESTHUBENDPOINT_URL, { transport: transportType }), protocol);
|
new signalR.HttpConnection(TESTHUBENDPOINT_URL, { transport: transportType }), protocol);
|
||||||
const message = "Hello SignalR";
|
const message = "你好 SignalR!";
|
||||||
|
|
||||||
let callbackPromise = new Promise((resolve, reject) => {
|
let callbackPromise = new Promise((resolve, reject) => {
|
||||||
client.on("Message", msg => {
|
client.on("Message", msg => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue