zhejiushizhuce 2 роки тому
батько
коміт
8dcb822d96

+ 27 - 6
src/App.js

@@ -41,7 +41,15 @@ import createCache from '@emotion/cache';
 import {BrowserRouter, HashRouter, Route, Routes, useLocation, useNavigate} from 'react-router-dom';
 import {ToastContainer} from 'react-toastify';
 import Layout from "@layout/Layout";
-import {getBFP, getFetchStatus, getHallServerUrl, getUserID, getUserInfo, isLogined} from '@features/mainSlice';
+import {
+    getBFP,
+    getFetchStatus,
+    getHallServerUrl, getKickState,
+    getUserID,
+    getUserInfo,
+    isLogined,
+    updateCurrGame
+} from '@features/mainSlice';
 import {useDispatch, useSelector} from "react-redux";
 import {REQ_STATUS} from "@api/config";
 import {
@@ -56,7 +64,7 @@ import {
 import LoadingScreen from "@components/LoadingScreen";
 import DropCoins from "@components/DropCoins";
 import {reqPayConfig} from "@features/paySlice";
-import {connectHall, disconnectHall} from "@features/actions/hallClient";
+import {connectHall, disconnectHall, hallSendState} from "@features/actions/hallClient";
 import {toast} from "react-toastify";
 import {useBlocker} from "react-router";
 import FontFaceObserver from 'fontfaceobserver';
@@ -86,7 +94,8 @@ const App = () => {
     const plugins = direction === 'rtl' ? [rtlPlugin] : [];
     const hallServerUrl=useSelector(getHallServerUrl);
     useGlobalClick();
-    const prevLocation=usePreviousRoute();
+    const {preLocation,gameID}=usePreviousRoute();
+    const serverKick=useSelector(getKickState);
     const muiTheme = createTheme({
         direction: direction,
     });
@@ -237,8 +246,8 @@ const App = () => {
         checkOpenCheckin();
     },[turnplate]);
     useEffect(()=>{
-        if (prevLocation){
-            let pathname=prevLocation.pathname;
+        if (preLocation){
+            let pathname=preLocation.pathname;
             if (pathname){
                 if (pathname.startsWith(ROUTE_PATH.GAME)){
                     //更新金币
@@ -246,7 +255,19 @@ const App = () => {
                 }
             }
         }
-    },[prevLocation])
+    },[preLocation,gameID])
+    useEffect(()=>{
+        dispatch(updateCurrGame(gameID))
+        dispatch(hallSendState());
+    },[gameID])
+    useEffect(()=>{
+        console.log("serverKick___________"+serverKick)
+        if (serverKick===1){
+            if (pathname.startsWith(ROUTE_PATH.GAME)){
+                navigate("");
+            }
+        }
+    },serverKick)
 
     const renderLayout=()=>{
         return (

+ 30 - 0
src/features/actions/hallClient.js

@@ -3,9 +3,13 @@ import {connectServer, disconnectServer, onDisconnect, sendToServer} from "@feat
 import {reqGameInfo} from "@features/api";
 import {updatePayFinish} from "@features/paySlice";
 import {trackEvent} from "../../tracking/TrackAll";
+import {toast} from "react-toastify";
+import {useLocation} from "react-router-dom";
+import {updateServerKick} from "@features/mainSlice";
 
 const roomName=APP_SERVER.ROOM_HALL;
 const serverUrl=APP_SERVER.SERVER_URL;
+const i18n=global.i18n;
 //信息处理
 const __playground_message_types=(message,dispatch)=>{
 
@@ -46,6 +50,18 @@ const roger=(message,dispatch)=>{
                 }
                 break;
             }
+            //踢
+            case "kick":{
+                // send("operate",{cmd:"kick",data:{reason:"hall.other_online"}});
+                if(!!message.data){
+                    let {data}=message;
+                    let reason=data.reason;
+                    if (reason!=null){
+                        toast.error(i18n.t(reason));
+                    }
+                }
+                dispatch(updateServerKick(1));
+            }
         }
     }
 }
@@ -61,7 +77,12 @@ const messageHandler={
 const onHallConnect=()=>{
     return (dispatch, getState) => {
         dispatch(hallSendReg());
+        dispatch(hallSendState());
+        // dispatch(hallSendState(0));
         // dispatch(hallSendChat("123456"));
+        // setInterval(()=>{
+        //     dispatch(hallSendChat("test"));
+        // },1000);
     }
 }
 const send=(type,message,dispatch)=>{
@@ -93,6 +114,7 @@ export const disconnectHall=()=>{
 }
 export const hallSendReg=()=>{
     return (dispatch, getState) => {
+        console.log("login user");
         let main=getState().main;
         let userInfo=main.userInfo;
         let {UserID,GlobalUID,FaceID,NickName}=userInfo;
@@ -104,3 +126,11 @@ export const hallSendChat=(message)=>{
         send("chat",message,dispatch);
     }
 }
+export const hallSendState=()=>{
+    return (dispatch, getState) => {
+        let main=getState().main;
+        let gameID=main.gameID;
+        let message={in_game:gameID};
+        send("state",message,dispatch);
+    }
+}

+ 52 - 8
src/features/colyseus/CSClient.js

@@ -1,13 +1,26 @@
 import { Client as ColyseusClient, Room } from "colyseus.js";
 class CSClient {
-    constructor(roomName, serverUrl,messageCB) {
+    constructor(roomName, serverUrl,messageCB,connectedCB,closeCB) {
         this.roomName=roomName;
         this.serverUrl=serverUrl;
         this.messageCB=messageCB;
+        this.connectedCB=connectedCB;
+        this.closeCB=closeCB;
         this.client=new ColyseusClient(serverUrl);
         this.callbacks=[];
+        this.retryTimer=null;
+        this.retryTimeout=1000;
+        this.maxRetry=15;
+        this.currRetry=0;
+        this.isKicked=false;
         this.unsetRoom();
     }
+    clearTimer(){
+        if (this.retryTimer!=null){
+            clearTimeout(this.retryTimer);
+            this.retryTimer = null;
+        }
+    }
     unsetRoom(){
         console.log("unsetRoomunsetRoom");
         if(this.currentRoom){
@@ -17,22 +30,51 @@ class CSClient {
     }
     setRoom(room){
         this.currentRoom=room;
+        this.currRetry=0;
         let self=this;
-        // room.connection.ws.addEventListener("close",()=>{
-        //     self.unsetRoom();
-        // });
+        room.connection.transport.ws.addEventListener("close",()=>{
+            console.log("connection closed");
+            if (!self.isKicked)self.reconnect();
+        });
         room.onStateChange((newState) => {
-            console.log(self.roomName, "has new state:", newState.mySynchronizedProperty);
+            // console.log(self.roomName, "has new state:", newState.mySynchronizedProperty);
             // skip unregistered (null) callbacks
             self.callbacks.filter((_) => _).forEach((callback) => callback(newState));
         });
         room.onMessage("*",(type,message)=>{
-            console.log("Room:"+self.roomName+" onMessage:"+" type:"+type+" message:"+JSON.stringify(message))
+            //被踢了
+            if (message!=null&&message.cmd==="kick"){
+                self.isKicked=true;
+            }
+            // console.log("Room:"+self.roomName+" onMessage:"+" type:"+type+" message:"+JSON.stringify(message))
             if (self.messageCB)self.messageCB(type,message);
         })
+        room.onError((code, message) => {
+            console.log("couldn't join", room.name,code,message);
+        });
 
         // when leaving, reset the connection state indicator
-        room.onLeave(self.unsetRoom);
+        room.onLeave((e)=>{
+            self.unsetRoom();
+        });
+        if (this.connectedCB)this.connectedCB(true);
+    }
+    async reconnect(resolve){
+        let during=this.retryTimeout+this.currRetry*2000;
+        this.clearTimer();
+        if (this.currRetry>=this.maxRetry){
+            if (resolve)resolve(false);
+            this.currRetry=0;
+            if (this.closeCB)this.closeCB();
+            return;
+        }
+        let self=this;
+        this.retryTimer=setTimeout(()=>{
+            self.currRetry++;
+            self.connect({}).then((data)=>{
+                if (resolve)resolve(data);
+            })
+        },during);
     }
     async connect(options={}){
         let self=this;
@@ -42,7 +84,8 @@ class CSClient {
                 self.setRoom(room);
                 resolve(true);
             }).catch((e)=>{
-                resolve(false);
+                // resolve(false);
+                self.reconnect(resolve);
             })
         });
     }
@@ -63,6 +106,7 @@ class CSClient {
     }
     send(type,message){
         if (this.currentRoom){
+            console.log("send:",type,message)
             this.currentRoom.send(type,message);
         }
     }

+ 2 - 2
src/features/colyseus/CSClientWrap.js

@@ -4,9 +4,9 @@ class CSClientWrap{
     constructor() {
         this.clients={};
     }
-    async connect(roomName, serverUrl,messageCB=null,options={}){
+    async connect(roomName, serverUrl,messageCB=null,connectedCB=null,closeCB=null,options={}){
         this.disconnect(roomName);
-        let client=new CSClient(roomName,serverUrl,messageCB);
+        let client=new CSClient(roomName,serverUrl,messageCB,connectedCB,closeCB);
         this.clients[roomName]=client;
         let isConnected=await client.connect(options);
         return isConnected;

+ 13 - 2
src/features/mainSlice.js

@@ -412,7 +412,9 @@ export const Main=createSlice({
         customServiceStatus:REQ_STATUS.NONE,
         customerInfo:[],
         hallServerUrl:'',
-        favorites:[]
+        favorites:[],
+        gameID:0,
+        serverKick:0,
     },
     reducers: {
         logout:(state, action)=>{
@@ -459,6 +461,12 @@ export const Main=createSlice({
         },
         onSliceChangeUser:(state,action)=>{
             state.favorites=[];
+        },
+        updateCurrGame:(state,action)=>{
+            state.gameID=action.payload;
+        },
+        updateServerKick:(state,action)=>{
+            state.serverKick=action.payload;
         }
     },
     extraReducers: (builder) => {
@@ -479,7 +487,7 @@ export const Main=createSlice({
         buildReqReducer(builder,reqFavoGet,reducerFavoGet,null);
     },
 })
-export const {logout,updateUserInfo,updateUserScore,updateAddScore,updateGameLike} = Main.actions;
+export const {logout,updateUserInfo,updateUserScore,updateAddScore,updateGameLike,updateCurrGame,updateServerKick} = Main.actions;
 //数据获取
 export const getFetchStatus=(state)=>{
     return state.main.status;
@@ -642,6 +650,9 @@ export const getGameLike=(id)=>(state)=>{
     if (favorites.includes(id))return 1;
     return 0;
 }
+export const getKickState=(state)=>{
+    return state.main.serverKick;
+}
 //数据获取
 export default Main.reducer;
 

+ 15 - 5
src/features/socketSlice.js

@@ -39,20 +39,30 @@ export const Socket=createSlice({
     },
 })
 export const {onConnect,onDisconnect,onSend,onMessage} = Socket.actions;
-
+export const getHallConnState=(state)=>{
+    let isConnected=false;
+    let clients=state.socket.clients;
+    if (clients!=null){
+        let hall=clients[APP_SERVER.ROOM_HALL];
+        if (hall!=null)return hall.isConnected;
+    }
+    return isConnected;
+}
 export default Socket.reducer;
 
 export const connectServer=({roomName, serverUrl,messageCB=null,onRoomConnect=null,options={}})=>{
     return async (dispatch, getState) => {
-        if (CSClientWrap.isConnected())return ;
+        if (CSClientWrap.isConnected(roomName))return ;
         let isConnected=await CSClientWrap.connect(roomName,serverUrl,(type,message)=>{
+            console.log(message);
             dispatch(onMessage({roomName,type,message}));
             if (messageCB!=null)dispatch(messageCB(type,message));
-        });
-        if(isConnected){
+        },(connected)=>{
             dispatch(onConnect(roomName));
             if (onRoomConnect!=null)dispatch(onRoomConnect());
-        }
+        },()=>{
+            dispatch(onDisconnect(roomName));
+        });
     }
 }
 export const disconnectServer=(roomName)=>{

+ 20 - 1
src/hooks/usePreviousRoute.js

@@ -1,17 +1,36 @@
 import {useLocation} from 'react-router-dom';
 import {useEffect, useRef, useState} from 'react';
 import {toast} from "react-toastify";
+import {ROUTE_PATH} from "@constants/routes";
 const usePreviousRoute = () => {
     const location = useLocation();
     const [preLocation, setPreLocation] = useState({});
     // const prevLocation = useRef(null);
     // const currentLocation = useRef(null);
     const [currentLocation, setCurrentLocation] = useState({});
+    const [gameID, setGameID] = useState(0);
+    const parseGameID = ()=>{
+        let pathname=location.pathname;
+        let gid=0;
+        if (pathname.startsWith(ROUTE_PATH.GAME)){
+            let path="";
+            let temp=pathname.split("?");
+            path=temp.shift();
+            temp=path.split("/");
+            path=temp.pop();
+            gid=Number(path);
+        }
+        setGameID(gid);
+    }
     useEffect(() => {
             setPreLocation({...currentLocation})
             setCurrentLocation({...location});
+            parseGameID();
         }, [location]);
-    return preLocation;
+    return {
+        preLocation,
+        gameID
+    };
 }
 
 export default usePreviousRoute

+ 3 - 0
src/locales/languages/en_US.json

@@ -572,6 +572,9 @@
     "last_get": "Next Bonus in:",
     "get_success": "Successfully received"
   },
+  "hall": {
+    "offline": "You are already online somewhere else and are forced offline here."
+  },
   "web": {
     "activity": {
       "redpack_not_available": "There is no RedPack",

+ 3 - 0
src/locales/languages/es_MX.json

@@ -561,6 +561,9 @@
     "last_get": "Próximo bono a las:",
     "get_success": "Recibido exitosamente"
   },
+  "hall": {
+    "offline": "Ya estabas conectado en otro lugar y te obligaron a desconectarte aquí."
+  },
   "web": {
     "activity": {
       "redpack_not_available": "No hay RedPack",

+ 3 - 0
src/locales/languages/pt_BR.json

@@ -561,6 +561,9 @@
     "last_get": "Próximo Bônus em:",
     "get_success": "Recebido com sucesso"
   },
+  "hall": {
+    "offline": "Você já estava online em outro lugar e foi forçado a ficar offline aqui."
+  },
   "web": {
     "activity": {
       "redpack_not_available": "Não há RedPack",

+ 3 - 0
src/locales/languages/ru_RU.json

@@ -561,6 +561,9 @@
     "last_get": "Следующий бонус в:",
     "get_success": "Получено успешно"
   },
+  "hall": {
+    "offline": "Вы уже были онлайн в другом месте и были вынуждены отключиться здесь."
+  },
   "web": {
     "activity": {
       "redpack_not_available": "Нет RedPack",

+ 3 - 0
src/locales/languages/zh_TW.json

@@ -561,6 +561,9 @@
     "last_get": "下一個獎金時間:",
     "get_success": "領取成功"
   },
+  "hall": {
+    "offline": "您已經在其他地方上線,此處被迫下線。"
+  },
   "web": {
     "activity": {
       "redpack_not_available": "沒有紅包",

+ 11 - 3
src/widgets/WGame/index.jsx

@@ -11,8 +11,9 @@ import {ReactComponent as Circlebg} from '@assets/singlesvg/back/circlebg.svg';
 import {ReactComponent as Circlearrow} from '@assets/singlesvg/back/circlearrow.svg';
 import LoadingScreen from "@components/LoadingScreen";
 import {ROUTE_PATH} from "@constants/routes";
-import {useDispatch} from "react-redux";
+import {useDispatch, useSelector} from "react-redux";
 import {reqGameInfo} from "@features/api";
+import {getHallConnState} from "@features/socketSlice";
 const i18n=global.i18n;
 
 const WGame=()=>{
@@ -22,6 +23,7 @@ const WGame=()=>{
     const [openBox,setOpenBox]=useState(false);
     const [openPrompt,setOpenPrompt]=useState(false);
     const [isGameLoad,setIsGameLoad]=useState(false);
+    const isConnected=useSelector(getHallConnState);
     var gameURL="";
     const navigate=useNavigate();
     const onBack=()=>{
@@ -133,8 +135,14 @@ const WGame=()=>{
     }
     return (
         <div className={styles.container}>
-            {renderGame()}
-            {renderBackBox()}
+            {
+                isConnected?(
+                    <>
+                        {renderGame()}
+                        {renderBackBox()}
+                    </>
+                ):(<></>)
+            }
             {renderLoading()}
         </div>
     )