finalized basic udp server

This commit is contained in:
2024-04-17 16:40:14 +02:00
parent 5bb336944d
commit 302388379f

View File

@@ -1,72 +1,117 @@
package main
import (
"crypto/rand"
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
"io"
"net"
"os"
"github.com/gorilla/websocket"
"github.com/joho/godotenv"
)
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
type Payload struct {
Type string `json:"type"`
Message string `json:"msg,omitempty"`
Direction *struct {
X int `json:"x,omitempty"`
Y int `json:"y,omitempty"`
} `json:"direction,omitempty"`
SessionID string `json:"session_id,omitempty"`
}
var clients = make(map[*websocket.Conn]bool) // connected clients
var broadcast = make(chan []byte) // broadcast channel
// Generate a unique session ID
func generateSessionID() string {
b := make([]byte, 32)
if _, err := io.ReadFull(rand.Reader, b); err != nil {
return ""
}
return base64.URLEncoding.EncodeToString(b)
}
func main() {
godotenv.Load()
http.HandleFunc("/ws", handleConnections)
go handleMessages()
fmt.Println("Server running on " + os.Getenv("PORT"))
http.ListenAndServeTLS(os.Getenv("PORT"), "cert.pem", "key.pem", nil)
}
port := os.Getenv("PORT")
if port == "" {
port = "4477" // Default port if not specified
}
func handleConnections(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
addr, err := net.ResolveUDPAddr("udp", ":"+port)
if err != nil {
fmt.Println(err)
return
}
defer conn.Close() // Closes the connection at the end
clients[conn] = true // Add a new WebSocket connection to the clients map.
conn, err := net.ListenUDP("udp", addr)
if err != nil {
fmt.Println(err)
return
}
defer conn.Close()
fmt.Println("Server running on " + port)
buf := make([]byte, 1024)
clients := make(map[string]string) // Map to keep track of clients and their session IDs
for {
_, msg, err := conn.ReadMessage()
n, addr, err := conn.ReadFromUDP(buf)
if err != nil {
delete(clients, conn)
break
fmt.Println(err)
continue
}
// Parse the received message as JSON
var payload map[string]interface{}
err = json.Unmarshal(msg, &payload)
var payload Payload
err = json.Unmarshal(buf[:n], &payload)
if err != nil {
fmt.Println("Error parsing JSON:", err)
continue
}
// Check if the JSON object contains the key "type" with the value "broadcast"
if payload["type"] == "broadcast" {
broadcast <- msg // Send received WebSocket Message to Broadcast
// Use the client's IP and port as the key to uniquely identify the connection
key := addr.String()
// Check if the client's connection already has a session ID
if _, ok := clients[key]; !ok {
// The client is new, generate a session ID
sessionID := generateSessionID()
clients[key] = sessionID
// Send the session ID back to the client
responsePayload := Payload{SessionID: sessionID}
response, _ := json.Marshal(responsePayload)
conn.WriteToUDP(response, addr)
}
switch payload.Type {
case "init":
fmt.Printf("Received initiation generated SessionID: %s", clients[key])
case "move":
fmt.Printf("Received move message from Session ID: %s : X=%d, Y=%d\n", clients[key], payload.Direction.X, payload.Direction.Y)
// Handle movement logic here
case "message":
fmt.Printf("Received message from Session ID: %s : %s\n", clients[key], payload.Message)
broadcastMessage(conn, clients, payload.Message)
default:
fmt.Printf("Received unknown message type Session ID: %s\n", clients[key])
}
}
}
func handleMessages() {
for {
msg := <-broadcast
for client := range clients {
err := client.WriteMessage(websocket.TextMessage, msg)
if err != nil {
client.Close()
delete(clients, client)
}
func broadcastMessage(conn *net.UDPConn, clients map[string]string, message string) {
for clientKey := range clients {
// Parse the clientKey to get the *net.UDPAddr
clientAddr, err := net.ResolveUDPAddr("udp", clientKey)
if err != nil {
fmt.Println("Error resolving UDP address:", err)
continue
}
payload := Payload{
Type: "message",
Message: message,
}
response, _ := json.Marshal(payload)
conn.WriteToUDP(response, clientAddr)
}
}