feat(eventsub): add basic parse tests and benchmark (#5952)
This commit is contained in:
@@ -471,17 +471,17 @@ boost::json::result_for<Resubscription, boost::json::value>::type tag_invoke(
|
||||
|
||||
static_assert(std::is_trivially_copyable_v<std::remove_reference_t<
|
||||
decltype(std::declval<Resubscription>().isPrime)>>);
|
||||
std::optional<bool> isPrime = std::nullopt;
|
||||
const auto *jvisPrime = root.if_contains("is_prime");
|
||||
if (jvisPrime == nullptr)
|
||||
if (jvisPrime != nullptr && !jvisPrime->is_null())
|
||||
{
|
||||
EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
|
||||
}
|
||||
auto tisPrime = boost::json::try_value_to<bool>(*jvisPrime);
|
||||
|
||||
auto isPrime = boost::json::try_value_to<bool>(*jvisPrime);
|
||||
|
||||
if (isPrime.has_error())
|
||||
{
|
||||
return isPrime.error();
|
||||
if (tisPrime.has_error())
|
||||
{
|
||||
return tisPrime.error();
|
||||
}
|
||||
isPrime = tisPrime.value();
|
||||
}
|
||||
|
||||
static_assert(std::is_trivially_copyable_v<std::remove_reference_t<
|
||||
@@ -502,18 +502,18 @@ boost::json::result_for<Resubscription, boost::json::value>::type tag_invoke(
|
||||
static_assert(
|
||||
std::is_trivially_copyable_v<std::remove_reference_t<
|
||||
decltype(std::declval<Resubscription>().gifterIsAnonymous)>>);
|
||||
std::optional<bool> gifterIsAnonymous = std::nullopt;
|
||||
const auto *jvgifterIsAnonymous = root.if_contains("gifter_is_anonymous");
|
||||
if (jvgifterIsAnonymous == nullptr)
|
||||
if (jvgifterIsAnonymous != nullptr && !jvgifterIsAnonymous->is_null())
|
||||
{
|
||||
EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
|
||||
}
|
||||
auto tgifterIsAnonymous =
|
||||
boost::json::try_value_to<bool>(*jvgifterIsAnonymous);
|
||||
|
||||
auto gifterIsAnonymous =
|
||||
boost::json::try_value_to<bool>(*jvgifterIsAnonymous);
|
||||
|
||||
if (gifterIsAnonymous.has_error())
|
||||
{
|
||||
return gifterIsAnonymous.error();
|
||||
if (tgifterIsAnonymous.has_error())
|
||||
{
|
||||
return tgifterIsAnonymous.error();
|
||||
}
|
||||
gifterIsAnonymous = tgifterIsAnonymous.value();
|
||||
}
|
||||
|
||||
std::optional<std::string> gifterUserID = std::nullopt;
|
||||
@@ -563,9 +563,9 @@ boost::json::result_for<Resubscription, boost::json::value>::type tag_invoke(
|
||||
.durationMonths = durationMonths.value(),
|
||||
.streakMonths = streakMonths,
|
||||
.subTier = std::move(subTier.value()),
|
||||
.isPrime = isPrime.value(),
|
||||
.isPrime = isPrime,
|
||||
.isGift = isGift.value(),
|
||||
.gifterIsAnonymous = gifterIsAnonymous.value(),
|
||||
.gifterIsAnonymous = gifterIsAnonymous,
|
||||
.gifterUserID = std::move(gifterUserID),
|
||||
.gifterUserName = std::move(gifterUserName),
|
||||
.gifterUserLogin = std::move(gifterUserLogin),
|
||||
@@ -1327,46 +1327,46 @@ boost::json::result_for<Event, boost::json::value>::type tag_invoke(
|
||||
return broadcasterUserName.error();
|
||||
}
|
||||
|
||||
std::optional<std::string> chatterUserID = std::nullopt;
|
||||
const auto *jvchatterUserID = root.if_contains("chatter_user_id");
|
||||
if (jvchatterUserID == nullptr)
|
||||
if (jvchatterUserID != nullptr && !jvchatterUserID->is_null())
|
||||
{
|
||||
EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
|
||||
}
|
||||
|
||||
auto chatterUserID =
|
||||
boost::json::try_value_to<std::string>(*jvchatterUserID);
|
||||
|
||||
if (chatterUserID.has_error())
|
||||
{
|
||||
return chatterUserID.error();
|
||||
auto tchatterUserID =
|
||||
boost::json::try_value_to<std::string>(*jvchatterUserID);
|
||||
|
||||
if (tchatterUserID.has_error())
|
||||
{
|
||||
return tchatterUserID.error();
|
||||
}
|
||||
chatterUserID = std::move(tchatterUserID.value());
|
||||
}
|
||||
|
||||
std::optional<std::string> chatterUserLogin = std::nullopt;
|
||||
const auto *jvchatterUserLogin = root.if_contains("chatter_user_login");
|
||||
if (jvchatterUserLogin == nullptr)
|
||||
if (jvchatterUserLogin != nullptr && !jvchatterUserLogin->is_null())
|
||||
{
|
||||
EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
|
||||
}
|
||||
|
||||
auto chatterUserLogin =
|
||||
boost::json::try_value_to<std::string>(*jvchatterUserLogin);
|
||||
|
||||
if (chatterUserLogin.has_error())
|
||||
{
|
||||
return chatterUserLogin.error();
|
||||
auto tchatterUserLogin =
|
||||
boost::json::try_value_to<std::string>(*jvchatterUserLogin);
|
||||
|
||||
if (tchatterUserLogin.has_error())
|
||||
{
|
||||
return tchatterUserLogin.error();
|
||||
}
|
||||
chatterUserLogin = std::move(tchatterUserLogin.value());
|
||||
}
|
||||
|
||||
std::optional<std::string> chatterUserName = std::nullopt;
|
||||
const auto *jvchatterUserName = root.if_contains("chatter_user_name");
|
||||
if (jvchatterUserName == nullptr)
|
||||
if (jvchatterUserName != nullptr && !jvchatterUserName->is_null())
|
||||
{
|
||||
EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
|
||||
}
|
||||
auto tchatterUserName =
|
||||
boost::json::try_value_to<std::string>(*jvchatterUserName);
|
||||
|
||||
auto chatterUserName =
|
||||
boost::json::try_value_to<std::string>(*jvchatterUserName);
|
||||
|
||||
if (chatterUserName.has_error())
|
||||
{
|
||||
return chatterUserName.error();
|
||||
if (tchatterUserName.has_error())
|
||||
{
|
||||
return tchatterUserName.error();
|
||||
}
|
||||
chatterUserName = std::move(tchatterUserName.value());
|
||||
}
|
||||
|
||||
static_assert(std::is_trivially_copyable_v<std::remove_reference_t<
|
||||
@@ -1656,9 +1656,9 @@ boost::json::result_for<Event, boost::json::value>::type tag_invoke(
|
||||
.broadcasterUserID = std::move(broadcasterUserID.value()),
|
||||
.broadcasterUserLogin = std::move(broadcasterUserLogin.value()),
|
||||
.broadcasterUserName = std::move(broadcasterUserName.value()),
|
||||
.chatterUserID = std::move(chatterUserID.value()),
|
||||
.chatterUserLogin = std::move(chatterUserLogin.value()),
|
||||
.chatterUserName = std::move(chatterUserName.value()),
|
||||
.chatterUserID = std::move(chatterUserID),
|
||||
.chatterUserLogin = std::move(chatterUserLogin),
|
||||
.chatterUserName = std::move(chatterUserName),
|
||||
.chatterIsAnonymous = chatterIsAnonymous.value(),
|
||||
.color = std::move(color.value()),
|
||||
.badges = std::move(vbadges),
|
||||
|
||||
@@ -32,14 +32,15 @@ using EventSubSubscription = std::pair<std::string, std::string>;
|
||||
|
||||
using NotificationHandlers = std::unordered_map<
|
||||
EventSubSubscription,
|
||||
std::function<void(messages::Metadata, boost::json::value,
|
||||
std::unique_ptr<Listener> &)>,
|
||||
std::function<boost::system::error_code(
|
||||
messages::Metadata, boost::json::value, std::unique_ptr<Listener> &)>,
|
||||
boost::hash<EventSubSubscription>>;
|
||||
|
||||
using MessageHandlers = std::unordered_map<
|
||||
std::string, std::function<void(messages::Metadata, boost::json::value,
|
||||
std::unique_ptr<Listener> &,
|
||||
const NotificationHandlers &)>>;
|
||||
using MessageHandlers =
|
||||
std::unordered_map<std::string, std::function<boost::system::error_code(
|
||||
messages::Metadata, boost::json::value,
|
||||
std::unique_ptr<Listener> &,
|
||||
const NotificationHandlers &)>>;
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -51,13 +52,12 @@ namespace {
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::optional<T> parsePayload(const boost::json::value &jv)
|
||||
boost::system::result<T> parsePayload(const boost::json::value &jv)
|
||||
{
|
||||
auto result = boost::json::try_value_to<T>(jv);
|
||||
if (!result.has_value())
|
||||
{
|
||||
fail(result.error(), "parsing payload");
|
||||
return std::nullopt;
|
||||
return result.error();
|
||||
}
|
||||
|
||||
return std::move(result.value());
|
||||
@@ -72,9 +72,10 @@ namespace {
|
||||
parsePayload<payload::channel_ban::v1::Payload>(jv);
|
||||
if (!oPayload)
|
||||
{
|
||||
return;
|
||||
return oPayload.error();
|
||||
}
|
||||
listener->onChannelBan(metadata, *oPayload);
|
||||
return boost::system::error_code{};
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -84,9 +85,10 @@ namespace {
|
||||
parsePayload<payload::stream_online::v1::Payload>(jv);
|
||||
if (!oPayload)
|
||||
{
|
||||
return;
|
||||
return oPayload.error();
|
||||
}
|
||||
listener->onStreamOnline(metadata, *oPayload);
|
||||
return boost::system::error_code{};
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -96,9 +98,10 @@ namespace {
|
||||
parsePayload<payload::stream_offline::v1::Payload>(jv);
|
||||
if (!oPayload)
|
||||
{
|
||||
return;
|
||||
return oPayload.error();
|
||||
}
|
||||
listener->onStreamOffline(metadata, *oPayload);
|
||||
return boost::system::error_code{};
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -108,9 +111,10 @@ namespace {
|
||||
payload::channel_chat_notification::v1::Payload>(jv);
|
||||
if (!oPayload)
|
||||
{
|
||||
return;
|
||||
return oPayload.error();
|
||||
}
|
||||
listener->onChannelChatNotification(metadata, *oPayload);
|
||||
return boost::system::error_code{};
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -120,9 +124,10 @@ namespace {
|
||||
parsePayload<payload::channel_update::v1::Payload>(jv);
|
||||
if (!oPayload)
|
||||
{
|
||||
return;
|
||||
return oPayload.error();
|
||||
}
|
||||
listener->onChannelUpdate(metadata, *oPayload);
|
||||
return boost::system::error_code{};
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -133,9 +138,10 @@ namespace {
|
||||
jv);
|
||||
if (!oPayload)
|
||||
{
|
||||
return;
|
||||
return oPayload.error();
|
||||
}
|
||||
listener->onChannelChatMessage(metadata, *oPayload);
|
||||
return boost::system::error_code{};
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -145,9 +151,10 @@ namespace {
|
||||
parsePayload<payload::channel_moderate::v2::Payload>(jv);
|
||||
if (!oPayload)
|
||||
{
|
||||
return;
|
||||
return oPayload.error();
|
||||
}
|
||||
listener->onChannelModerate(metadata, std::move(*oPayload));
|
||||
return boost::system::error_code{};
|
||||
},
|
||||
},
|
||||
// Add your new subscription types above this line
|
||||
@@ -163,11 +170,12 @@ namespace {
|
||||
if (!oPayload)
|
||||
{
|
||||
// TODO: error handling
|
||||
return;
|
||||
return oPayload.error();
|
||||
}
|
||||
const auto &payload = *oPayload;
|
||||
|
||||
listener->onSessionWelcome(metadata, payload);
|
||||
return boost::system::error_code{};
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -175,6 +183,7 @@ namespace {
|
||||
[](const auto &metadata, const auto &jv, auto &listener,
|
||||
const auto ¬ificationHandlers) {
|
||||
// TODO: should we do something here?
|
||||
return boost::system::error_code{};
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -186,7 +195,7 @@ namespace {
|
||||
if (!metadata.subscriptionType || !metadata.subscriptionVersion)
|
||||
{
|
||||
// TODO: error handling
|
||||
return;
|
||||
return boost::system::error_code{};
|
||||
}
|
||||
|
||||
auto it =
|
||||
@@ -194,11 +203,10 @@ namespace {
|
||||
*metadata.subscriptionVersion});
|
||||
if (it == notificationHandlers.end())
|
||||
{
|
||||
// TODO: error handling
|
||||
return;
|
||||
EVENTSUB_BAIL_HERE(error::Kind::NoMessageHandler);
|
||||
}
|
||||
|
||||
it->second(metadata, jv, listener);
|
||||
return it->second(metadata, jv, listener);
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -251,9 +259,8 @@ boost::system::error_code handleMessage(std::unique_ptr<Listener> &listener,
|
||||
EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
|
||||
}
|
||||
|
||||
handler->second(metadata, *payloadV, listener, NOTIFICATION_HANDLERS);
|
||||
|
||||
return {};
|
||||
return handler->second(metadata, *payloadV, listener,
|
||||
NOTIFICATION_HANDLERS);
|
||||
}
|
||||
|
||||
// Resolver and socket require an io_context
|
||||
@@ -396,7 +403,7 @@ void Session::onRead(beast::error_code ec, std::size_t bytes_transferred)
|
||||
auto messageError = handleMessage(this->listener, this->buffer);
|
||||
if (messageError)
|
||||
{
|
||||
return fail(messageError, "handleMessage");
|
||||
fail(messageError, "handleMessage");
|
||||
}
|
||||
|
||||
this->buffer.clear();
|
||||
|
||||
Reference in New Issue
Block a user