import { Post } from '../types' export interface MessageContent { [key: string]: any height?: number parent?: Post } export interface IncomingMessageData { name: string content: MessageContent publicKey: string } export interface OutgoingMessageData { name: string content?: MessageContent error?: string settings?: object } interface Listener { resolve: (value?: MessageContent | PromiseLike) => void reject: (reason: any) => void once: boolean } interface ListenerCollection { [name: string]: Listener } type PostOptions = Post export class Communicator { private origin = 'http://localhost:8080' private publicKey: string private listeners: ListenerCollection constructor(publicKey: string) { this.publicKey = publicKey this.listeners = {} window.addEventListener('message', (event: MessageEvent) => { if (event.origin !== this.origin) return try { const data = JSON.parse(event.data) as OutgoingMessageData this.emit(data) } catch (err) { console.error(err) return } }, false) } private emit(data: OutgoingMessageData) { const listener = this.listeners[data.name] if (listener) { if (data.content) listener.resolve(data.content) if (data.error) listener.reject(data.error) if (listener.once) delete this.listeners[data.name] } } private async postAndReceive(name: string, content?: MessageContent) { if (window.parent) { window.parent.postMessage(JSON.stringify({ name, content, publicKey: this.publicKey, }), this.origin) return new Promise((resolve, reject) => { this.listeners[name] = { resolve, reject, once: true, } }) } } async init() { return this.postAndReceive('init') } async setHeight(height: number) { return this.postAndReceive('setHeight', { height }) } async post(options: PostOptions) { return this.postAndReceive('post', options) } }