From 7a44092b2ff88ba8683021ef53a07cf8f43f1763 Mon Sep 17 00:00:00 2001
From: Beric Bearnson <beric.bearnson@vasion.com>
Date: Wed, 14 Aug 2024 17:26:51 -0600
Subject: [PATCH] more networking

---
 internal/netwrk/game.go              |  45 ++++++
 internal/netwrk/game_messages.pb.go  |   2 +-
 internal/netwrk/lobby.go             | 113 +++++++++++++++
 internal/netwrk/lobby_messages.pb.go |  28 ++--
 internal/netwrk/netwrk.go            | 203 +--------------------------
 proto/lobby_messages.proto           |   5 +-
 6 files changed, 188 insertions(+), 208 deletions(-)
 create mode 100644 internal/netwrk/game.go
 create mode 100644 internal/netwrk/lobby.go

diff --git a/internal/netwrk/game.go b/internal/netwrk/game.go
new file mode 100644
index 0000000..9e3ec39
--- /dev/null
+++ b/internal/netwrk/game.go
@@ -0,0 +1,45 @@
+package netwrk
+
+import (
+	"log"
+	"net"
+)
+
+func handleGameConnection(conn net.Conn) {
+	defer conn.Close()
+
+	messageBytes := make([]byte, 126)
+
+	n, err := conn.Read(messageBytes)
+	if err != nil {
+		log.Printf("Error reading game ID on connection", err)
+	}
+
+	gameID := string(messageBytes[:n])
+	if err != nil {
+		log.Printf("Game id was not a string?", err)
+	}
+
+	clientChan := make(chan GameMessage)
+
+	n, err = conn.Read(messageBytes)
+	if err != nil {
+		log.Printf("Error reading message %v", err)
+		return
+	}
+
+	gameClients, ok := gameChans.games[gameID]
+	if !ok {
+		newGameClients := GameClients{
+			client1: clientChan,
+			client2: nil,
+		}
+		gameChans.games[gameID] = newGameClients
+	} else {
+		gameClients.client2 = clientChan
+	}
+}
+
+func handleGameMessage(conn net.Conn, message *GameMessage) error {
+	return nil
+}
diff --git a/internal/netwrk/game_messages.pb.go b/internal/netwrk/game_messages.pb.go
index 1142d2b..633a1a8 100644
--- a/internal/netwrk/game_messages.pb.go
+++ b/internal/netwrk/game_messages.pb.go
@@ -1,7 +1,7 @@
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
 // 	protoc-gen-go v1.34.2
-// 	protoc        v5.27.3
+// 	protoc        v5.27.1
 // source: proto/game_messages.proto
 
 package netwrk
