Compare commits

...

3 Commits

7 changed files with 57 additions and 10 deletions

View File

@ -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

View File

@ -74,7 +74,7 @@
"chat": {
"header": "Chat settings",
"cooldown-tip": "Global chat cooldown for commands (in seconds)",
"default-user": "Using stream account, use the button below to authenticate with a different account.",
"default-user": "Currently using stream account, use the button above to authenticate with a different account.",
"chat-account": "Chat account",
"clear-button": "Revert to default account",
"account-copy": "You can use a different account for repling to chat commands and writing alerts instead of your channel one. To do so, click the button below and authenticate and authorize using your secondary account."

View File

@ -341,7 +341,7 @@
"cooldown-tip": "Tempo minimo di attesa tra comandi (in secondi)",
"chat-account": "Account chat",
"header": "Impostazioni chat",
"default-user": "Utilizzando l'account principale, usa il pulsante qui sotto per autenticarti con un account diverso per le funzionalità di chat.",
"default-user": "Utilizzando l'account principale, usa il pulsante qui sopra per autenticarti con un account diverso per le funzionalità di chat.",
"clear-button": "Torna ad usare l'account principale",
"account-copy": "Puoi utilizzare un account diverso per rispondendere ai comandi della chat e invia notifiche al posto di quello del tuo canale. \nPer fare ciò, fai clic sul pulsante in basso e autentica e autorizza l'utilizzo del tuo account secondario."
},

View File

@ -20,7 +20,6 @@ export default function TwitchChatSettings() {
const [chatConfig, setChatConfig, loadStatus] = useModule(
modules.twitchChatConfig,
);
const [twitchConfig, setTwitchConfig] = useModule(modules.twitchConfig);
const kv = useAppSelector((state) => state.api.client);
const authKey = 'twitch/chat/chatter-account';
const authKeyValue = useLiveKeyString('twitch/chat/chatter-account');
@ -32,7 +31,6 @@ export default function TwitchChatSettings() {
return (
<form
onSubmit={(ev) => {
void dispatch(setTwitchConfig(twitchConfig));
void dispatch(setChatConfig(chatConfig));
ev.preventDefault();
}}
@ -44,6 +42,7 @@ export default function TwitchChatSettings() {
<FlexRow align="left" spacing="1" css={{ marginBottom: '1rem' }}>
<Button
variation="primary"
type="button"
onClick={() => {
void startAuthFlow('chat');
}}
@ -53,6 +52,7 @@ export default function TwitchChatSettings() {
{authKeyValue && (
<Button
variation="danger"
type="button"
onClick={() => {
kv.deleteKey(authKey);
}}

4
go.mod
View File

@ -4,8 +4,8 @@ go 1.22
require (
git.sr.ht/~ashkeel/containers v0.3.6
git.sr.ht/~ashkeel/kilovolt-driver-pebble v1.3.3
git.sr.ht/~ashkeel/kilovolt/v12 v12.0.2
git.sr.ht/~ashkeel/kilovolt-driver-pebble v1.3.4
git.sr.ht/~ashkeel/kilovolt/v12 v12.0.3
github.com/Masterminds/sprig/v3 v3.2.3
github.com/apenwarr/fixconsole v0.0.0-20191012055117-5a9f6489cc29
github.com/cockroachdb/pebble v1.1.0

8
go.sum
View File

@ -33,10 +33,10 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
git.sr.ht/~ashkeel/containers v0.3.6 h1:+umWlQGKhLxGQlaEUt/F6rBZGpeBd1T01fM3wro+qTY=
git.sr.ht/~ashkeel/containers v0.3.6/go.mod h1:i2KocnJfRH0FwfgPi4nw7/ehYLEoLlP3iwdDoBeVdME=
git.sr.ht/~ashkeel/kilovolt-driver-pebble v1.3.3 h1:+tu5DBT150HRR2gpVEpQwpTclE3niEsy9IyGqLfUZbQ=
git.sr.ht/~ashkeel/kilovolt-driver-pebble v1.3.3/go.mod h1:Jdf48ldD5UTw8m1AB72H3t0ryUotSeobVkkzrxikYVY=
git.sr.ht/~ashkeel/kilovolt/v12 v12.0.2 h1:8NMO/sKsB9rlkFWxeBwv5mKrUvFEQ4RN7/BOcTgrnqU=
git.sr.ht/~ashkeel/kilovolt/v12 v12.0.2/go.mod h1:dRSJpl6ZXNoTAF3pTMC4AO7MLkRgzQqaZYR8S5a46TI=
git.sr.ht/~ashkeel/kilovolt-driver-pebble v1.3.4 h1:Yi1SqnHBHOMqdKAK7PpWt97vyq6JTytlxCU+Q8JfJ/g=
git.sr.ht/~ashkeel/kilovolt-driver-pebble v1.3.4/go.mod h1:O3o7hvyVwH+AFFk7vWU3YN86dKIGrstii2NJv34MgZc=
git.sr.ht/~ashkeel/kilovolt/v12 v12.0.3 h1:ag9MK/qVLbT5Vq4faJyMg5iUHP+XoRZTHyHgs0lKGak=
git.sr.ht/~ashkeel/kilovolt/v12 v12.0.3/go.mod h1:dRSJpl6ZXNoTAF3pTMC4AO7MLkRgzQqaZYR8S5a46TI=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=

View File

@ -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: