Skip to content

Commit

Permalink
useIframe
Browse files Browse the repository at this point in the history
  • Loading branch information
btcSteven committed Sep 10, 2024
1 parent 2f0c69f commit 10c672f
Show file tree
Hide file tree
Showing 7 changed files with 408 additions and 1 deletion.
2 changes: 1 addition & 1 deletion packages/vue/src/composables/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export * from "./useChain";
export * from "./useChains";
export * from "./useChainWallet";
// export * from "./useIframe";
export * from "./useIframe";
export * from "./useManager";
export * from "./useNameService";
export * from "./useWallet";
Expand Down
169 changes: 169 additions & 0 deletions packages/vue/src/composables/useIframe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
import { ref, watch, onMounted, onUnmounted, Ref } from "vue";
import { OfflineAminoSigner } from "@cosmjs/amino";
import { OfflineDirectSigner } from "@cosmjs/proto-signing";
import {
COSMIFRAME_KEYSTORECHANGE_EVENT,
COSMIFRAME_NOT_CONNECTED_MESSAGE,
MainWalletBase,
WalletClient,
WalletName,
} from "@cosmos-kit/core";
import {
Cosmiframe,
OverrideHandler,
ParentMetadata,
} from "@dao-dao/cosmiframe";
import { useWallet } from "./useWallet";

export type FunctionKeys<T> = {
[K in keyof T]: T[K] extends (...args: unknown[]) => unknown ? K : never;
}[keyof T];

export type UseIframeOptions = {
walletName?: WalletName;
metadata?: ParentMetadata;
walletClientOverrides?: Partial<{
[K in FunctionKeys<WalletClient>]: (
...params: Parameters<WalletClient[K]>
) => OverrideHandler | Promise<OverrideHandler>;
}>;
signerOverrides?: Partial<{
[K in keyof (OfflineAminoSigner & OfflineDirectSigner)]: (
...params: Parameters<(OfflineAminoSigner & OfflineDirectSigner)[K]>
) => OverrideHandler | Promise<OverrideHandler>;
}>;
origins?: string[];
};

export const useIframe = ({
walletName,
metadata,
walletClientOverrides,
signerOverrides,
origins,
}: UseIframeOptions = {}): {
wallet: MainWalletBase;
iframeRef: Ref<HTMLIFrameElement | null>;
} => {
const walletContext = useWallet(walletName);
const iframeRef = ref<HTMLIFrameElement | null>(null);

// 保存 walletClientOverrides 和 signerOverrides 的 ref
const walletClientOverridesRef = ref(walletClientOverrides);
const signerOverridesRef = ref(signerOverrides);

const notifyIframe = () => {
iframeRef.value?.contentWindow?.postMessage(
{ event: COSMIFRAME_KEYSTORECHANGE_EVENT },
"*"
);
};

// 添加事件监听
const addEventListeners = () => {
if (!walletContext.mainWallet || typeof window === "undefined") return;

notifyIframe();

walletContext.mainWallet.walletInfo.connectEventNamesOnWindow?.forEach(
(eventName) => {
window.addEventListener(eventName, notifyIframe);
}
);

walletContext.mainWallet.walletInfo.connectEventNamesOnClient?.forEach(
async (eventName) => {
walletContext.mainWallet.client?.on?.(eventName, notifyIframe);
}
);
};

// 移除事件监听
const removeEventListeners = () => {
walletContext?.mainWallet?.walletInfo.connectEventNamesOnWindow?.forEach(
(eventName) => {
window.removeEventListener(eventName, notifyIframe);
}
);

walletContext.mainWallet.walletInfo.connectEventNamesOnClient?.forEach(
async (eventName) => {
walletContext?.mainWallet.client?.off?.(eventName, notifyIframe);
}
);
};

// 监听 mainWallet 和 iframeRef 的变化
watch(
[() => walletContext.mainWallet, iframeRef],
([newMainWallet, newIframe]) => {
if (newMainWallet && newIframe) {
notifyIframe();
addEventListeners();
}
}
);

// 在组件挂载时添加 Cosmiframe 监听
onMounted(() => {
if (!iframeRef.value) return;

const removeListener = Cosmiframe.listen({
iframe: iframeRef.value,
target: walletContext.mainWallet?.client || {},
getOfflineSignerDirect:
walletContext.mainWallet?.client.getOfflineSignerDirect.bind(
walletContext.mainWallet?.client
) || (() => Promise.reject(COSMIFRAME_NOT_CONNECTED_MESSAGE)),
getOfflineSignerAmino:
walletContext.mainWallet?.client.getOfflineSignerAmino.bind(
walletContext.mainWallet.client
) || (() => Promise.reject(COSMIFRAME_NOT_CONNECTED_MESSAGE)),
nonSignerOverrides: () => ({
...walletClientOverridesRef.value,
connect: async (...params) => {
if (walletClientOverridesRef.value?.connect) {
return await walletClientOverridesRef.value.connect(
params[0],
params[1]
);
} else if (walletContext.mainWallet?.client?.connect) {
await walletContext.mainWallet.client.connect(params[0], params[1]);
} else {
return {
type: "error",
error: COSMIFRAME_NOT_CONNECTED_MESSAGE,
};
}
},
}),
signerOverrides: () => signerOverridesRef.value,
origins,
metadata: {
name:
metadata?.name ||
`${walletContext.mainWallet?.walletInfo.prettyName} (Outer Wallet)`,
imageUrl:
metadata?.imageUrl ||
(walletContext.mainWallet?.walletInfo.logo
? typeof walletContext.mainWallet?.walletInfo.logo === "string"
? walletContext.mainWallet?.walletInfo.logo
: "major" in walletContext.mainWallet?.walletInfo.logo
? walletContext.mainWallet?.walletInfo.logo.major
: undefined
: undefined),
},
});

// 在组件销毁时移除 Cosmiframe 监听
onUnmounted(() => {
removeListener();
removeEventListeners();
});
});

return {
wallet: walletContext.mainWallet as MainWalletBase,
iframeRef,
};
};
44 changes: 44 additions & 0 deletions packages/vue/src/composables/useManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { inject } from "vue";
import { ManagerContext } from "@cosmos-kit/core";