diff --git a/internal/netwrk/lobby.go b/internal/netwrk/lobby.go
new file mode 100644
index 0000000..c2b211d
--- /dev/null
+++ b/internal/netwrk/lobby.go
@@ -0,0 +1,113 @@
+package netwrk
+
+import (
+	"fmt"
+	"log"
+	"net"
+	"time"
+
+	"google.golang.org/protobuf/proto"
+)
+
+func handleLobbyConnection(conn net.Conn) {
+	defer conn.Close()
+
+	messageBytes := make([]byte, 4096)
+
+	for {
+		n, err := conn.Read(messageBytes)
+		if err != nil {
+			log.Printf("Error reading message %v", err)
+			return
+		}
+
+		if isDone, err := handleLobbyMessage(conn, messageBytes[:n]); err != nil || isDone {
+			return
+		}
+	}
+}
+
+// Returns a bool of whether the player has disconnected from the lobby and an error
+func handleLobbyMessage(playerConnection net.Conn, bytes []byte) (bool, error) {
+
+	message := LobbyMessage{}
+
+	err := proto.Unmarshal(bytes, &message)
+	if err != nil {
+		return false, fmt.Errorf("Invalid message received from client")
+	}
+
+	switch message.Type {
+	case "name":
+		_, ok := clientPool.clients[message.Content]
+		if ok {
+			SendMessageToClient(playerConnection, &LobbyMessage{Type: "error", Content: "Sorry, that name is already taken"})
+			return false, nil
+		}
+		playerID := message.Content
+		clientPool.clients[playerID] = Client{
+			name:  playerID,
+			conn:  playerConnection,
+			ready: false,
+		}
+		for _, player := range clientPool.clients {
+			err := SendMessageToClient(playerConnection, &LobbyMessage{PlayerId: player.name, Type: "connect", Content: player.name})
+			if err != nil {
+				log.Println("There was an error sending the list of lobby players to client", message.Content)
+			}
+		}
+
+		broadcastToLobby(&LobbyMessage{PlayerId: "", Type: "connect", Content: playerID})
+
+		return false, SendMessageToClient(playerConnection, &LobbyMessage{PlayerId: playerID, Type: "name", Content: playerID})
+	case "invite_player":
+		invitee, ok := clientPool.clients[message.Content]
+		if !ok {
+			SendMessageToClient(playerConnection, &LobbyMessage{Type: "text", Content: "Sorry, that player is not available..."})
+			return false, nil
+		}
+		SendMessageToClient(invitee.conn, &LobbyMessage{Type: "invite", Content: message.PlayerId})
+		return false, nil
+	case "accept_game":
+		player := clientPool.clients[message.Content]
+
+		if err := SendMessageToClient(player.conn, &LobbyMessage{Type: "accept", Content: ""}); err != nil {
+			SendMessageToClient(playerConnection, &LobbyMessage{Type: "error", Content: "Sorry that game is no longer available..."})
+			return false, nil
+		}
+
+		return true, nil
+	case "decline_game":
+		inviter := clientPool.clients[message.Content]
+		SendMessageToClient(inviter.conn, &LobbyMessage{Type: "decline_game", Content: ""})
+		return false, nil
+	case "quit":
+		delete(clientPool.clients, message.PlayerId)
+		broadcastToLobby(&LobbyMessage{Type: "disconnect", Content: message.PlayerId})
+		return true, nil
+	case "ping":
+		SendMessageToClient(playerConnection, &LobbyMessage{Type: "pong", Content: "pong"})
+		return false, nil
+	default:
+		SendMessageToClient(playerConnection, &LobbyMessage{Type: "pong", Content: "pong"})
+		return false, nil
+	}
+}
+
+func SendMessageToClient(connection net.Conn, message *LobbyMessage) error {
+	bytes, err := proto.Marshal(message)
+	if err != nil {
+		return fmt.Errorf("Error marshalling message. Your protobuf is wack yo.")
+	}
+	_, err = connection.Write(bytes)
+	if err != nil {
+		return fmt.Errorf("Error writing to client connection")
+	}
+	return nil
+}
+
+func broadcastToLobby(message *LobbyMessage) {
+	for _, player := range clientPool.clients {
+		SendMessageToClient(player.conn, message)
+	}
+}
diff --git a/internal/netwrk/lobby_messages.pb.go b/internal/netwrk/lobby_messages.pb.go
index 5ca1a59..2010eed 100644
--- a/internal/netwrk/lobby_messages.pb.go
+++ b/internal/netwrk/lobby_messages.pb.go
@@ -1,7 +1,7 @@
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
 // 	protoc-gen-go v1.34.2
-// 	protoc        v5.27.3
+// 	protoc        v5.27.1
 // source: proto/lobby_messages.proto
 
 package netwrk
