Add connection resilience and reconnect commands for Kosmi and Jackbox
Kosmi WebSocket would silently die after hours/days with no reconnection. Jackbox WebSocket failed to reconnect after API server restarts (stale JWT) and leaked heartbeat goroutines on each reconnect cycle. Kosmi changes: - Add WebSocket ping/pong keepalive (30s ping, 90s read deadline) - Send EventFailure on unexpected disconnect to trigger gateway reconnectBridge() - Add intentionalDisconnect flag to prevent false failure events on clean shutdown - Fix Disconnect() to be safe for reconnect cycles Jackbox changes: - Add read deadline (90s) to detect stale connections - Fix heartbeat goroutine leak via per-connection listenDone channel - Re-authenticate for fresh JWT before each reconnect attempt - Add Manager.Reconnect() for on-demand teardown and rebuild IRC commands: - !kreconnect - reconnect Kosmi bridge - !jreconnect - reconnect Jackbox WebSocket - !reconnect - reconnect all services (Kosmi + Jackbox) Made-with: Cursor
This commit is contained in:
@@ -242,6 +242,37 @@ func (m *Manager) monitorActiveSessions() {
|
||||
}
|
||||
}
|
||||
|
||||
// Reconnect tears down the existing WebSocket client and establishes a new
|
||||
// connection (re-authenticating for a fresh JWT). Safe to call even when
|
||||
// already disconnected.
|
||||
func (m *Manager) Reconnect() error {
|
||||
if !m.enabled || !m.useWebSocket {
|
||||
return fmt.Errorf("Jackbox WebSocket is not enabled")
|
||||
}
|
||||
|
||||
m.log.Info("Forcing Jackbox WebSocket reconnection...")
|
||||
|
||||
// Tear down existing client
|
||||
if m.wsClient != nil {
|
||||
if err := m.wsClient.Close(); err != nil {
|
||||
m.log.Errorf("Error closing existing WebSocket client: %v", err)
|
||||
}
|
||||
m.wsClient = nil
|
||||
}
|
||||
|
||||
// Re-authenticate for a fresh JWT
|
||||
if err := m.client.Authenticate(); err != nil {
|
||||
return fmt.Errorf("re-authentication failed: %w", err)
|
||||
}
|
||||
|
||||
// Rebuild the WebSocket client using the original callback
|
||||
if m.messageCallback == nil {
|
||||
return fmt.Errorf("no message callback registered")
|
||||
}
|
||||
|
||||
return m.startWebSocketClient(m.messageCallback)
|
||||
}
|
||||
|
||||
// GetClient returns the Jackbox API client (may be nil if disabled)
|
||||
func (m *Manager) GetClient() *Client {
|
||||
return m.client
|
||||
|
||||
Reference in New Issue
Block a user