@luffalab/luffa-endless-sdk
Version:
luffa endless ts sdk
269 lines (249 loc) • 8.41 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 BUILD_PLATFORM !== 'MINIPROGRAM'
if (isLuffa()) {
window.endlessWallet = {
sendResponse: this.sendResponse.bind(this),
};
}
/// #endif
}
// 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 MethodName.NETWORK_CHANGE: {
const network = networkMap[msg.data?.data?.network] ?? msg.data?.data?.network;
this.emit(EndLessSDKEvent.NETWORK_CHANGE, { name: network, chainId: msg.data?.data?.blockChainId });
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 {
// web and WebView
/// #if BUILD_PLATFORM !== 'MINIPROGRAM'
if (isLuffa()) {
this.sendLuffaMessage(data, callback);
return;
} else {
this.sendMiniProgramMessage(data, callback);
}
/// #endif
/// #if BUILD_PLATFORM === 'MINIPROGRAM'
this.sendMiniProgramMessage(data, callback);
/// #endif
} catch (error) {
callback && callback({
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;
}
console.log('luffa-endless-sdk sendLuffaMessage data: ', data);
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('luffa-endless-sdk responseData: ', responseData);
this.receive({
data: responseData,
});
}
private sendMiniProgramMessage(data: IMessageData, callback?: (data: any) => void) {
let funName = 'invokeNativePlugin';
const accountAddress = EndlessLuffaSdk.getAccountAddress();
const initData = data?.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) => {
callback &&
callback({
status: 'success',
...(res.data || {}),
});
};
let callbackErrorFun = (res: any) => {
callback &&
callback({
status: 'error',
...(res.data || {}),
});
};
switch (data.methodName) {
case MethodName.CONNECT:
case MethodName.GETACCOUNT:
callbackSuccessFun = (res) => {
EndlessLuffaSdk.setAccountAddress(res.data.account);
callback &&
callback({
account: res?.data?.address || '',
...(res.data || {}),
});
};
callbackErrorFun = () => {
callback &&
callback({
account: '',
});
};
break;
case MethodName.SIGN_MESSAGE:
case MethodName.SIGN_BUILD_TRANSACTION:
case MethodName.SIGN_AND_SUBMIT_TRANSACTION:
case MethodName.PACKAGETRANSACTIONV2:
callbackSuccessFun = (res: any) => {
callback &&
callback({
status: 'success',
...(res.data || {}),
});
};
callbackErrorFun = (res: any) => {
callback &&
callback({
status: 'error',
...(res.data || {}),
});
};
break;
default:
break;
}
console.log('funName: ', funName);
console.log('params: ', params);
/// #if BUILD_PLATFORM !== 'MINIPROGRAM'
if (isLuffaMiniProgramWebview()) {
window.WeixinJSBridge?.invoke(funName, params, (res) => {
console.log(`luffa-endless-sdk WeixinJSBridge ${funName} res: `, res);
if (res.status === undefined) {
callback && callback({
...res,
});
} else if (res.status === 'success') {
console.log('res.status === success: ', res.status === 'success');
callbackSuccessFun(res);
this.receive({
data: res,
});
} else {
callbackErrorFun(res);
}
});
}
/// #endif
/// #if BUILD_PLATFORM === 'MINIPROGRAM'
wx.invokeNativePlugin({
...params,
complete: (res: any) => {
console.log(`wx ${funName} res: `, res);
if (res.status === undefined) {
callback && callback({
...res,
});
} else if (res.status === 'success') {
callbackSuccessFun(res);
this.receive({
data: res,
});
} else {
callbackErrorFun(res);
}
}
});
/// #endif
}
}