frontend/src/external_app/external_messaging.ts
Robbie Trencheny d05b1ef9cc Add connection events to bus (#3117)
* Add connection events

* Fix types

* Fix order
2019-04-24 10:56:53 -07:00

108 lines
2.4 KiB
TypeScript

import { externalForwardConnectionEvents } from "./external_events_forwarder";
const CALLBACK_EXTERNAL_BUS = "externalBus";
interface CommandInFlight {
resolve: (data: any) => void;
reject: (err: ExternalError) => void;
}
export interface InternalMessage {
id?: number;
type: string;
payload?: unknown;
}
interface ExternalError {
code: string;
message: string;
}
interface ExternalMessageResult {
id: number;
type: "result";
success: true;
result: unknown;
}
interface ExternalMessageResultError {
id: number;
type: "result";
success: false;
error: ExternalError;
}
type ExternalMessage = ExternalMessageResult | ExternalMessageResultError;
export class ExternalMessaging {
public commands: { [msgId: number]: CommandInFlight } = {};
public cache: { [key: string]: any } = {};
public msgId = 0;
public attach() {
externalForwardConnectionEvents(this);
window[CALLBACK_EXTERNAL_BUS] = (msg) => this.receiveMessage(msg);
}
/**
* Send message to external app that expects a response.
* @param msg message to send
*/
public sendMessage<T>(msg: InternalMessage): Promise<T> {
const msgId = ++this.msgId;
msg.id = msgId;
this.fireMessage(msg);
return new Promise<T>((resolve, reject) => {
this.commands[msgId] = { resolve, reject };
});
}
/**
* Send message to external app without expecting a response.
* @param msg message to send
*/
public fireMessage(msg: InternalMessage) {
if (!msg.id) {
msg.id = ++this.msgId;
}
this._sendExternal(msg);
}
public receiveMessage(msg: ExternalMessage) {
if (__DEV__) {
// tslint:disable-next-line: no-console
console.log("Receiving message from external app", msg);
}
const pendingCmd = this.commands[msg.id];
if (!pendingCmd) {
// tslint:disable-next-line: no-console
console.warn(`Received unknown msg ID`, msg.id);
return;
}
if (msg.type === "result") {
if (msg.success) {
pendingCmd.resolve(msg.result);
} else {
pendingCmd.reject(msg.error);
}
}
}
protected _sendExternal(msg: InternalMessage) {
if (__DEV__) {
// tslint:disable-next-line: no-console
console.log("Sending message to external app", msg);
}
if (window.externalApp) {
window.externalApp.externalBus(JSON.stringify(msg));
} else {
window.webkit!.messageHandlers.externalBus.postMessage(msg);
}
}
}