Fix race condition in Twitch event sub reconnection logic

This commit is contained in:
WarmUpTill 2026-05-29 19:35:06 +02:00 committed by WarmUpTill
parent ea2d1e7e9d
commit baf3d0e63c

View File

@ -262,12 +262,21 @@ std::string EventSub::AddEventSubscription(std::shared_ptr<TwitchToken> token,
return "";
}
// Capture the session ID and release the lock before making the HTTP
// request. Holding the mutex during a network call would block
// SubscriptionIsActive() on the condition-check thread for the entire
// duration of the request, causing visibly slow macro evaluations.
const std::string sessionID = eventSub->_sessionID;
lock.unlock();
OBSDataAutoRelease postData = copyData(subscription.data);
setTransportData(postData.Get(), eventSub->_sessionID);
setTransportData(postData.Get(), sessionID);
auto result = SendPostRequest(*token, registerSubscriptionURL.data(),
registerSubscriptionPath.data(), {},
postData.Get());
lock.lock();
if (result.status != 202) {
const char *error = obs_data_get_string(result.data, "error");
const char *message =
@ -280,6 +289,24 @@ std::string EventSub::AddEventSubscription(std::shared_ptr<TwitchToken> token,
return "";
}
// Verify the session has not been replaced while the HTTP request was
// in flight (e.g. a reconnect occurred). If it was, the subscription
// we just created belongs to a dead session and must be discarded so
// the caller will retry with the new session ID.
if (eventSub->_sessionID != sessionID) {
blog(LOG_INFO,
"discarding Twitch EventSub registration - session ID "
"changed during HTTP request");
return "";
}
// Another thread may have registered the same subscription while the
// lock was released.
if (isAlreadySubscribed(eventSub->_activeSubscriptions, subscription)) {
eventSub->LogActiveSubscriptions();
return eventSub->_activeSubscriptions.find(subscription)->id;
}
OBSDataArrayAutoRelease replyArray =
obs_data_get_array(result.data, "data");
OBSDataAutoRelease replyData = obs_data_array_item(replyArray, 0);
@ -439,9 +466,10 @@ void EventSub::OnMessage(connection_hdl, EventSubWSClient::message_ptr message)
void EventSub::HandleWelcome(obs_data_t *data)
{
std::lock_guard<std::mutex> lock(_subscriptionMtx);
OBSDataAutoRelease session = obs_data_get_obj(data, "session");
_sessionID = obs_data_get_string(session, "id");
ClearActiveSubscriptions();
_activeSubscriptions.clear();
blog(LOG_INFO, "Twitch EventSub connected");
vblog(LOG_INFO, "Twitch EventSub session id: %s", _sessionID.c_str());
}