networking protocol refactor
This commit is contained in:
parent
a97bd301d5
commit
15e7f20f1a
|
@ -21,8 +21,8 @@ func main() {
|
||||||
fmt.Println("Welcome to sshpong!")
|
fmt.Println("Welcome to sshpong!")
|
||||||
fmt.Println("Please enter your username")
|
fmt.Println("Please enter your username")
|
||||||
|
|
||||||
egress := make(chan lobby.LobbyMessage)
|
egress := make(chan []byte)
|
||||||
ingress := make(chan lobby.LobbyMessage)
|
ingress := make(chan []byte)
|
||||||
interrupter := make(chan client.InterrupterMessage, 100)
|
interrupter := make(chan client.InterrupterMessage, 100)
|
||||||
exit := make(chan string)
|
exit := make(chan string)
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// User input handler
|
// User input handler
|
||||||
go func(egress chan lobby.LobbyMessage) {
|
go func() {
|
||||||
buf := make([]byte, 1024)
|
buf := make([]byte, 1024)
|
||||||
for {
|
for {
|
||||||
n, err := os.Stdin.Read(buf)
|
n, err := os.Stdin.Read(buf)
|
||||||
|
@ -51,7 +51,7 @@ func main() {
|
||||||
input := string(buf[:n-1])
|
input := string(buf[:n-1])
|
||||||
args := strings.Fields(input)
|
args := strings.Fields(input)
|
||||||
|
|
||||||
userMessage := lobby.LobbyMessage{}
|
userMessage := []byte{}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case msg := <-interrupter:
|
case msg := <-interrupter:
|
||||||
|
@ -67,20 +67,14 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
egress <- userMessage
|
egress <- userMessage
|
||||||
if userMessage.MessageType == "accept" || userMessage.MessageType == "disconect" {
|
if userMessage[0] == lobby.Accept || userMessage[0] == lobby.Disconnect {
|
||||||
slog.Debug("Closing input handler with accept or disconnect message", slog.Any("message content", userMessage.Message))
|
slog.Debug("Closing input handler with accept or disconnect message")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if userMessage.MessageType == "start_game" {
|
if userMessage[0] == lobby.StartGame {
|
||||||
slog.Debug("closing input handler with start_game message and sending exit signal")
|
slog.Debug("closing input handler with start_game message and sending exit signal")
|
||||||
|
|
||||||
// TODO: This is a wierd one...
|
exit <- msg.Content
|
||||||
sg, ok := userMessage.Message.(lobby.StartGame)
|
|
||||||
if !ok {
|
|
||||||
slog.Debug("Start game interrupt message was improperly formatted... Could be indicative of an error in the HandleinterruptInput method")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
exit <- sg.GameID
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,10 +92,10 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}(egress)
|
}()
|
||||||
|
|
||||||
// Ingress Handler
|
// Ingress Handler
|
||||||
go func(oc chan lobby.LobbyMessage) {
|
go func() {
|
||||||
for {
|
for {
|
||||||
msg := <-ingress
|
msg := <-ingress
|
||||||
|
|
||||||
|
@ -114,47 +108,36 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}(ingress)
|
}()
|
||||||
|
|
||||||
// Network writer
|
// Network writer
|
||||||
go func(userMessages chan lobby.LobbyMessage) {
|
go func() {
|
||||||
for {
|
for {
|
||||||
msg := <-userMessages
|
msg := <-egress
|
||||||
bytes, err := lobby.Marshal(msg)
|
slog.Debug("writing egress message to server", "message", msg)
|
||||||
if err != nil {
|
|
||||||
log.Panic("Malformed proto message", err)
|
_, err = conn.Write(msg)
|
||||||
}
|
|
||||||
_, err = conn.Write(bytes)
|
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
log.Panic("Server disconnected sorry...")
|
log.Panic("Server disconnected, sorry...")
|
||||||
} else if err != nil {
|
|
||||||
log.Panic("Error reading from server connection...")
|
|
||||||
}
|
}
|
||||||
if msg.MessageType == "start_game" || msg.MessageType == "disconnect" {
|
if msg[0] == lobby.StartGame || msg[0] == lobby.Disconnect {
|
||||||
slog.Debug("closing network writer ")
|
slog.Debug("closing network writer ")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}(egress)
|
}()
|
||||||
|
|
||||||
// Network reader
|
// Network reader
|
||||||
go func(serverMessages chan lobby.LobbyMessage) {
|
go func() {
|
||||||
buf := make([]byte, 1024)
|
buf := make([]byte, 1024)
|
||||||
for {
|
for {
|
||||||
n, err := conn.Read(buf)
|
n, err := conn.Read(buf)
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
fmt.Println("disconnected from lobby")
|
log.Panic("disconnected from lobby")
|
||||||
} else if err != nil {
|
|
||||||
log.Panic("Error reading from server connection...", err)
|
|
||||||
}
|
}
|
||||||
|
ingress <- buf[:n]
|
||||||
message, err := lobby.Unmarshal(buf[:n])
|
|
||||||
if err != nil {
|
|
||||||
log.Panic("Error reading message from server", err)
|
|
||||||
}
|
}
|
||||||
serverMessages <- message
|
}()
|
||||||
}
|
|
||||||
}(ingress)
|
|
||||||
|
|
||||||
fmt.Println("Waiting for an exit message")
|
fmt.Println("Waiting for an exit message")
|
||||||
isStartGame := <-exit
|
isStartGame := <-exit
|
||||||
|
@ -179,7 +162,7 @@ func ConnectToLobby(username string) (net.Conn, error) {
|
||||||
return nil, fmt.Errorf("Sorry, failed to connect to server...")
|
return nil, fmt.Errorf("Sorry, failed to connect to server...")
|
||||||
}
|
}
|
||||||
|
|
||||||
loginMsg, err := lobby.Marshal(lobby.LobbyMessage{MessageType: "name", Message: lobby.Name{Name: username}})
|
loginMsg, err := lobby.Marshal(lobby.NameData{Name: username}, lobby.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Sorry bro but your username is wack AF...")
|
return nil, fmt.Errorf("Sorry bro but your username is wack AF...")
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,23 @@ func LobbyListen() {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
go l.HandleLobbyConnection(conn)
|
|
||||||
|
go func() {
|
||||||
|
client, msgOut := l.InitialConnectionHandler(conn)
|
||||||
|
_, err = conn.Write(msgOut)
|
||||||
|
if err != nil {
|
||||||
|
slog.Debug("error writing to new player... disconnecting")
|
||||||
|
msg, err := lobby.Marshal(lobby.DisconnectData{
|
||||||
|
From: client.Username,
|
||||||
|
}, lobby.Disconnect)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("error marshalling disconnect message on player connect")
|
||||||
|
}
|
||||||
|
l.BroadcastToLobby(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
go l.HandleLobbyConnection(client)
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,121 +19,116 @@ var help = fmt.Errorf("use invite <player name> to invite a player\nchat or / to
|
||||||
var red = "\x1b[31m"
|
var red = "\x1b[31m"
|
||||||
var normal = "\033[0m"
|
var normal = "\033[0m"
|
||||||
|
|
||||||
func HandleUserInput(args []string, username string) (lobby.LobbyMessage, error) {
|
func HandleUserInput(args []string, username string) ([]byte, error) {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return lobby.LobbyMessage{}, help
|
return []byte{}, help
|
||||||
}
|
}
|
||||||
switch args[0] {
|
switch args[0] {
|
||||||
case "invite":
|
case "invite":
|
||||||
if args[1] != "" {
|
if args[1] != "" {
|
||||||
return lobby.LobbyMessage{
|
msg, err := lobby.Marshal(lobby.InviteData{From: username, To: args[1]}, lobby.Invite)
|
||||||
MessageType: "invite",
|
if err != nil {
|
||||||
Message: lobby.Invite{From: username, To: args[1]}}, nil
|
slog.Debug("invite message was not properly marshalled", "error", err)
|
||||||
|
}
|
||||||
|
return msg, err
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("Please provide a player to invite ")
|
fmt.Println("Please provide a player to invite ")
|
||||||
}
|
}
|
||||||
case "chat":
|
case "chat":
|
||||||
if args[1] != "" {
|
if args[1] != "" {
|
||||||
return lobby.LobbyMessage{
|
msg, err := lobby.Marshal(lobby.ChatData{
|
||||||
MessageType: "chat",
|
|
||||||
Message: lobby.Chat{
|
|
||||||
From: username,
|
From: username,
|
||||||
Message: args[1],
|
Message: strings.Join(args[1:], " "),
|
||||||
},
|
}, lobby.Chat)
|
||||||
}, nil
|
if err != nil {
|
||||||
|
slog.Debug("chat message was not properly marshalled", "error", err)
|
||||||
|
}
|
||||||
|
return msg, err
|
||||||
}
|
}
|
||||||
case "/":
|
case "/":
|
||||||
if args[1] != "" {
|
if args[1] != "" {
|
||||||
return lobby.LobbyMessage{
|
msg, err := lobby.Marshal(lobby.ChatData{
|
||||||
MessageType: "chat",
|
|
||||||
Message: lobby.Chat{
|
|
||||||
From: username,
|
From: username,
|
||||||
Message: args[1],
|
Message: strings.Join(args[1:], " "),
|
||||||
},
|
}, lobby.Chat)
|
||||||
}, nil
|
if err != nil {
|
||||||
|
slog.Debug("chat slash message was not properly marshalled", "error", err)
|
||||||
|
}
|
||||||
|
return msg, err
|
||||||
}
|
}
|
||||||
case "quit":
|
case "quit":
|
||||||
return lobby.LobbyMessage{}, io.EOF
|
return []byte{}, io.EOF
|
||||||
case "q":
|
case "q":
|
||||||
return lobby.LobbyMessage{}, io.EOF
|
return []byte{}, io.EOF
|
||||||
case "help":
|
case "help":
|
||||||
return lobby.LobbyMessage{}, help
|
return []byte{}, help
|
||||||
case "h":
|
case "h":
|
||||||
return lobby.LobbyMessage{}, help
|
return []byte{}, help
|
||||||
default:
|
default:
|
||||||
if strings.Index(args[0], "/") == 0 {
|
if strings.Index(args[0], "/") == 0 {
|
||||||
return lobby.LobbyMessage{
|
msg, err := lobby.Marshal(lobby.ChatData{
|
||||||
MessageType: "chat",
|
|
||||||
Message: lobby.Chat{
|
|
||||||
From: username,
|
From: username,
|
||||||
Message: args[1],
|
Message: strings.Join(args, " ")[1:],
|
||||||
},
|
}, lobby.Chat)
|
||||||
}, nil
|
if err != nil {
|
||||||
|
slog.Debug("chat slash default message was not properly marshalled", "error", err)
|
||||||
}
|
}
|
||||||
return lobby.LobbyMessage{}, help
|
return msg, err
|
||||||
}
|
}
|
||||||
return lobby.LobbyMessage{}, nil
|
return []byte{}, help
|
||||||
|
}
|
||||||
|
return []byte{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandleInterruptInput(incoming InterrupterMessage, args []string, username string) (lobby.LobbyMessage, error) {
|
func HandleInterruptInput(incoming InterrupterMessage, args []string, username string) ([]byte, error) {
|
||||||
|
|
||||||
switch incoming.InterruptType {
|
switch incoming.InterruptType {
|
||||||
|
// Respond with yes if you accept game
|
||||||
case "invite":
|
case "invite":
|
||||||
if len(args) < 1 {
|
if len(args) < 1 {
|
||||||
return lobby.LobbyMessage{
|
return []byte{}, nil
|
||||||
MessageType: "decline",
|
|
||||||
Message: lobby.Decline{
|
|
||||||
From: username,
|
|
||||||
To: incoming.Content,
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
} else {
|
} else {
|
||||||
if strings.ToLower(args[0]) == "y" || strings.ToLower(args[0]) == "yes" {
|
if strings.ToLower(args[0]) == "y" || strings.ToLower(args[0]) == "yes" {
|
||||||
return lobby.LobbyMessage{MessageType: "accept", Message: lobby.Accept{
|
msg, err := lobby.Marshal(lobby.AcceptData{
|
||||||
From: username,
|
From: username,
|
||||||
To: incoming.Content,
|
To: incoming.Content,
|
||||||
},
|
}, lobby.Accept)
|
||||||
}, nil
|
if err != nil {
|
||||||
|
slog.Debug("accept message was not properly marshalled", "error", err)
|
||||||
|
}
|
||||||
|
return msg, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// // Cancel waiting for invite? we aren't doing this I guess.
|
|
||||||
// case "decline":
|
|
||||||
// return nil,
|
|
||||||
// Disconnect and connect to game
|
// Disconnect and connect to game
|
||||||
case "accepted":
|
case "accepted":
|
||||||
return lobby.LobbyMessage{
|
msg, err := lobby.Marshal(lobby.DisconnectData{
|
||||||
MessageType: "disconnect",
|
|
||||||
Message: lobby.Disconnect{
|
|
||||||
From: incoming.Content,
|
From: incoming.Content,
|
||||||
},
|
}, lobby.Disconnect)
|
||||||
}, nil
|
if err != nil {
|
||||||
|
slog.Debug("disconnect message was not properly marshalled", "error", err)
|
||||||
|
}
|
||||||
|
return msg, err
|
||||||
case "start_game":
|
case "start_game":
|
||||||
return lobby.LobbyMessage{
|
msg, err := lobby.Marshal(lobby.StartGameData{
|
||||||
MessageType: "start_game",
|
To: "",
|
||||||
Message: lobby.StartGame{GameID: incoming.Content},
|
GameID: incoming.Content,
|
||||||
}, nil
|
}, lobby.Chat)
|
||||||
|
if err != nil {
|
||||||
|
slog.Debug("start game message was not properly marshalled", "error", err)
|
||||||
|
}
|
||||||
|
return msg, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return lobby.LobbyMessage{}, fmt.Errorf("received a interrupt message that could not be handled %v", incoming)
|
return []byte{}, fmt.Errorf("received a interrupt message that could not be handled %v", incoming)
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandleServerMessage(message lobby.LobbyMessage) (InterrupterMessage, error) {
|
func HandleServerMessage(msg []byte) (InterrupterMessage, error) {
|
||||||
|
header := msg[0]
|
||||||
|
|
||||||
msg := message.Message
|
switch header {
|
||||||
switch message.MessageType {
|
case lobby.Invite:
|
||||||
case "name":
|
imsg, err := lobby.Unmarshal[lobby.InviteData](msg)
|
||||||
|
if err != nil {
|
||||||
nmsg, ok := msg.(lobby.Name)
|
|
||||||
if !ok {
|
|
||||||
return InterrupterMessage{}, errors.New("Not a properly formatted name message")
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("Current Players\n%s\n", nmsg)
|
|
||||||
case "invite":
|
|
||||||
|
|
||||||
imsg, ok := msg.(lobby.Invite)
|
|
||||||
if !ok {
|
|
||||||
return InterrupterMessage{}, errors.New("Not a propertly formatted invite message")
|
return InterrupterMessage{}, errors.New("Not a propertly formatted invite message")
|
||||||
}
|
}
|
||||||
fmt.Println(imsg.From, "is inviting you to a game\nType y to accept...")
|
fmt.Println(imsg.From, "is inviting you to a game\nType y to accept...")
|
||||||
|
@ -141,17 +136,17 @@ func HandleServerMessage(message lobby.LobbyMessage) (InterrupterMessage, error)
|
||||||
InterruptType: "invite",
|
InterruptType: "invite",
|
||||||
Content: imsg.From,
|
Content: imsg.From,
|
||||||
}, nil
|
}, nil
|
||||||
case "pending_invite":
|
|
||||||
|
|
||||||
pimsg, ok := msg.(lobby.PendingInvite)
|
case lobby.PendingInvite:
|
||||||
if !ok {
|
pimsg, err := lobby.Unmarshal[lobby.PendingInviteData](msg)
|
||||||
|
if err != nil {
|
||||||
return InterrupterMessage{}, errors.New("Not a properly formatted pending invite message")
|
return InterrupterMessage{}, errors.New("Not a properly formatted pending invite message")
|
||||||
}
|
}
|
||||||
fmt.Println("Invite sent to", pimsg.Recipient, "\nWaiting for response...")
|
fmt.Println("Invite sent to", pimsg.Recipient, "\nWaiting for response...")
|
||||||
case "accepted":
|
|
||||||
|
|
||||||
amsg, ok := msg.(lobby.Accepted)
|
case lobby.Accepted:
|
||||||
if !ok {
|
amsg, err := lobby.Unmarshal[lobby.AcceptedData](msg)
|
||||||
|
if err != nil {
|
||||||
return InterrupterMessage{}, errors.New("Not a properly formatted accepted message")
|
return InterrupterMessage{}, errors.New("Not a properly formatted accepted message")
|
||||||
}
|
}
|
||||||
fmt.Println(amsg.Accepter, "accepted your invite.", "Press Enter to connect to game...")
|
fmt.Println(amsg.Accepter, "accepted your invite.", "Press Enter to connect to game...")
|
||||||
|
@ -159,54 +154,60 @@ func HandleServerMessage(message lobby.LobbyMessage) (InterrupterMessage, error)
|
||||||
InterruptType: "start_game",
|
InterruptType: "start_game",
|
||||||
Content: amsg.GameID,
|
Content: amsg.GameID,
|
||||||
}, nil
|
}, nil
|
||||||
case "start_game":
|
|
||||||
|
|
||||||
sgmsg, ok := msg.(lobby.StartGame)
|
case lobby.StartGame:
|
||||||
if !ok {
|
sgmsg, err := lobby.Unmarshal[lobby.StartGameData](msg)
|
||||||
|
if err != nil {
|
||||||
return InterrupterMessage{}, errors.New("Not a properly formatted start game message")
|
return InterrupterMessage{}, errors.New("Not a properly formatted start game message")
|
||||||
}
|
}
|
||||||
return InterrupterMessage{
|
return InterrupterMessage{
|
||||||
InterruptType: "start_game",
|
InterruptType: "start_game",
|
||||||
Content: sgmsg.GameID,
|
Content: sgmsg.GameID,
|
||||||
}, nil
|
}, nil
|
||||||
case "chat":
|
|
||||||
cmsg, ok := msg.(lobby.Chat)
|
case lobby.Chat:
|
||||||
if !ok {
|
cmsg, err := lobby.Unmarshal[lobby.ChatData](msg)
|
||||||
|
if err != nil {
|
||||||
return InterrupterMessage{}, errors.New("Not a properly formatted chat message")
|
return InterrupterMessage{}, errors.New("Not a properly formatted chat message")
|
||||||
}
|
}
|
||||||
fmt.Println(cmsg.From, ":", cmsg.Message)
|
fmt.Println(cmsg.From, ":", cmsg.Message)
|
||||||
case "decline":
|
|
||||||
dmsg, ok := msg.(lobby.Decline)
|
case lobby.Decline:
|
||||||
if !ok {
|
dmsg, err := lobby.Unmarshal[lobby.DeclineData](msg)
|
||||||
|
if err != nil {
|
||||||
return InterrupterMessage{}, errors.New("Not a properly formatted decline message")
|
return InterrupterMessage{}, errors.New("Not a properly formatted decline message")
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(dmsg.From, "declined your game invite")
|
fmt.Println(dmsg.From, "declined your game invite")
|
||||||
case "disconnect":
|
|
||||||
|
|
||||||
dmsg, ok := msg.(lobby.Disconnect)
|
case lobby.Disconnect:
|
||||||
if !ok {
|
dmsg, err := lobby.Unmarshal[lobby.DisconnectData](msg)
|
||||||
|
if err != nil {
|
||||||
return InterrupterMessage{}, errors.New("Not a properly formatted disconnect message")
|
return InterrupterMessage{}, errors.New("Not a properly formatted disconnect message")
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(dmsg.From, "has disconnected")
|
fmt.Println(dmsg.From, "has disconnected")
|
||||||
case "connect":
|
|
||||||
|
|
||||||
cmsg, ok := msg.(lobby.Connect)
|
case lobby.Connect:
|
||||||
if !ok {
|
cmsg, err := lobby.Unmarshal[lobby.ConnectData](msg)
|
||||||
|
if err != nil {
|
||||||
return InterrupterMessage{}, errors.New("Not a properly formated connect message")
|
return InterrupterMessage{}, errors.New("Not a properly formated connect message")
|
||||||
}
|
}
|
||||||
fmt.Println(cmsg.From, "has connected")
|
fmt.Println(cmsg.From, "has connected")
|
||||||
case "pong":
|
|
||||||
fmt.Println("Received pong")
|
case lobby.CurrentlyConnected:
|
||||||
case "error":
|
ccmsg, err := lobby.Unmarshal[lobby.CurrentlyConnectedData](msg)
|
||||||
em, ok := msg.(lobby.Error)
|
if err != nil {
|
||||||
if !ok {
|
return InterrupterMessage{}, errors.New("Not a properly formated connect message")
|
||||||
slog.Debug("Received an indecipherable error message...", slog.Any("msg", msg))
|
}
|
||||||
|
fmt.Printf("Current Players\n%s\n", ccmsg.Players)
|
||||||
|
|
||||||
|
case lobby.Error:
|
||||||
|
em, err := lobby.Unmarshal[lobby.ErrorData](msg)
|
||||||
|
if err != nil {
|
||||||
|
slog.Debug("Received an indecipherable error message...", slog.Any("msg", msg[1:]))
|
||||||
}
|
}
|
||||||
fmt.Println(red, em.Message, normal)
|
fmt.Println(red, em.Message, normal)
|
||||||
default:
|
|
||||||
fmt.Println("Received", message.MessageType, message.Message)
|
|
||||||
}
|
}
|
||||||
return InterrupterMessage{}, nil
|
return InterrupterMessage{}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package lobby
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"log"
|
"log"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net"
|
"net"
|
||||||
|
@ -24,7 +23,7 @@ type Client struct {
|
||||||
type ExternalMessage struct {
|
type ExternalMessage struct {
|
||||||
From string
|
From string
|
||||||
Target string
|
Target string
|
||||||
Message LobbyMessage
|
Message []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateLobby() *Lobby {
|
func CreateLobby() *Lobby {
|
||||||
|
@ -52,13 +51,7 @@ func CreateLobby() *Lobby {
|
||||||
slog.Debug("Item that was not a client found in the lobby map...", slog.Any("key", msg.From))
|
slog.Debug("Item that was not a client found in the lobby map...", slog.Any("key", msg.From))
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
em := LobbyMessage{
|
b, err := Marshal(ErrorData{Message: fmt.Sprintf("Sorry player %s is not available...", msg.Target)}, Error)
|
||||||
MessageType: "error",
|
|
||||||
Message: Error{
|
|
||||||
Message: fmt.Sprintf("Sorry, player %s is not available...", msg.Target),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
b, err := Marshal(em)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Debug("Could not marshall error message for missing player", slog.Any("error", err))
|
slog.Debug("Could not marshall error message for missing player", slog.Any("error", err))
|
||||||
}
|
}
|
||||||
|
@ -68,16 +61,12 @@ func CreateLobby() *Lobby {
|
||||||
}
|
}
|
||||||
c, ok := tc.(Client)
|
c, ok := tc.(Client)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
||||||
slog.Debug("Item that was not a client found in the lobby map...", slog.Any("key", msg.From))
|
slog.Debug("Item that was not a client found in the lobby map...", slog.Any("key", msg.From))
|
||||||
|
lm.Delete(msg.Target)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
b, err := Marshal(msg.Message)
|
c.Conn.Write(msg.Message)
|
||||||
if err != nil {
|
|
||||||
slog.Debug("Could not marshal external message...", slog.Any("error", err))
|
|
||||||
}
|
|
||||||
c.Conn.Write(b)
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -86,33 +75,33 @@ func CreateLobby() *Lobby {
|
||||||
return &l
|
return &l
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Lobby) HandleLobbyConnection(conn net.Conn) {
|
func (l *Lobby) HandleLobbyConnection(client Client) {
|
||||||
messageBytes := make([]byte, 4096)
|
messageBytes := make([]byte, 4096)
|
||||||
|
|
||||||
ingress := make(chan LobbyMessage)
|
ingress := make(chan []byte)
|
||||||
egress := make(chan LobbyMessage)
|
egress := make(chan []byte)
|
||||||
|
|
||||||
// Network Reader
|
// Network Reader
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
n, err := conn.Read(messageBytes)
|
n, err := client.Conn.Read(messageBytes)
|
||||||
if err == io.EOF {
|
|
||||||
conn.Close()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
conn.Close()
|
client.Conn.Close()
|
||||||
log.Printf("Error reading message %v", err)
|
log.Printf("Error reading message %v", err)
|
||||||
|
l.lobbyMembers.Delete(client.Username)
|
||||||
|
|
||||||
|
// Server receives a disconnect message of the user
|
||||||
|
msg, err := Marshal(DisconnectData{
|
||||||
|
From: client.Username,
|
||||||
|
}, Disconnect)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("error marshalling responsive disconnect of EOF error", "error", err)
|
||||||
|
} else {
|
||||||
|
ingress <- msg
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
ingress <- messageBytes[:n]
|
||||||
message := LobbyMessage{}
|
|
||||||
|
|
||||||
message, err = Unmarshal(messageBytes[:n])
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Invalid message received from client", err)
|
|
||||||
}
|
|
||||||
ingress <- message
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -120,21 +109,21 @@ func (l *Lobby) HandleLobbyConnection(conn net.Conn) {
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
msg := <-egress
|
msg := <-egress
|
||||||
bytes, err := Marshal(msg)
|
_, err := client.Conn.Write(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error marshalling message to send to user...", err)
|
client.Conn.Close()
|
||||||
}
|
|
||||||
_, err = conn.Write(bytes)
|
|
||||||
if err == io.EOF {
|
|
||||||
conn.Close()
|
|
||||||
log.Println("User has disconnected", err)
|
|
||||||
|
|
||||||
// TODO: write message for disconnect to everyone?
|
l.lobbyMembers.Delete(client.Username)
|
||||||
slog.Debug("Sending bad disconnect message")
|
|
||||||
ingress <- LobbyMessage{MessageType: "disconnect", Message: Disconnect{}}
|
// Server receives a disconnect message of the user
|
||||||
}
|
msg, err := Marshal(DisconnectData{
|
||||||
|
From: client.Username,
|
||||||
|
}, Disconnect)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error writing to user...", err)
|
slog.Error("error marshalling responsive disconnect of EOF error", "error", err)
|
||||||
|
} else {
|
||||||
|
ingress <- msg
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -143,139 +132,158 @@ func (l *Lobby) HandleLobbyConnection(conn net.Conn) {
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
msg := <-ingress
|
msg := <-ingress
|
||||||
serverMsg, err := l.handleClientLobbyMessage(&msg, conn)
|
slog.Debug("Received an ingress message", "message", msg)
|
||||||
|
|
||||||
|
resMsg, err := l.handleClientLobbyMessage(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error handling client lobby message...", err)
|
resMsg, err = Marshal(ErrorData{
|
||||||
|
Message: err.Error(),
|
||||||
|
}, Error)
|
||||||
}
|
}
|
||||||
if serverMsg.MessageType != "" {
|
if len(resMsg) > 0 {
|
||||||
egress <- serverMsg
|
egress <- resMsg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a bool of whether the player has disconnected from the lobby and an error
|
func (l *Lobby) handleClientLobbyMessage(msg []byte) ([]byte, error) {
|
||||||
func (l *Lobby) handleClientLobbyMessage(message *LobbyMessage, conn net.Conn) (LobbyMessage, error) {
|
header := msg[0]
|
||||||
switch message.MessageType {
|
|
||||||
// Handle an name/login message from a player
|
switch header {
|
||||||
// Store the new player in the l.lobbyMembers
|
case Chat:
|
||||||
// Send a connection message for each of the l.lobbyMembers to the new player
|
l.BroadcastToLobby(msg)
|
||||||
// Send a connection message to all members in the lobby
|
return []byte{}, nil
|
||||||
case "name":
|
case Invite:
|
||||||
_, ok := l.lobbyMembers.Load(message.Message)
|
i, err := Unmarshal[InviteData](msg)
|
||||||
if ok {
|
if err != nil {
|
||||||
return LobbyMessage{MessageType: "error", Message: Error{Message: "Sorry, that name is already taken, please try a different name"}}, nil
|
slog.Debug("error unmarshalling invite message", "error", err)
|
||||||
|
return []byte{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
nm, ok := message.Message.(Name)
|
msg, err := Marshal(InviteData{
|
||||||
if !ok {
|
From: i.From,
|
||||||
return LobbyMessage{MessageType: "error", Message: Error{Message: "Sorry the message value and type were not matching for name"}}, nil
|
To: i.To,
|
||||||
|
}, Invite)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("error marshalling invite data...", "error", err)
|
||||||
|
return []byte{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
l.lobbyMembers.Store(nm.Name, Client{Username: nm.Name, Conn: conn})
|
|
||||||
|
|
||||||
// Build current lobby list
|
|
||||||
var lobby []string
|
|
||||||
l.lobbyMembers.Range(func(lobbyUsername any, client any) bool {
|
|
||||||
usernameString, _ := lobbyUsername.(string)
|
|
||||||
lobby = append(lobby, usernameString)
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
|
|
||||||
l.broadcastToLobby(LobbyMessage{MessageType: "connect", Message: Name{Name: nm.Name}})
|
|
||||||
|
|
||||||
return LobbyMessage{MessageType: "name", Message: Name{
|
|
||||||
Name: nm.Name,
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
|
|
||||||
// Handle an invite message by sending a message to the target player
|
|
||||||
// Send an invite message to the invitee: message.Content
|
|
||||||
// Send an ack message to the inviter: message.PlayerId
|
|
||||||
case "invite":
|
|
||||||
|
|
||||||
i, ok := message.Message.(Invite)
|
|
||||||
if !ok {
|
|
||||||
return LobbyMessage{MessageType: "error", Message: Error{Message: "Sorry the message value and type were not matching for invite"}}, nil
|
|
||||||
}
|
|
||||||
// TODO: figure out this shit
|
|
||||||
l.ExternalMessageChannel <- ExternalMessage{
|
l.ExternalMessageChannel <- ExternalMessage{
|
||||||
From: i.From,
|
From: i.From,
|
||||||
Target: i.To,
|
Target: i.To,
|
||||||
Message: LobbyMessage{},
|
Message: msg,
|
||||||
}
|
}
|
||||||
|
|
||||||
return LobbyMessage{MessageType: "pending_invite", Message: PendingInvite{
|
return Marshal(PendingInviteData{
|
||||||
Recipient: i.To,
|
Recipient: i.To,
|
||||||
}}, nil
|
}, PendingInvite)
|
||||||
|
|
||||||
// Handle a accept message from a player that was invited
|
// TODO: is pending invite really something that we need?
|
||||||
// Send a game_start message back to the player: message.Content
|
// case PendingInvite:
|
||||||
// Send an accepted message back to the inviter: message.PlayerId
|
// pi, err := Unmarshal[PendingInviteData](msg)
|
||||||
case "accept":
|
// if err != nil {
|
||||||
gameID := uuid.NewString()
|
// slog.Debug("error unmarshalling pending invite message", err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
am, ok := message.Message.(Accept)
|
case Accept:
|
||||||
if !ok {
|
a, err := Unmarshal[AcceptData](msg)
|
||||||
return LobbyMessage{MessageType: "error", Message: Error{Message: "Sorry the message value and type were not matching for accept"}}, nil
|
if err != nil {
|
||||||
|
slog.Debug("error unmarshalling accept message", "error", err)
|
||||||
|
return []byte{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
slog.Debug("incoming accept message", slog.Any("From", am.From), slog.Any("To", am.To))
|
gID := uuid.NewString()
|
||||||
|
|
||||||
|
msg, err := Marshal(AcceptedData{
|
||||||
|
Accepter: a.From,
|
||||||
|
GameID: gID,
|
||||||
|
}, Accepted)
|
||||||
|
|
||||||
l.ExternalMessageChannel <- ExternalMessage{
|
l.ExternalMessageChannel <- ExternalMessage{
|
||||||
Target: am.To,
|
From: a.From,
|
||||||
Message: LobbyMessage{MessageType: "accepted", Message: Accepted{
|
Target: a.To,
|
||||||
Accepter: am.From,
|
Message: msg,
|
||||||
GameID: gameID,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
|
|
||||||
return LobbyMessage{MessageType: "start_game", Message: StartGame{To: am.From, GameID: gameID}}, nil
|
|
||||||
// Handle a chat message from a player with PlayerId
|
|
||||||
case "chat":
|
|
||||||
c, ok := message.Message.(Chat)
|
|
||||||
if !ok {
|
|
||||||
return LobbyMessage{MessageType: "error", Message: Error{Message: "Sorry the message value and type were not matching for chat"}}, nil
|
|
||||||
}
|
}
|
||||||
l.broadcastToLobby(LobbyMessage{MessageType: "text", Message: Chat{
|
|
||||||
From: c.From,
|
|
||||||
Message: c.Message,
|
|
||||||
}})
|
|
||||||
return LobbyMessage{}, nil
|
|
||||||
|
|
||||||
// Handle a quit message from a player that was connected
|
return Marshal(StartGameData{
|
||||||
// broadcast the player quit to the lobby
|
To: a.From,
|
||||||
case "quit":
|
GameID: gID,
|
||||||
q, ok := message.Message.(Disconnect)
|
}, StartGame)
|
||||||
if !ok {
|
|
||||||
return LobbyMessage{MessageType: "error", Message: Error{Message: "Sorry the message value and type were not matching for quit"}}, nil
|
case Accepted:
|
||||||
|
a, err := Unmarshal[AcceptedData](msg)
|
||||||
|
if err != nil {
|
||||||
|
slog.Debug("error unmarshalling accpeted message", "error", err)
|
||||||
|
return []byte{}, err
|
||||||
}
|
}
|
||||||
l.lobbyMembers.Delete(q.From)
|
|
||||||
l.broadcastToLobby(LobbyMessage{MessageType: "disconnect", Message: Disconnect{
|
|
||||||
From: q.From,
|
|
||||||
}})
|
|
||||||
return LobbyMessage{}, nil
|
|
||||||
|
|
||||||
// Ping and pong
|
// TODO: figure out the accepted and start game data situation... To field is a little hard to fill.
|
||||||
case "ping":
|
return Marshal(StartGameData{
|
||||||
return LobbyMessage{MessageType: "pong", Message: "pong"}, nil
|
To: "",
|
||||||
|
GameID: a.GameID,
|
||||||
|
}, StartGame)
|
||||||
|
|
||||||
// Ping and pong
|
// TODO: Like pending invite, I think start game is only a client message
|
||||||
default:
|
// case StartGame:
|
||||||
return LobbyMessage{MessageType: "pong", Message: "pong"}, nil
|
// sg, err := Unmarshal[StartGameData](msg)
|
||||||
|
// if err != nil {
|
||||||
|
// slog.Debug("error unmarshalling start game message", err)
|
||||||
|
// return []byte{}, err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// TODO: Do we even want to support decline responses?
|
||||||
|
// case Decline:
|
||||||
|
// d, err := Unmarshal[DeclineData](msg)
|
||||||
|
// if err != nil {
|
||||||
|
// slog.Debug("error unmarshalling decline message", err)
|
||||||
|
// return []byte{}, err
|
||||||
|
// }
|
||||||
|
|
||||||
|
case Disconnect:
|
||||||
|
d, err := Unmarshal[DisconnectData](msg)
|
||||||
|
if err != nil {
|
||||||
|
slog.Debug("error unmarshalling disconnect message", "error", err)
|
||||||
|
return []byte{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
l.lobbyMembers.Delete(d.From)
|
||||||
|
|
||||||
|
msg, err := Marshal(DisconnectData{
|
||||||
|
From: d.From,
|
||||||
|
}, Disconnect)
|
||||||
|
|
||||||
|
l.BroadcastToLobby(msg)
|
||||||
|
|
||||||
|
// TODO: how do we handle a disconnect for the client's side
|
||||||
|
return []byte{}, nil
|
||||||
|
|
||||||
|
// TODO: This is just a client side message right...?
|
||||||
|
// case Connect:
|
||||||
|
// c, err := Unmarshal[ConnectData](msg)
|
||||||
|
// if err != nil {
|
||||||
|
// slog.Debug("error unmarshalling connect message", err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
// TODO: This is just a client side message right...?
|
||||||
|
// case Error:
|
||||||
|
// e, err := Unmarshal[ErrorData](msg)
|
||||||
|
// if err != nil {
|
||||||
|
// slog.Debug("error unmarshalling error message", err)
|
||||||
|
// return []byte{}, err
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
return []byte{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Lobby) broadcastToLobby(message LobbyMessage) {
|
func (l *Lobby) BroadcastToLobby(bytes []byte) {
|
||||||
var disconnectedUsers []string
|
var disconnectedUsers []string
|
||||||
l.lobbyMembers.Range(func(playerId, player interface{}) bool {
|
l.lobbyMembers.Range(func(playerId, player interface{}) bool {
|
||||||
bytes, err := Marshal(message)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Error marshalling broadcast message", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
client := player.(Client)
|
client := player.(Client)
|
||||||
_, err = client.Conn.Write(bytes)
|
_, err := client.Conn.Write(bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error broadcasting to clients...", err)
|
log.Println("Error broadcasting to clients...", err)
|
||||||
disconnectedUsers = append(disconnectedUsers, playerId.(string))
|
disconnectedUsers = append(disconnectedUsers, playerId.(string))
|
||||||
|
@ -288,3 +296,62 @@ func (l *Lobby) broadcastToLobby(message LobbyMessage) {
|
||||||
l.lobbyMembers.Delete(player)
|
l.lobbyMembers.Delete(player)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func (l *Lobby) InitialConnectionHandler(conn net.Conn) (Client, []byte) {
|
||||||
|
msg := make([]byte, 256)
|
||||||
|
nb, err := conn.Read(msg)
|
||||||
|
if err != nil {
|
||||||
|
slog.Debug("error reading from initial connection")
|
||||||
|
}
|
||||||
|
msg = msg[:nb]
|
||||||
|
n, err := Unmarshal[NameData](msg)
|
||||||
|
if err != nil {
|
||||||
|
slog.Debug("error unmarshalling name message:", "error", err.Error(), "message", msg[1:nb])
|
||||||
|
|
||||||
|
msgOut, err := Marshal(ErrorData{
|
||||||
|
Message: "incorrectly formatted username in name message",
|
||||||
|
}, Error)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("error marshalling error message for incorrectly formatted username")
|
||||||
|
}
|
||||||
|
return Client{}, msgOut
|
||||||
|
}
|
||||||
|
_, ok := l.lobbyMembers.Load(n.Name)
|
||||||
|
if ok {
|
||||||
|
msg, err := Marshal(ErrorData{
|
||||||
|
Message: "Sorry that name is already taken, please try a different name",
|
||||||
|
}, Error)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("error marshalling error on name already taken msg")
|
||||||
|
}
|
||||||
|
return Client{}, msg
|
||||||
|
}
|
||||||
|
h, err := Marshal(ConnectData{
|
||||||
|
From: n.Name,
|
||||||
|
}, Connect)
|
||||||
|
if err != nil {
|
||||||
|
slog.Debug("error marshalling broadcast connect message on player connect", "error", err)
|
||||||
|
return Client{Username: n.Name, Conn: conn}, h
|
||||||
|
}
|
||||||
|
l.BroadcastToLobby(h)
|
||||||
|
|
||||||
|
// Build current lobby list
|
||||||
|
var lobby []string
|
||||||
|
l.lobbyMembers.Range(func(lobbyUsername any, client any) bool {
|
||||||
|
usernameString, _ := lobbyUsername.(string)
|
||||||
|
lobby = append(lobby, usernameString)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
msgOut, err := Marshal(CurrentlyConnectedData{Players: lobby}, CurrentlyConnected)
|
||||||
|
if err != nil {
|
||||||
|
slog.Debug("Error marshalling currectly connected data on player connect")
|
||||||
|
}
|
||||||
|
|
||||||
|
client := Client{
|
||||||
|
Username: n.Name,
|
||||||
|
Conn: conn,
|
||||||
|
}
|
||||||
|
|
||||||
|
l.lobbyMembers.Store(n.Name, client)
|
||||||
|
|
||||||
|
return client, msgOut
|
||||||
|
}
|
||||||
|
|
|
@ -1,244 +1,94 @@
|
||||||
package lobby
|
package lobby
|
||||||
|
|
||||||
import (
|
import "encoding/json"
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
const (
|
||||||
"errors"
|
Name = iota
|
||||||
"log/slog"
|
Chat
|
||||||
"reflect"
|
Invite
|
||||||
"strings"
|
PendingInvite
|
||||||
|
Accept
|
||||||
|
Accepted
|
||||||
|
StartGame
|
||||||
|
Decline
|
||||||
|
Disconnect
|
||||||
|
Connect
|
||||||
|
CurrentlyConnected
|
||||||
|
Error
|
||||||
)
|
)
|
||||||
|
|
||||||
type LobbyMessage struct {
|
type NameData struct {
|
||||||
MessageType string `json:"message_type"`
|
|
||||||
Message any `json:"message"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Name struct {
|
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Chat struct {
|
type ChatData struct {
|
||||||
From string `json:"from"`
|
From string `json:"from"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Invite struct {
|
type InviteData struct {
|
||||||
From string `json:"from"`
|
From string `json:"from"`
|
||||||
To string `json:"to"`
|
To string `json:"to"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PendingInvite struct {
|
type PendingInviteData struct {
|
||||||
Recipient string `json:"recipient"`
|
Recipient string `json:"recipient"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Accept struct {
|
type AcceptData struct {
|
||||||
From string `json:"from"`
|
From string `json:"from"`
|
||||||
To string `json:"to"`
|
To string `json:"to"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Accepted struct {
|
type AcceptedData struct {
|
||||||
Accepter string `json:"accepter"`
|
Accepter string `json:"accepter"`
|
||||||
GameID string `json:"game_id"`
|
GameID string `json:"game_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type StartGame struct {
|
type StartGameData struct {
|
||||||
To string `json:"to"`
|
To string `json:"to"`
|
||||||
GameID string `json:"game_id"`
|
GameID string `json:"game_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Decline struct {
|
type DeclineData struct {
|
||||||
From string `json:"from"`
|
From string `json:"from"`
|
||||||
To string `json:"to"`
|
To string `json:"to"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Disconnect struct {
|
type DisconnectData struct {
|
||||||
From string `json:"from"`
|
From string `json:"from"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Connect struct {
|
type ConnectData struct {
|
||||||
From string `json:"from"`
|
From string `json:"from"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Error struct {
|
type CurrentlyConnectedData struct {
|
||||||
|
Players []string `json:"players"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ErrorData struct {
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func Marshal(a LobbyMessage) ([]byte, error) {
|
func Unmarshal[T NameData | ChatData | InviteData | PendingInviteData | AcceptData | AcceptedData | StartGameData | DeclineData | DisconnectData | ConnectData | CurrentlyConnectedData | ErrorData](msg []byte) (T, error) {
|
||||||
slog.Debug("Marshalling message", slog.Any("message type", a.MessageType))
|
var d T
|
||||||
bm, err := json.Marshal(a.Message)
|
err := json.Unmarshal(msg[1:], &d)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return d, err
|
||||||
}
|
}
|
||||||
|
return d, nil
|
||||||
a.Message = bm
|
|
||||||
return json.Marshal(a)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use this to get the appropriate message type into the message field then assert the
|
func Marshal[T NameData | ChatData | InviteData | PendingInviteData | AcceptData | AcceptedData | StartGameData | DeclineData | DisconnectData | ConnectData | CurrentlyConnectedData | ErrorData](msg T, header int) ([]byte, error) {
|
||||||
// right struct accordingly to safely access the fields you need.
|
mb, err := json.Marshal(msg)
|
||||||
func Unmarshal(b []byte) (LobbyMessage, error) {
|
|
||||||
lm := LobbyMessage{}
|
|
||||||
err := json.Unmarshal(b, &lm)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return lm, err
|
return mb, err
|
||||||
}
|
}
|
||||||
|
|
||||||
smsg, ok := lm.Message.(string)
|
b := []byte{byte(header)}
|
||||||
if !ok {
|
|
||||||
slog.Debug("error asserting message to string")
|
|
||||||
}
|
|
||||||
slog.Debug("type of message", slog.Any("type of message", reflect.TypeOf(smsg)), slog.String("message", smsg))
|
|
||||||
|
|
||||||
jsonBytes, err := base64.StdEncoding.DecodeString(smsg)
|
b = append(b, mb...)
|
||||||
lm.Message = jsonBytes
|
|
||||||
|
|
||||||
switch strings.ToLower(lm.MessageType) {
|
return b, nil
|
||||||
case "name":
|
|
||||||
n := Name{}
|
|
||||||
bs, ok := lm.Message.([]byte)
|
|
||||||
if !ok {
|
|
||||||
return lm, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err := json.Unmarshal(bs, &n)
|
|
||||||
if err != nil {
|
|
||||||
slog.Debug("Error", slog.Any("error", err))
|
|
||||||
return lm, err
|
|
||||||
}
|
|
||||||
lm.Message = n
|
|
||||||
return lm, nil
|
|
||||||
case "chat":
|
|
||||||
c := Chat{}
|
|
||||||
bs, ok := lm.Message.([]byte)
|
|
||||||
if !ok {
|
|
||||||
return lm, err
|
|
||||||
}
|
|
||||||
err := json.Unmarshal(bs, &c)
|
|
||||||
if err != nil {
|
|
||||||
slog.Debug("chat", slog.Any("error", err))
|
|
||||||
return lm, err
|
|
||||||
}
|
|
||||||
lm.Message = c
|
|
||||||
return lm, nil
|
|
||||||
case "invite":
|
|
||||||
i := Invite{}
|
|
||||||
bs, ok := lm.Message.([]byte)
|
|
||||||
if !ok {
|
|
||||||
return lm, err
|
|
||||||
}
|
|
||||||
err := json.Unmarshal(bs, &i)
|
|
||||||
if err != nil {
|
|
||||||
slog.Debug("invite", slog.Any("error", err))
|
|
||||||
return lm, err
|
|
||||||
}
|
|
||||||
lm.Message = i
|
|
||||||
return lm, nil
|
|
||||||
case "pending_invite":
|
|
||||||
pi := PendingInvite{}
|
|
||||||
bs, ok := lm.Message.([]byte)
|
|
||||||
if !ok {
|
|
||||||
return lm, err
|
|
||||||
}
|
|
||||||
err := json.Unmarshal(bs, &pi)
|
|
||||||
if err != nil {
|
|
||||||
slog.Debug("pending_invite", slog.Any("error", err))
|
|
||||||
return lm, err
|
|
||||||
}
|
|
||||||
lm.Message = pi
|
|
||||||
case "accept":
|
|
||||||
a := Accept{}
|
|
||||||
bs, ok := lm.Message.([]byte)
|
|
||||||
if !ok {
|
|
||||||
return lm, err
|
|
||||||
}
|
|
||||||
err := json.Unmarshal(bs, &a)
|
|
||||||
if err != nil {
|
|
||||||
slog.Debug("accept", slog.Any("error", err))
|
|
||||||
return lm, err
|
|
||||||
}
|
|
||||||
lm.Message = a
|
|
||||||
return lm, nil
|
|
||||||
case "accepted":
|
|
||||||
a := Accepted{}
|
|
||||||
bs, ok := lm.Message.([]byte)
|
|
||||||
if !ok {
|
|
||||||
return lm, err
|
|
||||||
}
|
|
||||||
err := json.Unmarshal(bs, &a)
|
|
||||||
if err != nil {
|
|
||||||
slog.Debug("accepted", slog.Any("error", err))
|
|
||||||
return lm, err
|
|
||||||
}
|
|
||||||
lm.Message = a
|
|
||||||
return lm, nil
|
|
||||||
case "start_game":
|
|
||||||
sg := StartGame{}
|
|
||||||
bs, ok := lm.Message.([]byte)
|
|
||||||
if !ok {
|
|
||||||
return lm, err
|
|
||||||
}
|
|
||||||
err := json.Unmarshal(bs, &sg)
|
|
||||||
if err != nil {
|
|
||||||
slog.Debug("start_game", slog.Any("error", err))
|
|
||||||
return lm, err
|
|
||||||
}
|
|
||||||
lm.Message = sg
|
|
||||||
return lm, nil
|
|
||||||
case "decline":
|
|
||||||
d := Decline{}
|
|
||||||
bs, ok := lm.Message.([]byte)
|
|
||||||
if !ok {
|
|
||||||
return lm, err
|
|
||||||
}
|
|
||||||
err := json.Unmarshal(bs, &d)
|
|
||||||
if err != nil {
|
|
||||||
slog.Debug("decline", slog.Any("error", err))
|
|
||||||
return lm, err
|
|
||||||
}
|
|
||||||
lm.Message = d
|
|
||||||
return lm, nil
|
|
||||||
case "disconnect":
|
|
||||||
di := Disconnect{}
|
|
||||||
bs, ok := lm.Message.([]byte)
|
|
||||||
if !ok {
|
|
||||||
return lm, err
|
|
||||||
}
|
|
||||||
err := json.Unmarshal(bs, &di)
|
|
||||||
if err != nil {
|
|
||||||
slog.Debug("disconnect", slog.Any("error", err))
|
|
||||||
return lm, err
|
|
||||||
}
|
|
||||||
lm.Message = di
|
|
||||||
return lm, nil
|
|
||||||
case "connect":
|
|
||||||
co := Connect{}
|
|
||||||
bs, ok := lm.Message.([]byte)
|
|
||||||
if !ok {
|
|
||||||
return lm, err
|
|
||||||
}
|
|
||||||
err := json.Unmarshal(bs, &co)
|
|
||||||
if err != nil {
|
|
||||||
slog.Debug("connect", slog.Any("error", err))
|
|
||||||
return lm, err
|
|
||||||
}
|
|
||||||
lm.Message = co
|
|
||||||
return lm, nil
|
|
||||||
case "error":
|
|
||||||
e := Error{}
|
|
||||||
bs, ok := lm.Message.([]byte)
|
|
||||||
if !ok {
|
|
||||||
return lm, err
|
|
||||||
}
|
|
||||||
err := json.Unmarshal(bs, &e)
|
|
||||||
if err != nil {
|
|
||||||
slog.Debug("error", slog.Any("error", err))
|
|
||||||
return lm, err
|
|
||||||
}
|
|
||||||
lm.Message = e
|
|
||||||
return lm, nil
|
|
||||||
default:
|
|
||||||
return lm, errors.New("unknown message type")
|
|
||||||
}
|
|
||||||
return lm, errors.New("unknown message type")
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user