Initialize Redis-backed RoomRegistry for room-to-pod assignment and add Pod-specific game.join handling logic with NATS subscriptions. Update cache-busting version for client assets.
All checks were successful
Dynamic Branch Deploy / build-and-deploy (push) Successful in 2m30s
All checks were successful
Dynamic Branch Deploy / build-and-deploy (push) Successful in 2m30s
This commit is contained in:
105
cmd/server/room_registry.go
Normal file
105
cmd/server/room_registry.go
Normal file
@@ -0,0 +1,105 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
// RoomRegistry verwaltet die Zuordnung von Räumen zu Pods via Redis
|
||||
type RoomRegistry struct {
|
||||
client *redis.Client
|
||||
ctx context.Context
|
||||
podID string // Eindeutige Pod-ID
|
||||
ttl time.Duration
|
||||
}
|
||||
|
||||
// NewRoomRegistry erstellt eine neue Room-Registry
|
||||
func NewRoomRegistry(redisAddr string, podID string) (*RoomRegistry, error) {
|
||||
client := redis.NewClient(&redis.Options{
|
||||
Addr: redisAddr,
|
||||
Password: "", // kein Password
|
||||
DB: 0, // default DB
|
||||
})
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Test connection
|
||||
_, err := client.Ping(ctx).Result()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Redis connection failed: %w", err)
|
||||
}
|
||||
|
||||
log.Printf("✅ Redis verbunden: %s", redisAddr)
|
||||
|
||||
return &RoomRegistry{
|
||||
client: client,
|
||||
ctx: ctx,
|
||||
podID: podID,
|
||||
ttl: 5 * time.Minute, // Räume verfallen nach 5 Minuten Inaktivität
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ClaimRoom versucht, einen Raum für diesen Pod zu claimen
|
||||
// Gibt zurück: (claimed bool, assignedPodID string, error)
|
||||
func (rr *RoomRegistry) ClaimRoom(roomID string) (bool, string, error) {
|
||||
key := fmt.Sprintf("room:%s:pod", roomID)
|
||||
|
||||
// Versuche den Raum zu claimen (nur wenn noch nicht existiert)
|
||||
success, err := rr.client.SetNX(rr.ctx, key, rr.podID, rr.ttl).Result()
|
||||
if err != nil {
|
||||
return false, "", fmt.Errorf("failed to claim room: %w", err)
|
||||
}
|
||||
|
||||
if success {
|
||||
// Erfolgreich geclaimed!
|
||||
log.Printf("🏠 Raum '%s' für Pod %s geclaimed", roomID, rr.podID)
|
||||
return true, rr.podID, nil
|
||||
}
|
||||
|
||||
// Raum existiert bereits - hole den zugewiesenen Pod
|
||||
assignedPod, err := rr.client.Get(rr.ctx, key).Result()
|
||||
if err == redis.Nil {
|
||||
// Key existiert nicht mehr - retry
|
||||
return rr.ClaimRoom(roomID)
|
||||
} else if err != nil {
|
||||
return false, "", fmt.Errorf("failed to get room pod: %w", err)
|
||||
}
|
||||
|
||||
// Raum gehört einem anderen Pod
|
||||
return false, assignedPod, nil
|
||||
}
|
||||
|
||||
// RenewRoom erneuert die TTL eines Raums
|
||||
func (rr *RoomRegistry) RenewRoom(roomID string) error {
|
||||
key := fmt.Sprintf("room:%s:pod", roomID)
|
||||
return rr.client.Expire(rr.ctx, key, rr.ttl).Err()
|
||||
}
|
||||
|
||||
// GetRoomPod gibt den Pod zurück, der einen Raum hostet
|
||||
func (rr *RoomRegistry) GetRoomPod(roomID string) (string, error) {
|
||||
key := fmt.Sprintf("room:%s:pod", roomID)
|
||||
podID, err := rr.client.Get(rr.ctx, key).Result()
|
||||
if err == redis.Nil {
|
||||
return "", fmt.Errorf("room not found")
|
||||
}
|
||||
return podID, err
|
||||
}
|
||||
|
||||
// ReleaseRoom gibt einen Raum frei
|
||||
func (rr *RoomRegistry) ReleaseRoom(roomID string) error {
|
||||
key := fmt.Sprintf("room:%s:pod", roomID)
|
||||
return rr.client.Del(rr.ctx, key).Err()
|
||||
}
|
||||
|
||||
// IsMyRoom prüft, ob dieser Pod der Owner eines Raums ist
|
||||
func (rr *RoomRegistry) IsMyRoom(roomID string) bool {
|
||||
podID, err := rr.GetRoomPod(roomID)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return podID == rr.podID
|
||||
}
|
||||
Reference in New Issue
Block a user