Skip to content
This repository has been archived by the owner on Apr 6, 2022. It is now read-only.

Commit

Permalink
Add support for binary decoder in addition to json decoder
Browse files Browse the repository at this point in the history
  • Loading branch information
dbuos committed Oct 16, 2020
1 parent 99dabf7 commit c871d87
Show file tree
Hide file tree
Showing 11 changed files with 257 additions and 48 deletions.
17 changes: 14 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
"all": true
},
"keywords": [
"pusher",
"async",
"notifications",
"websocket"
Expand All @@ -43,6 +42,7 @@
"@types/pusher-js": "^4.2.0",
"@types/sinon": "^5.0.3",
"chai": "^4.2.0",
"fast-text-encoding": "^1.0.3",
"fetch-mock": "^7.0.7",
"mocha": "^5.2.0",
"mocha-sonarqube-reporter": "^1.0.2",
Expand Down
14 changes: 10 additions & 4 deletions src/async-client.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {Serializer} from "./serializer";
import {JsonDecoder} from "./json-decoder";
import {MessageDecoder} from "./serializer"
import {ChannelMessage} from "./channel-message";
import {RetryTimer} from "./retry-timer";

Expand All @@ -17,16 +18,16 @@ export class AsyncClient {
private readonly heartbeatIntervalMs : number;
private tearingDown : boolean = false;
private reconnectTimer : RetryTimer;
private serializer: MessageDecoder = new JsonDecoder();

constructor(private config: AsyncConfig, private transport : any = null) {
constructor(private config: AsyncConfig, private readonly transport : any = null) {
const intWindow = typeof window !== "undefined" ? window : null;
this.transport = transport || intWindow['WebSocket'];
this.heartbeatIntervalMs = config.heartbeat_interval || 750;
this.reconnectTimer = new RetryTimer(() => this.teardown(() => this.connect()));
this.actualToken = config.channel_secret;
}


public connect(){
if (this.socket) return;
this.socket = new this.transport(this.socketUrl());
Expand Down Expand Up @@ -58,7 +59,7 @@ export class AsyncClient {
}

private onSocketMessage(event) {
const message = Serializer.decode(event.data)
const message = this.serializer.decode(event)
if (!this.isActive && message.event == "AuthOk"){
this.isActive = true;
console.log("#DBG5 change active to true!")
Expand Down Expand Up @@ -153,6 +154,10 @@ export class AsyncClient {
return this.socket;
}

public getDecoder() : MessageDecoder {
return this.serializer;
}

private socketUrl() : string {
return `${this.config.socket_url}?channel=${this.config.channel_ref}`;
}
Expand Down Expand Up @@ -205,6 +210,7 @@ export interface AsyncConfig{
socket_url: string;
channel_ref:string;
channel_secret: string;
only_json?: boolean;
heartbeat_interval? : number;
}

Expand Down
47 changes: 47 additions & 0 deletions src/binary-decoder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/* The Binary serializer for encoding and decoding messages */


import {ChannelMessage} from "./channel-message";
import {MessageDecoder} from "./serializer";

export class BinaryDecoder implements MessageDecoder {

private textDecoder : TextDecoder;

constructor() {
this.textDecoder = new TextDecoder();
}

public decode(messageEvent: MessageEvent): ChannelMessage {
const buffer: ArrayBuffer = messageEvent.data;
const view = new DataView(buffer)

const control = view.getUint8(0);
if (control != 255){
throw new Error('Invalid binary data; no control byte match')
}

const extractor: Extractor = new Extractor(this.textDecoder, buffer, 4);
const message_id = extractor.decodeChunk(view.getUint8(1));
const correlation_id = extractor.decodeChunk(view.getUint8(2));
const event = extractor.decodeChunk(view.getUint8(3));
const payload = extractor.decodeChunk(null);

return new ChannelMessage(message_id, event, correlation_id, payload);
}
}

class Extractor {
constructor(private readonly textDecoder : TextDecoder,
private readonly buffer: ArrayBuffer,
private offset: number) {
}

public decodeChunk(size: number) : string {
const endIndex = size ? this.offset + size : this.buffer.byteLength + 1;
const data = this.textDecoder.decode(this.buffer.slice(this.offset, endIndex));
this.offset = endIndex;
return data;
}
}

14 changes: 14 additions & 0 deletions src/json-decoder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/* The Json serializer for encoding and decoding messages */


import {ChannelMessage} from "./channel-message";
import {MessageDecoder} from "./serializer";

export class JsonDecoder implements MessageDecoder {

public decode(messageEvent: MessageEvent): ChannelMessage {
const [message_id, correlation_id, event, payload] = JSON.parse(messageEvent.data);
return new ChannelMessage(message_id, event, correlation_id, payload);
}
}

17 changes: 3 additions & 14 deletions src/serializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,7 @@

import {ChannelMessage} from "./channel-message";

export class Serializer {

public static decode(rawPayload: string): ChannelMessage {
const [message_id, correlation_id, event, payload] = JSON.parse(rawPayload);
return new ChannelMessage(message_id, event, correlation_id, payload);
}

public static encode(message: ChannelMessage): string {
let payload = [
message.message_id, message.correlation_id, message.event, message.payload
]
return JSON.stringify(payload);
}
export interface MessageDecoder {
decode(event: MessageEvent) : ChannelMessage;
// encode(message: ChannelMessage): any;
}

20 changes: 20 additions & 0 deletions test/async-client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {AsyncClient} from "../src/async-client";
import { WebSocket, Server } from 'mock-socket';

import {ChannelMessage} from "../src/channel-message";
import {JsonDecoder} from "../src/json-decoder";

const assert = chai.assert;

Expand Down Expand Up @@ -250,3 +251,22 @@ describe('Refresh token Tests', () => {
});

});


describe('Setup and configuration Tests', () => {

const baseConf = {
socket_url: "wss://reconnect.local:8985/socket",
channel_ref: "ab771f3434aaghjgr",
channel_secret: "secret234342432dsfghjikujyg1221"
};

it('Should use Json decoder when specified' , () => {
let config = {...baseConf,
only_json: true
};
let client : AsyncClient = new AsyncClient(config, WebSocket);
assert.instanceOf(client.getDecoder(), JsonDecoder);
});

});
67 changes: 67 additions & 0 deletions test/binary-serializer.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import * as chai from 'chai';

import {ChannelMessage} from "../src/channel-message";
import {MessageDecoder} from "../src/serializer";
import {MessageEvent} from "./support/event"
import {BinaryDecoder} from "../src/binary-decoder";
import "fast-text-encoding"

const assert = chai.assert;
describe('Binary Serializer Tests', function() {

const serializer: MessageDecoder = new BinaryDecoder();

it('Should decode basic binary payload' , () => {

const data: ArrayBuffer = binaryData();
const event = new MessageEvent('test', {
data : data
});

const message = serializer.decode(event);

assert.deepEqual(message, new ChannelMessage("message_id2", "event_name2", "correlation_id2", "message_data1"));
});

it('Should decode UTF-8 with special characters binary payload' , () => {
const plainPayload = "{\"strange_message: \"áéíóú@ñ&%$#!especíalç\", \"strange_message: \"áéíóú@ñ&%$#!especíal2ç\"}";
const data: ArrayBuffer = specialBinaryData();
const event = new MessageEvent('test', {
data : data
});

const message = serializer.decode(event);

assert.deepEqual(message, new ChannelMessage("message_id2", "event_name2", "correlation_id2", plainPayload));
});

});

/*
message_id: "message_id2",
correlation_id: "correlation_id2",
message_data: "message_data1",
event_name: "event_name2"
*/
function binaryData() : ArrayBuffer {
const rawData = [255, 11, 15, 11, 109, 101, 115, 115, 97, 103, 101, 95, 105, 100, 50, 99, 111,
114, 114, 101, 108, 97, 116, 105, 111, 110, 95, 105, 100, 50, 101, 118, 101,
110, 116, 95, 110, 97, 109, 101, 50, 109, 101, 115, 115, 97, 103, 101, 95,
100, 97, 116, 97, 49];
const byteArray = new Uint8Array(rawData);
return byteArray.buffer;
}

function specialBinaryData() : ArrayBuffer {
const rawData = [255, 11, 15, 11, 109, 101, 115, 115, 97, 103, 101, 95, 105, 100, 50, 99, 111,
114, 114, 101, 108, 97, 116, 105, 111, 110, 95, 105, 100, 50, 101, 118, 101,
110, 116, 95, 110, 97, 109, 101, 50, 123, 34, 115, 116, 114, 97, 110, 103,
101, 95, 109, 101, 115, 115, 97, 103, 101, 58, 32, 34, 195, 161, 195, 169,
195, 173, 195, 179, 195, 186, 64, 195, 177, 38, 37, 36, 35, 33, 101, 115, 112,
101, 99, 195, 173, 97, 108, 195, 167, 34, 44, 32, 34, 115, 116, 114, 97, 110,
103, 101, 95, 109, 101, 115, 115, 97, 103, 101, 58, 32, 34, 195, 161, 195,
169, 195, 173, 195, 179, 195, 186, 64, 195, 177, 38, 37, 36, 35, 33, 101, 115,
112, 101, 99, 195, 173, 97, 108, 50, 195, 167, 34, 125];
const byteArray = new Uint8Array(rawData);
return byteArray.buffer;
}
23 changes: 23 additions & 0 deletions test/json-serializer.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import * as chai from 'chai';

import {JsonDecoder} from "../src/json-decoder";
import {ChannelMessage} from "../src/channel-message";
import {MessageDecoder} from "../src/serializer";
import {MessageEvent} from "./support/event"

const assert = chai.assert;
describe('Json Serializer Tests', function() {

const serializer: MessageDecoder = new JsonDecoder()

it('Should decode basic string payload' , () => {
let payload = "[\"ids332msg1\", \"\", \"person.registered\", \"someData\"]";
// @ts-ignore
const event = new MessageEvent('test', {
data : payload
});
const message = serializer.decode(event);
assert.deepEqual(message, new ChannelMessage("ids332msg1", "person.registered", "", "someData"));
});

});
26 changes: 0 additions & 26 deletions test/serializer.test.ts

This file was deleted.

Loading

0 comments on commit c871d87

Please sign in to comment.