From fe029996638ac8cfd951d67cab4f9243cbe71673 Mon Sep 17 00:00:00 2001 From: Ash Keel Date: Sat, 20 Apr 2024 16:07:54 +0200 Subject: [PATCH] feat: add old subscription cleanup routine --- CHANGELOG.md | 2 ++ twitch/eventsub/client.go | 45 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1633269..3263beb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,10 +22,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The Twitch chat integration has been rewritten from the ground up to not use an IRC bot and rely on EventSub. This means that you will need to reconfigure your twitch account, especially if you used a different account as the "bot" account. Because of this rewrite, the terminology around chat functionalities have been renamed from "Bot" to "Chat" (e.g. "Bot commands" are now "Chat commands"). - The (i) icon next to "Recent events" in the dashboard now uses a custom tooltip that shows up more consistently. - The "strimertul is already running" message now pops up from the currently running instance. +- Setting up a secondary user for chat interactions is now much simpler through an auth flow much like the one for setting up the main user. ### Fixed - Updated Kilovolt to a version that fixes an annoying crash when managing subscriptions. +- A new cleanup routine will remove old eventsub subscriptions that are no longer used. This should remove most of the errors when trying to set new API keys about "too many subscriptions". ### Removed diff --git a/twitch/eventsub/client.go b/twitch/eventsub/client.go index b6120b2..7aa7ea7 100644 --- a/twitch/eventsub/client.go +++ b/twitch/eventsub/client.go @@ -51,6 +51,9 @@ func Setup(ctx context.Context, twitchAPI *helix.Client, user helix.User, db dat } func (c *Client) eventSubLoop() { + // Cleanup subscriptions for dead sessions so we don't get hit by the sub limit + go c.cleanupSubscriptions() + endpoint := websocketEndpoint var err error var connection *websocket.Conn @@ -231,6 +234,48 @@ func (c *Client) addSubscriptionsForSession(session string) error { return nil } +func (c *Client) cleanupSubscriptions() { + // Clear all subscriptions for dead/broken sessions + c.cleanupSubscriptionForStatus("websocket_disconnected") + c.cleanupSubscriptionForStatus("websocket_failed_ping_pong") + c.cleanupSubscriptionForStatus("websocket_received_inbound_traffic") + c.cleanupSubscriptionForStatus("websocket_connection_unused") + c.cleanupSubscriptionForStatus("websocket_internal_error") + c.cleanupSubscriptionForStatus("websocket_network_timeout") + c.cleanupSubscriptionForStatus("websocket_network_error") + c.cleanupSubscriptionForStatus("websocket_failed_to_reconnect") +} + +func (c *Client) cleanupSubscriptionForStatus(status string) { + var cursor string + for { + subscriptions, err := c.twitchAPI.GetEventSubSubscriptions(&helix.EventSubSubscriptionsParams{ + Status: status, + After: cursor, + }) + if err != nil { + c.logger.Warn("Could not get subscriptions for status", slog.String("status", status), log.Error(err)) + } + + // Unsubscribe from all subscriptions for dead sessions + for _, sub := range subscriptions.Data.EventSubSubscriptions { + res, err := c.twitchAPI.RemoveEventSubSubscription(sub.ID) + if err != nil { + c.logger.Warn("Could not unsubscribe from dead session", slog.String("session-id", sub.Transport.SessionID), slog.String("subscription-id", sub.ID), log.Error(err)) + } + if res.ErrorMessage != "" { + c.logger.Warn("Could not unsubscribe from dead session", slog.String("session-id", sub.Transport.SessionID), slog.String("subscription-id", sub.ID), slog.String("message", res.ErrorMessage), slog.Int("messageCode", res.ErrorStatus)) + } + } + + // Check for cursor + if subscriptions.Data.Pagination.Cursor == "" { + break + } + cursor = subscriptions.Data.Pagination.Cursor + } +} + func topicCondition(topic string, id string) helix.EventSubCondition { switch topic { case helix.EventSubTypeChannelRaid: