package main
import (
// "flag"
// "fmt"
"embed"
"fmt"
"net/http"
"strings"
"github.com/gin-contrib/gzip"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/gorilla/websocket"
)
//go:embed toe
var staticFiles embed.FS
var waitingPlayers = make(map[string][]*websocket.Conn)
func SetCustomContentType() gin.HandlerFunc {
return func(c *gin.Context) {
requestPath := c.Request.URL.Path
if strings.Contains(requestPath, ".") {
c.Header("Cache-Control", "public, max-age=31536000, immutable")
}
if strings.HasPrefix(requestPath, "/tic/tac/toe") && !strings.Contains(requestPath, ".") {
c.Header("Content-Type", "text/html; charset=UTF-8")
} else if strings.HasSuffix(requestPath, ".ico") {
c.Header("Content-Type", "image/svg+xml")
} else if strings.HasSuffix(requestPath, ".js") {
c.Header("Content-Type", "application/javascript")
} else if strings.HasSuffix(requestPath, ".css") {
c.Header("Content-Type", "text/css")
}
c.Next()
}
}
func multiplayerHandler(c *gin.Context) {
if c.GetHeader("Accept") == "*/*" {
c.String(http.StatusTeapot, "Preload not allowed")
}
if c.Query("g") == "" {
u, err := uuid.NewV7()
if err != nil {
fmt.Println("Error:", err)
return
}
c.Redirect(http.StatusPermanentRedirect, "/multiplayer?g="+u.String())
}
c.Header("Content-Type", "text/html; charset=UTF-8")
c.String(http.StatusOK, "")
}
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
origin := r.Header.Get("Origin")
host := r.Host
return origin == "http://"+host || origin == "https://"+host
},
}
func wsHandler(c *gin.Context) {
game_id := c.Query("g")
if game_id == "" {
c.String(http.StatusTeapot, "No game id")
return
}
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
fmt.Println("Upgrade error:", err)
return
}
fmt.Println("New client connected")
waitingPlayers[game_id] = append(waitingPlayers[game_id], conn)
defer func() {
conn.Close()
fmt.Println("Client disconnected")
}()
for {
messageType, message, err := conn.ReadMessage()
if err != nil {
fmt.Println("Read error:", err)
break
}
fmt.Printf("Received: %s\n", message)
// Рассылка всем клиентам
for _, c := range waitingPlayers[game_id] {
if c != conn {
err := c.WriteMessage(messageType, message)
if err != nil {
fmt.Println("Broadcast error:", err)
}
}
}
}
}
var favicon = ""
func main() {
embeddedFilesSystem := http.FS(staticFiles)
router := gin.Default()
router.Use(SetCustomContentType())
router.Use(gzip.Gzip(gzip.DefaultCompression))
router.GET("/", func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "/tic/tac/toe/index")
})
router.GET("/favicon.ico", func(c *gin.Context) {
c.String(http.StatusOK, favicon)
})
router.GET("/ws", wsHandler)
router.GET("/multiplayer", multiplayerHandler)
router.StaticFS("/tic/tac", embeddedFilesSystem)
router.Run(":8080")
}