From 0b73e74af371c466ec1daf68e4e05d4d08ca7aa5 Mon Sep 17 00:00:00 2001
From: Alex Constantin-Gomez <ac3419@ic.ac.uk>
Date: Sat, 8 Feb 2020 17:37:32 +0000
Subject: [PATCH] backend v1

---
 main.go | 104 +++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 91 insertions(+), 13 deletions(-)

diff --git a/main.go b/main.go
index 73eebfb..45923ab 100644
--- a/main.go
+++ b/main.go
@@ -3,8 +3,11 @@ package main
 import (
 	"encoding/json"
 	"fmt"
+	"io/ioutil"
 	"log"
 	"net/http"
+	"strconv"
+	"sync"
 )
 
 /******************** DATA STRUCTS ***********************/
@@ -19,8 +22,8 @@ type Player struct {
 type Game struct {
 	ID       int
 	Channels [2]chan string
-	Player1 string
-	Player2 string
+	Player1  string
+	Player2  string
 }
 
 // Move represents a move in the game
@@ -32,21 +35,25 @@ type Move struct {
 }
 
 var (
-	gameData  map[int]Game
-	idCounter int
+	gameData      map[int]*Game
+	gameDataMutex sync.RWMutex
+
+	idCounter      int
+	idCounterMutex sync.RWMutex
 )
 
 /************** MAIN FUNCTION **********************/
 
 func main() {
 	// Initialise global variables
-	gameData = make(map[int]Game)
+	gameData = make(map[int]*Game)
 
 	http.HandleFunc("/", hello)
 
 	http.HandleFunc("/move", move)
 	http.HandleFunc("/create", createGame)
 	http.HandleFunc("/join", joinGame)
+	http.HandleFunc("/wait", checkJoinGame)
 
 	err := http.ListenAndServe(":8080", nil)
 	if err != nil {
@@ -69,7 +76,9 @@ func move(w http.ResponseWriter, r *http.Request) {
 		log.Println("could not decode json data into Move struct")
 	}
 
+	gameDataMutex.RLock()
 	game := gameData[move.GameID]
+	gameDataMutex.RUnlock()
 	sendChan := game.Channels[move.Player]
 	recChan := game.Channels[1-move.Player]
 	sendChan <- move.MoveData
@@ -83,26 +92,95 @@ func move(w http.ResponseWriter, r *http.Request) {
 	fmt.Fprintf(w, response)
 }
 
+// Creates a game with one player
 func createGame(w http.ResponseWriter, r *http.Request) {
-	//jsonData := readJsonFromRequest(r)
+	jsonData := readJsonFromRequest(r)
+
+	var playerData struct {
+		Player string `json:"player"`
+	}
+	err := json.Unmarshal(jsonData, &playerData)
+	if err != nil {
+		log.Println("could not decode json data into Move struct")
+	}
 
 	newGameID := generateID()
-	newGame := Game{
-		ID: newGameID,
-		// Player1: ,
-		// Player2: ,
+	newGame := &Game{
+		ID:       newGameID,
+		Channels: [2]chan string{make(chan string, 1), make(chan string, 1)},
+		Player1:  playerData.Player,
 	}
+	gameDataMutex.Lock()
 	gameData[newGameID] = newGame
+	gameDataMutex.Unlock()
 
-	fmt.Fprintf(w, "hello")
+	fmt.Fprintf(w, strconv.Itoa(newGame.ID))
 }
 
+// Adds a 2nd player to a game, given the game id
 func joinGame(w http.ResponseWriter, r *http.Request) {
-	fmt.Fprintf(w, "hello")
+	jsonData := readJsonFromRequest(r)
+
+	var join struct {
+		GameID int    `json:"game_id"`
+		Player string `json:"player"`
+	}
+	err := json.Unmarshal(jsonData, &join)
+	if err != nil {
+		log.Println("could not decode json data")
+	}
+
+	gameDataMutex.RLock()
+	game, found := gameData[join.GameID]
+	gameDataMutex.RUnlock()
+	if !found {
+		fmt.Fprintf(w, "error: could not find game ID in checkJoinGame endpoint")
+		return
+	}
+
+	game.Player2 = join.Player
+	game.Channels[0] <- join.Player
+	fmt.Fprintf(w, game.Player1)
+}
+
+// Returns if the 2nd player has joined the game yet
+func checkJoinGame(w http.ResponseWriter, r *http.Request) {
+	jsonData := readJsonFromRequest(r)
+
+	var gameID struct {
+		GameID int `json:"game_id"`
+	}
+	err := json.Unmarshal(jsonData, &gameID)
+	if err != nil {
+		log.Println("could not decode json data")
+	}
+
+	// check if player 2 joined
+	gameDataMutex.RLock()
+	game, found := gameData[gameID.GameID]
+	gameDataMutex.RUnlock()
+	if !found {
+		log.Println("error: could not find game ID in checkJoinGame endpoint")
+		return
+	}
+	p2 := <-game.Channels[0]
+
+	fmt.Fprintf(w, p2) // send player2's name
 }
 
 /************** Helper functions *******************/
 
 func generateID() int {
-	return idCounter + 1
+	idCounterMutex.Lock()
+	defer idCounterMutex.Unlock()
+	idCounter++
+	return idCounter
+}
+
+func readJsonFromRequest(r *http.Request) []byte {
+	data, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		log.Println("could not read json from body")
+	}
+	return data
 }
-- 
GitLab