From 95b97f42e6f09050a6e80e4ebd26f17785129f2e Mon Sep 17 00:00:00 2001 From: nerix Date: Thu, 27 Feb 2025 21:53:48 +0100 Subject: [PATCH] feat(eventsub): add `automod.message.*` and `channel.suspicious_user.*` (#6003) --- CHANGELOG.md | 2 +- lib/twitch-eventsub-ws/ast/lib/member.py | 4 + .../ast/lib/templates/field-variant.tmpl | 10 +- .../benchmarks/src/parse.cpp | 34 ++ .../include/twitch-eventsub-ws/listener.hpp | 21 ++ .../payloads/automod-message-hold-v2.hpp | 42 +++ .../payloads/automod-message-hold-v2.inc | 5 + .../payloads/automod-message-update-v2.hpp | 50 +++ .../payloads/automod-message-update-v2.inc | 5 + .../payloads/automod-message.hpp | 41 +++ .../payloads/automod-message.inc | 13 + .../payloads/channel-chat-message-v1.hpp | 35 +- .../payloads/channel-chat-message-v1.inc | 16 - .../payloads/channel-chat-notification-v1.hpp | 35 +- .../payloads/channel-chat-notification-v1.inc | 16 - .../channel-suspicious-user-message-v1.hpp | 46 +++ .../channel-suspicious-user-message-v1.inc | 5 + .../channel-suspicious-user-update-v1.hpp | 40 +++ .../channel-suspicious-user-update-v1.inc | 5 + .../payloads/structured-message.hpp | 54 +++ .../payloads/structured-message.inc | 18 + lib/twitch-eventsub-ws/src/CMakeLists.txt | 6 + .../payloads/automod-message-hold-v2.cpp | 253 ++++++++++++++ .../payloads/automod-message-update-v2.cpp | 312 +++++++++++++++++ .../generated/payloads/automod-message.cpp | 242 +++++++++++++ .../payloads/channel-chat-message-v1.cpp | 323 +----------------- .../payloads/channel-chat-notification-v1.cpp | 323 +----------------- .../channel-suspicious-user-message-v1.cpp | 238 +++++++++++++ .../channel-suspicious-user-update-v1.cpp | 218 ++++++++++++ .../generated/payloads/structured-message.cpp | 318 +++++++++++++++++ lib/twitch-eventsub-ws/src/session.cpp | 54 +++ .../messages/automod.message.hold.json | 71 ++++ .../messages/automod.message.update.json | 75 ++++ .../channel.suspicious_user.message.json | 61 ++++ .../channel.suspicious_user.update.json | 36 ++ lib/twitch-eventsub-ws/tests/src/parse.cpp | 23 ++ src/providers/twitch/eventsub/Connection.cpp | 35 ++ src/providers/twitch/eventsub/Connection.hpp | 20 ++ 38 files changed, 2357 insertions(+), 748 deletions(-) create mode 100644 lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/automod-message-hold-v2.hpp create mode 100644 lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/automod-message-hold-v2.inc create mode 100644 lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/automod-message-update-v2.hpp create mode 100644 lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/automod-message-update-v2.inc create mode 100644 lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/automod-message.hpp create mode 100644 lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/automod-message.inc create mode 100644 lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-suspicious-user-message-v1.hpp create mode 100644 lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-suspicious-user-message-v1.inc create mode 100644 lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-suspicious-user-update-v1.hpp create mode 100644 lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-suspicious-user-update-v1.inc create mode 100644 lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/structured-message.hpp create mode 100644 lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/structured-message.inc create mode 100644 lib/twitch-eventsub-ws/src/generated/payloads/automod-message-hold-v2.cpp create mode 100644 lib/twitch-eventsub-ws/src/generated/payloads/automod-message-update-v2.cpp create mode 100644 lib/twitch-eventsub-ws/src/generated/payloads/automod-message.cpp create mode 100644 lib/twitch-eventsub-ws/src/generated/payloads/channel-suspicious-user-message-v1.cpp create mode 100644 lib/twitch-eventsub-ws/src/generated/payloads/channel-suspicious-user-update-v1.cpp create mode 100644 lib/twitch-eventsub-ws/src/generated/payloads/structured-message.cpp create mode 100644 lib/twitch-eventsub-ws/tests/resources/messages/automod.message.hold.json create mode 100644 lib/twitch-eventsub-ws/tests/resources/messages/automod.message.update.json create mode 100644 lib/twitch-eventsub-ws/tests/resources/messages/channel.suspicious_user.message.json create mode 100644 lib/twitch-eventsub-ws/tests/resources/messages/channel.suspicious_user.update.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 085546a6..3a58bff5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,7 +30,7 @@ - Bugfix: Fixed the input font not immediately updating when zooming in/out. (#5960) - Bugfix: Fixed color input thinking blue is also red. (#5982) - Dev: Subscriptions to PubSub channel points redemption topics now use no auth token, making it continue to work during PubSub shutdown. (#5947) -- Dev: Add initial experimental EventSub support. (#5837, #5895, #5897, #5904, #5910, #5903, #5915, #5916, #5930, #5935, #5932, #5943, #5952, #5953, #5968, #5973, #5974, #5980, #5981, #5985, #5990, #5992, #5993, #5996, #5995, #6000, #6001, #6002) +- Dev: Add initial experimental EventSub support. (#5837, #5895, #5897, #5904, #5910, #5903, #5915, #5916, #5930, #5935, #5932, #5943, #5952, #5953, #5968, #5973, #5974, #5980, #5981, #5985, #5990, #5992, #5993, #5996, #5995, #6000, #6001, #6002, #6003) - Dev: Remove unneeded platform specifier for toasts. (#5914) - Dev: Highlight checks now use non-capturing groups for the boundaries. (#5784) - Dev: Removed unused PubSub whisper code. (#5898) diff --git a/lib/twitch-eventsub-ws/ast/lib/member.py b/lib/twitch-eventsub-ws/ast/lib/member.py index 04ffa9b1..29f20b0e 100644 --- a/lib/twitch-eventsub-ws/ast/lib/member.py +++ b/lib/twitch-eventsub-ws/ast/lib/member.py @@ -61,6 +61,10 @@ class VariantType: trivial: bool empty: bool + @property + def id(self) -> str: + return self.name.replace(":", "") + class Member: def __init__( diff --git a/lib/twitch-eventsub-ws/ast/lib/templates/field-variant.tmpl b/lib/twitch-eventsub-ws/ast/lib/templates/field-variant.tmpl index 74a12138..cc1c1699 100644 --- a/lib/twitch-eventsub-ws/ast/lib/templates/field-variant.tmpl +++ b/lib/twitch-eventsub-ws/ast/lib/templates/field-variant.tmpl @@ -26,15 +26,15 @@ decltype(std::declval<{{struct.full_name}}>().{{field.name}}) {{field.name}}; { EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); } - auto {{field.name}}{{type.name}} = boost::json::try_value_to<{{type.name}}>(*{{field.name}}Val); - if ({{field.name}}{{type.name}}.has_error()) + auto {{field.name}}{{type.id}} = boost::json::try_value_to<{{type.name}}>(*{{field.name}}Val); + if ({{field.name}}{{type.id}}.has_error()) { - return {{field.name}}{{type.name}}.error(); + return {{field.name}}{{type.id}}.error(); } {% if type.trivial -%} - {{field.name}}.emplace<{{type.name}}>({{field.name}}{{type.name}}.value()); + {{field.name}}.emplace<{{type.name}}>({{field.name}}{{type.id}}.value()); {%- else -%} - {{field.name}}.emplace<{{type.name}}>(std::move({{field.name}}{{type.name}}.value())); + {{field.name}}.emplace<{{type.name}}>(std::move({{field.name}}{{type.id}}.value())); {%- endif %} {%- endif -%} } diff --git a/lib/twitch-eventsub-ws/benchmarks/src/parse.cpp b/lib/twitch-eventsub-ws/benchmarks/src/parse.cpp index bc064f42..e23e4b99 100644 --- a/lib/twitch-eventsub-ws/benchmarks/src/parse.cpp +++ b/lib/twitch-eventsub-ws/benchmarks/src/parse.cpp @@ -111,6 +111,40 @@ public: benchmark::DoNotOptimize(&metadata); benchmark::DoNotOptimize(&payload); } + + void onAutomodMessageHold( + const messages::Metadata &metadata, + const payload::automod_message_hold::v2::Payload &payload) override + { + benchmark::DoNotOptimize(&metadata); + benchmark::DoNotOptimize(&payload); + } + + void onAutomodMessageUpdate( + const messages::Metadata &metadata, + const payload::automod_message_update::v2::Payload &payload) override + { + benchmark::DoNotOptimize(&metadata); + benchmark::DoNotOptimize(&payload); + } + + void onChannelSuspiciousUserMessage( + const messages::Metadata &metadata, + const payload::channel_suspicious_user_message::v1::Payload &payload) + override + { + benchmark::DoNotOptimize(&metadata); + benchmark::DoNotOptimize(&payload); + } + + void onChannelSuspiciousUserUpdate( + const messages::Metadata &metadata, + const payload::channel_suspicious_user_update::v1::Payload &payload) + override + { + benchmark::DoNotOptimize(&metadata); + benchmark::DoNotOptimize(&payload); + } // NOLINTEND(cppcoreguidelines-pro-type-const-cast) }; diff --git a/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/listener.hpp b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/listener.hpp index b0b7c2f6..83963358 100644 --- a/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/listener.hpp +++ b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/listener.hpp @@ -1,10 +1,14 @@ #pragma once #include "twitch-eventsub-ws/messages/metadata.hpp" +#include "twitch-eventsub-ws/payloads/automod-message-hold-v2.hpp" +#include "twitch-eventsub-ws/payloads/automod-message-update-v2.hpp" #include "twitch-eventsub-ws/payloads/channel-ban-v1.hpp" #include "twitch-eventsub-ws/payloads/channel-chat-message-v1.hpp" #include "twitch-eventsub-ws/payloads/channel-chat-notification-v1.hpp" #include "twitch-eventsub-ws/payloads/channel-moderate-v2.hpp" +#include "twitch-eventsub-ws/payloads/channel-suspicious-user-message-v1.hpp" +#include "twitch-eventsub-ws/payloads/channel-suspicious-user-update-v1.hpp" #include "twitch-eventsub-ws/payloads/channel-update-v1.hpp" #include "twitch-eventsub-ws/payloads/session-welcome.hpp" #include "twitch-eventsub-ws/payloads/stream-offline-v1.hpp" @@ -53,6 +57,23 @@ public: const messages::Metadata &metadata, const payload::channel_moderate::v2::Payload &payload) = 0; + virtual void onAutomodMessageHold( + const messages::Metadata &metadata, + const payload::automod_message_hold::v2::Payload &payload) = 0; + + virtual void onAutomodMessageUpdate( + const messages::Metadata &metadata, + const payload::automod_message_update::v2::Payload &payload) = 0; + + virtual void onChannelSuspiciousUserMessage( + const messages::Metadata &metadata, + const payload::channel_suspicious_user_message::v1::Payload + &payload) = 0; + + virtual void onChannelSuspiciousUserUpdate( + const messages::Metadata &metadata, + const payload::channel_suspicious_user_update::v1::Payload + &payload) = 0; // Add your new subscription types above this line }; diff --git a/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/automod-message-hold-v2.hpp b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/automod-message-hold-v2.hpp new file mode 100644 index 00000000..0bc87b26 --- /dev/null +++ b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/automod-message-hold-v2.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include "twitch-eventsub-ws/payloads/automod-message.hpp" +#include "twitch-eventsub-ws/payloads/structured-message.hpp" +#include "twitch-eventsub-ws/payloads/subscription.hpp" + +#include + +#include + +namespace chatterino::eventsub::lib::payload::automod_message_hold::v2 { + +struct Event { + // Broadcaster of the channel the message was sent in + std::string broadcasterUserID; + std::string broadcasterUserLogin; + std::string broadcasterUserName; + + // User who sent the message + std::string userID; + std::string userLogin; + std::string userName; + + std::string messageID; + chat::Message message; + + // TODO: use chrono? + std::string heldAt; + + /// json_tag=reason + std::variant reason; +}; + +struct Payload { + subscription::Subscription subscription; + + Event event; +}; + +#include "twitch-eventsub-ws/payloads/automod-message-hold-v2.inc" + +} // namespace chatterino::eventsub::lib::payload::automod_message_hold::v2 diff --git a/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/automod-message-hold-v2.inc b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/automod-message-hold-v2.inc new file mode 100644 index 00000000..9a88467f --- /dev/null +++ b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/automod-message-hold-v2.inc @@ -0,0 +1,5 @@ +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag, const boost::json::value &jvRoot); + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag, const boost::json::value &jvRoot); diff --git a/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/automod-message-update-v2.hpp b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/automod-message-update-v2.hpp new file mode 100644 index 00000000..fdd63b6f --- /dev/null +++ b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/automod-message-update-v2.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include "twitch-eventsub-ws/payloads/automod-message.hpp" +#include "twitch-eventsub-ws/payloads/structured-message.hpp" +#include "twitch-eventsub-ws/payloads/subscription.hpp" + +#include + +#include + +namespace chatterino::eventsub::lib::payload::automod_message_update::v2 { + +struct Event { + // Broadcaster of the channel the message was sent in + std::string broadcasterUserID; + std::string broadcasterUserLogin; + std::string broadcasterUserName; + + // User who sent the message + std::string userID; + std::string userLogin; + std::string userName; + + // Moderator who updated the message (possibly empty) + std::string moderatorUserID; + std::string moderatorUserLogin; + std::string moderatorUserName; + + std::string messageID; + chat::Message message; + + // "Approved", "Denied", or "Expired" + std::string status; + + // TODO: use chrono? + std::string heldAt; + + /// json_tag=reason + std::variant reason; +}; + +struct Payload { + subscription::Subscription subscription; + + Event event; +}; + +#include "twitch-eventsub-ws/payloads/automod-message-update-v2.inc" + +} // namespace chatterino::eventsub::lib::payload::automod_message_update::v2 diff --git a/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/automod-message-update-v2.inc b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/automod-message-update-v2.inc new file mode 100644 index 00000000..9a88467f --- /dev/null +++ b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/automod-message-update-v2.inc @@ -0,0 +1,5 @@ +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag, const boost::json::value &jvRoot); + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag, const boost::json::value &jvRoot); diff --git a/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/automod-message.hpp b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/automod-message.hpp new file mode 100644 index 00000000..10886a96 --- /dev/null +++ b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/automod-message.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include "twitch-eventsub-ws/string.hpp" + +#include + +#include +#include + +namespace chatterino::eventsub::lib::automod { + +struct Boundary { + int startPos; + int endPos; +}; + +struct AutomodReason { + static constexpr std::string_view TAG = "automod"; + + String category; + int level; + std::vector boundaries; +}; + +struct FoundTerm { + std::string termID; + Boundary boundary; + std::string ownerBroadcasterUserID; + std::string ownerBroadcasterUserLogin; + std::string ownerBroadcasterUserName; +}; + +struct BlockedTermReason { + static constexpr std::string_view TAG = "blocked_term"; + + std::vector termsFound; +}; + +#include "twitch-eventsub-ws/payloads/automod-message.inc" + +} // namespace chatterino::eventsub::lib::automod diff --git a/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/automod-message.inc b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/automod-message.inc new file mode 100644 index 00000000..0760c997 --- /dev/null +++ b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/automod-message.inc @@ -0,0 +1,13 @@ +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag, const boost::json::value &jvRoot); + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag, + const boost::json::value &jvRoot); + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag, const boost::json::value &jvRoot); + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag, + const boost::json::value &jvRoot); diff --git a/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-chat-message-v1.hpp b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-chat-message-v1.hpp index a98917b2..cb441b55 100644 --- a/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-chat-message-v1.hpp +++ b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-chat-message-v1.hpp @@ -1,5 +1,6 @@ #pragma once +#include "twitch-eventsub-ws/payloads/structured-message.hpp" #include "twitch-eventsub-ws/payloads/subscription.hpp" #include @@ -60,38 +61,6 @@ struct Badge { std::string info; }; -struct Cheermote { - std::string prefix; - int bits; - int tier; -}; - -struct Emote { - std::string id; - std::string emoteSetID; - std::string ownerID; - std::vector format; -}; - -struct Mention { - std::string userID; - std::string userName; - std::string userLogin; -}; - -struct MessageFragment { - std::string type; - std::string text; - std::optional cheermote; - std::optional emote; - std::optional mention; -}; - -struct Message { - std::string text; - std::vector fragments; -}; - struct Cheer { int bits; }; @@ -127,7 +96,7 @@ struct Event { std::string messageID; std::string messageType; - Message message; + chat::Message message; std::optional cheer; std::optional reply; diff --git a/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-chat-message-v1.inc b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-chat-message-v1.inc index 9fd0868e..51afbd8a 100644 --- a/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-chat-message-v1.inc +++ b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-chat-message-v1.inc @@ -1,22 +1,6 @@ boost::json::result_for::type tag_invoke( boost::json::try_value_to_tag, const boost::json::value &jvRoot); -boost::json::result_for::type tag_invoke( - boost::json::try_value_to_tag, const boost::json::value &jvRoot); - -boost::json::result_for::type tag_invoke( - boost::json::try_value_to_tag, const boost::json::value &jvRoot); - -boost::json::result_for::type tag_invoke( - boost::json::try_value_to_tag, const boost::json::value &jvRoot); - -boost::json::result_for::type tag_invoke( - boost::json::try_value_to_tag, - const boost::json::value &jvRoot); - -boost::json::result_for::type tag_invoke( - boost::json::try_value_to_tag, const boost::json::value &jvRoot); - boost::json::result_for::type tag_invoke( boost::json::try_value_to_tag, const boost::json::value &jvRoot); diff --git a/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-chat-notification-v1.hpp b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-chat-notification-v1.hpp index d467b72b..c20391d5 100644 --- a/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-chat-notification-v1.hpp +++ b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-chat-notification-v1.hpp @@ -1,5 +1,6 @@ #pragma once +#include "twitch-eventsub-ws/payloads/structured-message.hpp" #include "twitch-eventsub-ws/payloads/subscription.hpp" #include @@ -16,33 +17,6 @@ struct Badge { std::string info; }; -struct Cheermote { - std::string prefix; - int bits; - int tier; -}; - -struct Emote { - std::string id; - std::string emoteSetID; - std::string ownerID; - std::vector format; -}; - -struct Mention { - std::string userID; - std::string userName; - std::string userLogin; -}; - -struct MessageFragment { - std::string type; - std::string text; - std::optional cheermote; - std::optional emote; - std::optional mention; -}; - struct Subcription { static constexpr std::string_view TAG = "sub"; @@ -153,11 +127,6 @@ struct BitsBadgeTier { int tier; }; -struct Message { - std::string text; - std::vector fragments; -}; - struct Event { std::string broadcasterUserID; std::string broadcasterUserLogin; @@ -170,7 +139,7 @@ struct Event { std::vector badges; std::string systemMessage; std::string messageID; - Message message; + chat::Message message; /// json_tag=notice_type std::variant::type tag_invoke( boost::json::try_value_to_tag, const boost::json::value &jvRoot); -boost::json::result_for::type tag_invoke( - boost::json::try_value_to_tag, const boost::json::value &jvRoot); - -boost::json::result_for::type tag_invoke( - boost::json::try_value_to_tag, const boost::json::value &jvRoot); - -boost::json::result_for::type tag_invoke( - boost::json::try_value_to_tag, const boost::json::value &jvRoot); - -boost::json::result_for::type tag_invoke( - boost::json::try_value_to_tag, - const boost::json::value &jvRoot); - boost::json::result_for::type tag_invoke( boost::json::try_value_to_tag, const boost::json::value &jvRoot); @@ -64,9 +51,6 @@ boost::json::result_for::type tag_invoke( boost::json::try_value_to_tag, const boost::json::value &jvRoot); -boost::json::result_for::type tag_invoke( - boost::json::try_value_to_tag, const boost::json::value &jvRoot); - boost::json::result_for::type tag_invoke( boost::json::try_value_to_tag, const boost::json::value &jvRoot); diff --git a/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-suspicious-user-message-v1.hpp b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-suspicious-user-message-v1.hpp new file mode 100644 index 00000000..6d8c2788 --- /dev/null +++ b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-suspicious-user-message-v1.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include "twitch-eventsub-ws/payloads/structured-message.hpp" +#include "twitch-eventsub-ws/payloads/subscription.hpp" + +#include + +#include + +namespace chatterino::eventsub::lib::payload::channel_suspicious_user_message:: + v1 { + +struct Event { + // Broadcaster of the channel the message was sent in + std::string broadcasterUserID; + std::string broadcasterUserLogin; + std::string broadcasterUserName; + + // User who sent the message + std::string userID; + std::string userLogin; + std::string userName; + + // "none", "active_monitoring", "restricted" + std::string lowTrustStatus; + + std::vector sharedBanChannelIds; + + // "manual", "ban_evader_detector", or "shared_channel_ban" + std::vector types; + + // "unknown", "possible", "likely" + std::string banEvasionEvaluation; + // this event also has the ID in this message (hopefully we don't need it) + chat::Message message; +}; + +struct Payload { + subscription::Subscription subscription; + + Event event; +}; + +#include "twitch-eventsub-ws/payloads/channel-suspicious-user-message-v1.inc" + +} // namespace chatterino::eventsub::lib::payload::channel_suspicious_user_message::v1 diff --git a/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-suspicious-user-message-v1.inc b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-suspicious-user-message-v1.inc new file mode 100644 index 00000000..9a88467f --- /dev/null +++ b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-suspicious-user-message-v1.inc @@ -0,0 +1,5 @@ +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag, const boost::json::value &jvRoot); + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag, const boost::json::value &jvRoot); diff --git a/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-suspicious-user-update-v1.hpp b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-suspicious-user-update-v1.hpp new file mode 100644 index 00000000..86cdb87c --- /dev/null +++ b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-suspicious-user-update-v1.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include "twitch-eventsub-ws/payloads/subscription.hpp" + +#include + +#include + +namespace chatterino::eventsub::lib::payload::channel_suspicious_user_update:: + v1 { + +struct Event { + // Broadcaster of the channel + std::string broadcasterUserID; + std::string broadcasterUserLogin; + std::string broadcasterUserName; + + // Affected user + std::string userID; + std::string userLogin; + std::string userName; + + // Moderator who updated the user + std::string moderatorUserID; + std::string moderatorUserLogin; + std::string moderatorUserName; + + // "none", "active_monitoring", or "restricted" + std::string lowTrustStatus; +}; + +struct Payload { + subscription::Subscription subscription; + + Event event; +}; + +#include "twitch-eventsub-ws/payloads/channel-suspicious-user-update-v1.inc" + +} // namespace chatterino::eventsub::lib::payload::channel_suspicious_user_update::v1 diff --git a/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-suspicious-user-update-v1.inc b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-suspicious-user-update-v1.inc new file mode 100644 index 00000000..9a88467f --- /dev/null +++ b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/channel-suspicious-user-update-v1.inc @@ -0,0 +1,5 @@ +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag, const boost::json::value &jvRoot); + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag, const boost::json::value &jvRoot); diff --git a/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/structured-message.hpp b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/structured-message.hpp new file mode 100644 index 00000000..718e6f66 --- /dev/null +++ b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/structured-message.hpp @@ -0,0 +1,54 @@ +#pragma once + +#include "twitch-eventsub-ws/string.hpp" + +#include +#include +#include + +namespace chatterino::eventsub::lib::chat { + +struct Cheermote { + static constexpr std::string_view TAG = "cheermote"; + + String prefix; + int bits; + int tier; +}; + +struct Emote { + static constexpr std::string_view TAG = "emote"; + + String id; + String emoteSetID; + // XXX: this isn't included in automod-ish messages and we don't have a + // need for it right now + // String ownerID; +}; + +struct Mention { + static constexpr std::string_view TAG = "mention"; + + String userID; + String userName; + String userLogin; +}; + +struct Text { + static constexpr std::string_view TAG = "text"; +}; + +struct MessageFragment { + String text; + /// json_tag=type + std::variant inner; +}; + +struct Message { + String text; + std::vector fragments; +}; + +#include "twitch-eventsub-ws/payloads/structured-message.inc" + +} // namespace chatterino::eventsub::lib::chat diff --git a/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/structured-message.inc b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/structured-message.inc new file mode 100644 index 00000000..32d1ad28 --- /dev/null +++ b/lib/twitch-eventsub-ws/include/twitch-eventsub-ws/payloads/structured-message.inc @@ -0,0 +1,18 @@ +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag, const boost::json::value &jvRoot); + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag, const boost::json::value &jvRoot); + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag, const boost::json::value &jvRoot); + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag, const boost::json::value &jvRoot); + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag, + const boost::json::value &jvRoot); + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag, const boost::json::value &jvRoot); diff --git a/lib/twitch-eventsub-ws/src/CMakeLists.txt b/lib/twitch-eventsub-ws/src/CMakeLists.txt index d5b65cfa..0c03b475 100644 --- a/lib/twitch-eventsub-ws/src/CMakeLists.txt +++ b/lib/twitch-eventsub-ws/src/CMakeLists.txt @@ -6,14 +6,20 @@ generate_json_impls( HEADERS include/twitch-eventsub-ws/messages/metadata.hpp + include/twitch-eventsub-ws/payloads/automod-message-hold-v2.hpp + include/twitch-eventsub-ws/payloads/automod-message-update-v2.hpp + include/twitch-eventsub-ws/payloads/automod-message.hpp include/twitch-eventsub-ws/payloads/channel-ban-v1.hpp include/twitch-eventsub-ws/payloads/channel-chat-message-v1.hpp include/twitch-eventsub-ws/payloads/channel-chat-notification-v1.hpp include/twitch-eventsub-ws/payloads/channel-moderate-v2.hpp + include/twitch-eventsub-ws/payloads/channel-suspicious-user-message-v1.hpp + include/twitch-eventsub-ws/payloads/channel-suspicious-user-update-v1.hpp include/twitch-eventsub-ws/payloads/channel-update-v1.hpp include/twitch-eventsub-ws/payloads/session-welcome.hpp include/twitch-eventsub-ws/payloads/stream-offline-v1.hpp include/twitch-eventsub-ws/payloads/stream-online-v1.hpp + include/twitch-eventsub-ws/payloads/structured-message.hpp include/twitch-eventsub-ws/payloads/subscription.hpp ) diff --git a/lib/twitch-eventsub-ws/src/generated/payloads/automod-message-hold-v2.cpp b/lib/twitch-eventsub-ws/src/generated/payloads/automod-message-hold-v2.cpp new file mode 100644 index 00000000..e5fbf3a2 --- /dev/null +++ b/lib/twitch-eventsub-ws/src/generated/payloads/automod-message-hold-v2.cpp @@ -0,0 +1,253 @@ +// WARNING: This file is automatically generated. Any changes will be lost. +#include "twitch-eventsub-ws/chrono.hpp" // IWYU pragma: keep +#include "twitch-eventsub-ws/detail/errors.hpp" +#include "twitch-eventsub-ws/detail/variant.hpp" // IWYU pragma: keep +#include "twitch-eventsub-ws/payloads/automod-message-hold-v2.hpp" + +#include + +namespace chatterino::eventsub::lib::payload::automod_message_hold::v2 { + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag /* tag */, + const boost::json::value &jvRoot) +{ + if (!jvRoot.is_object()) + { + EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject); + } + const auto &root = jvRoot.get_object(); + + const auto *jvbroadcasterUserID = root.if_contains("broadcaster_user_id"); + if (jvbroadcasterUserID == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto broadcasterUserID = + boost::json::try_value_to(*jvbroadcasterUserID); + + if (broadcasterUserID.has_error()) + { + return broadcasterUserID.error(); + } + + const auto *jvbroadcasterUserLogin = + root.if_contains("broadcaster_user_login"); + if (jvbroadcasterUserLogin == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto broadcasterUserLogin = + boost::json::try_value_to(*jvbroadcasterUserLogin); + + if (broadcasterUserLogin.has_error()) + { + return broadcasterUserLogin.error(); + } + + const auto *jvbroadcasterUserName = + root.if_contains("broadcaster_user_name"); + if (jvbroadcasterUserName == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto broadcasterUserName = + boost::json::try_value_to(*jvbroadcasterUserName); + + if (broadcasterUserName.has_error()) + { + return broadcasterUserName.error(); + } + + const auto *jvuserID = root.if_contains("user_id"); + if (jvuserID == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto userID = boost::json::try_value_to(*jvuserID); + + if (userID.has_error()) + { + return userID.error(); + } + + const auto *jvuserLogin = root.if_contains("user_login"); + if (jvuserLogin == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto userLogin = boost::json::try_value_to(*jvuserLogin); + + if (userLogin.has_error()) + { + return userLogin.error(); + } + + const auto *jvuserName = root.if_contains("user_name"); + if (jvuserName == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto userName = boost::json::try_value_to(*jvuserName); + + if (userName.has_error()) + { + return userName.error(); + } + + const auto *jvmessageID = root.if_contains("message_id"); + if (jvmessageID == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto messageID = boost::json::try_value_to(*jvmessageID); + + if (messageID.has_error()) + { + return messageID.error(); + } + + const auto *jvmessage = root.if_contains("message"); + if (jvmessage == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto message = boost::json::try_value_to(*jvmessage); + + if (message.has_error()) + { + return message.error(); + } + + const auto *jvheldAt = root.if_contains("held_at"); + if (jvheldAt == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto heldAt = boost::json::try_value_to(*jvheldAt); + + if (heldAt.has_error()) + { + return heldAt.error(); + } + + const auto *jvreasonTag = root.if_contains("reason"); + if (jvreasonTag == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto reasonTagRes = + boost::json::try_value_to(*jvreasonTag); + if (reasonTagRes.has_error()) + { + return reasonTagRes.error(); + } + std::string_view reasonTag = *reasonTagRes; + decltype(std::declval().reason) reason; + if (reasonTag == automod::AutomodReason::TAG) + { + const auto *reasonVal = + root.if_contains(detail::fieldFor()); + if (!reasonVal) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + auto reasonautomodAutomodReason = + boost::json::try_value_to(*reasonVal); + if (reasonautomodAutomodReason.has_error()) + { + return reasonautomodAutomodReason.error(); + } + reason.emplace( + std::move(reasonautomodAutomodReason.value())); + } + else if (reasonTag == automod::BlockedTermReason::TAG) + { + const auto *reasonVal = + root.if_contains(detail::fieldFor()); + if (!reasonVal) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + auto reasonautomodBlockedTermReason = + boost::json::try_value_to(*reasonVal); + if (reasonautomodBlockedTermReason.has_error()) + { + return reasonautomodBlockedTermReason.error(); + } + reason.emplace( + std::move(reasonautomodBlockedTermReason.value())); + } + else + { + EVENTSUB_BAIL_HERE(error::Kind::UnknownVariant); + } + + return Event{ + .broadcasterUserID = std::move(broadcasterUserID.value()), + .broadcasterUserLogin = std::move(broadcasterUserLogin.value()), + .broadcasterUserName = std::move(broadcasterUserName.value()), + .userID = std::move(userID.value()), + .userLogin = std::move(userLogin.value()), + .userName = std::move(userName.value()), + .messageID = std::move(messageID.value()), + .message = std::move(message.value()), + .heldAt = std::move(heldAt.value()), + .reason = std::move(reason), + }; +} + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag /* tag */, + const boost::json::value &jvRoot) +{ + if (!jvRoot.is_object()) + { + EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject); + } + const auto &root = jvRoot.get_object(); + + const auto *jvsubscription = root.if_contains("subscription"); + if (jvsubscription == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto subscription = + boost::json::try_value_to(*jvsubscription); + + if (subscription.has_error()) + { + return subscription.error(); + } + + const auto *jvevent = root.if_contains("event"); + if (jvevent == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto event = boost::json::try_value_to(*jvevent); + + if (event.has_error()) + { + return event.error(); + } + + return Payload{ + .subscription = std::move(subscription.value()), + .event = std::move(event.value()), + }; +} + +} // namespace chatterino::eventsub::lib::payload::automod_message_hold::v2 diff --git a/lib/twitch-eventsub-ws/src/generated/payloads/automod-message-update-v2.cpp b/lib/twitch-eventsub-ws/src/generated/payloads/automod-message-update-v2.cpp new file mode 100644 index 00000000..27b2def2 --- /dev/null +++ b/lib/twitch-eventsub-ws/src/generated/payloads/automod-message-update-v2.cpp @@ -0,0 +1,312 @@ +// WARNING: This file is automatically generated. Any changes will be lost. +#include "twitch-eventsub-ws/chrono.hpp" // IWYU pragma: keep +#include "twitch-eventsub-ws/detail/errors.hpp" +#include "twitch-eventsub-ws/detail/variant.hpp" // IWYU pragma: keep +#include "twitch-eventsub-ws/payloads/automod-message-update-v2.hpp" + +#include + +namespace chatterino::eventsub::lib::payload::automod_message_update::v2 { + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag /* tag */, + const boost::json::value &jvRoot) +{ + if (!jvRoot.is_object()) + { + EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject); + } + const auto &root = jvRoot.get_object(); + + const auto *jvbroadcasterUserID = root.if_contains("broadcaster_user_id"); + if (jvbroadcasterUserID == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto broadcasterUserID = + boost::json::try_value_to(*jvbroadcasterUserID); + + if (broadcasterUserID.has_error()) + { + return broadcasterUserID.error(); + } + + const auto *jvbroadcasterUserLogin = + root.if_contains("broadcaster_user_login"); + if (jvbroadcasterUserLogin == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto broadcasterUserLogin = + boost::json::try_value_to(*jvbroadcasterUserLogin); + + if (broadcasterUserLogin.has_error()) + { + return broadcasterUserLogin.error(); + } + + const auto *jvbroadcasterUserName = + root.if_contains("broadcaster_user_name"); + if (jvbroadcasterUserName == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto broadcasterUserName = + boost::json::try_value_to(*jvbroadcasterUserName); + + if (broadcasterUserName.has_error()) + { + return broadcasterUserName.error(); + } + + const auto *jvuserID = root.if_contains("user_id"); + if (jvuserID == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto userID = boost::json::try_value_to(*jvuserID); + + if (userID.has_error()) + { + return userID.error(); + } + + const auto *jvuserLogin = root.if_contains("user_login"); + if (jvuserLogin == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto userLogin = boost::json::try_value_to(*jvuserLogin); + + if (userLogin.has_error()) + { + return userLogin.error(); + } + + const auto *jvuserName = root.if_contains("user_name"); + if (jvuserName == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto userName = boost::json::try_value_to(*jvuserName); + + if (userName.has_error()) + { + return userName.error(); + } + + const auto *jvmoderatorUserID = root.if_contains("moderator_user_id"); + if (jvmoderatorUserID == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto moderatorUserID = + boost::json::try_value_to(*jvmoderatorUserID); + + if (moderatorUserID.has_error()) + { + return moderatorUserID.error(); + } + + const auto *jvmoderatorUserLogin = root.if_contains("moderator_user_login"); + if (jvmoderatorUserLogin == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto moderatorUserLogin = + boost::json::try_value_to(*jvmoderatorUserLogin); + + if (moderatorUserLogin.has_error()) + { + return moderatorUserLogin.error(); + } + + const auto *jvmoderatorUserName = root.if_contains("moderator_user_name"); + if (jvmoderatorUserName == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto moderatorUserName = + boost::json::try_value_to(*jvmoderatorUserName); + + if (moderatorUserName.has_error()) + { + return moderatorUserName.error(); + } + + const auto *jvmessageID = root.if_contains("message_id"); + if (jvmessageID == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto messageID = boost::json::try_value_to(*jvmessageID); + + if (messageID.has_error()) + { + return messageID.error(); + } + + const auto *jvmessage = root.if_contains("message"); + if (jvmessage == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto message = boost::json::try_value_to(*jvmessage); + + if (message.has_error()) + { + return message.error(); + } + + const auto *jvstatus = root.if_contains("status"); + if (jvstatus == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto status = boost::json::try_value_to(*jvstatus); + + if (status.has_error()) + { + return status.error(); + } + + const auto *jvheldAt = root.if_contains("held_at"); + if (jvheldAt == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto heldAt = boost::json::try_value_to(*jvheldAt); + + if (heldAt.has_error()) + { + return heldAt.error(); + } + + const auto *jvreasonTag = root.if_contains("reason"); + if (jvreasonTag == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto reasonTagRes = + boost::json::try_value_to(*jvreasonTag); + if (reasonTagRes.has_error()) + { + return reasonTagRes.error(); + } + std::string_view reasonTag = *reasonTagRes; + decltype(std::declval().reason) reason; + if (reasonTag == automod::AutomodReason::TAG) + { + const auto *reasonVal = + root.if_contains(detail::fieldFor()); + if (!reasonVal) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + auto reasonautomodAutomodReason = + boost::json::try_value_to(*reasonVal); + if (reasonautomodAutomodReason.has_error()) + { + return reasonautomodAutomodReason.error(); + } + reason.emplace( + std::move(reasonautomodAutomodReason.value())); + } + else if (reasonTag == automod::BlockedTermReason::TAG) + { + const auto *reasonVal = + root.if_contains(detail::fieldFor()); + if (!reasonVal) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + auto reasonautomodBlockedTermReason = + boost::json::try_value_to(*reasonVal); + if (reasonautomodBlockedTermReason.has_error()) + { + return reasonautomodBlockedTermReason.error(); + } + reason.emplace( + std::move(reasonautomodBlockedTermReason.value())); + } + else + { + EVENTSUB_BAIL_HERE(error::Kind::UnknownVariant); + } + + return Event{ + .broadcasterUserID = std::move(broadcasterUserID.value()), + .broadcasterUserLogin = std::move(broadcasterUserLogin.value()), + .broadcasterUserName = std::move(broadcasterUserName.value()), + .userID = std::move(userID.value()), + .userLogin = std::move(userLogin.value()), + .userName = std::move(userName.value()), + .moderatorUserID = std::move(moderatorUserID.value()), + .moderatorUserLogin = std::move(moderatorUserLogin.value()), + .moderatorUserName = std::move(moderatorUserName.value()), + .messageID = std::move(messageID.value()), + .message = std::move(message.value()), + .status = std::move(status.value()), + .heldAt = std::move(heldAt.value()), + .reason = std::move(reason), + }; +} + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag /* tag */, + const boost::json::value &jvRoot) +{ + if (!jvRoot.is_object()) + { + EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject); + } + const auto &root = jvRoot.get_object(); + + const auto *jvsubscription = root.if_contains("subscription"); + if (jvsubscription == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto subscription = + boost::json::try_value_to(*jvsubscription); + + if (subscription.has_error()) + { + return subscription.error(); + } + + const auto *jvevent = root.if_contains("event"); + if (jvevent == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto event = boost::json::try_value_to(*jvevent); + + if (event.has_error()) + { + return event.error(); + } + + return Payload{ + .subscription = std::move(subscription.value()), + .event = std::move(event.value()), + }; +} + +} // namespace chatterino::eventsub::lib::payload::automod_message_update::v2 diff --git a/lib/twitch-eventsub-ws/src/generated/payloads/automod-message.cpp b/lib/twitch-eventsub-ws/src/generated/payloads/automod-message.cpp new file mode 100644 index 00000000..fa3d2b18 --- /dev/null +++ b/lib/twitch-eventsub-ws/src/generated/payloads/automod-message.cpp @@ -0,0 +1,242 @@ +// WARNING: This file is automatically generated. Any changes will be lost. +#include "twitch-eventsub-ws/chrono.hpp" // IWYU pragma: keep +#include "twitch-eventsub-ws/detail/errors.hpp" +#include "twitch-eventsub-ws/detail/variant.hpp" // IWYU pragma: keep +#include "twitch-eventsub-ws/payloads/automod-message.hpp" + +#include + +namespace chatterino::eventsub::lib::automod { + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag /* tag */, + const boost::json::value &jvRoot) +{ + if (!jvRoot.is_object()) + { + EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject); + } + const auto &root = jvRoot.get_object(); + + static_assert(std::is_trivially_copyable_v().startPos)>>); + const auto *jvstartPos = root.if_contains("start_pos"); + if (jvstartPos == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto startPos = boost::json::try_value_to(*jvstartPos); + + if (startPos.has_error()) + { + return startPos.error(); + } + + static_assert(std::is_trivially_copyable_v().endPos)>>); + const auto *jvendPos = root.if_contains("end_pos"); + if (jvendPos == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto endPos = boost::json::try_value_to(*jvendPos); + + if (endPos.has_error()) + { + return endPos.error(); + } + + return Boundary{ + .startPos = startPos.value(), + .endPos = endPos.value(), + }; +} + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag /* tag */, + const boost::json::value &jvRoot) +{ + if (!jvRoot.is_object()) + { + EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject); + } + const auto &root = jvRoot.get_object(); + + const auto *jvcategory = root.if_contains("category"); + if (jvcategory == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto category = boost::json::try_value_to(*jvcategory); + + if (category.has_error()) + { + return category.error(); + } + + static_assert(std::is_trivially_copyable_v().level)>>); + const auto *jvlevel = root.if_contains("level"); + if (jvlevel == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto level = boost::json::try_value_to(*jvlevel); + + if (level.has_error()) + { + return level.error(); + } + + std::vector vboundaries; + const auto *jvboundaries = root.if_contains("boundaries"); + if (jvboundaries != nullptr && !jvboundaries->is_null()) + { + auto boundaries = + boost::json::try_value_to>(*jvboundaries); + if (boundaries.has_error()) + { + return boundaries.error(); + } + else + { + vboundaries = std::move(boundaries.value()); + } + } + + return AutomodReason{ + .category = std::move(category.value()), + .level = level.value(), + .boundaries = std::move(vboundaries), + }; +} + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag /* tag */, + const boost::json::value &jvRoot) +{ + if (!jvRoot.is_object()) + { + EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject); + } + const auto &root = jvRoot.get_object(); + + const auto *jvtermID = root.if_contains("term_id"); + if (jvtermID == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto termID = boost::json::try_value_to(*jvtermID); + + if (termID.has_error()) + { + return termID.error(); + } + + static_assert(std::is_trivially_copyable_v().boundary)>>); + const auto *jvboundary = root.if_contains("boundary"); + if (jvboundary == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto boundary = boost::json::try_value_to(*jvboundary); + + if (boundary.has_error()) + { + return boundary.error(); + } + + const auto *jvownerBroadcasterUserID = + root.if_contains("owner_broadcaster_user_id"); + if (jvownerBroadcasterUserID == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto ownerBroadcasterUserID = + boost::json::try_value_to(*jvownerBroadcasterUserID); + + if (ownerBroadcasterUserID.has_error()) + { + return ownerBroadcasterUserID.error(); + } + + const auto *jvownerBroadcasterUserLogin = + root.if_contains("owner_broadcaster_user_login"); + if (jvownerBroadcasterUserLogin == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto ownerBroadcasterUserLogin = + boost::json::try_value_to(*jvownerBroadcasterUserLogin); + + if (ownerBroadcasterUserLogin.has_error()) + { + return ownerBroadcasterUserLogin.error(); + } + + const auto *jvownerBroadcasterUserName = + root.if_contains("owner_broadcaster_user_name"); + if (jvownerBroadcasterUserName == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto ownerBroadcasterUserName = + boost::json::try_value_to(*jvownerBroadcasterUserName); + + if (ownerBroadcasterUserName.has_error()) + { + return ownerBroadcasterUserName.error(); + } + + return FoundTerm{ + .termID = std::move(termID.value()), + .boundary = boundary.value(), + .ownerBroadcasterUserID = std::move(ownerBroadcasterUserID.value()), + .ownerBroadcasterUserLogin = + std::move(ownerBroadcasterUserLogin.value()), + .ownerBroadcasterUserName = std::move(ownerBroadcasterUserName.value()), + }; +} + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag /* tag */, + const boost::json::value &jvRoot) +{ + if (!jvRoot.is_object()) + { + EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject); + } + const auto &root = jvRoot.get_object(); + + std::vector vtermsFound; + const auto *jvtermsFound = root.if_contains("terms_found"); + if (jvtermsFound != nullptr && !jvtermsFound->is_null()) + { + auto termsFound = + boost::json::try_value_to>(*jvtermsFound); + if (termsFound.has_error()) + { + return termsFound.error(); + } + else + { + vtermsFound = std::move(termsFound.value()); + } + } + + return BlockedTermReason{ + .termsFound = std::move(vtermsFound), + }; +} + +} // namespace chatterino::eventsub::lib::automod diff --git a/lib/twitch-eventsub-ws/src/generated/payloads/channel-chat-message-v1.cpp b/lib/twitch-eventsub-ws/src/generated/payloads/channel-chat-message-v1.cpp index 893db7fb..15a89492 100644 --- a/lib/twitch-eventsub-ws/src/generated/payloads/channel-chat-message-v1.cpp +++ b/lib/twitch-eventsub-ws/src/generated/payloads/channel-chat-message-v1.cpp @@ -64,327 +64,6 @@ boost::json::result_for::type tag_invoke( }; } -boost::json::result_for::type tag_invoke( - boost::json::try_value_to_tag /* tag */, - const boost::json::value &jvRoot) -{ - if (!jvRoot.is_object()) - { - EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject); - } - const auto &root = jvRoot.get_object(); - - const auto *jvprefix = root.if_contains("prefix"); - if (jvprefix == nullptr) - { - EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); - } - - auto prefix = boost::json::try_value_to(*jvprefix); - - if (prefix.has_error()) - { - return prefix.error(); - } - - static_assert( - std::is_trivially_copyable_v< - std::remove_reference_t().bits)>>); - const auto *jvbits = root.if_contains("bits"); - if (jvbits == nullptr) - { - EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); - } - - auto bits = boost::json::try_value_to(*jvbits); - - if (bits.has_error()) - { - return bits.error(); - } - - static_assert( - std::is_trivially_copyable_v< - std::remove_reference_t().tier)>>); - const auto *jvtier = root.if_contains("tier"); - if (jvtier == nullptr) - { - EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); - } - - auto tier = boost::json::try_value_to(*jvtier); - - if (tier.has_error()) - { - return tier.error(); - } - - return Cheermote{ - .prefix = std::move(prefix.value()), - .bits = bits.value(), - .tier = tier.value(), - }; -} - -boost::json::result_for::type tag_invoke( - boost::json::try_value_to_tag /* tag */, - const boost::json::value &jvRoot) -{ - if (!jvRoot.is_object()) - { - EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject); - } - const auto &root = jvRoot.get_object(); - - const auto *jvid = root.if_contains("id"); - if (jvid == nullptr) - { - EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); - } - - auto id = boost::json::try_value_to(*jvid); - - if (id.has_error()) - { - return id.error(); - } - - const auto *jvemoteSetID = root.if_contains("emote_set_id"); - if (jvemoteSetID == nullptr) - { - EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); - } - - auto emoteSetID = boost::json::try_value_to(*jvemoteSetID); - - if (emoteSetID.has_error()) - { - return emoteSetID.error(); - } - - const auto *jvownerID = root.if_contains("owner_id"); - if (jvownerID == nullptr) - { - EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); - } - - auto ownerID = boost::json::try_value_to(*jvownerID); - - if (ownerID.has_error()) - { - return ownerID.error(); - } - - std::vector vformat; - const auto *jvformat = root.if_contains("format"); - if (jvformat != nullptr && !jvformat->is_null()) - { - auto format = - boost::json::try_value_to>(*jvformat); - if (format.has_error()) - { - return format.error(); - } - else - { - vformat = std::move(format.value()); - } - } - - return Emote{ - .id = std::move(id.value()), - .emoteSetID = std::move(emoteSetID.value()), - .ownerID = std::move(ownerID.value()), - .format = std::move(vformat), - }; -} - -boost::json::result_for::type tag_invoke( - boost::json::try_value_to_tag /* tag */, - const boost::json::value &jvRoot) -{ - if (!jvRoot.is_object()) - { - EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject); - } - const auto &root = jvRoot.get_object(); - - const auto *jvuserID = root.if_contains("user_id"); - if (jvuserID == nullptr) - { - EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); - } - - auto userID = boost::json::try_value_to(*jvuserID); - - if (userID.has_error()) - { - return userID.error(); - } - - const auto *jvuserName = root.if_contains("user_name"); - if (jvuserName == nullptr) - { - EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); - } - - auto userName = boost::json::try_value_to(*jvuserName); - - if (userName.has_error()) - { - return userName.error(); - } - - const auto *jvuserLogin = root.if_contains("user_login"); - if (jvuserLogin == nullptr) - { - EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); - } - - auto userLogin = boost::json::try_value_to(*jvuserLogin); - - if (userLogin.has_error()) - { - return userLogin.error(); - } - - return Mention{ - .userID = std::move(userID.value()), - .userName = std::move(userName.value()), - .userLogin = std::move(userLogin.value()), - }; -} - -boost::json::result_for::type tag_invoke( - boost::json::try_value_to_tag /* tag */, - const boost::json::value &jvRoot) -{ - if (!jvRoot.is_object()) - { - EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject); - } - const auto &root = jvRoot.get_object(); - - const auto *jvtype = root.if_contains("type"); - if (jvtype == nullptr) - { - EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); - } - - auto type = boost::json::try_value_to(*jvtype); - - if (type.has_error()) - { - return type.error(); - } - - const auto *jvtext = root.if_contains("text"); - if (jvtext == nullptr) - { - EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); - } - - auto text = boost::json::try_value_to(*jvtext); - - if (text.has_error()) - { - return text.error(); - } - - std::optional cheermote = std::nullopt; - const auto *jvcheermote = root.if_contains("cheermote"); - if (jvcheermote != nullptr && !jvcheermote->is_null()) - { - auto tcheermote = boost::json::try_value_to(*jvcheermote); - - if (tcheermote.has_error()) - { - return tcheermote.error(); - } - cheermote = std::move(tcheermote.value()); - } - - std::optional emote = std::nullopt; - const auto *jvemote = root.if_contains("emote"); - if (jvemote != nullptr && !jvemote->is_null()) - { - auto temote = boost::json::try_value_to(*jvemote); - - if (temote.has_error()) - { - return temote.error(); - } - emote = std::move(temote.value()); - } - - std::optional mention = std::nullopt; - const auto *jvmention = root.if_contains("mention"); - if (jvmention != nullptr && !jvmention->is_null()) - { - auto tmention = boost::json::try_value_to(*jvmention); - - if (tmention.has_error()) - { - return tmention.error(); - } - mention = std::move(tmention.value()); - } - - return MessageFragment{ - .type = std::move(type.value()), - .text = std::move(text.value()), - .cheermote = std::move(cheermote), - .emote = std::move(emote), - .mention = std::move(mention), - }; -} - -boost::json::result_for::type tag_invoke( - boost::json::try_value_to_tag /* tag */, - const boost::json::value &jvRoot) -{ - if (!jvRoot.is_object()) - { - EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject); - } - const auto &root = jvRoot.get_object(); - - const auto *jvtext = root.if_contains("text"); - if (jvtext == nullptr) - { - EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); - } - - auto text = boost::json::try_value_to(*jvtext); - - if (text.has_error()) - { - return text.error(); - } - - std::vector vfragments; - const auto *jvfragments = root.if_contains("fragments"); - if (jvfragments != nullptr && !jvfragments->is_null()) - { - auto fragments = - boost::json::try_value_to>( - *jvfragments); - if (fragments.has_error()) - { - return fragments.error(); - } - else - { - vfragments = std::move(fragments.value()); - } - } - - return Message{ - .text = std::move(text.value()), - .fragments = std::move(vfragments), - }; -} - boost::json::result_for::type tag_invoke( boost::json::try_value_to_tag /* tag */, const boost::json::value &jvRoot) @@ -718,7 +397,7 @@ boost::json::result_for::type tag_invoke( EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); } - auto message = boost::json::try_value_to(*jvmessage); + auto message = boost::json::try_value_to(*jvmessage); if (message.has_error()) { diff --git a/lib/twitch-eventsub-ws/src/generated/payloads/channel-chat-notification-v1.cpp b/lib/twitch-eventsub-ws/src/generated/payloads/channel-chat-notification-v1.cpp index d082a717..2d8e3a64 100644 --- a/lib/twitch-eventsub-ws/src/generated/payloads/channel-chat-notification-v1.cpp +++ b/lib/twitch-eventsub-ws/src/generated/payloads/channel-chat-notification-v1.cpp @@ -64,281 +64,6 @@ boost::json::result_for::type tag_invoke( }; } -boost::json::result_for::type tag_invoke( - boost::json::try_value_to_tag /* tag */, - const boost::json::value &jvRoot) -{ - if (!jvRoot.is_object()) - { - EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject); - } - const auto &root = jvRoot.get_object(); - - const auto *jvprefix = root.if_contains("prefix"); - if (jvprefix == nullptr) - { - EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); - } - - auto prefix = boost::json::try_value_to(*jvprefix); - - if (prefix.has_error()) - { - return prefix.error(); - } - - static_assert( - std::is_trivially_copyable_v< - std::remove_reference_t().bits)>>); - const auto *jvbits = root.if_contains("bits"); - if (jvbits == nullptr) - { - EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); - } - - auto bits = boost::json::try_value_to(*jvbits); - - if (bits.has_error()) - { - return bits.error(); - } - - static_assert( - std::is_trivially_copyable_v< - std::remove_reference_t().tier)>>); - const auto *jvtier = root.if_contains("tier"); - if (jvtier == nullptr) - { - EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); - } - - auto tier = boost::json::try_value_to(*jvtier); - - if (tier.has_error()) - { - return tier.error(); - } - - return Cheermote{ - .prefix = std::move(prefix.value()), - .bits = bits.value(), - .tier = tier.value(), - }; -} - -boost::json::result_for::type tag_invoke( - boost::json::try_value_to_tag /* tag */, - const boost::json::value &jvRoot) -{ - if (!jvRoot.is_object()) - { - EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject); - } - const auto &root = jvRoot.get_object(); - - const auto *jvid = root.if_contains("id"); - if (jvid == nullptr) - { - EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); - } - - auto id = boost::json::try_value_to(*jvid); - - if (id.has_error()) - { - return id.error(); - } - - const auto *jvemoteSetID = root.if_contains("emote_set_id"); - if (jvemoteSetID == nullptr) - { - EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); - } - - auto emoteSetID = boost::json::try_value_to(*jvemoteSetID); - - if (emoteSetID.has_error()) - { - return emoteSetID.error(); - } - - const auto *jvownerID = root.if_contains("owner_id"); - if (jvownerID == nullptr) - { - EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); - } - - auto ownerID = boost::json::try_value_to(*jvownerID); - - if (ownerID.has_error()) - { - return ownerID.error(); - } - - std::vector vformat; - const auto *jvformat = root.if_contains("format"); - if (jvformat != nullptr && !jvformat->is_null()) - { - auto format = - boost::json::try_value_to>(*jvformat); - if (format.has_error()) - { - return format.error(); - } - else - { - vformat = std::move(format.value()); - } - } - - return Emote{ - .id = std::move(id.value()), - .emoteSetID = std::move(emoteSetID.value()), - .ownerID = std::move(ownerID.value()), - .format = std::move(vformat), - }; -} - -boost::json::result_for::type tag_invoke( - boost::json::try_value_to_tag /* tag */, - const boost::json::value &jvRoot) -{ - if (!jvRoot.is_object()) - { - EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject); - } - const auto &root = jvRoot.get_object(); - - const auto *jvuserID = root.if_contains("user_id"); - if (jvuserID == nullptr) - { - EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); - } - - auto userID = boost::json::try_value_to(*jvuserID); - - if (userID.has_error()) - { - return userID.error(); - } - - const auto *jvuserName = root.if_contains("user_name"); - if (jvuserName == nullptr) - { - EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); - } - - auto userName = boost::json::try_value_to(*jvuserName); - - if (userName.has_error()) - { - return userName.error(); - } - - const auto *jvuserLogin = root.if_contains("user_login"); - if (jvuserLogin == nullptr) - { - EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); - } - - auto userLogin = boost::json::try_value_to(*jvuserLogin); - - if (userLogin.has_error()) - { - return userLogin.error(); - } - - return Mention{ - .userID = std::move(userID.value()), - .userName = std::move(userName.value()), - .userLogin = std::move(userLogin.value()), - }; -} - -boost::json::result_for::type tag_invoke( - boost::json::try_value_to_tag /* tag */, - const boost::json::value &jvRoot) -{ - if (!jvRoot.is_object()) - { - EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject); - } - const auto &root = jvRoot.get_object(); - - const auto *jvtype = root.if_contains("type"); - if (jvtype == nullptr) - { - EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); - } - - auto type = boost::json::try_value_to(*jvtype); - - if (type.has_error()) - { - return type.error(); - } - - const auto *jvtext = root.if_contains("text"); - if (jvtext == nullptr) - { - EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); - } - - auto text = boost::json::try_value_to(*jvtext); - - if (text.has_error()) - { - return text.error(); - } - - std::optional cheermote = std::nullopt; - const auto *jvcheermote = root.if_contains("cheermote"); - if (jvcheermote != nullptr && !jvcheermote->is_null()) - { - auto tcheermote = boost::json::try_value_to(*jvcheermote); - - if (tcheermote.has_error()) - { - return tcheermote.error(); - } - cheermote = std::move(tcheermote.value()); - } - - std::optional emote = std::nullopt; - const auto *jvemote = root.if_contains("emote"); - if (jvemote != nullptr && !jvemote->is_null()) - { - auto temote = boost::json::try_value_to(*jvemote); - - if (temote.has_error()) - { - return temote.error(); - } - emote = std::move(temote.value()); - } - - std::optional mention = std::nullopt; - const auto *jvmention = root.if_contains("mention"); - if (jvmention != nullptr && !jvmention->is_null()) - { - auto tmention = boost::json::try_value_to(*jvmention); - - if (tmention.has_error()) - { - return tmention.error(); - } - mention = std::move(tmention.value()); - } - - return MessageFragment{ - .type = std::move(type.value()), - .text = std::move(text.value()), - .cheermote = std::move(cheermote), - .emote = std::move(emote), - .mention = std::move(mention), - }; -} - boost::json::result_for::type tag_invoke( boost::json::try_value_to_tag /* tag */, const boost::json::value &jvRoot) @@ -1227,52 +952,6 @@ boost::json::result_for::type tag_invoke( }; } -boost::json::result_for::type tag_invoke( - boost::json::try_value_to_tag /* tag */, - const boost::json::value &jvRoot) -{ - if (!jvRoot.is_object()) - { - EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject); - } - const auto &root = jvRoot.get_object(); - - const auto *jvtext = root.if_contains("text"); - if (jvtext == nullptr) - { - EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); - } - - auto text = boost::json::try_value_to(*jvtext); - - if (text.has_error()) - { - return text.error(); - } - - std::vector vfragments; - const auto *jvfragments = root.if_contains("fragments"); - if (jvfragments != nullptr && !jvfragments->is_null()) - { - auto fragments = - boost::json::try_value_to>( - *jvfragments); - if (fragments.has_error()) - { - return fragments.error(); - } - else - { - vfragments = std::move(fragments.value()); - } - } - - return Message{ - .text = std::move(text.value()), - .fragments = std::move(vfragments), - }; -} - boost::json::result_for::type tag_invoke( boost::json::try_value_to_tag /* tag */, const boost::json::value &jvRoot) @@ -1445,7 +1124,7 @@ boost::json::result_for::type tag_invoke( EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); } - auto message = boost::json::try_value_to(*jvmessage); + auto message = boost::json::try_value_to(*jvmessage); if (message.has_error()) { diff --git a/lib/twitch-eventsub-ws/src/generated/payloads/channel-suspicious-user-message-v1.cpp b/lib/twitch-eventsub-ws/src/generated/payloads/channel-suspicious-user-message-v1.cpp new file mode 100644 index 00000000..54b838fe --- /dev/null +++ b/lib/twitch-eventsub-ws/src/generated/payloads/channel-suspicious-user-message-v1.cpp @@ -0,0 +1,238 @@ +// WARNING: This file is automatically generated. Any changes will be lost. +#include "twitch-eventsub-ws/chrono.hpp" // IWYU pragma: keep +#include "twitch-eventsub-ws/detail/errors.hpp" +#include "twitch-eventsub-ws/detail/variant.hpp" // IWYU pragma: keep +#include "twitch-eventsub-ws/payloads/channel-suspicious-user-message-v1.hpp" + +#include + +namespace chatterino::eventsub::lib::payload::channel_suspicious_user_message:: + v1 { + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag /* tag */, + const boost::json::value &jvRoot) +{ + if (!jvRoot.is_object()) + { + EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject); + } + const auto &root = jvRoot.get_object(); + + const auto *jvbroadcasterUserID = root.if_contains("broadcaster_user_id"); + if (jvbroadcasterUserID == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto broadcasterUserID = + boost::json::try_value_to(*jvbroadcasterUserID); + + if (broadcasterUserID.has_error()) + { + return broadcasterUserID.error(); + } + + const auto *jvbroadcasterUserLogin = + root.if_contains("broadcaster_user_login"); + if (jvbroadcasterUserLogin == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto broadcasterUserLogin = + boost::json::try_value_to(*jvbroadcasterUserLogin); + + if (broadcasterUserLogin.has_error()) + { + return broadcasterUserLogin.error(); + } + + const auto *jvbroadcasterUserName = + root.if_contains("broadcaster_user_name"); + if (jvbroadcasterUserName == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto broadcasterUserName = + boost::json::try_value_to(*jvbroadcasterUserName); + + if (broadcasterUserName.has_error()) + { + return broadcasterUserName.error(); + } + + const auto *jvuserID = root.if_contains("user_id"); + if (jvuserID == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto userID = boost::json::try_value_to(*jvuserID); + + if (userID.has_error()) + { + return userID.error(); + } + + const auto *jvuserLogin = root.if_contains("user_login"); + if (jvuserLogin == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto userLogin = boost::json::try_value_to(*jvuserLogin); + + if (userLogin.has_error()) + { + return userLogin.error(); + } + + const auto *jvuserName = root.if_contains("user_name"); + if (jvuserName == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto userName = boost::json::try_value_to(*jvuserName); + + if (userName.has_error()) + { + return userName.error(); + } + + const auto *jvlowTrustStatus = root.if_contains("low_trust_status"); + if (jvlowTrustStatus == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto lowTrustStatus = + boost::json::try_value_to(*jvlowTrustStatus); + + if (lowTrustStatus.has_error()) + { + return lowTrustStatus.error(); + } + + std::vector vsharedBanChannelIds; + const auto *jvsharedBanChannelIds = + root.if_contains("shared_ban_channel_ids"); + if (jvsharedBanChannelIds != nullptr && !jvsharedBanChannelIds->is_null()) + { + auto sharedBanChannelIds = + boost::json::try_value_to>( + *jvsharedBanChannelIds); + if (sharedBanChannelIds.has_error()) + { + return sharedBanChannelIds.error(); + } + else + { + vsharedBanChannelIds = std::move(sharedBanChannelIds.value()); + } + } + + std::vector vtypes; + const auto *jvtypes = root.if_contains("types"); + if (jvtypes != nullptr && !jvtypes->is_null()) + { + auto types = + boost::json::try_value_to>(*jvtypes); + if (types.has_error()) + { + return types.error(); + } + else + { + vtypes = std::move(types.value()); + } + } + const auto *jvbanEvasionEvaluation = + root.if_contains("ban_evasion_evaluation"); + if (jvbanEvasionEvaluation == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto banEvasionEvaluation = + boost::json::try_value_to(*jvbanEvasionEvaluation); + + if (banEvasionEvaluation.has_error()) + { + return banEvasionEvaluation.error(); + } + + const auto *jvmessage = root.if_contains("message"); + if (jvmessage == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto message = boost::json::try_value_to(*jvmessage); + + if (message.has_error()) + { + return message.error(); + } + + return Event{ + .broadcasterUserID = std::move(broadcasterUserID.value()), + .broadcasterUserLogin = std::move(broadcasterUserLogin.value()), + .broadcasterUserName = std::move(broadcasterUserName.value()), + .userID = std::move(userID.value()), + .userLogin = std::move(userLogin.value()), + .userName = std::move(userName.value()), + .lowTrustStatus = std::move(lowTrustStatus.value()), + .sharedBanChannelIds = std::move(vsharedBanChannelIds), + .types = std::move(vtypes), + .banEvasionEvaluation = std::move(banEvasionEvaluation.value()), + .message = std::move(message.value()), + }; +} + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag /* tag */, + const boost::json::value &jvRoot) +{ + if (!jvRoot.is_object()) + { + EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject); + } + const auto &root = jvRoot.get_object(); + + const auto *jvsubscription = root.if_contains("subscription"); + if (jvsubscription == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto subscription = + boost::json::try_value_to(*jvsubscription); + + if (subscription.has_error()) + { + return subscription.error(); + } + + const auto *jvevent = root.if_contains("event"); + if (jvevent == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto event = boost::json::try_value_to(*jvevent); + + if (event.has_error()) + { + return event.error(); + } + + return Payload{ + .subscription = std::move(subscription.value()), + .event = std::move(event.value()), + }; +} + +} // namespace chatterino::eventsub::lib::payload::channel_suspicious_user_message::v1 diff --git a/lib/twitch-eventsub-ws/src/generated/payloads/channel-suspicious-user-update-v1.cpp b/lib/twitch-eventsub-ws/src/generated/payloads/channel-suspicious-user-update-v1.cpp new file mode 100644 index 00000000..edddeae4 --- /dev/null +++ b/lib/twitch-eventsub-ws/src/generated/payloads/channel-suspicious-user-update-v1.cpp @@ -0,0 +1,218 @@ +// WARNING: This file is automatically generated. Any changes will be lost. +#include "twitch-eventsub-ws/chrono.hpp" // IWYU pragma: keep +#include "twitch-eventsub-ws/detail/errors.hpp" +#include "twitch-eventsub-ws/detail/variant.hpp" // IWYU pragma: keep +#include "twitch-eventsub-ws/payloads/channel-suspicious-user-update-v1.hpp" + +#include + +namespace chatterino::eventsub::lib::payload::channel_suspicious_user_update:: + v1 { + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag /* tag */, + const boost::json::value &jvRoot) +{ + if (!jvRoot.is_object()) + { + EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject); + } + const auto &root = jvRoot.get_object(); + + const auto *jvbroadcasterUserID = root.if_contains("broadcaster_user_id"); + if (jvbroadcasterUserID == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto broadcasterUserID = + boost::json::try_value_to(*jvbroadcasterUserID); + + if (broadcasterUserID.has_error()) + { + return broadcasterUserID.error(); + } + + const auto *jvbroadcasterUserLogin = + root.if_contains("broadcaster_user_login"); + if (jvbroadcasterUserLogin == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto broadcasterUserLogin = + boost::json::try_value_to(*jvbroadcasterUserLogin); + + if (broadcasterUserLogin.has_error()) + { + return broadcasterUserLogin.error(); + } + + const auto *jvbroadcasterUserName = + root.if_contains("broadcaster_user_name"); + if (jvbroadcasterUserName == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto broadcasterUserName = + boost::json::try_value_to(*jvbroadcasterUserName); + + if (broadcasterUserName.has_error()) + { + return broadcasterUserName.error(); + } + + const auto *jvuserID = root.if_contains("user_id"); + if (jvuserID == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto userID = boost::json::try_value_to(*jvuserID); + + if (userID.has_error()) + { + return userID.error(); + } + + const auto *jvuserLogin = root.if_contains("user_login"); + if (jvuserLogin == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto userLogin = boost::json::try_value_to(*jvuserLogin); + + if (userLogin.has_error()) + { + return userLogin.error(); + } + + const auto *jvuserName = root.if_contains("user_name"); + if (jvuserName == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto userName = boost::json::try_value_to(*jvuserName); + + if (userName.has_error()) + { + return userName.error(); + } + + const auto *jvmoderatorUserID = root.if_contains("moderator_user_id"); + if (jvmoderatorUserID == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto moderatorUserID = + boost::json::try_value_to(*jvmoderatorUserID); + + if (moderatorUserID.has_error()) + { + return moderatorUserID.error(); + } + + const auto *jvmoderatorUserLogin = root.if_contains("moderator_user_login"); + if (jvmoderatorUserLogin == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto moderatorUserLogin = + boost::json::try_value_to(*jvmoderatorUserLogin); + + if (moderatorUserLogin.has_error()) + { + return moderatorUserLogin.error(); + } + + const auto *jvmoderatorUserName = root.if_contains("moderator_user_name"); + if (jvmoderatorUserName == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto moderatorUserName = + boost::json::try_value_to(*jvmoderatorUserName); + + if (moderatorUserName.has_error()) + { + return moderatorUserName.error(); + } + + const auto *jvlowTrustStatus = root.if_contains("low_trust_status"); + if (jvlowTrustStatus == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto lowTrustStatus = + boost::json::try_value_to(*jvlowTrustStatus); + + if (lowTrustStatus.has_error()) + { + return lowTrustStatus.error(); + } + + return Event{ + .broadcasterUserID = std::move(broadcasterUserID.value()), + .broadcasterUserLogin = std::move(broadcasterUserLogin.value()), + .broadcasterUserName = std::move(broadcasterUserName.value()), + .userID = std::move(userID.value()), + .userLogin = std::move(userLogin.value()), + .userName = std::move(userName.value()), + .moderatorUserID = std::move(moderatorUserID.value()), + .moderatorUserLogin = std::move(moderatorUserLogin.value()), + .moderatorUserName = std::move(moderatorUserName.value()), + .lowTrustStatus = std::move(lowTrustStatus.value()), + }; +} + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag /* tag */, + const boost::json::value &jvRoot) +{ + if (!jvRoot.is_object()) + { + EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject); + } + const auto &root = jvRoot.get_object(); + + const auto *jvsubscription = root.if_contains("subscription"); + if (jvsubscription == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto subscription = + boost::json::try_value_to(*jvsubscription); + + if (subscription.has_error()) + { + return subscription.error(); + } + + const auto *jvevent = root.if_contains("event"); + if (jvevent == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto event = boost::json::try_value_to(*jvevent); + + if (event.has_error()) + { + return event.error(); + } + + return Payload{ + .subscription = std::move(subscription.value()), + .event = std::move(event.value()), + }; +} + +} // namespace chatterino::eventsub::lib::payload::channel_suspicious_user_update::v1 diff --git a/lib/twitch-eventsub-ws/src/generated/payloads/structured-message.cpp b/lib/twitch-eventsub-ws/src/generated/payloads/structured-message.cpp new file mode 100644 index 00000000..6e202a05 --- /dev/null +++ b/lib/twitch-eventsub-ws/src/generated/payloads/structured-message.cpp @@ -0,0 +1,318 @@ +// WARNING: This file is automatically generated. Any changes will be lost. +#include "twitch-eventsub-ws/chrono.hpp" // IWYU pragma: keep +#include "twitch-eventsub-ws/detail/errors.hpp" +#include "twitch-eventsub-ws/detail/variant.hpp" // IWYU pragma: keep +#include "twitch-eventsub-ws/payloads/structured-message.hpp" + +#include + +namespace chatterino::eventsub::lib::chat { + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag /* tag */, + const boost::json::value &jvRoot) +{ + if (!jvRoot.is_object()) + { + EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject); + } + const auto &root = jvRoot.get_object(); + + const auto *jvprefix = root.if_contains("prefix"); + if (jvprefix == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto prefix = boost::json::try_value_to(*jvprefix); + + if (prefix.has_error()) + { + return prefix.error(); + } + + static_assert( + std::is_trivially_copyable_v< + std::remove_reference_t().bits)>>); + const auto *jvbits = root.if_contains("bits"); + if (jvbits == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto bits = boost::json::try_value_to(*jvbits); + + if (bits.has_error()) + { + return bits.error(); + } + + static_assert( + std::is_trivially_copyable_v< + std::remove_reference_t().tier)>>); + const auto *jvtier = root.if_contains("tier"); + if (jvtier == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto tier = boost::json::try_value_to(*jvtier); + + if (tier.has_error()) + { + return tier.error(); + } + + return Cheermote{ + .prefix = std::move(prefix.value()), + .bits = bits.value(), + .tier = tier.value(), + }; +} + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag /* tag */, + const boost::json::value &jvRoot) +{ + if (!jvRoot.is_object()) + { + EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject); + } + const auto &root = jvRoot.get_object(); + + const auto *jvid = root.if_contains("id"); + if (jvid == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto id = boost::json::try_value_to(*jvid); + + if (id.has_error()) + { + return id.error(); + } + + const auto *jvemoteSetID = root.if_contains("emote_set_id"); + if (jvemoteSetID == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto emoteSetID = boost::json::try_value_to(*jvemoteSetID); + + if (emoteSetID.has_error()) + { + return emoteSetID.error(); + } + + return Emote{ + .id = std::move(id.value()), + .emoteSetID = std::move(emoteSetID.value()), + }; +} + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag /* tag */, + const boost::json::value &jvRoot) +{ + if (!jvRoot.is_object()) + { + EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject); + } + const auto &root = jvRoot.get_object(); + + const auto *jvuserID = root.if_contains("user_id"); + if (jvuserID == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto userID = boost::json::try_value_to(*jvuserID); + + if (userID.has_error()) + { + return userID.error(); + } + + const auto *jvuserName = root.if_contains("user_name"); + if (jvuserName == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto userName = boost::json::try_value_to(*jvuserName); + + if (userName.has_error()) + { + return userName.error(); + } + + const auto *jvuserLogin = root.if_contains("user_login"); + if (jvuserLogin == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto userLogin = boost::json::try_value_to(*jvuserLogin); + + if (userLogin.has_error()) + { + return userLogin.error(); + } + + return Mention{ + .userID = std::move(userID.value()), + .userName = std::move(userName.value()), + .userLogin = std::move(userLogin.value()), + }; +} + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag /* tag */, + const boost::json::value & /* jvRoot */) +{ + return Text{}; +} + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag /* tag */, + const boost::json::value &jvRoot) +{ + if (!jvRoot.is_object()) + { + EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject); + } + const auto &root = jvRoot.get_object(); + + const auto *jvtext = root.if_contains("text"); + if (jvtext == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto text = boost::json::try_value_to(*jvtext); + + if (text.has_error()) + { + return text.error(); + } + + const auto *jvinnerTag = root.if_contains("type"); + if (jvinnerTag == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto innerTagRes = + boost::json::try_value_to(*jvinnerTag); + if (innerTagRes.has_error()) + { + return innerTagRes.error(); + } + std::string_view innerTag = *innerTagRes; + decltype(std::declval().inner) inner; + if (innerTag == Text::TAG) + { + inner.emplace(); + } + else if (innerTag == Cheermote::TAG) + { + const auto *innerVal = root.if_contains(detail::fieldFor()); + if (!innerVal) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + auto innerCheermote = boost::json::try_value_to(*innerVal); + if (innerCheermote.has_error()) + { + return innerCheermote.error(); + } + inner.emplace(std::move(innerCheermote.value())); + } + else if (innerTag == Emote::TAG) + { + const auto *innerVal = root.if_contains(detail::fieldFor()); + if (!innerVal) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + auto innerEmote = boost::json::try_value_to(*innerVal); + if (innerEmote.has_error()) + { + return innerEmote.error(); + } + inner.emplace(std::move(innerEmote.value())); + } + else if (innerTag == Mention::TAG) + { + const auto *innerVal = root.if_contains(detail::fieldFor()); + if (!innerVal) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + auto innerMention = boost::json::try_value_to(*innerVal); + if (innerMention.has_error()) + { + return innerMention.error(); + } + inner.emplace(std::move(innerMention.value())); + } + else + { + EVENTSUB_BAIL_HERE(error::Kind::UnknownVariant); + } + + return MessageFragment{ + .text = std::move(text.value()), + .inner = std::move(inner), + }; +} + +boost::json::result_for::type tag_invoke( + boost::json::try_value_to_tag /* tag */, + const boost::json::value &jvRoot) +{ + if (!jvRoot.is_object()) + { + EVENTSUB_BAIL_HERE(error::Kind::ExpectedObject); + } + const auto &root = jvRoot.get_object(); + + const auto *jvtext = root.if_contains("text"); + if (jvtext == nullptr) + { + EVENTSUB_BAIL_HERE(error::Kind::FieldMissing); + } + + auto text = boost::json::try_value_to(*jvtext); + + if (text.has_error()) + { + return text.error(); + } + + std::vector vfragments; + const auto *jvfragments = root.if_contains("fragments"); + if (jvfragments != nullptr && !jvfragments->is_null()) + { + auto fragments = + boost::json::try_value_to>( + *jvfragments); + if (fragments.has_error()) + { + return fragments.error(); + } + else + { + vfragments = std::move(fragments.value()); + } + } + + return Message{ + .text = std::move(text.value()), + .fragments = std::move(vfragments), + }; +} + +} // namespace chatterino::eventsub::lib::chat diff --git a/lib/twitch-eventsub-ws/src/session.cpp b/lib/twitch-eventsub-ws/src/session.cpp index e633edcf..ebe01f9c 100644 --- a/lib/twitch-eventsub-ws/src/session.cpp +++ b/lib/twitch-eventsub-ws/src/session.cpp @@ -158,6 +158,60 @@ namespace { return boost::system::error_code{}; }, }, + { + {"automod.message.hold", "2"}, + [](const auto &metadata, const auto &jv, auto &listener) { + auto oPayload = + parsePayload( + jv); + if (!oPayload) + { + return oPayload.error(); + } + listener->onAutomodMessageHold(metadata, *oPayload); + return boost::system::error_code{}; + }, + }, + { + {"automod.message.update", "2"}, + [](const auto &metadata, const auto &jv, auto &listener) { + auto oPayload = + parsePayload( + jv); + if (!oPayload) + { + return oPayload.error(); + } + listener->onAutomodMessageUpdate(metadata, *oPayload); + return boost::system::error_code{}; + }, + }, + { + {"channel.suspicious_user.message", "1"}, + [](const auto &metadata, const auto &jv, auto &listener) { + auto oPayload = parsePayload< + payload::channel_suspicious_user_message::v1::Payload>(jv); + if (!oPayload) + { + return oPayload.error(); + } + listener->onChannelSuspiciousUserMessage(metadata, *oPayload); + return boost::system::error_code{}; + }, + }, + { + {"channel.suspicious_user.update", "1"}, + [](const auto &metadata, const auto &jv, auto &listener) { + auto oPayload = parsePayload< + payload::channel_suspicious_user_update::v1::Payload>(jv); + if (!oPayload) + { + return oPayload.error(); + } + listener->onChannelSuspiciousUserUpdate(metadata, *oPayload); + return boost::system::error_code{}; + }, + }, // Add your new subscription types above this line }; diff --git a/lib/twitch-eventsub-ws/tests/resources/messages/automod.message.hold.json b/lib/twitch-eventsub-ws/tests/resources/messages/automod.message.hold.json new file mode 100644 index 00000000..e9ad8347 --- /dev/null +++ b/lib/twitch-eventsub-ws/tests/resources/messages/automod.message.hold.json @@ -0,0 +1,71 @@ +{ + "metadata": { + "message_id": "e6095757-c068-4a97-b6b4-46cb45c8d507", + "message_type": "notification", + "message_timestamp": "2023-05-14T12:31:47.995298776Z", + "subscription_type": "automod.message.hold", + "subscription_version": "2" + }, + "payload": { + "subscription": { + "id": "f1c2a387-161a-49f9-a165-0f21d7a4e1c4", + "type": "automod.message.hold", + "version": "2", + "status": "enabled", + "cost": 0, + "condition": { + "broadcaster_user_id": "1337", + "moderator_user_id": "9001" + }, + "transport": { "method": "websocket", "session_id": "38de428e_b11f07be" }, + "created_at": "2023-04-11T10:11:12.123Z" + }, + "event": { + "broadcaster_user_id": "1337", + "broadcaster_user_login": "blah", + "broadcaster_user_name": "blahblah", + "user_id": "4242", + "user_login": "baduser", + "user_name": "badbaduser", + "message_id": "bad-message-id", + "message": { + "text": "This is a bad message… pogchamp", + "fragments": [ + { + "type": "text", + "text": "This is a bad message… ", + "cheermote": null, + "emote": null + }, + { + "type": "cheermote", + "text": "pogchamp", + "cheermote": { + "prefix": "pogchamp", + "bits": 1000, + "tier": 1 + }, + "emote": null + } + ] + }, + "reason": "automod", + "automod": { + "category": "aggressive", + "level": 1, + "boundaries": [ + { + "start_pos": 0, + "end_pos": 10 + }, + { + "start_pos": 20, + "end_pos": 30 + } + ] + }, + "blocked_term": null, + "held_at": "2022-12-02T15:00:00.00Z" + } + } +} diff --git a/lib/twitch-eventsub-ws/tests/resources/messages/automod.message.update.json b/lib/twitch-eventsub-ws/tests/resources/messages/automod.message.update.json new file mode 100644 index 00000000..411161d6 --- /dev/null +++ b/lib/twitch-eventsub-ws/tests/resources/messages/automod.message.update.json @@ -0,0 +1,75 @@ +{ + "metadata": { + "message_id": "e6095757-c068-4a97-b6b4-46cb45c8d507", + "message_type": "notification", + "message_timestamp": "2023-05-14T12:31:47.995298776Z", + "subscription_type": "automod.message.update", + "subscription_version": "2" + }, + "payload": { + "subscription": { + "id": "f1c2a387-161a-49f9-a165-0f21d7a4e1c4", + "type": "automod.message.update", + "version": "2", + "status": "enabled", + "cost": 0, + "condition": { + "broadcaster_user_id": "1337", + "moderator_user_id": "9001" + }, + "transport": { "method": "websocket", "session_id": "38de428e_b11f07be" }, + "created_at": "2023-04-11T10:11:12.123Z" + }, + "event": { + "broadcaster_user_id": "1337", + "broadcaster_user_login": "blah", + "broadcaster_user_name": "blahblah", + "moderator_user_id": "9001", + "moderator_user_login": "the_mod", + "moderator_user_name": "The_Mod", + "user_id": "4242", + "user_login": "baduser", + "user_name": "badbaduser", + "message_id": "bad-message-id", + "message": { + "text": "This is a bad message… pogchamp", + "fragments": [ + { + "type": "text", + "text": "This is a bad message… ", + "cheermote": null, + "emote": null + }, + { + "type": "cheermote", + "text": "pogchamp", + "cheermote": { + "prefix": "pogchamp", + "bits": 1000, + "tier": 1 + }, + "emote": null + } + ] + }, + "reason": "blocked_term", + "automod": null, + "blocked_term": { + "terms_found": [ + { + "term_id": "123", + "owner_broadcaster_user_id": "1337", + "owner_broadcaster_user_login": "blah", + "owner_broadcaster_user_name": "blahblah", + "boundary": { + "start_pos": 0, + "end_pos": 30 + } + } + ] + }, + "status": "approved", + "held_at": "2022-12-02T15:00:00.00Z" + } + } +} diff --git a/lib/twitch-eventsub-ws/tests/resources/messages/channel.suspicious_user.message.json b/lib/twitch-eventsub-ws/tests/resources/messages/channel.suspicious_user.message.json new file mode 100644 index 00000000..6a0c9a89 --- /dev/null +++ b/lib/twitch-eventsub-ws/tests/resources/messages/channel.suspicious_user.message.json @@ -0,0 +1,61 @@ +{ + "metadata": { + "message_id": "bf6e248f-a523-4bf8-b215-ea1822e60223", + "message_type": "notification", + "message_timestamp": "2024-05-14T12:31:47.995298776Z", + "subscription_type": "channel.suspicious_user.message", + "subscription_version": "1" + }, + "payload": { + "subscription": { + "id": "f1c2a387-161a-49f9-a165-0f21d7a4e1c4", + "type": "channel.suspicious_user.message", + "version": "1", + "status": "enabled", + "cost": 0, + "condition": { + "moderator_user_id": "9001", + "broadcaster_user_id": "1050263432" + }, + "transport": { "method": "websocket", "session_id": "38de428e_b11f07be" }, + "created_at": "2023-04-11T10:11:12.123Z" + }, + "event": { + "broadcaster_user_id": "1050263432", + "broadcaster_user_name": "dcf9dd9336034d23b65", + "broadcaster_user_login": "dcf9dd9336034d23b65", + "user_id": "1050263434", + "user_name": "4a46e2cf2e2f4d6a9e6", + "user_login": "4a46e2cf2e2f4d6a9e6", + "low_trust_status": "active_monitoring", + "shared_ban_channel_ids": ["100", "200"], + "types": ["ban_evader"], + "ban_evasion_evaluation": "likely", + "message": { + "message_id": "101010", + "text": "bad stuff pogchamp", + "fragments": [ + { + "type": "emote", + "text": "bad stuff", + "cheermote": null, + "emote": { + "id": "899", + "emote_set_id": "1" + } + }, + { + "type": "cheermote", + "text": "pogchamp", + "cheermote": { + "prefix": "pogchamp", + "bits": 100, + "tier": 1 + }, + "emote": null + } + ] + } + } + } +} diff --git a/lib/twitch-eventsub-ws/tests/resources/messages/channel.suspicious_user.update.json b/lib/twitch-eventsub-ws/tests/resources/messages/channel.suspicious_user.update.json new file mode 100644 index 00000000..e9d996f2 --- /dev/null +++ b/lib/twitch-eventsub-ws/tests/resources/messages/channel.suspicious_user.update.json @@ -0,0 +1,36 @@ +{ + "metadata": { + "message_id": "bf6e248f-a523-4bf8-b215-ea1822e60223", + "message_type": "notification", + "message_timestamp": "2024-05-14T12:31:47.995298776Z", + "subscription_type": "channel.suspicious_user.update", + "subscription_version": "1" + }, + "payload": { + "subscription": { + "id": "f1c2a387-161a-49f9-a165-0f21d7a4e1c4", + "type": "channel.suspicious_user.update", + "version": "1", + "status": "enabled", + "cost": 0, + "condition": { + "broadcaster_user_id": "1050263435", + "moderator_user_id": "1050263436" + }, + "transport": { "method": "websocket", "session_id": "38de428e_b11f07be" }, + "created_at": "2023-04-11T10:11:12.123Z" + }, + "event": { + "broadcaster_user_id": "1050263435", + "broadcaster_user_name": "77f111cbb75341449f5", + "broadcaster_user_login": "77f111cbb75341449f5", + "moderator_user_id": "1050263436", + "moderator_user_name": "29087e59dfc441968f6", + "moderator_user_login": "29087e59dfc441968f6", + "user_id": "1050263437", + "user_name": "06fbcc75952245c5a87", + "user_login": "06fbcc75952245c5a87", + "low_trust_status": "restricted" + } + } +} diff --git a/lib/twitch-eventsub-ws/tests/src/parse.cpp b/lib/twitch-eventsub-ws/tests/src/parse.cpp index 32b949ab..258e30d5 100644 --- a/lib/twitch-eventsub-ws/tests/src/parse.cpp +++ b/lib/twitch-eventsub-ws/tests/src/parse.cpp @@ -106,6 +106,29 @@ class NoOpListener : public chatterino::eventsub::lib::Listener const payload::channel_moderate::v2::Payload &payload) override { } + + void onAutomodMessageHold( + const messages::Metadata &metadata, + const payload::automod_message_hold::v2::Payload &payload) override + { + } + void onAutomodMessageUpdate( + const messages::Metadata &metadata, + const payload::automod_message_update::v2::Payload &payload) override + { + } + void onChannelSuspiciousUserMessage( + const messages::Metadata &metadata, + const payload::channel_suspicious_user_message::v1::Payload &payload) + override + { + } + void onChannelSuspiciousUserUpdate( + const messages::Metadata &metadata, + const payload::channel_suspicious_user_update::v1::Payload &payload) + override + { + } }; } // namespace diff --git a/src/providers/twitch/eventsub/Connection.cpp b/src/providers/twitch/eventsub/Connection.cpp index c18a048a..15921c8c 100644 --- a/src/providers/twitch/eventsub/Connection.cpp +++ b/src/providers/twitch/eventsub/Connection.cpp @@ -173,6 +173,41 @@ void Connection::onChannelModerate( payload.event.action); } +void Connection::onAutomodMessageHold( + const lib::messages::Metadata &metadata, + const lib::payload::automod_message_hold::v2::Payload &payload) +{ + (void)metadata; + qCDebug(LOG) << "On automod message hold for" + << payload.event.broadcasterUserLogin.c_str(); +} +void Connection::onAutomodMessageUpdate( + const lib::messages::Metadata &metadata, + const lib::payload::automod_message_update::v2::Payload &payload) +{ + (void)metadata; + qCDebug(LOG) << "On automod message update for" + << payload.event.broadcasterUserLogin.c_str(); +} + +void Connection::onChannelSuspiciousUserMessage( + const lib::messages::Metadata &metadata, + const lib::payload::channel_suspicious_user_message::v1::Payload &payload) +{ + (void)metadata; + qCDebug(LOG) << "On channel suspicious user message for" + << payload.event.broadcasterUserLogin.c_str(); +} + +void Connection::onChannelSuspiciousUserUpdate( + const lib::messages::Metadata &metadata, + const lib::payload::channel_suspicious_user_update::v1::Payload &payload) +{ + (void)metadata; + qCDebug(LOG) << "On channel suspicious user update for" + << payload.event.broadcasterUserLogin.c_str(); +} + QString Connection::getSessionID() const { return this->sessionID; diff --git a/src/providers/twitch/eventsub/Connection.hpp b/src/providers/twitch/eventsub/Connection.hpp index b28ba649..9a04b729 100644 --- a/src/providers/twitch/eventsub/Connection.hpp +++ b/src/providers/twitch/eventsub/Connection.hpp @@ -51,6 +51,26 @@ public: const lib::messages::Metadata &metadata, const lib::payload::channel_moderate::v2::Payload &payload) override; + void onAutomodMessageHold( + const lib::messages::Metadata &metadata, + const lib::payload::automod_message_hold::v2::Payload &payload) + override; + + void onAutomodMessageUpdate( + const lib::messages::Metadata &metadata, + const lib::payload::automod_message_update::v2::Payload &payload) + override; + + void onChannelSuspiciousUserMessage( + const lib::messages::Metadata &metadata, + const lib::payload::channel_suspicious_user_message::v1::Payload + &payload) override; + + void onChannelSuspiciousUserUpdate( + const lib::messages::Metadata &metadata, + const lib::payload::channel_suspicious_user_update::v1::Payload + &payload) override; + QString getSessionID() const; bool isSubscribedTo(const SubscriptionRequest &request) const;