package serverCommunication import ( "context" "crypto/rand" "math/big" "time" "github.com/gofiber/websocket/v2" "go.mongodb.org/mongo-driver/bson" "krakatoa.net/backend/modules/cache" kraSettingsConfig "krakatoa.net/backend/modules/configs/kraSettingsConfig" "krakatoa.net/backend/modules/kraProtocol" "krakatoa.net/backend/modules/logger" "krakatoa.net/backend/modules/mongo" "krakatoa.net/backend/modules/structs" ) func HandleWebMessage(isVoice bool, conn *websocket.Conn, uuid string, msg []byte) { var err error var raw []byte webClient := getWebClientByConn(conn) if webClient == nil { logger.Web.Debugln("webClient is nil") return } status, cmdID, dest, cmdNumber, args := kraProtocol.DecodeWebMessage(msg) if status == kraProtocol.StatusReply { if isVoice { for _, data := range webClient.VoiceCmdIDsByBackend { if data.WebCmdID == cmdID { // forward to target dest mcClient := GetMinecraftClientByName(getMinecraftServerNameByDest(data.DestFromMinecraftServer)) raw = kraProtocol.EncodeJavaMessage(kraProtocol.StatusReply, data.CmdIDFromMinecraftServer, 0, webClient.Uuid, 0, "") err = mcClient.SendBinaryMessage(raw) if err != nil { logger.Web.Warnln("write:", err) return } // remove cmdID from VoiceCMDIDsByBackend list webClient.RemoveVoiceCmdIDByBackend(cmdID) // remove cmdID from minecraftCmdIDs mcClient.RemoveCmdID(data.CmdIDFromMinecraftServer) return } } if isCmdIDInList(webClient.VoiceCmdIDs, cmdID) { webClient.RemoveVoiceCmdID(cmdID) } } else { for _, data := range webClient.MobileCmdIDsByBackend { if data.WebCmdID == cmdID { // forward to target dest mcClient := GetMinecraftClientByName(getMinecraftServerNameByDest(data.DestFromMinecraftServer)) raw = kraProtocol.EncodeJavaMessage(kraProtocol.StatusReply, data.CmdIDFromMinecraftServer, 0, webClient.Uuid, 0, "") err = mcClient.SendBinaryMessage(raw) if err != nil { logger.Web.Warnln("write:", err) return } // remove cmdID from VoiceCMDIDsByBackend list webClient.RemoveMobileCmdIDByBackend(cmdID) // remove cmdID from minecraftCmdIDs mcClient.RemoveCmdID(data.CmdIDFromMinecraftServer) return } } if isCmdIDInList(webClient.MobileCmdIDs, cmdID) { webClient.RemoveMobileCmdID(cmdID) } } return } // ack if status == kraProtocol.StatusGet { var cmdIDInList bool logger.Web.Println("cmdID", isVoice, webClient.VoiceCmdIDs, webClient.MobileCmdIDs) if isVoice { cmdIDInList = isCmdIDInList(webClient.VoiceCmdIDs, cmdID) } else { cmdIDInList = isCmdIDInList(webClient.MobileCmdIDs, cmdID) } if cmdIDInList { // cmdID already in queue raw = kraProtocol.EncodeWebMessage(kraProtocol.StatusMessageAlreadyInQueue, cmdID, cmdNumber, "") err = webClient.SendBinaryMessage(conn, raw) if err != nil { logger.WebVoice.Warnln("write:", err) } return } // add cmdID to list if isVoice { logger.Web.Debugln("voiceCmdIDs", webClient.VoiceCmdIDs) webClient.VoiceCmdIDs = append(webClient.VoiceCmdIDs, cmdID) logger.Web.Debugln("after voiceCmdIDs", webClient.VoiceCmdIDs) } else { logger.Web.Debugln("MobileCmdIDs", webClient.MobileCmdIDs) webClient.MobileCmdIDs = append(webClient.MobileCmdIDs, cmdID) logger.Web.Debugln("after MobileCmdIDs", webClient.MobileCmdIDs) } } // no ack if dest == kraProtocol.DestProxy || dest == kraProtocol.DestPlayersCurrentServer { // forwarding message to java / minecraft var originDest int if isVoice { originDest = kraProtocol.DestVoice } else { originDest = kraProtocol.DestMobile } err = SendMessageToMinecraftServer(originDest, status, dest, uuid, cmdNumber, args) if err != nil { raw := kraProtocol.EncodeWebMessage(kraProtocol.StatusErrTryAgain, cmdID, cmdNumber, args) webClient.SendBinaryMessage(conn, raw) } return } else { // web if isVoice { // message from voice if dest == kraProtocol.DestMobile { // forwarding message to mobile if webClient.MobileConn != nil { // mobile is connected raw = kraProtocol.EncodeWebMessage(kraProtocol.StatusReply, cmdID, cmdNumber, args) err = webClient.SendBinaryMessage(webClient.MobileConn, raw) if err != nil { logger.WebVoice.Warnln("write:", err) } } else { // mobile not connected raw = kraProtocol.EncodeWebMessage(kraProtocol.StatusSend, 58299, cmdNumber, "") err = webClient.SendBinaryMessage(conn, raw) if err != nil { logger.WebVoice.Warnln("write:", err) } } } else if dest == kraProtocol.DestBackend { resArgs := voiceCommandHandler(cmdNumber, uuid) if status == kraProtocol.StatusGet { logger.Web.Debugln("status get reply") raw = kraProtocol.EncodeWebMessage(kraProtocol.StatusReply, cmdID, cmdNumber, resArgs) err = webClient.SendBinaryMessage(conn, raw) if err != nil { logger.WebVoice.Warnln("write:", err) } } } } else { // message from mobile if dest == kraProtocol.DestVoice { // forwarding message to voice if webClient.VoiceConn != nil { // voice connected raw = kraProtocol.EncodeWebMessage(kraProtocol.StatusSend, cmdID, cmdNumber, args) err = webClient.SendBinaryMessage(webClient.VoiceConn, raw) if err != nil { logger.WebMobile.Warnln("write:", err) } } else { // voice not connected raw = kraProtocol.EncodeWebMessage(kraProtocol.StatusSend, 5456, cmdNumber, "") err = webClient.SendBinaryMessage(conn, raw) if err != nil { logger.WebMobile.Warnln("write:", err) } } } else if dest == kraProtocol.DestBackend { resArgs := mobileCommandHandler(cmdNumber) if status == kraProtocol.StatusGet { raw = kraProtocol.EncodeWebMessage(kraProtocol.StatusReply, cmdID, cmdNumber, resArgs) err = webClient.SendBinaryMessage(conn, raw) if err != nil { logger.WebVoice.Warnln("write:", err) } } } else { // err dest unknown raw = kraProtocol.EncodeWebMessage(kraProtocol.StatusErrTryAgain, cmdID, cmdNumber, "") err = webClient.SendBinaryMessage(conn, raw) if err != nil { logger.WebMobile.Warnln("write:", err) } } } } /* TODO: delete cmdID if ack was answered if webClient != nil { // remove cmdID from list if isVoice { webClient.RemoveVoiceCmdID(cmdID) } else { webClient.RemoveMobileCmdID(cmdID) } /*var newArr []int if isVoice { newArr, err = removeCmdIDFromList(client.VoiceCmdIDs, cmdID) if err != nil { logger.WebVoice.Warnln("removeCmdIDFromList:", err) } else { client.VoiceCmdIDs = newArr } } else { newArr, err = removeCmdIDFromList(client.MobileCmdIDs, cmdID) if err != nil { logger.WebMobile.Warnln("removeCmdIDFromList:", err) } else { client.MobileCmdIDs = newArr } } } */ } func voiceCommandHandler(cmdNumber int, uuid string) (args string) { switch cmdNumber { case 36006: // mobile web code logger.WebMobile.Println("case 36006", uuid) mobileWebCode, err := generateMobileWebCode() if err != nil { logger.WebVoice.Warnln("gen mobileWebCode", err) } filter := bson.D{{"uuid", uuid}} update := bson.D{{"$set", bson.D{{"mobileWebCode", mobileWebCode}}}} _, err = mongo.PlayersCollection.UpdateOne(context.TODO(), filter, update) if err != nil { logger.WebVoice.Println("updRes", err) } return mobileWebCode case 28450: // testing message to mobile time.Sleep(time.Second * 10) return "hello my friend" default: logger.WebVoice.Println("case default", cmdNumber) return "vdefault" } } func mobileCommandHandler(cmdNumber int) (args string) { switch cmdNumber { case 15857: // testing message from voice return "from voice" default: logger.WebMobile.Println("case default", cmdNumber) return "mdefault" } } func generateMobileWebCode() (string, error) { mobileWebCodeLetters := kraSettingsConfig.Cfg.VoiceWebCode.Letters mobileWebCodeLength := kraSettingsConfig.Cfg.VoiceWebCode.Length ret := make([]byte, mobileWebCodeLength) for i := 0; i < mobileWebCodeLength; i++ { num, err := rand.Int(rand.Reader, big.NewInt(int64(len(mobileWebCodeLetters)))) if err != nil { return "", err } ret[i] = mobileWebCodeLetters[num.Int64()] } return string(ret), nil } /* func IsMessageInAckQueue(conn *websocket.Conn, cmdID int) bool { for _, client := range cache.VoiceCmdIDs { if client.CmdID == cmdID && client.Conn == conn { return true } } return false } */ func getWebClientByConn(conn *websocket.Conn) *structs.WebClient { for _, client := range cache.WebClients { if client.VoiceConn == conn || client.MobileConn == conn { return client } } return nil } func GetWebClientOrCreateNewByUuid(uuid string) *structs.WebClient { webClient := GetWebClientByUuid(uuid) if webClient == nil { // add to clients list client := &structs.WebClient{Uuid: uuid} cache.WebClients[uuid] = client logger.Web.Debugln("new client") return client } return webClient } func GetWebClientByUuid(Uuid string) *structs.WebClient { logger.Web.Debugln("len clients", len(cache.WebClients), Uuid) // return client from clients list for uuid, client := range cache.WebClients { if uuid == Uuid { logger.Web.Debugln("return client", client.Uuid) return client } } logger.Web.Debugln("GetWebClientByUuid not found") return nil } // @Deprecated func IsVoiceAndMobileSocketConnected(uuid string) string { webClient := GetWebClientByUuid(uuid) if webClient == nil { return "0" } if webClient.MobileConn == nil && webClient.VoiceConn == nil { return "0" } else { return "1" } } func isCmdIDInList(arr []int, cmdID int) bool { for i := 0; i < len(arr); i++ { if arr[i] == cmdID { return true } } return false }