working state

This commit is contained in:
cottongin
2026-02-07 12:37:21 -05:00
parent 1e0cb63b1c
commit fd42ac0e7c
3 changed files with 56 additions and 37 deletions

View File

@@ -128,9 +128,20 @@ func (m *Manager) startWebSocketClient(messageCallback func(string)) error {
// Get EnableRoomCodeImage setting from config (defaults to false)
enableRoomCodeImage := m.config.Viper().GetBool("jackbox.EnableRoomCodeImage")
// Get configurable delays for room code broadcast
imageDelay := time.Duration(m.config.Viper().GetInt("jackbox.RoomCodeImageDelay")) * time.Second
plaintextDelay := time.Duration(m.config.Viper().GetInt("jackbox.RoomCodePlaintextDelay")) * time.Second
if plaintextDelay == 0 {
plaintextDelay = 29 * time.Second // default
}
m.log.Infof("Room code delays: imageDelay=%v, plaintextDelay=%v (raw config: image=%d, plaintext=%d)",
imageDelay, plaintextDelay,
m.config.Viper().GetInt("jackbox.RoomCodeImageDelay"),
m.config.Viper().GetInt("jackbox.RoomCodePlaintextDelay"))
// Create WebSocket client (pass the API client for vote tracking)
m.wsClient = NewWebSocketClient(apiURL, token, wrappedCallback, m.client, enableRoomCodeImage, m.log)
m.wsClient = NewWebSocketClient(apiURL, token, wrappedCallback, m.client, enableRoomCodeImage, imageDelay, plaintextDelay, m.log)
// Connect to WebSocket
if err := m.wsClient.Connect(); err != nil {

View File

@@ -305,10 +305,10 @@ func GenerateRoomCodeImage(roomCode, gameTitle string) ([]byte, error) {
}
// Animation parameters
initialPauseFrames := 25 // Initial pause before animation starts (2.5 seconds at 10fps)
fadeFrames := 10 // Number of frames for fade-in (1 second at 10fps)
pauseFrames := 30 // Frames to pause between characters (3 seconds at 10fps)
frameDelay := 10 // 10/100 second = 0.1s per frame (10 fps)
initialPauseFrames := 1 // Initial pause before animation starts (2.5 seconds at 10fps)
fadeFrames := 10 // Number of frames for fade-in (1 second at 10fps)
pauseFrames := 30 // Frames to pause between characters (3 seconds at 10fps)
frameDelay := 10 // 10/100 second = 0.1s per frame (10 fps)
// Helper function to draw a frame and convert to paletted
drawFrame := func(charIndex int, fadeProgress float64) *image.Paletted {

View File

@@ -24,8 +24,10 @@ type WebSocketClient struct {
stopChan chan struct{}
connected bool
authenticated bool
subscribedSession int
enableRoomCodeImage bool // Whether to upload room code images to Kosmi
subscribedSession int
enableRoomCodeImage bool // Whether to upload room code images to Kosmi
roomCodeImageDelay time.Duration // Delay before sending image announcement
roomCodePlaintextDelay time.Duration // Delay before sending plaintext room code
}
// WebSocket message types
@@ -67,17 +69,19 @@ type GameAddedData struct {
}
// NewWebSocketClient creates a new WebSocket client
func NewWebSocketClient(apiURL, token string, messageCallback func(string), apiClient *Client, enableRoomCodeImage bool, log *logrus.Entry) *WebSocketClient {
func NewWebSocketClient(apiURL, token string, messageCallback func(string), apiClient *Client, enableRoomCodeImage bool, roomCodeImageDelay, roomCodePlaintextDelay time.Duration, log *logrus.Entry) *WebSocketClient {
return &WebSocketClient{
apiURL: apiURL,
token: token,
messageCallback: messageCallback,
apiClient: apiClient,
enableRoomCodeImage: enableRoomCodeImage,
log: log,
reconnectDelay: 1 * time.Second,
maxReconnect: 30 * time.Second,
stopChan: make(chan struct{}),
apiURL: apiURL,
token: token,
messageCallback: messageCallback,
apiClient: apiClient,
enableRoomCodeImage: enableRoomCodeImage,
roomCodeImageDelay: roomCodeImageDelay,
roomCodePlaintextDelay: roomCodePlaintextDelay,
log: log,
reconnectDelay: 1 * time.Second,
maxReconnect: 30 * time.Second,
stopChan: make(chan struct{}),
}
}
@@ -93,7 +97,7 @@ func (c *WebSocketClient) Connect() error {
} else if len(wsURL) > 8 && wsURL[:8] == "https://" {
wsURL = "wss://" + wsURL[8:]
}
wsURL += "/api/sessions/live"
c.log.Infof("Connecting to WebSocket: %s", wsURL)
@@ -169,7 +173,7 @@ func (c *WebSocketClient) Unsubscribe(sessionID int) error {
if c.subscribedSession == sessionID {
c.subscribedSession = 0
}
c.log.Infof("Unsubscribed from session %d", sessionID)
return nil
}
@@ -327,7 +331,7 @@ func (c *WebSocketClient) handleGameAdded(data json.RawMessage) {
// The message parameter should contain the full game announcement including any vote results
func (c *WebSocketClient) broadcastWithRoomCodeImage(message, gameTitle, roomCode string) {
c.log.Infof("🎨 Starting room code image generation and upload for: %s - %s", gameTitle, roomCode)
// Generate room code image (animated GIF) with game title embedded
c.log.Infof("📝 Step 1: Generating image...")
imageData, err := GenerateRoomCodeImage(roomCode, gameTitle)
@@ -360,6 +364,10 @@ func (c *WebSocketClient) broadcastWithRoomCodeImage(message, gameTitle, roomCod
c.log.Infof("✅ Step 2 complete: Uploaded to %s", imageURL)
// Now that upload succeeded, send the full announcement with the message and URL
if c.roomCodeImageDelay > 0 {
c.log.Infof("⏳ Step 3: Waiting %v before broadcasting game announcement...", c.roomCodeImageDelay)
time.Sleep(c.roomCodeImageDelay)
}
c.log.Infof("📢 Step 3: Broadcasting game announcement with URL...")
fullMessage := fmt.Sprintf("%s %s", message, imageURL)
if c.messageCallback != nil {
@@ -369,18 +377,19 @@ func (c *WebSocketClient) broadcastWithRoomCodeImage(message, gameTitle, roomCod
c.log.Error("❌ Step 3 failed: messageCallback is nil")
}
// Send the plaintext room code after 19 seconds (to sync with animation completion)
// Send the plaintext room code after configured delay (to sync with animation completion)
// Capture callback and logger in closure
callback := c.messageCallback
logger := c.log
plainRoomCode := roomCode // Capture room code for plain text message
c.log.Infof("⏰ Step 4: Starting 19-second timer goroutine for plaintext room code...")
plaintextDelay := c.roomCodePlaintextDelay
c.log.Infof("⏰ Step 4: Starting %v timer goroutine for plaintext room code...", plaintextDelay)
go func() {
logger.Infof("⏰ [Goroutine started] Waiting 19 seconds before sending plaintext room code: %s", plainRoomCode)
time.Sleep(19 * time.Second)
logger.Infof("⏰ [19 seconds elapsed] Now sending plaintext room code...")
logger.Infof("⏰ [Goroutine started] Waiting %v before sending plaintext room code: %s", plaintextDelay, plainRoomCode)
time.Sleep(plaintextDelay)
logger.Infof("⏰ [%v elapsed] Now sending plaintext room code...", plaintextDelay)
if callback != nil {
// Send just the room code in plaintext (for easy copy/paste)
plaintextMessage := fmt.Sprintf("Room Code: %s", plainRoomCode)
@@ -391,8 +400,8 @@ func (c *WebSocketClient) broadcastWithRoomCodeImage(message, gameTitle, roomCod
logger.Error("❌ Message callback is nil when trying to send delayed room code")
}
}()
c.log.Infof("✅ Step 4 complete: Goroutine launched, will fire in 19 seconds")
c.log.Infof("✅ Step 4 complete: Goroutine launched, will fire in %v", plaintextDelay)
}
// handleSessionEnded processes session.ended events
@@ -409,14 +418,14 @@ func (c *WebSocketClient) AnnounceSessionEnd() {
lastVote := c.apiClient.GetAndClearLastVoteResponse()
if lastVote != nil {
// Include final vote results
message = fmt.Sprintf("🗳️ Final votes for %s: %d👍 %d👎 (Score: %d)\n🌙 Game Night has ended! Thanks for playing!",
message = fmt.Sprintf("🗳️ Final votes for %s: %d👍 %d👎 (Score: %d)\n🌙 Game Night has ended! Thanks for playing!",
lastVote.Game.Title,
lastVote.Game.Upvotes, lastVote.Game.Downvotes, lastVote.Game.PopularityScore)
} else {
// No votes for final game
message = "🌙 Game Night has ended! Thanks for playing!"
}
// Clear the active session
c.apiClient.SetActiveSession(0)
} else {
@@ -486,10 +495,10 @@ func (c *WebSocketClient) handleDisconnect() {
return
case <-time.After(delay):
c.log.Infof("Reconnecting... (delay: %v)", delay)
if err := c.Connect(); err != nil {
c.log.Errorf("Reconnection failed: %v", err)
// Increase delay with exponential backoff
delay *= 2
if delay > c.maxReconnect {
@@ -500,14 +509,14 @@ func (c *WebSocketClient) handleDisconnect() {
// Reconnected successfully
c.log.Info("Reconnected successfully")
// Re-subscribe if we were subscribed before
if c.subscribedSession > 0 {
if err := c.Subscribe(c.subscribedSession); err != nil {
c.log.Errorf("Failed to re-subscribe: %v", err)
}
}
return
}
}
@@ -545,4 +554,3 @@ func (c *WebSocketClient) IsSubscribed() bool {
defer c.mu.Unlock()
return c.subscribedSession > 0
}