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 { logger.WebVoice.Debugln("Reply from Web Voice", webClient.SendVoiceQueueMessages) for _, data := range webClient.SendVoiceQueueMessages { if data.CmdID == cmdID { // forward to target dest mcClient := GetMinecraftClientByDest(data.OriginDest) if mcClient == nil { logger.WebVoice.Warnln("mcClient is nil -> given dest", data.OriginDest) continue } logger.WebVoice.Debugln("Forwarding reply from web voice to mc client", mcClient.Name, "cmdID", data.OriginCmdID) raw = kraProtocol.EncodeJavaMessage(kraProtocol.StatusReply, data.OriginCmdID, 0, webClient.Uuid, 0, "") err = mcClient.SendBinaryMessage(raw) if err != nil { logger.Web.Warnln("write:", err) continue } webClient.RemoveMessageFromVoiceSendQueueByCmdID(cmdID) mcClient.RemoveMessageFromReceivedQueueByCmdID(data.OriginCmdID) } } } else { logger.WebMobile.Debugln("Reply from Web Mobile", webClient.SendMobileQueueMessages) for _, data := range webClient.SendMobileQueueMessages { if data.CmdID == cmdID { // forward to target dest mcClient := GetMinecraftClientByDest(data.OriginDest) if mcClient == nil { logger.WebVoice.Warnln("mcClient is nil -> given dest", data.OriginDest) continue } logger.WebMobile.Debugln("Forwarding reply from web mobile to mc client", mcClient.Name, "cmdID", data.OriginCmdID) raw = kraProtocol.EncodeJavaMessage(kraProtocol.StatusReply, data.OriginCmdID, 0, webClient.Uuid, 0, "") err = mcClient.SendBinaryMessage(raw) if err != nil { logger.Web.Warnln("write:", err) return } webClient.RemoveMessageFromMobileSendQueueByCmdID(cmdID) mcClient.RemoveMessageFromReceivedQueueByCmdID(data.OriginCmdID) return } } } return } // ack if status == kraProtocol.StatusGet { var cmdIDInList bool if isVoice { cmdIDInList = webClient.IsCmdIDInReceivedVoiceMessagesQueue(cmdID) } else { cmdIDInList = webClient.IsCmdIDInReceivedMobileMessagesQueue(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 } if isVoice { webClient.AddMessageToVoiceReceivedQueue(kraProtocol.DestVoice, cmdID, raw) } else { webClient.AddMessageToMobileReceivedQueue(kraProtocol.DestMobile, cmdID, raw) } } 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, cmdID, 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) } } } } } 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 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 }