Add support for the Create EventSub Subscription Helix API

This commit is contained in:
Rasmus Karlsson 2023-11-11 12:09:31 +01:00
parent 7d7f1b3bea
commit 33ab6149bf
3 changed files with 193 additions and 0 deletions

View file

@ -392,6 +392,15 @@ public:
(FailureCallback<HelixSendShoutoutError, QString> failureCallback)), (FailureCallback<HelixSendShoutoutError, QString> failureCallback)),
(override)); (override));
MOCK_METHOD(void, createEventSubSubscription,
(const QString &type, const QString &version,
const QString &sessionID, const QJsonObject &condition,
ResultCallback<HelixCreateEventSubSubscriptionResponse>
successCallback,
(FailureCallback<HelixCreateEventSubSubscriptionError, QString>
failureCallback)),
(override));
MOCK_METHOD(void, update, (QString clientId, QString oauthToken), MOCK_METHOD(void, update, (QString clientId, QString oauthToken),
(override)); (override));

View file

@ -2836,6 +2836,115 @@ void Helix::sendShoutout(
.execute(); .execute();
} }
void Helix::createEventSubSubscription(
const QString &type, const QString &version, const QString &sessionID,
const QJsonObject &condition,
ResultCallback<HelixCreateEventSubSubscriptionResponse> successCallback,
FailureCallback<HelixCreateEventSubSubscriptionError, QString>
failureCallback)
{
using Error = HelixCreateEventSubSubscriptionError;
QJsonObject body;
body.insert("type", type);
body.insert("version", version);
body.insert("condition", condition);
QJsonObject transport;
transport.insert("method", "websocket");
transport.insert("session_id", sessionID);
body.insert("transport", transport);
this->makePost("eventsub/subscriptions", {})
.json(body)
.onSuccess([successCallback](const auto &result) {
if (result.status() != 202)
{
qCWarning(chatterinoTwitch)
<< "Success result for creating eventsub subscription was "
<< result.formatError() << "but we expected it to be 202";
}
HelixCreateEventSubSubscriptionResponse response(
result.parseJson());
successCallback(response);
})
.onError([failureCallback](const NetworkResult &result) {
if (!result.status())
{
failureCallback(Error::Forwarded, result.formatError());
return;
}
const auto obj = result.parseJson();
auto message = obj["message"].toString();
switch (*result.status())
{
case 400: {
failureCallback(Error::BadRequest, message);
}
break;
case 401: {
failureCallback(Error::Unauthorized, message);
}
break;
case 403: {
failureCallback(Error::Forbidden, message);
}
break;
case 429: {
failureCallback(Error::Ratelimited, message);
}
break;
case 500: {
if (message.isEmpty())
{
failureCallback(Error::Forwarded,
"Twitch internal server error");
}
else
{
failureCallback(Error::Forwarded, message);
}
}
break;
default: {
qCWarning(chatterinoTwitch)
<< "Helix Create EventSub Subscription, unhandled "
"error data:"
<< result.formatError() << result.getData() << obj;
failureCallback(Error::Forwarded, message);
}
}
})
.execute();
}
QDebug &operator<<(QDebug &dbg,
const HelixCreateEventSubSubscriptionResponse &data)
{
dbg << "HelixCreateEventSubSubscriptionResponse{ id:" << data.subscriptionID
<< "status:" << data.subscriptionStatus
<< "type:" << data.subscriptionType
<< "version:" << data.subscriptionVersion
<< "condition:" << data.subscriptionCondition
<< "createdAt:" << data.subscriptionCreatedAt
<< "sessionID:" << data.subscriptionSessionID
<< "connectedAt:" << data.subscriptionConnectedAt
<< "cost:" << data.subscriptionCost << "total:" << data.total
<< "totalCost:" << data.totalCost
<< "maxTotalCost:" << data.maxTotalCost << '}';
return dbg;
}
NetworkRequest Helix::makeRequest(const QString &url, const QUrlQuery &urlQuery, NetworkRequest Helix::makeRequest(const QString &url, const QUrlQuery &urlQuery,
NetworkRequestType type) NetworkRequestType type)
{ {

View file

@ -706,6 +706,65 @@ struct HelixError {
using HelixGetChannelBadgesError = HelixGetGlobalBadgesError; using HelixGetChannelBadgesError = HelixGetGlobalBadgesError;
struct HelixCreateEventSubSubscriptionResponse {
QString subscriptionID;
QString subscriptionStatus;
QString subscriptionType;
QString subscriptionVersion;
QJsonObject subscriptionCondition;
QString subscriptionCreatedAt;
QString subscriptionSessionID;
QString subscriptionConnectedAt;
int subscriptionCost;
int total;
int totalCost;
int maxTotalCost;
explicit HelixCreateEventSubSubscriptionResponse(
const QJsonObject &jsonObject)
{
{
auto jsonData = jsonObject.value("data").toArray().at(0).toObject();
this->subscriptionID = jsonData.value("id").toString();
this->subscriptionStatus = jsonData.value("status").toString();
this->subscriptionType = jsonData.value("type").toString();
this->subscriptionVersion = jsonData.value("version").toString();
this->subscriptionCondition =
jsonData.value("condition").toObject();
this->subscriptionCreatedAt =
jsonData.value("created_at").toString();
this->subscriptionSessionID = jsonData.value("transport")
.toObject()
.value("session_id")
.toString();
this->subscriptionConnectedAt = jsonData.value("transport")
.toObject()
.value("connected_at")
.toString();
this->subscriptionCost = jsonData.value("cost").toInt();
}
this->total = jsonObject.value("total").toInt();
this->totalCost = jsonObject.value("total_cost").toInt();
this->maxTotalCost = jsonObject.value("max_total_cost").toInt();
}
friend QDebug &operator<<(
QDebug &dbg, const HelixCreateEventSubSubscriptionResponse &data);
};
enum class HelixCreateEventSubSubscriptionError {
BadRequest,
Unauthorized,
Forbidden,
Conflict,
Ratelimited,
// The error message is forwarded directly from the Twitch API
Forwarded,
};
class IHelix class IHelix
{ {
public: public:
@ -1019,6 +1078,14 @@ public:
ResultCallback<> successCallback, ResultCallback<> successCallback,
FailureCallback<HelixSendShoutoutError, QString> failureCallback) = 0; FailureCallback<HelixSendShoutoutError, QString> failureCallback) = 0;
// https://dev.twitch.tv/docs/api/reference/#create-eventsub-subscription
virtual void createEventSubSubscription(
const QString &type, const QString &version, const QString &sessionID,
const QJsonObject &condition,
ResultCallback<HelixCreateEventSubSubscriptionResponse> successCallback,
FailureCallback<HelixCreateEventSubSubscriptionError, QString>
failureCallback) = 0;
virtual void update(QString clientId, QString oauthToken) = 0; virtual void update(QString clientId, QString oauthToken) = 0;
protected: protected:
@ -1333,6 +1400,14 @@ public:
ResultCallback<> successCallback, ResultCallback<> successCallback,
FailureCallback<HelixSendShoutoutError, QString> failureCallback) final; FailureCallback<HelixSendShoutoutError, QString> failureCallback) final;
// https://dev.twitch.tv/docs/api/reference/#create-eventsub-subscription
void createEventSubSubscription(
const QString &type, const QString &version, const QString &sessionID,
const QJsonObject &condition,
ResultCallback<HelixCreateEventSubSubscriptionResponse> successCallback,
FailureCallback<HelixCreateEventSubSubscriptionError, QString>
failureCallback) final;
void update(QString clientId, QString oauthToken) final; void update(QString clientId, QString oauthToken) final;
static void initialize(); static void initialize();