mirror of
https://github.com/hexastack/hexabot
synced 2025-05-23 13:34:58 +00:00
fix: resolve broadcastChannel duplication tab bug
This commit is contained in:
parent
bc156fcefe
commit
b852fa76a1
@ -15,8 +15,6 @@ import {
|
|||||||
useRef,
|
useRef,
|
||||||
} from "react";
|
} from "react";
|
||||||
|
|
||||||
import { generateId } from "@/utils/generateId";
|
|
||||||
|
|
||||||
export enum EBCEvent {
|
export enum EBCEvent {
|
||||||
LOGIN = "login",
|
LOGIN = "login",
|
||||||
LOGOUT = "logout",
|
LOGOUT = "logout",
|
||||||
@ -28,7 +26,6 @@ type BroadcastChannelPayload = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type BroadcastChannelData = {
|
type BroadcastChannelData = {
|
||||||
tabId: string;
|
|
||||||
payload: BroadcastChannelPayload;
|
payload: BroadcastChannelPayload;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -45,19 +42,6 @@ interface IBroadcastChannelContext {
|
|||||||
postMessage: (payload: BroadcastChannelPayload) => void;
|
postMessage: (payload: BroadcastChannelPayload) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getOrCreateTabId = () => {
|
|
||||||
let storedTabId = sessionStorage.getItem("tab_uuid");
|
|
||||||
|
|
||||||
if (storedTabId) {
|
|
||||||
return storedTabId;
|
|
||||||
}
|
|
||||||
|
|
||||||
storedTabId = generateId();
|
|
||||||
sessionStorage.setItem("tab_uuid", storedTabId);
|
|
||||||
|
|
||||||
return storedTabId;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const BroadcastChannelContext = createContext<
|
export const BroadcastChannelContext = createContext<
|
||||||
IBroadcastChannelContext | undefined
|
IBroadcastChannelContext | undefined
|
||||||
>(undefined);
|
>(undefined);
|
||||||
@ -75,15 +59,10 @@ export const BroadcastChannelProvider: FC<IBroadcastChannelProps> = ({
|
|||||||
Array<Parameters<IBroadcastChannelContext["subscribe"]>["1"]>
|
Array<Parameters<IBroadcastChannelContext["subscribe"]>["1"]>
|
||||||
>
|
>
|
||||||
>({});
|
>({});
|
||||||
const tabUuid = getOrCreateTabId();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleMessage = ({ data }: MessageEvent<BroadcastChannelData>) => {
|
const handleMessage = ({ data }: MessageEvent<BroadcastChannelData>) => {
|
||||||
const { tabId, payload } = data;
|
const { payload } = data;
|
||||||
|
|
||||||
if (tabId === tabUuid) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
subscribersRef.current[payload.event].forEach((callback) =>
|
subscribersRef.current[payload.event].forEach((callback) =>
|
||||||
callback(data),
|
callback(data),
|
||||||
@ -115,7 +94,6 @@ export const BroadcastChannelProvider: FC<IBroadcastChannelProps> = ({
|
|||||||
};
|
};
|
||||||
const postMessage: IBroadcastChannelContext["postMessage"] = (payload) => {
|
const postMessage: IBroadcastChannelContext["postMessage"] = (payload) => {
|
||||||
channelRef.current.postMessage({
|
channelRef.current.postMessage({
|
||||||
tabId: tabUuid,
|
|
||||||
payload,
|
payload,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -15,8 +15,6 @@ import {
|
|||||||
useRef,
|
useRef,
|
||||||
} from "react";
|
} from "react";
|
||||||
|
|
||||||
import { generateId } from "../utils/generateId";
|
|
||||||
|
|
||||||
export enum EBCEvent {
|
export enum EBCEvent {
|
||||||
LOGOUT = "logout",
|
LOGOUT = "logout",
|
||||||
}
|
}
|
||||||
@ -27,7 +25,6 @@ type BroadcastChannelPayload = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type BroadcastChannelData = {
|
type BroadcastChannelData = {
|
||||||
tabId: string;
|
|
||||||
payload: BroadcastChannelPayload;
|
payload: BroadcastChannelPayload;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -44,19 +41,6 @@ interface IBroadcastChannelContext {
|
|||||||
postMessage: (payload: BroadcastChannelPayload) => void;
|
postMessage: (payload: BroadcastChannelPayload) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getOrCreateTabId = () => {
|
|
||||||
let storedTabId = sessionStorage.getItem("tab_uuid");
|
|
||||||
|
|
||||||
if (storedTabId) {
|
|
||||||
return storedTabId;
|
|
||||||
}
|
|
||||||
|
|
||||||
storedTabId = generateId();
|
|
||||||
sessionStorage.setItem("tab_uuid", storedTabId);
|
|
||||||
|
|
||||||
return storedTabId;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const BroadcastChannelContext = createContext<
|
export const BroadcastChannelContext = createContext<
|
||||||
IBroadcastChannelContext | undefined
|
IBroadcastChannelContext | undefined
|
||||||
>(undefined);
|
>(undefined);
|
||||||
@ -74,15 +58,10 @@ export const BroadcastChannelProvider: FC<IBroadcastChannelProps> = ({
|
|||||||
Array<Parameters<IBroadcastChannelContext["subscribe"]>["1"]>
|
Array<Parameters<IBroadcastChannelContext["subscribe"]>["1"]>
|
||||||
>
|
>
|
||||||
>({});
|
>({});
|
||||||
const tabUuid = getOrCreateTabId();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleMessage = ({ data }: MessageEvent<BroadcastChannelData>) => {
|
const handleMessage = ({ data }: MessageEvent<BroadcastChannelData>) => {
|
||||||
const { tabId, payload } = data;
|
const { payload } = data;
|
||||||
|
|
||||||
if (tabId === tabUuid) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
subscribersRef.current[payload.event].forEach((callback) =>
|
subscribersRef.current[payload.event].forEach((callback) =>
|
||||||
callback(data),
|
callback(data),
|
||||||
@ -116,7 +95,6 @@ export const BroadcastChannelProvider: FC<IBroadcastChannelProps> = ({
|
|||||||
};
|
};
|
||||||
const postMessage: IBroadcastChannelContext["postMessage"] = (payload) => {
|
const postMessage: IBroadcastChannelContext["postMessage"] = (payload) => {
|
||||||
channelRef.current.postMessage({
|
channelRef.current.postMessage({
|
||||||
tabId: tabUuid,
|
|
||||||
payload,
|
payload,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2025 Hexastack. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
|
|
||||||
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
|
|
||||||
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
import { getRandom } from "./safeRandom";
|
|
||||||
|
|
||||||
export const generateId = () => {
|
|
||||||
const d =
|
|
||||||
typeof performance === "undefined" ? Date.now() : performance.now() * 1000;
|
|
||||||
|
|
||||||
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
||||||
const r = (getRandom() * 16 + d) % 16 | 0;
|
|
||||||
|
|
||||||
return (c == "x" ? r : (r & 0x3) | 0x8).toString(16);
|
|
||||||
});
|
|
||||||
};
|
|
@ -1,16 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2025 Hexastack. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
|
|
||||||
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
|
|
||||||
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a cryptographically secure random value between 0 and 1
|
|
||||||
*
|
|
||||||
* @returns A cryptographically secure random value between 0 and 1
|
|
||||||
*/
|
|
||||||
export const getRandom = (): number =>
|
|
||||||
window.crypto.getRandomValues(new Uint32Array(1))[0] * Math.pow(2, -32);
|
|
Loading…
Reference in New Issue
Block a user