import { AccountAddress } from '@endlesslab/endless-ts-sdk'; import { AccountInfo, EndlessJsSdk, MethodName } from '../'; import { Modal, IframeID, ENDLESS_WALLET_COLOR_MODE_KEY, ENDLESS_WALLET_WEB3_SDK_ENABLETHEME_TOGGLE_KEY } from '../ui/modal'; import type { IMessageData, EndLessSDKEventListenersType, EndLessSDKEventPayload, EndLessSDKEventType } from './types'; import { EndLessSDKEvent, PromiseMap } from './types'; import { getNetworkInfo } from '../utils'; export class PostMessage { private static _instance: PostMessage; static readonly ENDLESS_MESSAGE_TARGET = 'endless-web3-sdk'; static readonly ENDLESS_WALLET_TARGET = 'endless-wallet-sdk'; static promiseMap: PromiseMap = {}; private uuids: string[] = []; callbacks: { [key: string]: (data: unknown) => void; } = {}; private listeners: EndLessSDKEventListenersType = {}; modal: Modal | null = null; constructor(modal: Modal) { if (PostMessage._instance) return PostMessage._instance; this.modal = modal; PostMessage._instance = this; window.addEventListener('message', this.receive, false); } // wallet emit sdk // SDK processing method itself private readonly receive = (msg: MessageEvent) => { console.log('receive msg: ', msg.data); if (msg.data.target !== PostMessage.ENDLESS_MESSAGE_TARGET) return; if (this.modal?.modalConfig?.url.indexOf(msg.origin) === -1) return; const eventType = msg.data.methodName as EndLessSDKEventType | MethodName; // sdk callbacks if (this.uuids.includes(msg.data.uuid)) { if (this.callbacks[msg.data.uuid + eventType]) { this.callbacks[msg.data.uuid + eventType](msg.data.data); delete this.callbacks[msg.data.uuid + eventType]; } } // Some events are being monitored by dapp and require running a monitoring callback switch (eventType) { case EndLessSDKEvent.WALLET_INIT_LOAD: { this.modal?.loaded(); break; } case EndLessSDKEvent.COLOR_MODE_CHANGE : { if (this.modal) { this.modal?.setWalletContainerColorMode({ colorMode: msg.data.data.colorMode, }); localStorage.setItem(ENDLESS_WALLET_WEB3_SDK_ENABLETHEME_TOGGLE_KEY, msg.data.data.colorMode); localStorage.setItem(ENDLESS_WALLET_COLOR_MODE_KEY, msg.data.data.colorMode); this.emit(eventType, msg.data.data); } break; } case EndLessSDKEvent.OPEN: { if (this.modal) { this.modal?.openModal(); this.emit(eventType, msg.data.data); } break; } case EndLessSDKEvent.CLOSE: { if (this.modal) { this.modal?.closeModal(); this.emit(eventType, msg.data.data); } break; } case EndLessSDKEvent.NETWORK_CHANGE: { const network = msg.data.data.network; this.emit(eventType, getNetworkInfo(network)); break; } // wallet to sdk send onAccountChange | connect // sdk to dapp send event // CONNECT and ACCOUNT_CHANGE return account as AccountAddress case EndLessSDKEvent.CONNECT: case EndLessSDKEvent.ACCOUNT_CHANGE: { const accountInfo: AccountInfo = { ...msg.data.data, }; if (msg?.data?.data?.account) { EndlessJsSdk.setAccountAddress(AccountAddress.fromBs58String(msg.data.data.account)); } else { EndlessJsSdk.setAccountAddress(null); } this.emit(eventType, accountInfo); break; } case EndLessSDKEvent.DISCONNECT: { EndlessJsSdk.setAccountAddress(null); this.emit(eventType, msg.data.data); break; } default: this.emit(eventType as EndLessSDKEventType, msg.data.data); break; } }; readonly addListener = ( methodName: K, callback: (payload: EndLessSDKEventPayload) => void ) => { if (!this.listeners[methodName]) { this.listeners[methodName] = []; } this.listeners[methodName].push(callback); }; readonly removeListener = ( methodName: K, callback?: (payload: EndLessSDKEventPayload) => void ) => { if (callback) { const index = this.listeners[methodName]?.indexOf(callback) ?? -1; if (index > -1) { this.listeners?.[methodName]?.splice(index, 1); } } else { this.listeners[methodName] = []; } }; readonly emit = (methodName: K, payload: EndLessSDKEventPayload) => { this.listeners?.[methodName]?.forEach((d) => d(payload)); }; readonly sendMessage = (data: IMessageData, callback?: (data: any) => void) => { if (this.modal) { const iframe: HTMLIFrameElement = document.getElementById(IframeID) as HTMLIFrameElement; if (iframe) { this.uuids.push(data.uuid); if (callback) { this.callbacks[data.uuid + data.methodName] = callback; } iframe?.contentWindow?.postMessage( { ...data, target: PostMessage.ENDLESS_WALLET_TARGET, }, iframe.src ); } } }; } export const ENDLESS_MESSAGE_TARGET = PostMessage.ENDLESS_MESSAGE_TARGET; export const ENDLESS_WALLET_TARGET = PostMessage.ENDLESS_WALLET_TARGET;