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 }