///
module openflow {
"use strict";
interface IHashTable {
[key: string]: T;
}
export interface WebAppInterface {
getFirebaseToken(): any;
getOneSignalRegisteredId(): any;
isProductPurchased(): any;
showLoader(): void;
hideLoader(): void;
rateApp(): void;
playSound(file: string): void;
createNotification(displayname: string, message: string): void;
}
export declare var android: WebAppInterface;
type QueuedMessageCallback = (msg: any) => any;
export class QueuedMessage {
constructor(message: any, cb: QueuedMessageCallback) {
this.id = message.id;
this.message = message;
this.cb = cb;
}
public cb: QueuedMessageCallback;
public id: string;
public message: any;
}
function iosGetOnesignalToken() {
return new Promise(async (resolve, reject) => {
try {
(window as any).bridge.post('onesignaltoken', {}, (results, error) => {
if (error) { return reject(error); }
console.log(results);
resolve(results);
});
} catch (error) {
reject(error);
}
});
}
export class WebSocketClient {
private _socketObject: ReconnectingWebSocket = null;
private _url: string = null;
private static instance: WebSocketClient = null;
private _receiveQueue: SocketMessage[] = [];
private _sendQueue: SocketMessage[] = [];
public user: TokenUser = null;
public jwt: string = null;
static $inject = ["$rootScope", "$location", "$window"];
public messageQueue: IHashTable = {};
constructor(public $rootScope: ng.IRootScopeService, public $location, public $window: any) {
this.getJSON("/config", async (error: any, data: any) => {
console.debug("WebSocketClient::onopen: connecting to " + data.wshost);
this._socketObject = new ReconnectingWebSocket(data.wshost);
this._socketObject.onopen = (this.onopen).bind(this);
this._socketObject.onmessage = (this.onmessage).bind(this);
this._socketObject.onclose = (this.onclose).bind(this);
this._socketObject.onerror = (this.onerror).bind(this);
WebSocketClient.instance = this;
});
}
public connect(): void {
}
getJSON(url: string, callback: any): void {
var xhr: XMLHttpRequest = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.responseType = "json";
xhr.onload = function (): void {
var status: number = xhr.status;
if (status === 200) {
callback(null, xhr.response);
} else {
callback(status, xhr.response);
}
};
xhr.send();
}
onSignedin(callback) {
if (this.user !== null) {
callback(this.user);
return;
}
var cleanup = this.$rootScope.$on('signin', (event, data) => {
if (event && data) { }
cleanup();
callback(this.user);
});
}
private async onopen(evt: Event): Promise {
console.log("WebSocketClient::onopen: connected");
var me: WebSocketClient = WebSocketClient.instance;
var q: SigninMessage = new SigninMessage();
this.getJSON("/jwt", async (error: any, data: any) => {
try {
if (data === null || data === undefined) {
if ((data.jwt === null || data.jwt === undefined || data.jwt.trim() === "") ||
(data.rawAssertion === null || data.rawAssertion === undefined || data.rawAssertion.trim() === "")) {
data = null;
}
}
if (data === null || data === undefined) {
if (this.$location.path() !== "/Login") {
console.log("path: " + this.$location.path());
console.log("WebSocketClient::onopen: Not signed in, redirect /Login");
this.$location.path("/Login");
this.$rootScope.$apply();
}
return;
}
var _android: WebAppInterface = null;
try {
_android = android;
} catch (error) {
}
q.jwt = data.jwt;
q.rawAssertion = data.rawAssertion;
q.realm = "browser";
console.log("WebSocketClient::onopen: Validate jwt");
if (_android != null) {
q.realm = "android";
try {
console.debug("getFirebaseToken");
q.firebasetoken = _android.getFirebaseToken();
} catch (error) {
console.log(error);
}
try {
console.debug("getOneSignalRegisteredId");
q.onesignalid = _android.getOneSignalRegisteredId();
} catch (error) {
console.log(error);
}
}
try {
console.debug("WebSocketClient::iosGetOnesignalToken");
var results = await iosGetOnesignalToken();
q.onesignalid = results.token;
} catch (error) {
console.log(error);
}
console.debug("signing in with token");
var msg: Message = new Message(); msg.command = "signin"; msg.data = JSON.stringify(q);
var a: any = await this.Send(msg);
var result: SigninMessage = a;
this.user = result.user;
this.$rootScope.$broadcast(msg.command, result);
} catch (error) {
this.user = null;
console.error(error);
this.$location.path("/Login");
this.$rootScope.$apply();
}
});
}
private onclose(evt: CloseEvent): void {
var me: WebSocketClient = WebSocketClient.instance;
}
private onerror(evt: ErrorEvent): void {
var me: WebSocketClient = WebSocketClient.instance;
}
private onmessage(evt: MessageEvent): void {
var me: WebSocketClient = WebSocketClient.instance;
let msg: SocketMessage = SocketMessage.fromjson(evt.data);
me._receiveQueue.push(msg);
me.ProcessQueue.bind(me)();
}
public async Send(message: Message): Promise {
return new Promise(async (resolve, reject) => {
this._Send(message, ((msg) => {
if (msg.error !== null && msg.error !== undefined) { console.log(message); return reject(msg.error); }
resolve(msg);
}).bind(this));
});
}
private _Send(message: Message, cb: QueuedMessageCallback): void {
var messages: string[] = this.chunkString(message.data, 500);
if (messages === null || messages === undefined || messages.length === 0) {
var singlemessage: SocketMessage = SocketMessage.frommessage(message, "", 1, 0);
if (message.replyto === null || message.replyto === undefined) {
this.messageQueue[singlemessage.id] = new QueuedMessage(singlemessage, cb);
}
this._sendQueue.push(singlemessage);
return;
}
if (message.id === null || message.id === undefined) { message.id = Math.random().toString(36).substr(2, 9); }
for (let i: number = 0; i < messages.length; i++) {
var _message: SocketMessage = SocketMessage.frommessage(message, messages[i], messages.length, i);
this._sendQueue.push(_message);
}
if (message.replyto === null || message.replyto === undefined) {
this.messageQueue[message.id] = new QueuedMessage(message, cb);
}
this.ProcessQueue();
}
public chunkString(str: string, length: number): string[] {
if (str === null || str === undefined) {
return [];
}
// tslint:disable-next-line: quotemark
return str.match(new RegExp('.{1,' + length + '}', 'g'));
}
private ProcessQueue(): void {
let ids: string[] = [];
this._receiveQueue.forEach(msg => {
if (ids.indexOf(msg.id) === -1) { ids.push(msg.id); }
});
ids.forEach(id => {
var msgs: SocketMessage[] = this._receiveQueue.filter(function (msg: SocketMessage): boolean { return msg.id === id; });
msgs.sort((a, b) => a.index - b.index);
var first: SocketMessage = msgs[0];
if (first.count === msgs.length) {
if (msgs.length === 1) {
var singleresult: Message = Message.frommessage(first, first.data);
this._receiveQueue = this._receiveQueue.filter(function (msg: SocketMessage): boolean { return msg.id !== id; });
singleresult.Process(this);
} else {
var buffer: string = "";
msgs.forEach(msg => {
if (msg.data !== null && msg.data !== undefined) { buffer += msg.data; }
});
var result: Message = Message.frommessage(first, buffer);
this._receiveQueue = this._receiveQueue.filter(function (msg: SocketMessage): boolean { return msg.id !== id; });
result.Process(this);
}
this._receiveQueue = this._receiveQueue.filter(function (msg: SocketMessage): boolean { return msg.id !== id; });
}
});
if (this._socketObject !== null && this._socketObject.readyState !== 1) {
this.connect();
setTimeout(() => {
this.ProcessQueue();
}, 1500);
return;
}
this._sendQueue.forEach(msg => {
try {
if (this._socketObject !== null && this._socketObject.readyState === 1) {
let id: string = msg.id;
this._socketObject.send(JSON.stringify(msg));
this._sendQueue = this._sendQueue.filter(function (msg: SocketMessage): boolean { return msg.id !== id; });
}
} catch (error) {
console.error(error);
}
});
}
}
}