import { CbEvents, LogLevel } from "@openim/wasm-client-sdk"; import { MessageType, SessionType } from "@openim/wasm-client-sdk"; import { BlackUserItem, ConversationItem, FriendApplicationItem, FriendUserItem, GroupApplicationItem, GroupItem, GroupMemberItem, MessageItem, RevokedInfo, SelfUserInfo, WSEvent, WsResponse, } from "@openim/wasm-client-sdk/lib/types/entity"; import { t } from "i18next"; import { useEffect, useRef } from "react"; import { useNavigate } from "react-router-dom"; import { CustomType } from "@/constants"; import { API_URL, WS_URL } from "@/config/endpoints"; import { pushNewMessage, updateOneMessage, } from "@/pages/chat/queryChat/useHistoryMessageList"; import { useConversationStore, useUserStore } from "@/store"; import { useContactStore } from "@/store/contact"; import { feedbackToast } from "@/utils/common"; import { initStore } from "@/utils/imCommon"; import { clearIMProfile, getIMToken, getIMUserID } from "@/utils/storage"; import { IMSDK } from "./MainContentWrap"; export function useGlobalEvent() { const navigate = useNavigate(); const resume = useRef(false); // user const updateSyncState = useUserStore((state) => state.updateSyncState); const updateProgressState = useUserStore((state) => state.updateProgressState); const updateReinstallState = useUserStore((state) => state.updateReinstallState); const updateIsLogining = useUserStore((state) => state.updateIsLogining); const updateConnectState = useUserStore((state) => state.updateConnectState); const updateSelfInfo = useUserStore((state) => state.updateSelfInfo); const userLogout = useUserStore((state) => state.userLogout); // conversation const updateConversationList = useConversationStore( (state) => state.updateConversationList, ); const updateUnReadCount = useConversationStore((state) => state.updateUnReadCount); const updateCurrentGroupInfo = useConversationStore( (state) => state.updateCurrentGroupInfo, ); const getCurrentGroupInfoByReq = useConversationStore( (state) => state.getCurrentGroupInfoByReq, ); const setCurrentMemberInGroup = useConversationStore( (state) => state.setCurrentMemberInGroup, ); const getCurrentMemberInGroupByReq = useConversationStore( (state) => state.getCurrentMemberInGroupByReq, ); const tryUpdateCurrentMemberInGroup = useConversationStore( (state) => state.tryUpdateCurrentMemberInGroup, ); const getConversationListByReq = useConversationStore( (state) => state.getConversationListByReq, ); const getUnReadCountByReq = useConversationStore( (state) => state.getUnReadCountByReq, ); // contact const getFriendListByReq = useContactStore((state) => state.getFriendListByReq); const getGroupListByReq = useContactStore((state) => state.getGroupListByReq); const updateFriend = useContactStore((state) => state.updateFriend); const pushNewFriend = useContactStore((state) => state.pushNewFriend); const updateBlack = useContactStore((state) => state.updateBlack); const pushNewBlack = useContactStore((state) => state.pushNewBlack); const updateGroup = useContactStore((state) => state.updateGroup); const pushNewGroup = useContactStore((state) => state.pushNewGroup); const updateRecvFriendApplication = useContactStore( (state) => state.updateRecvFriendApplication, ); const updateSendFriendApplication = useContactStore( (state) => state.updateSendFriendApplication, ); const updateRecvGroupApplication = useContactStore( (state) => state.updateRecvGroupApplication, ); const updateSendGroupApplication = useContactStore( (state) => state.updateSendGroupApplication, ); useEffect(() => { loginCheck(); setIMListener(); setIpcListener(); window.addEventListener("online", () => { IMSDK.networkStatusChanged(); }); window.addEventListener("offline", () => { IMSDK.networkStatusChanged(); }); return () => { disposeIMListener(); }; }, []); const loginCheck = async () => { const IMToken = (await getIMToken()) as string; const IMUserID = (await getIMUserID()) as string; if (!IMToken || !IMUserID) { clearIMProfile(); navigate("/login"); return; } tryLogin(); }; const tryLogin = async () => { updateIsLogining(true); const IMToken = (await getIMToken()) as string; const IMUserID = (await getIMUserID()) as string; try { const apiAddr = API_URL; const wsAddr = WS_URL; if (window.electronAPI) { await IMSDK.initSDK({ platformID: window.electronAPI?.getPlatform() ?? 5, apiAddr, wsAddr, dataDir: window.electronAPI.getDataPath("sdkResources") || "./", logFilePath: window.electronAPI.getDataPath("logsPath") || "./", logLevel: LogLevel.Debug, isLogStandardOutput: false, systemType: "electron", }); await IMSDK.login({ userID: IMUserID, token: IMToken, }); } else { await IMSDK.login({ userID: IMUserID, token: IMToken, platformID: 5, apiAddr, wsAddr, logLevel: LogLevel.Debug, }); } initStore(); } catch (error) { console.error(error); if ((error as WsResponse).errCode !== 10102) { navigate("/login"); } } updateIsLogining(false); }; const setIMListener = () => { // account IMSDK.on(CbEvents.OnSelfInfoUpdated, selfUpdateHandler); IMSDK.on(CbEvents.OnConnecting, connectingHandler); IMSDK.on(CbEvents.OnConnectFailed, connectFailedHandler); IMSDK.on(CbEvents.OnConnectSuccess, connectSuccessHandler); IMSDK.on(CbEvents.OnKickedOffline, kickHandler); IMSDK.on(CbEvents.OnUserTokenExpired, expiredHandler); IMSDK.on(CbEvents.OnUserTokenInvalid, expiredHandler); // sync IMSDK.on(CbEvents.OnSyncServerStart, syncStartHandler); IMSDK.on(CbEvents.OnSyncServerProgress, syncProgressHandler); IMSDK.on(CbEvents.OnSyncServerFinish, syncFinishHandler); IMSDK.on(CbEvents.OnSyncServerFailed, syncFailedHandler); // message IMSDK.on(CbEvents.OnRecvNewMessages, newMessageHandler); IMSDK.on(CbEvents.OnNewRecvMessageRevoked, revokedMessageHandler); // conversation IMSDK.on(CbEvents.OnConversationChanged, conversationChnageHandler); IMSDK.on(CbEvents.OnNewConversation, newConversationHandler); IMSDK.on(CbEvents.OnTotalUnreadMessageCountChanged, totalUnreadChangeHandler); // friend IMSDK.on(CbEvents.OnFriendInfoChanged, friednInfoChangeHandler); IMSDK.on(CbEvents.OnFriendAdded, friednAddedHandler); IMSDK.on(CbEvents.OnFriendDeleted, friednDeletedHandler); // blacklist IMSDK.on(CbEvents.OnBlackAdded, blackAddedHandler); IMSDK.on(CbEvents.OnBlackDeleted, blackDeletedHandler); // group IMSDK.on(CbEvents.OnJoinedGroupAdded, joinedGroupAddedHandler); IMSDK.on(CbEvents.OnJoinedGroupDeleted, joinedGroupDeletedHandler); IMSDK.on(CbEvents.OnGroupDismissed, joinedGroupDismissHandler); IMSDK.on(CbEvents.OnGroupInfoChanged, groupInfoChangedHandler); IMSDK.on(CbEvents.OnGroupMemberAdded, groupMemberAddedHandler); IMSDK.on(CbEvents.OnGroupMemberDeleted, groupMemberDeletedHandler); IMSDK.on(CbEvents.OnGroupMemberInfoChanged, groupMemberInfoChangedHandler); // application IMSDK.on(CbEvents.OnFriendApplicationAdded, friendApplicationProcessedHandler); IMSDK.on(CbEvents.OnFriendApplicationAccepted, friendApplicationProcessedHandler); IMSDK.on(CbEvents.OnFriendApplicationRejected, friendApplicationProcessedHandler); IMSDK.on(CbEvents.OnGroupApplicationAdded, groupApplicationProcessedHandler); IMSDK.on(CbEvents.OnGroupApplicationAccepted, groupApplicationProcessedHandler); IMSDK.on(CbEvents.OnGroupApplicationRejected, groupApplicationProcessedHandler); }; const selfUpdateHandler = ({ data }: WSEvent) => { updateSelfInfo(data); }; const connectingHandler = () => { updateConnectState("loading"); console.log("connecting..."); }; const connectFailedHandler = ({ errCode, errMsg }: WSEvent) => { updateConnectState("failed"); console.error("connectFailedHandler", errCode, errMsg); if (errCode === 705) { tryOut(t("toast.loginExpiration")); } }; const connectSuccessHandler = () => { updateConnectState("success"); console.log("connect success..."); }; const kickHandler = () => tryOut(t("toast.accountKicked")); const expiredHandler = () => tryOut(t("toast.loginExpiration")); const tryOut = (msg: string) => feedbackToast({ msg, error: msg, onClose: () => { userLogout(true); }, }); // sync const syncStartHandler = ({ data }: WSEvent) => { updateSyncState("loading"); updateReinstallState(data); }; const syncProgressHandler = ({ data }: WSEvent) => { updateProgressState(data); }; const syncFinishHandler = () => { updateSyncState("success"); getFriendListByReq(); getGroupListByReq(); getConversationListByReq(false); getUnReadCountByReq(); }; const syncFailedHandler = () => { updateSyncState("failed"); feedbackToast({ msg: t("toast.syncFailed"), error: t("toast.syncFailed") }); }; // message const newMessageHandler = ({ data }: WSEvent) => { if (useUserStore.getState().syncState === "loading" || resume.current) { return; } data.map((message) => handleNewMessage(message)); }; const revokedMessageHandler = ({ data }: WSEvent) => { updateOneMessage({ clientMsgID: data.clientMsgID, contentType: MessageType.RevokeMessage, notificationElem: { detail: JSON.stringify(data), }, } as MessageItem); }; const notPushType = [MessageType.TypingMessage, MessageType.RevokeMessage]; const handleNewMessage = (newServerMsg: MessageItem) => { if (newServerMsg.contentType === MessageType.CustomMessage) { const customData = JSON.parse(newServerMsg.customElem!.data); if ( CustomType.CallingInvite <= customData.customType && customData.customType <= CustomType.CallingHungup ) { return; } } if (!inCurrentConversation(newServerMsg)) return; if (!notPushType.includes(newServerMsg.contentType)) { pushNewMessage(newServerMsg); } }; const inCurrentConversation = (newServerMsg: MessageItem) => { switch (newServerMsg.sessionType) { case SessionType.Single: return ( newServerMsg.sendID === useConversationStore.getState().currentConversation?.userID || (newServerMsg.sendID === useUserStore.getState().selfInfo.userID && newServerMsg.recvID === useConversationStore.getState().currentConversation?.userID) ); case SessionType.Group: case SessionType.WorkingGroup: return ( newServerMsg.groupID === useConversationStore.getState().currentConversation?.groupID ); case SessionType.Notification: return ( newServerMsg.sendID === useConversationStore.getState().currentConversation?.userID ); default: return false; } }; // conversation const conversationChnageHandler = ({ data }: WSEvent) => { updateConversationList(data, "filter"); }; const newConversationHandler = ({ data }: WSEvent) => { updateConversationList(data, "push"); }; const totalUnreadChangeHandler = ({ data }: WSEvent) => { if (data === useConversationStore.getState().unReadCount) return; updateUnReadCount(data); }; // friend const friednInfoChangeHandler = ({ data }: WSEvent) => { updateFriend(data); }; const friednAddedHandler = ({ data }: WSEvent) => { pushNewFriend(data); }; const friednDeletedHandler = ({ data }: WSEvent) => { updateFriend(data, true); }; // blacklist const blackAddedHandler = ({ data }: WSEvent) => { pushNewBlack(data); }; const blackDeletedHandler = ({ data }: WSEvent) => { IMSDK.getSpecifiedFriendsInfo({ friendUserIDList: [data.userID], }).then(({ data }) => { if (data.length) { pushNewFriend(data[0]); } }); updateBlack(data, true); }; // group const joinedGroupAddedHandler = ({ data }: WSEvent) => { if (data.groupID === useConversationStore.getState().currentConversation?.groupID) { updateCurrentGroupInfo(data); getCurrentMemberInGroupByReq(data.groupID); } pushNewGroup(data); }; const joinedGroupDeletedHandler = ({ data }: WSEvent) => { if (data.groupID === useConversationStore.getState().currentConversation?.groupID) { getCurrentGroupInfoByReq(data.groupID); setCurrentMemberInGroup(); } updateGroup(data, true); }; const joinedGroupDismissHandler = ({ data }: WSEvent) => { if (data.groupID === useConversationStore.getState().currentConversation?.groupID) { getCurrentMemberInGroupByReq(data.groupID); } }; const groupInfoChangedHandler = ({ data }: WSEvent) => { updateGroup(data); if (data.groupID === useConversationStore.getState().currentConversation?.groupID) { updateCurrentGroupInfo(data); } }; const groupMemberAddedHandler = ({ data }: WSEvent) => { if ( data.groupID === useConversationStore.getState().currentConversation?.groupID && data.userID === useUserStore.getState().selfInfo.userID ) { getCurrentMemberInGroupByReq(data.groupID); } }; const groupMemberDeletedHandler = ({ data }: WSEvent) => { if ( data.groupID === useConversationStore.getState().currentConversation?.groupID && data.userID === useUserStore.getState().selfInfo.userID ) { getCurrentMemberInGroupByReq(data.groupID); } }; const groupMemberInfoChangedHandler = ({ data }: WSEvent) => { if (data.groupID === useConversationStore.getState().currentConversation?.groupID) { tryUpdateCurrentMemberInGroup(data); } }; //application const friendApplicationProcessedHandler = ({ data, }: WSEvent) => { const isRecv = data.toUserID === useUserStore.getState().selfInfo.userID; if (isRecv) { updateRecvFriendApplication(data); } else { updateSendFriendApplication(data); } }; const groupApplicationProcessedHandler = ({ data, }: WSEvent) => { const isRecv = data.userID !== useUserStore.getState().selfInfo.userID; if (isRecv) { updateRecvGroupApplication(data); } else { updateSendGroupApplication(data); } }; const disposeIMListener = () => { IMSDK.off(CbEvents.OnSelfInfoUpdated, selfUpdateHandler); IMSDK.off(CbEvents.OnConnecting, connectingHandler); IMSDK.off(CbEvents.OnConnectFailed, connectFailedHandler); IMSDK.off(CbEvents.OnConnectSuccess, connectSuccessHandler); IMSDK.off(CbEvents.OnKickedOffline, kickHandler); IMSDK.off(CbEvents.OnUserTokenExpired, expiredHandler); IMSDK.off(CbEvents.OnUserTokenInvalid, expiredHandler); // sync IMSDK.off(CbEvents.OnSyncServerStart, syncStartHandler); IMSDK.off(CbEvents.OnSyncServerProgress, syncProgressHandler); IMSDK.off(CbEvents.OnSyncServerFinish, syncFinishHandler); IMSDK.off(CbEvents.OnSyncServerFailed, syncFailedHandler); // message IMSDK.off(CbEvents.OnRecvNewMessages, newMessageHandler); // conversation IMSDK.off(CbEvents.OnConversationChanged, conversationChnageHandler); IMSDK.off(CbEvents.OnNewConversation, newConversationHandler); IMSDK.off(CbEvents.OnTotalUnreadMessageCountChanged, totalUnreadChangeHandler); // friend IMSDK.off(CbEvents.OnFriendInfoChanged, friednInfoChangeHandler); IMSDK.off(CbEvents.OnFriendAdded, friednAddedHandler); IMSDK.off(CbEvents.OnFriendDeleted, friednDeletedHandler); // blacklist IMSDK.off(CbEvents.OnBlackAdded, blackAddedHandler); IMSDK.off(CbEvents.OnBlackDeleted, blackDeletedHandler); // group IMSDK.off(CbEvents.OnJoinedGroupAdded, joinedGroupAddedHandler); IMSDK.off(CbEvents.OnJoinedGroupDeleted, joinedGroupDeletedHandler); IMSDK.off(CbEvents.OnGroupDismissed, joinedGroupDismissHandler); IMSDK.off(CbEvents.OnGroupInfoChanged, groupInfoChangedHandler); IMSDK.off(CbEvents.OnGroupMemberAdded, groupMemberAddedHandler); IMSDK.off(CbEvents.OnGroupMemberDeleted, groupMemberDeletedHandler); IMSDK.off(CbEvents.OnGroupMemberInfoChanged, groupMemberInfoChangedHandler); // application IMSDK.off(CbEvents.OnFriendApplicationAdded, friendApplicationProcessedHandler); IMSDK.off(CbEvents.OnFriendApplicationAccepted, friendApplicationProcessedHandler); IMSDK.off(CbEvents.OnFriendApplicationRejected, friendApplicationProcessedHandler); IMSDK.off(CbEvents.OnGroupApplicationAdded, groupApplicationProcessedHandler); IMSDK.off(CbEvents.OnGroupApplicationAccepted, groupApplicationProcessedHandler); IMSDK.off(CbEvents.OnGroupApplicationRejected, groupApplicationProcessedHandler); }; const setIpcListener = () => { window.electronAPI?.subscribe("appResume", () => { if (resume.current) { return; } resume.current = true; setTimeout(() => { resume.current = false; }, 5000); }); }; }