@luffalab/luffa-endless-sdk
Version:
luffa endless ts sdk
253 lines (237 loc) • 8.06 kB
text/typescript
import { AccountInfo, EndlessLuffaSdk, MethodName } from '../index';
import type { IMessageData, EndLessSDKEventListenersType, EndLessSDKEventPayload, EndLessSDKEventType } from './types';
import { EndLessSDKEvent, IResponseMessageData } from './types';
import { getNetworkInfo, isLuffaMiniProgramWebview, isLuffaMiniProgram, isLuffa, networkMap } from '../utils';
export class PostMessage {
private static _instance: PostMessage;
callbacks: {
[key: string]: (data: unknown) => void;
} = {};
private listeners: EndLessSDKEventListenersType = {};
constructor() {
if (PostMessage._instance) return PostMessage._instance;
PostMessage._instance = this;
if (isLuffa()) {
window.endlessWallet = {
sendResponse: this.sendResponse.bind(this),
};
}
}
// wallet emit sdk
// SDK processing method itself
private readonly receive = (msg: { data: IResponseMessageData }) => {
const eventType = msg.data.methodName as EndLessSDKEventType | MethodName;
// sdk callbacks
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.NETWORK_CHANGE: {
let network = getNetworkInfo(msg.data.data.network);
if (isLuffaMiniProgram()) {
network = msg.data.data;
}
this.emit(eventType, 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) {
EndlessLuffaSdk.setAccountAddress(msg.data.data.account);
} else {
EndlessLuffaSdk.setAccountAddress(null);
}
this.emit(eventType, accountInfo);
break;
}
case EndLessSDKEvent.DISCONNECT: {
EndlessLuffaSdk.setAccountAddress(null);
this.emit(eventType, msg.data.data);
break;
}
default:
this.emit(eventType as EndLessSDKEventType, msg.data.data);
break;
}
};
readonly addListener = <K extends EndLessSDKEventType>(
methodName: K,
callback: (payload: EndLessSDKEventPayload<K>) => void
) => {
if (!this.listeners[methodName]) {
this.listeners[methodName] = [];
}
this.listeners[methodName].push(callback);
};
readonly removeListener = <K extends EndLessSDKEventType>(
methodName: K,
callback?: (payload: EndLessSDKEventPayload<K>) => 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 = <K extends EndLessSDKEventType>(methodName: K, payload: EndLessSDKEventPayload<K>) => {
this.listeners?.[methodName]?.forEach((d) => d(payload));
};
readonly sendMessage = (data: IMessageData, callback?: (data: any) => void) => {
try {
if (isLuffa()) {
this.sendLuffaMessage(data, callback);
return;
}
if (isLuffaMiniProgram() || isLuffaMiniProgramWebview()) {
this.sendMiniProgramMessage(data, callback);
return;
}
} catch (error) {
console.error('sendMessage error: ', error);
}
};
private sendLuffaMessage(data: IMessageData, callback?: (data: any) => void) {
const initData = data?.initData || EndlessLuffaSdk.getIninData();
data.initData = {
...(initData || {}),
network: networkMap[initData.network] ?? initData.network
},
data.from = EndlessLuffaSdk.getAccountAddress();
if (callback) {
this.callbacks[data.uuid + data.methodName] = callback;
}
if (window?._endlessWallet) {
window._endlessWallet?.sendMessage(JSON.stringify(data));
} else if (window?.webkit && window?.webkit?.messageHandlers?._endlessWallet) {
window.webkit.messageHandlers._endlessWallet?.postMessage(data);
}
}
private sendResponse(response: string) {
const responseData = JSON.parse(response);
console.log('responseData: ', responseData);
this.receive({
data: responseData,
});
}
private sendMiniProgramMessage(data: IMessageData, callback?: (data: any) => void) {
let funName = 'invokeNativePlugin';
const accountAddress = EndlessLuffaSdk.getAccountAddress();
const initData = EndlessLuffaSdk.getIninData();
let api_name = 'luffaWebRequest';
let params = {
api_name,
data: {
func: data.methodName,
chainType: 'endless',
...data,
initData: {
...initData,
network: networkMap[initData.network] ?? initData.network
},
from: accountAddress,
},
};
let callbackSuccessFun = (res: any) => {};
let callbackErrorFun = (res: any) => {};
switch (data.methodName) {
case MethodName.NETWORK_CHANGE:
this.emit(data.methodName as unknown as EndLessSDKEventType, data.data as any);
return;
case MethodName.DISCONNECT:
EndlessLuffaSdk.setAccountAddress(null);
this.emit(data.methodName as unknown as EndLessSDKEventType, undefined);
case MethodName.CONNECT:
case MethodName.GETACCOUNT:
callbackSuccessFun = (res) => {
EndlessLuffaSdk.setAccountAddress(res.data.account);
callback &&
callback({
account: res?.data?.address || '',
...(res.data || {}),
});
};
callbackErrorFun = (res) => {
callback &&
callback({
account: '',
});
};
break;
case MethodName.SIGN_MESSAGE:
case MethodName.SIGN_BUILD_TRANSACTION:
case MethodName.SIGN_AND_SUBMIT_TRANSACTION:
callbackSuccessFun = (res: any) => {
callback &&
callback({
status: 'success',
...(res.data || {}),
});
};
callbackErrorFun = (res: any) => {
callback &&
callback({
status: 'error',
...(res.data || {}),
});
};
break;
default:
callbackSuccessFun = (res: any) => {
callback &&
callback({
status: 'success',
...(res.data || {}),
});
};
callbackErrorFun = (res: any) => {
callback &&
callback({
status: 'error',
...(res.data || {}),
});
};
break;
}
console.log('funName: ', funName);
console.log('params: ', params);
if (isLuffaMiniProgram()) {
window.wx[funName]({
...params,
complete: (res: any) => {
console.log(`wx ${funName} res: `, res);
if (res.status === 'success') {
callbackSuccessFun(res);
this.receive({
data: res,
});
} else {
callbackErrorFun(res);
}
}
});
} else if (isLuffaMiniProgramWebview()) {
window.WeixinJSBridge?.invoke(funName, params, (res) => {
console.log(`WeixinJSBridge ${funName} res: `, res);
if (res.status === 'success') {
callbackSuccessFun(res);
this.receive({
data: res,
});
} else {
callbackErrorFun(res);
}
});
}
}
}