const walletContextKey = "walletManager";

export const useManager = (): ManagerContext => {
const context = inject(walletContextKey);

if (!context) {
throw new Error("You have forgotten to use ChainProvider.");
}

const walletManager: any = context;
const {
mainWallets,
chainRecords,
walletRepos,
defaultNameService,
getChainRecord,
getWalletRepo,
addChains,
addEndpoints,
getChainLogo,
getNameService,
on,
off,
} = walletManager;

// 返回 ManagerContext 对象
return {
chainRecords,
walletRepos,
mainWallets,
defaultNameService,
getChainRecord,
getWalletRepo,
addChains,
addEndpoints,
getChainLogo,
getNameService,
on,
off,
};
};
51 changes: 51 additions & 0 deletions packages/vue/src/composables/useNameService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import {
getNameServiceRegistryFromName,
Mutable,
NameService,
NameServiceName,
State,
} from "@cosmos-kit/core";
import { ref, computed, watchEffect, reactive, watch } from "vue";
import { useManager } from "./useManager";

export const useNameService = (name?: NameServiceName) => {
const serviceState = reactive({
state: State.Pending as State,
ns: null as NameService | null,
msg: null as string | null,
});

const { defaultNameService, getNameService } = useManager();
const registry = computed(() =>
getNameServiceRegistryFromName(name || defaultNameService)
);

if (!registry.value) {
throw new Error("No such name service: " + (name || defaultNameService));
}

watch(
() => name,
() => {
serviceState.state = State.Pending;

getNameService()
.then((nameService) => {
serviceState.ns = nameService;
serviceState.state = State.Done;
})
.catch((e) => {
serviceState.msg = (e as Error).message;
serviceState.state = State.Error;
})
.finally(() => {
if (serviceState.state === State.Pending) {
serviceState.state = State.Init;
}
});
},
{ immediate: true }
);

return serviceState;
};
76 changes: 76 additions & 0 deletions packages/vue/src/composables/useWallet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import {
ref,
reactive,
inject,
watch,
Reactive,
onMounted,
onUnmounted,
} from "vue";
import {
WalletContext,
WalletName,
WalletStatus,
State,
} from "@cosmos-kit/core";

const walletContextKey = "walletManager";

export const useWallet = (
walletName?: WalletName,
activeOnly = true
): Reactive<WalletContext> => {
const context = inject(walletContextKey);

if (!context) {
throw new Error("You have forgotten to use ChainProvider.");
}

const walletManager: any = context;
const state = reactive<WalletContext>({
mainWallet: null,
chainWallets: [],
wallet: undefined,
status: WalletStatus.Disconnected,
message: undefined,
});

const updateWalletState = () => {
const mainWallet = walletName
? walletManager.getMainWallet(walletName)
: walletManager.mainWallets.find(
(w) => w.isActive && w.clientMutable.state !== State.Error
);

if (!mainWallet) {
state.mainWallet = null;
state.chainWallets = [];
state.wallet = undefined;
state.status = WalletStatus.Disconnected;
state.message = undefined;
return;
}

const { walletInfo, getChainWalletList, getGlobalStatusAndMessage } =
mainWallet;
const [globalStatus, globalMessage] = getGlobalStatusAndMessage(activeOnly);

state.mainWallet = mainWallet;
state.chainWallets = getChainWalletList(false);
state.wallet = walletInfo;
state.status = globalStatus;
state.message = globalMessage;
};

onMounted(() => {
const timeoutId = setTimeout(() => {
updateWalletState();
}, 600);

onUnmounted(() => {
clearTimeout(timeoutId);
});
});

return state;
};
Loading

0 comments on commit 10c672f

Please sign in to comment.