package main import ( "context" "encoding/json" "fmt" "log" "mchess_server/api" "mchess_server/chess" lobbies "mchess_server/lobby_registry" "mchess_server/usher" "mchess_server/utils" "net/http" "os" "sync" "github.com/gin-gonic/gin" "github.com/google/uuid" "nhooyr.io/websocket" ) var cert_path = "/etc/letsencrypt/live/chess.sw-gross.de/" var cert_file = cert_path + "fullchain.pem" var key_file = cert_path + "privkey.pem" func main() { hostname, err := os.Hostname() if err != nil { log.Fatal(err) } router := gin.Default() router.GET("/api/random", registerForRandomGame) router.GET("/api/hostPrivate", hostPrivateGame) router.GET("/api/joinPrivate", joinPrivateGame) router.GET("/api/ws", registerWebSocketConnection) if hostname == "mbook" { log.Println("Starting service WITHOUT TLS") log.Fatal(router.Run("localhost:8080")) } else { gin.SetMode(gin.ReleaseMode) log.Println("Starting in release mode") log.Println("Starting service with TLS") log.Fatal(router.RunTLS("chess.sw-gross.de:9999", cert_file, key_file)) } } var mut sync.Mutex func registerForRandomGame(c *gin.Context) { player := chess.NewPlayer(uuid.New()) usher := usher.GetUsher() mut.Lock() lobby := usher.WelcomeNewPlayer(player) usher.AddPlayerToLobbyAndStartGameIfFull(player, lobby) mut.Unlock() info := api.PlayerInfo{ PlayerID: player.Uuid, LobbyID: lobby.Uuid, } log.Println("responding with info ", info) c.Header("Access-Control-Allow-Origin", "*") c.IndentedJSON(http.StatusOK, info) } func hostPrivateGame(c *gin.Context) { player := chess.NewPlayer(uuid.New()) u := usher.GetUsher() mut.Lock() lobby := u.FindNewPrivateLobby(player) u.AddPlayerToLobbyAndStartGameIfFull(player, lobby) mut.Unlock() passphrase := lobby.Passphrase.String() info := api.PlayerInfo{ PlayerID: player.Uuid, LobbyID: lobby.Uuid, Passphrase: &passphrase, } c.Header("Access-Control-Allow-Origin", "*") c.IndentedJSON(http.StatusOK, info) } func joinPrivateGame(c *gin.Context) { req := api.PlayerInfo{} err := c.ShouldBindJSON(req) if err!= nil || req.Passphrase == nil || *req.Passphrase == "" { c.IndentedJSON(http.StatusNotFound, req) } player := chess.NewPlayer(uuid.New()) u := usher.GetUsher() mut.Lock() defer mut.Unlock() lobby := u.FindExistingPrivateLobby(utils.Passphrase(*req.Passphrase)) if lobby != nil { u.AddPlayerToLobbyAndStartGameIfFull(player, lobby) } else { c.IndentedJSON(http.StatusNotFound, req) return } info := api.PlayerInfo{ PlayerID: player.Uuid, LobbyID: lobby.Uuid, Passphrase: req.Passphrase, } c.IndentedJSON(http.StatusOK, info) } func registerWebSocketConnection(c *gin.Context) { webSocketConn, err := websocket.Accept(c.Writer, c.Request, &websocket.AcceptOptions{OriginPatterns: []string{"chess.sw-gross.de", "localhost:*"}}) if err != nil { log.Println(err) return } go waitForAndHandlePlayerID(c, webSocketConn) } func waitForAndHandlePlayerID(ctx context.Context, conn *websocket.Conn) { msgType, msg, err := conn.Read(ctx) if err != nil { errorMessage := fmt.Sprintf("Reading from websocket connection did not work: %s", err) log.Println(errorMessage) conn.Close(websocket.StatusCode(400), errorMessage) return } log.Println("read from websocket: ", msgType, string(msg), err) var info api.PlayerInfo err = json.Unmarshal(msg, &info) if err != nil { errorMessage := fmt.Sprintf("Unmarshaling message did not work: %s", err) log.Println(errorMessage) conn.Close(websocket.StatusCode(400), errorMessage) return } lobby := lobbies.GetLobbyRegistry().GetLobbyByUUID(info.LobbyID) player, found := lobby.GetPlayerByUUID(info.PlayerID) if !found { conn.Close(websocket.StatusCode(400), "player not found") return } if player.Conn != nil { player.Conn.Close(websocket.StatusCode(400), "closing existing connection") } player.SetConnection(ctx, conn) log.Println("player after setting connection: ", player) }