@@ -25,8 +25,9 @@ type LobbyMessage struct {
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
-	Type    string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
-	Content string `protobuf:"bytes,2,opt,name=content,proto3" json:"content,omitempty"`
+	PlayerId string `protobuf:"bytes,1,opt,name=player_id,json=playerId,proto3" json:"player_id,omitempty"`
+	Type     string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
+	Content  string `protobuf:"bytes,3,opt,name=content,proto3" json:"content,omitempty"`
 }
 
 func (x *LobbyMessage) Reset() {
@@ -61,6 +62,13 @@ func (*LobbyMessage) Descriptor() ([]byte, []int) {
 	return file_proto_lobby_messages_proto_rawDescGZIP(), []int{0}
 }
 
+func (x *LobbyMessage) GetPlayerId() string {
+	if x != nil {
+		return x.PlayerId
+	}
+	return ""
+}
+
 func (x *LobbyMessage) GetType() string {
 	if x != nil {
 		return x.Type
@@ -80,12 +88,14 @@ var File_proto_lobby_messages_proto protoreflect.FileDescriptor
 var file_proto_lobby_messages_proto_rawDesc = []byte{
 	0x0a, 0x1a, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6c, 0x6f, 0x62, 0x62, 0x79, 0x5f, 0x6d, 0x65,
 	0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x6e, 0x65,
-	0x74, 0x77, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x22, 0x3c, 0x0a, 0x0c, 0x4c, 0x6f, 0x62, 0x62, 0x79,
-	0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18,
-	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63,
-	0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f,
-	0x6e, 0x74, 0x65, 0x6e, 0x74, 0x42, 0x0a, 0x5a, 0x08, 0x2e, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x72,
-	0x6b, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x74, 0x77, 0x72, 0x6b, 0x2e, 0x76, 0x31, 0x22, 0x59, 0x0a, 0x0c, 0x4c, 0x6f, 0x62, 0x62, 0x79,
+	0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x6c, 0x61, 0x79, 0x65,
+	0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x79,
+	0x65, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74,
+	0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65,
+	0x6e, 0x74, 0x42, 0x0a, 0x5a, 0x08, 0x2e, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x72, 0x6b, 0x62, 0x06,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
diff --git a/internal/netwrk/netwrk.go b/internal/netwrk/netwrk.go
index d685a33..3563347 100644
--- a/internal/netwrk/netwrk.go
+++ b/internal/netwrk/netwrk.go
@@ -1,13 +1,8 @@
 package netwrk
 
 import (
-	"fmt"
 	"log"
 	"net"
-	"time"
-
-	"github.com/google/uuid"
-	"google.golang.org/protobuf/proto"
 )
 
 type Client struct {
@@ -61,9 +56,15 @@ func Listen() {
 		games: map[string]GameClients{},
 	}
 
+	gameListener, err := net.Listen("tcp", ":42069")
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	defer gameListener.Close()
 	go func() {
 		for {
-			conn, err := listener.Accept()
+			conn, err := gameListener.Accept()
 			if err != nil {
 				log.Println(err)
 				continue
@@ -72,193 +73,3 @@ func Listen() {
 		}
 	}()
 }
-
-func handleGameConnection(conn net.Conn) {
-	defer conn.Close()
-
-	messageBytes := make([]byte, 126)
-
-	n, err := conn.Read(messageBytes)
-	if err != nil {
-		log.Printf("Error reading game ID on connection", err)
-	}
-
-	gameID := string(messageBytes[:n])
-	if err != nil {
-		log.Printf("Game id was not a string?", err)
-	}
-
-	clientChan := make(chan GameMessage)
-
-	n, err := conn.Read(messageBytes)
-	if err != nil {
-		log.Printf("Error reading message %v", err)
-		return
-	}
-
-	gameID := messageBytes[:n]
-
-	clientChan, ok := gameChans[gameID]
-	if !ok {
-		GameClients{
-			client1: clientChan,
-			client2: nil,
-		}
-	}
-}
-
-func handleGameMessage(conn net.Conn, message GameMessage) error {
-	return nil
-}
-
-func handleLobbyConnection(conn net.Conn) {
-	defer conn.Close()
-
-	messageBytes := make([]byte, 4096)
-
-	for {
-		n, err := conn.Read(messageBytes)
-		if err != nil {
-			log.Printf("Error reading message %v", err)
-			return
-		}
-
-		if isDone, err := handleLobbyMessage(conn, messageBytes[:n]); err != nil || isDone {
-			return
-		}
-	}
-}
-
-// Returns a bool of whether the player has disconnected from the lobby and an error
-func handleLobbyMessage(playerConnection net.Conn, bytes []byte) (bool, error) {
-
-	message := LobbyMessage{}
-
-	err := proto.Unmarshal(bytes, &message)
-	if err != nil {
-		return false, fmt.Errorf("Invalid message received from client")
-	}
-
-	switch message.Type {
-	case "name":
-		clientPool.clients[uuid.New().String()] = Client{
-			name:  message.Content,
-			conn:  playerConnection,
-			ready: false,
-		}
-		break
-	case "invite_player":
-		invitee, ok := clientPool.clients[message.Content]
-		if !ok {
-			SendMessageToClient(playerConnection, &LobbyMessage{Type: "text", Content: "Sorry that player is not available..."})
-			return false, nil
-		}
-		SendMessageToClient(invitee.conn, &LobbyMessage{Type: "invite", Content: playerID})
-		return false, nil
-	case "cancel_invite":
-
-	case "accept_game":
-		AcceptGame(message.Content)
-		return true, nil
-	case "decline_game":
-		DeclineGame()
-		return false, nil
-	case "quit":
-		DeletePlayer(message.Content)
-		return true, nil
-	case "ping":
-		PongPlayer(message.Content)
-		return false, nil
-	default:
-		PongPlayer(message.Content)
-		return false, nil
-	}
-	return false, nil
-
-}
-
-func SendMessageToClient(connection net.Conn, message *LobbyMessage) error {
-	bytes, err := proto.Marshal(message)
-	if err != nil {
-		return fmt.Errorf("Error marshalling message. Your protobuf is wack yo.")
-	}
-	_, err = connection.Write(bytes)
-	if err != nil {
-		return fmt.Errorf("Error writing to client connection")
-	}
-	return nil
-}
-
-func GetPool() (map[string]Client, bool) {
-	if clientPool.clients != nil {
-		return clientPool.clients, true
-	}
-	return clientPool.clients, false
-}
-
-func CreateGame(clientID1, clientID2 string) (string, error) {
-	client1, ok := clientPool.clients[clientID1]
-	if !ok {
-		return "", fmt.Errorf("Client 1 was not found in client pool :(")
-	}
-	if err := client1.conn.SetWriteDeadline(time.Time{}); err != nil {
-		return "", fmt.Errorf("Client 1 was not responsive")
-	}
-
-	client2, ok := clientPool.clients[clientID2]
-	if !ok {
-		return "", fmt.Errorf("Client 2 was not found in client pool :(")
-	}
-	if err := client2.conn.SetWriteDeadline(time.Time{}); err != nil {
-		return "", fmt.Errorf("Client 2 was not responsive")
-	}
-
-	gameID := uuid.New().String()
-	gameConnections.games[gameID] = GameClients{
-		client1: client1,
-		client2: client2,
-	}
-
-	return gameID, nil
-}
-
-func SendGameUpdateToLobbyClients(gameID string, message *LobbyMessage) error {
-	clients, ok := gameConnections.games[gameID]
-	if !ok {
-		return fmt.Errorf("Could not find game clients record")
-	}
-
-	bytes, err := proto.Marshal(message)
-	if err != nil {
-		return fmt.Errorf("message could not be marshalled")
-	}
-
-	_, err = clients.client1.conn.Write(bytes)
-	if err != nil {
-		return fmt.Errorf("Could not write to client1 connection")
-	}
-	_, err = clients.client1.conn.Write(bytes)
-	if err != nil {
-		return fmt.Errorf("Could not write to client2 connection")
-	}
-
-	return nil
-}
-
-func PingAndCleanLobbyClients() {
-	ping := []byte("ping")
-
-	deadClients := []string{}
-	for id, client := range clientPool.clients {
-		client.conn.SetWriteDeadline(time.Now().Add(time.Second))
-		_, err := client.conn.Write(ping)
-		if err != nil {
-			log.Println("Could not write to client, deleting connection:", id)
-			deadClients = append(deadClients, id)
-		}
-	}
-
-	for _, id := range deadClients {
-		delete(clientPool.clients, id)
-	}
-}
diff --git a/proto/lobby_messages.proto b/proto/lobby_messages.proto
index bfd4797..76d45c9 100644
--- a/proto/lobby_messages.proto
+++ b/proto/lobby_messages.proto
@@ -4,6 +4,7 @@ package netwrk.v1;
 option go_package = "./netwrk";
 
 message LobbyMessage {
-  string type = 1;
-  string content = 2;
+  string player_id = 1;
+  string type = 2;
+  string content = 3;
 }