Refactor 7TV EventAPI (#4342)
* refactor: remove file prefix * refactor: put eventapi into a namespace * refactor: support multiple conditions * fix: handle ack * docs: add changelog entry * fix: unsubscribe in destructor * fix: naming of parameter * fix: namespaces * chore: casing * fix: missing namespace --------- Co-authored-by: pajlada <rasmus.karlsson@pajlada.com>
This commit is contained in:
@@ -44,6 +44,7 @@
|
|||||||
- Dev: Format YAML and JSON files with prettier. (#4304)
|
- Dev: Format YAML and JSON files with prettier. (#4304)
|
||||||
- Dev: Added CMake Install Support on Windows. (#4300)
|
- Dev: Added CMake Install Support on Windows. (#4300)
|
||||||
- Dev: Changed conan generator to [`CMakeDeps`](https://docs.conan.io/en/latest/reference/conanfile/tools/cmake/cmakedeps.html) and [`CMakeToolchain`](https://docs.conan.io/en/latest/reference/conanfile/tools/cmake/cmaketoolchain.html). See PR for migration notes. (#4335)
|
- Dev: Changed conan generator to [`CMakeDeps`](https://docs.conan.io/en/latest/reference/conanfile/tools/cmake/cmakedeps.html) and [`CMakeToolchain`](https://docs.conan.io/en/latest/reference/conanfile/tools/cmake/cmaketoolchain.html). See PR for migration notes. (#4335)
|
||||||
|
- Dev: Refactored 7TV EventAPI implementation. (#4342)
|
||||||
|
|
||||||
## 2.4.0
|
## 2.4.0
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -19,8 +19,8 @@
|
|||||||
#include "providers/chatterino/ChatterinoBadges.hpp"
|
#include "providers/chatterino/ChatterinoBadges.hpp"
|
||||||
#include "providers/ffz/FfzBadges.hpp"
|
#include "providers/ffz/FfzBadges.hpp"
|
||||||
#include "providers/irc/Irc2.hpp"
|
#include "providers/irc/Irc2.hpp"
|
||||||
#include "providers/seventv/eventapi/SeventvEventAPIDispatch.hpp"
|
#include "providers/seventv/eventapi/Dispatch.hpp"
|
||||||
#include "providers/seventv/eventapi/SeventvEventAPISubscription.hpp"
|
#include "providers/seventv/eventapi/Subscription.hpp"
|
||||||
#include "providers/seventv/SeventvBadges.hpp"
|
#include "providers/seventv/SeventvBadges.hpp"
|
||||||
#include "providers/seventv/SeventvEventAPI.hpp"
|
#include "providers/seventv/SeventvEventAPI.hpp"
|
||||||
#include "providers/twitch/ChannelPointReward.hpp"
|
#include "providers/twitch/ChannelPointReward.hpp"
|
||||||
|
|||||||
+8
-8
@@ -250,14 +250,14 @@ set(SOURCE_FILES
|
|||||||
providers/seventv/SeventvEventAPI.cpp
|
providers/seventv/SeventvEventAPI.cpp
|
||||||
providers/seventv/SeventvEventAPI.hpp
|
providers/seventv/SeventvEventAPI.hpp
|
||||||
|
|
||||||
providers/seventv/eventapi/SeventvEventAPIClient.cpp
|
providers/seventv/eventapi/Client.cpp
|
||||||
providers/seventv/eventapi/SeventvEventAPIClient.hpp
|
providers/seventv/eventapi/Client.hpp
|
||||||
providers/seventv/eventapi/SeventvEventAPIDispatch.cpp
|
providers/seventv/eventapi/Dispatch.cpp
|
||||||
providers/seventv/eventapi/SeventvEventAPIDispatch.hpp
|
providers/seventv/eventapi/Dispatch.hpp
|
||||||
providers/seventv/eventapi/SeventvEventAPIMessage.cpp
|
providers/seventv/eventapi/Message.cpp
|
||||||
providers/seventv/eventapi/SeventvEventAPIMessage.hpp
|
providers/seventv/eventapi/Message.hpp
|
||||||
providers/seventv/eventapi/SeventvEventAPISubscription.cpp
|
providers/seventv/eventapi/Subscription.cpp
|
||||||
providers/seventv/eventapi/SeventvEventAPISubscription.hpp
|
providers/seventv/eventapi/Subscription.hpp
|
||||||
|
|
||||||
providers/twitch/ChannelPointReward.cpp
|
providers/twitch/ChannelPointReward.cpp
|
||||||
providers/twitch/ChannelPointReward.hpp
|
providers/twitch/ChannelPointReward.hpp
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#include "messages/Image.hpp"
|
#include "messages/Image.hpp"
|
||||||
#include "messages/ImageSet.hpp"
|
#include "messages/ImageSet.hpp"
|
||||||
#include "messages/MessageBuilder.hpp"
|
#include "messages/MessageBuilder.hpp"
|
||||||
#include "providers/seventv/eventapi/SeventvEventAPIDispatch.hpp"
|
#include "providers/seventv/eventapi/Dispatch.hpp"
|
||||||
#include "providers/twitch/TwitchChannel.hpp"
|
#include "providers/twitch/TwitchChannel.hpp"
|
||||||
#include "singletons/Settings.hpp"
|
#include "singletons/Settings.hpp"
|
||||||
|
|
||||||
@@ -30,6 +30,7 @@
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using namespace chatterino;
|
using namespace chatterino;
|
||||||
|
using namespace seventv::eventapi;
|
||||||
|
|
||||||
// These declarations won't throw an exception.
|
// These declarations won't throw an exception.
|
||||||
const QString CHANNEL_HAS_NO_EMOTES("This channel has no 7TV channel emotes.");
|
const QString CHANNEL_HAS_NO_EMOTES("This channel has no 7TV channel emotes.");
|
||||||
@@ -224,7 +225,7 @@ EmoteMap parseEmotes(const QJsonArray &emoteSetEmotes, bool isGlobal)
|
|||||||
}
|
}
|
||||||
|
|
||||||
EmotePtr createUpdatedEmote(const EmotePtr &oldEmote,
|
EmotePtr createUpdatedEmote(const EmotePtr &oldEmote,
|
||||||
const SeventvEventAPIEmoteUpdateDispatch &dispatch)
|
const EmoteUpdateDispatch &dispatch)
|
||||||
{
|
{
|
||||||
bool toNonAliased = oldEmote->baseName.has_value() &&
|
bool toNonAliased = oldEmote->baseName.has_value() &&
|
||||||
dispatch.emoteName == oldEmote->baseName->string;
|
dispatch.emoteName == oldEmote->baseName->string;
|
||||||
@@ -245,6 +246,8 @@ EmotePtr createUpdatedEmote(const EmotePtr &oldEmote,
|
|||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
|
using namespace seventv::eventapi;
|
||||||
|
|
||||||
SeventvEmotes::SeventvEmotes()
|
SeventvEmotes::SeventvEmotes()
|
||||||
: global_(std::make_shared<EmoteMap>())
|
: global_(std::make_shared<EmoteMap>())
|
||||||
{
|
{
|
||||||
@@ -401,7 +404,7 @@ void SeventvEmotes::loadChannelEmotes(
|
|||||||
|
|
||||||
boost::optional<EmotePtr> SeventvEmotes::addEmote(
|
boost::optional<EmotePtr> SeventvEmotes::addEmote(
|
||||||
Atomic<std::shared_ptr<const EmoteMap>> &map,
|
Atomic<std::shared_ptr<const EmoteMap>> &map,
|
||||||
const SeventvEventAPIEmoteAddDispatch &dispatch)
|
const EmoteAddDispatch &dispatch)
|
||||||
{
|
{
|
||||||
// Check for visibility first, so we don't copy the map.
|
// Check for visibility first, so we don't copy the map.
|
||||||
auto emoteData = dispatch.emoteJson["data"].toObject();
|
auto emoteData = dispatch.emoteJson["data"].toObject();
|
||||||
@@ -429,7 +432,7 @@ boost::optional<EmotePtr> SeventvEmotes::addEmote(
|
|||||||
|
|
||||||
boost::optional<EmotePtr> SeventvEmotes::updateEmote(
|
boost::optional<EmotePtr> SeventvEmotes::updateEmote(
|
||||||
Atomic<std::shared_ptr<const EmoteMap>> &map,
|
Atomic<std::shared_ptr<const EmoteMap>> &map,
|
||||||
const SeventvEventAPIEmoteUpdateDispatch &dispatch)
|
const EmoteUpdateDispatch &dispatch)
|
||||||
{
|
{
|
||||||
auto oldMap = map.get();
|
auto oldMap = map.get();
|
||||||
auto oldEmote = oldMap->findEmote(dispatch.emoteName, dispatch.emoteID);
|
auto oldEmote = oldMap->findEmote(dispatch.emoteName, dispatch.emoteID);
|
||||||
@@ -451,7 +454,7 @@ boost::optional<EmotePtr> SeventvEmotes::updateEmote(
|
|||||||
|
|
||||||
boost::optional<EmotePtr> SeventvEmotes::removeEmote(
|
boost::optional<EmotePtr> SeventvEmotes::removeEmote(
|
||||||
Atomic<std::shared_ptr<const EmoteMap>> &map,
|
Atomic<std::shared_ptr<const EmoteMap>> &map,
|
||||||
const SeventvEventAPIEmoteRemoveDispatch &dispatch)
|
const EmoteRemoveDispatch &dispatch)
|
||||||
{
|
{
|
||||||
// This copies the map.
|
// This copies the map.
|
||||||
EmoteMap updatedMap = *map.get();
|
EmoteMap updatedMap = *map.get();
|
||||||
|
|||||||
@@ -10,9 +10,12 @@
|
|||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
class Channel;
|
class Channel;
|
||||||
struct SeventvEventAPIEmoteAddDispatch;
|
|
||||||
struct SeventvEventAPIEmoteUpdateDispatch;
|
namespace seventv::eventapi {
|
||||||
struct SeventvEventAPIEmoteRemoveDispatch;
|
struct EmoteAddDispatch;
|
||||||
|
struct EmoteUpdateDispatch;
|
||||||
|
struct EmoteRemoveDispatch;
|
||||||
|
} // namespace seventv::eventapi
|
||||||
|
|
||||||
// https://github.com/SevenTV/API/blob/a84e884b5590dbb5d91a5c6b3548afabb228f385/data/model/emote-set.model.go#L29-L36
|
// https://github.com/SevenTV/API/blob/a84e884b5590dbb5d91a5c6b3548afabb228f385/data/model/emote-set.model.go#L29-L36
|
||||||
enum class SeventvActiveEmoteFlag : int64_t {
|
enum class SeventvActiveEmoteFlag : int64_t {
|
||||||
@@ -86,7 +89,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
static boost::optional<EmotePtr> addEmote(
|
static boost::optional<EmotePtr> addEmote(
|
||||||
Atomic<std::shared_ptr<const EmoteMap>> &map,
|
Atomic<std::shared_ptr<const EmoteMap>> &map,
|
||||||
const SeventvEventAPIEmoteAddDispatch &dispatch);
|
const seventv::eventapi::EmoteAddDispatch &dispatch);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates an emote in this `map`.
|
* Updates an emote in this `map`.
|
||||||
@@ -97,7 +100,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
static boost::optional<EmotePtr> updateEmote(
|
static boost::optional<EmotePtr> updateEmote(
|
||||||
Atomic<std::shared_ptr<const EmoteMap>> &map,
|
Atomic<std::shared_ptr<const EmoteMap>> &map,
|
||||||
const SeventvEventAPIEmoteUpdateDispatch &dispatch);
|
const seventv::eventapi::EmoteUpdateDispatch &dispatch);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes an emote from this `map`.
|
* Removes an emote from this `map`.
|
||||||
@@ -108,7 +111,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
static boost::optional<EmotePtr> removeEmote(
|
static boost::optional<EmotePtr> removeEmote(
|
||||||
Atomic<std::shared_ptr<const EmoteMap>> &map,
|
Atomic<std::shared_ptr<const EmoteMap>> &map,
|
||||||
const SeventvEventAPIEmoteRemoveDispatch &dispatch);
|
const seventv::eventapi::EmoteRemoveDispatch &dispatch);
|
||||||
|
|
||||||
/** Fetches an emote-set by its id */
|
/** Fetches an emote-set by its id */
|
||||||
static void getEmoteSet(
|
static void getEmoteSet(
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#include "providers/seventv/SeventvEventAPI.hpp"
|
#include "providers/seventv/SeventvEventAPI.hpp"
|
||||||
|
|
||||||
#include "providers/seventv/eventapi/SeventvEventAPIClient.hpp"
|
#include "providers/seventv/eventapi/Client.hpp"
|
||||||
#include "providers/seventv/eventapi/SeventvEventAPIDispatch.hpp"
|
#include "providers/seventv/eventapi/Dispatch.hpp"
|
||||||
#include "providers/seventv/eventapi/SeventvEventAPIMessage.hpp"
|
#include "providers/seventv/eventapi/Message.hpp"
|
||||||
|
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
|
|
||||||
@@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
|
using namespace seventv::eventapi;
|
||||||
|
|
||||||
SeventvEventAPI::SeventvEventAPI(
|
SeventvEventAPI::SeventvEventAPI(
|
||||||
QString host, std::chrono::milliseconds defaultHeartbeatInterval)
|
QString host, std::chrono::milliseconds defaultHeartbeatInterval)
|
||||||
: BasicPubSubManager(std::move(host))
|
: BasicPubSubManager(std::move(host))
|
||||||
@@ -22,13 +24,14 @@ void SeventvEventAPI::subscribeUser(const QString &userID,
|
|||||||
{
|
{
|
||||||
if (!userID.isEmpty() && this->subscribedUsers_.insert(userID).second)
|
if (!userID.isEmpty() && this->subscribedUsers_.insert(userID).second)
|
||||||
{
|
{
|
||||||
this->subscribe({userID, SeventvEventAPISubscriptionType::UpdateUser});
|
this->subscribe(
|
||||||
|
{ObjectIDCondition{userID}, SubscriptionType::UpdateUser});
|
||||||
}
|
}
|
||||||
if (!emoteSetID.isEmpty() &&
|
if (!emoteSetID.isEmpty() &&
|
||||||
this->subscribedEmoteSets_.insert(emoteSetID).second)
|
this->subscribedEmoteSets_.insert(emoteSetID).second)
|
||||||
{
|
{
|
||||||
this->subscribe(
|
this->subscribe(
|
||||||
{emoteSetID, SeventvEventAPISubscriptionType::UpdateEmoteSet});
|
{ObjectIDCondition{emoteSetID}, SubscriptionType::UpdateEmoteSet});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,7 +40,7 @@ void SeventvEventAPI::unsubscribeEmoteSet(const QString &id)
|
|||||||
if (this->subscribedEmoteSets_.erase(id) > 0)
|
if (this->subscribedEmoteSets_.erase(id) > 0)
|
||||||
{
|
{
|
||||||
this->unsubscribe(
|
this->unsubscribe(
|
||||||
{id, SeventvEventAPISubscriptionType::UpdateEmoteSet});
|
{ObjectIDCondition{id}, SubscriptionType::UpdateEmoteSet});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,27 +48,27 @@ void SeventvEventAPI::unsubscribeUser(const QString &id)
|
|||||||
{
|
{
|
||||||
if (this->subscribedUsers_.erase(id) > 0)
|
if (this->subscribedUsers_.erase(id) > 0)
|
||||||
{
|
{
|
||||||
this->unsubscribe({id, SeventvEventAPISubscriptionType::UpdateUser});
|
this->unsubscribe(
|
||||||
|
{ObjectIDCondition{id}, SubscriptionType::UpdateUser});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<BasicPubSubClient<SeventvEventAPISubscription>>
|
std::shared_ptr<BasicPubSubClient<Subscription>> SeventvEventAPI::createClient(
|
||||||
SeventvEventAPI::createClient(liveupdates::WebsocketClient &client,
|
liveupdates::WebsocketClient &client, websocketpp::connection_hdl hdl)
|
||||||
websocketpp::connection_hdl hdl)
|
|
||||||
{
|
{
|
||||||
auto shared = std::make_shared<SeventvEventAPIClient>(
|
auto shared =
|
||||||
client, hdl, this->heartbeatInterval_);
|
std::make_shared<Client>(client, hdl, this->heartbeatInterval_);
|
||||||
return std::static_pointer_cast<
|
return std::static_pointer_cast<BasicPubSubClient<Subscription>>(
|
||||||
BasicPubSubClient<SeventvEventAPISubscription>>(std::move(shared));
|
std::move(shared));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SeventvEventAPI::onMessage(
|
void SeventvEventAPI::onMessage(
|
||||||
websocketpp::connection_hdl hdl,
|
websocketpp::connection_hdl hdl,
|
||||||
BasicPubSubManager<SeventvEventAPISubscription>::WebsocketMessagePtr msg)
|
BasicPubSubManager<Subscription>::WebsocketMessagePtr msg)
|
||||||
{
|
{
|
||||||
const auto &payload = QString::fromStdString(msg->get_payload());
|
const auto &payload = QString::fromStdString(msg->get_payload());
|
||||||
|
|
||||||
auto pMessage = parseSeventvEventAPIBaseMessage(payload);
|
auto pMessage = parseBaseMessage(payload);
|
||||||
|
|
||||||
if (!pMessage)
|
if (!pMessage)
|
||||||
{
|
{
|
||||||
@@ -76,11 +79,10 @@ void SeventvEventAPI::onMessage(
|
|||||||
auto message = *pMessage;
|
auto message = *pMessage;
|
||||||
switch (message.op)
|
switch (message.op)
|
||||||
{
|
{
|
||||||
case SeventvEventAPIOpcode::Hello: {
|
case Opcode::Hello: {
|
||||||
if (auto client = this->findClient(hdl))
|
if (auto client = this->findClient(hdl))
|
||||||
{
|
{
|
||||||
if (auto *stvClient =
|
if (auto *stvClient = dynamic_cast<Client *>(client.get()))
|
||||||
dynamic_cast<SeventvEventAPIClient *>(client.get()))
|
|
||||||
{
|
{
|
||||||
stvClient->setHeartbeatInterval(
|
stvClient->setHeartbeatInterval(
|
||||||
message.data["heartbeat_interval"].toInt());
|
message.data["heartbeat_interval"].toInt());
|
||||||
@@ -88,19 +90,18 @@ void SeventvEventAPI::onMessage(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SeventvEventAPIOpcode::Heartbeat: {
|
case Opcode::Heartbeat: {
|
||||||
if (auto client = this->findClient(hdl))
|
if (auto client = this->findClient(hdl))
|
||||||
{
|
{
|
||||||
if (auto *stvClient =
|
if (auto *stvClient = dynamic_cast<Client *>(client.get()))
|
||||||
dynamic_cast<SeventvEventAPIClient *>(client.get()))
|
|
||||||
{
|
{
|
||||||
stvClient->handleHeartbeat();
|
stvClient->handleHeartbeat();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SeventvEventAPIOpcode::Dispatch: {
|
case Opcode::Dispatch: {
|
||||||
auto dispatch = message.toInner<SeventvEventAPIDispatch>();
|
auto dispatch = message.toInner<Dispatch>();
|
||||||
if (!dispatch)
|
if (!dispatch)
|
||||||
{
|
{
|
||||||
qCDebug(chatterinoSeventvEventAPI)
|
qCDebug(chatterinoSeventvEventAPI)
|
||||||
@@ -110,133 +111,37 @@ void SeventvEventAPI::onMessage(
|
|||||||
this->handleDispatch(*dispatch);
|
this->handleDispatch(*dispatch);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SeventvEventAPIOpcode::Reconnect: {
|
case Opcode::Reconnect: {
|
||||||
if (auto client = this->findClient(hdl))
|
if (auto client = this->findClient(hdl))
|
||||||
{
|
{
|
||||||
if (auto *stvClient =
|
if (auto *stvClient = dynamic_cast<Client *>(client.get()))
|
||||||
dynamic_cast<SeventvEventAPIClient *>(client.get()))
|
|
||||||
{
|
{
|
||||||
stvClient->close("Reconnecting");
|
stvClient->close("Reconnecting");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case Opcode::Ack: {
|
||||||
|
// unhandled
|
||||||
|
}
|
||||||
|
break;
|
||||||
default: {
|
default: {
|
||||||
qCDebug(chatterinoSeventvEventAPI) << "Unhandled op: " << payload;
|
qCDebug(chatterinoSeventvEventAPI) << "Unhandled op:" << payload;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SeventvEventAPI::handleDispatch(const SeventvEventAPIDispatch &dispatch)
|
void SeventvEventAPI::handleDispatch(const Dispatch &dispatch)
|
||||||
{
|
{
|
||||||
switch (dispatch.type)
|
switch (dispatch.type)
|
||||||
{
|
{
|
||||||
case SeventvEventAPISubscriptionType::UpdateEmoteSet: {
|
case SubscriptionType::UpdateEmoteSet: {
|
||||||
// dispatchBody: {
|
this->onEmoteSetUpdate(dispatch);
|
||||||
// pushed: Array<{ key, value }>,
|
|
||||||
// pulled: Array<{ key, old_value }>,
|
|
||||||
// updated: Array<{ key, value, old_value }>,
|
|
||||||
// }
|
|
||||||
for (const auto pushedRef : dispatch.body["pushed"].toArray())
|
|
||||||
{
|
|
||||||
auto pushed = pushedRef.toObject();
|
|
||||||
if (pushed["key"].toString() != "emotes")
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
SeventvEventAPIEmoteAddDispatch added(
|
|
||||||
dispatch, pushed["value"].toObject());
|
|
||||||
|
|
||||||
if (added.validate())
|
|
||||||
{
|
|
||||||
this->signals_.emoteAdded.invoke(added);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
qCDebug(chatterinoSeventvEventAPI)
|
|
||||||
<< "Invalid dispatch" << dispatch.body;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const auto updatedRef : dispatch.body["updated"].toArray())
|
|
||||||
{
|
|
||||||
auto updated = updatedRef.toObject();
|
|
||||||
if (updated["key"].toString() != "emotes")
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
SeventvEventAPIEmoteUpdateDispatch update(
|
|
||||||
dispatch, updated["old_value"].toObject(),
|
|
||||||
updated["value"].toObject());
|
|
||||||
|
|
||||||
if (update.validate())
|
|
||||||
{
|
|
||||||
this->signals_.emoteUpdated.invoke(update);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
qCDebug(chatterinoSeventvEventAPI)
|
|
||||||
<< "Invalid dispatch" << dispatch.body;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const auto pulledRef : dispatch.body["pulled"].toArray())
|
|
||||||
{
|
|
||||||
auto pulled = pulledRef.toObject();
|
|
||||||
if (pulled["key"].toString() != "emotes")
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
SeventvEventAPIEmoteRemoveDispatch removed(
|
|
||||||
dispatch, pulled["old_value"].toObject());
|
|
||||||
|
|
||||||
if (removed.validate())
|
|
||||||
{
|
|
||||||
this->signals_.emoteRemoved.invoke(removed);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
qCDebug(chatterinoSeventvEventAPI)
|
|
||||||
<< "Invalid dispatch" << dispatch.body;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SeventvEventAPISubscriptionType::UpdateUser: {
|
case SubscriptionType::UpdateUser: {
|
||||||
// dispatchBody: {
|
this->onUserUpdate(dispatch);
|
||||||
// updated: Array<{ key, value: Array<{key, value}> }>
|
|
||||||
// }
|
|
||||||
for (const auto updatedRef : dispatch.body["updated"].toArray())
|
|
||||||
{
|
|
||||||
auto updated = updatedRef.toObject();
|
|
||||||
if (updated["key"].toString() != "connections")
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (const auto valueRef : updated["value"].toArray())
|
|
||||||
{
|
|
||||||
auto value = valueRef.toObject();
|
|
||||||
if (value["key"].toString() != "emote_set")
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
SeventvEventAPIUserConnectionUpdateDispatch update(
|
|
||||||
dispatch, value, (size_t)updated["index"].toInt());
|
|
||||||
|
|
||||||
if (update.validate())
|
|
||||||
{
|
|
||||||
this->signals_.userUpdated.invoke(update);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
qCDebug(chatterinoSeventvEventAPI)
|
|
||||||
<< "Invalid dispatch" << dispatch.body;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default: {
|
default: {
|
||||||
@@ -248,4 +153,112 @@ void SeventvEventAPI::handleDispatch(const SeventvEventAPIDispatch &dispatch)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SeventvEventAPI::onEmoteSetUpdate(const Dispatch &dispatch)
|
||||||
|
{
|
||||||
|
// dispatchBody: {
|
||||||
|
// pushed: Array<{ key, value }>,
|
||||||
|
// pulled: Array<{ key, old_value }>,
|
||||||
|
// updated: Array<{ key, value, old_value }>,
|
||||||
|
// }
|
||||||
|
for (const auto pushedRef : dispatch.body["pushed"].toArray())
|
||||||
|
{
|
||||||
|
auto pushed = pushedRef.toObject();
|
||||||
|
if (pushed["key"].toString() != "emotes")
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const EmoteAddDispatch added(dispatch, pushed["value"].toObject());
|
||||||
|
|
||||||
|
if (added.validate())
|
||||||
|
{
|
||||||
|
this->signals_.emoteAdded.invoke(added);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qCDebug(chatterinoSeventvEventAPI)
|
||||||
|
<< "Invalid dispatch" << dispatch.body;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto updatedRef : dispatch.body["updated"].toArray())
|
||||||
|
{
|
||||||
|
auto updated = updatedRef.toObject();
|
||||||
|
if (updated["key"].toString() != "emotes")
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const EmoteUpdateDispatch update(dispatch,
|
||||||
|
updated["old_value"].toObject(),
|
||||||
|
updated["value"].toObject());
|
||||||
|
|
||||||
|
if (update.validate())
|
||||||
|
{
|
||||||
|
this->signals_.emoteUpdated.invoke(update);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qCDebug(chatterinoSeventvEventAPI)
|
||||||
|
<< "Invalid dispatch" << dispatch.body;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto pulledRef : dispatch.body["pulled"].toArray())
|
||||||
|
{
|
||||||
|
auto pulled = pulledRef.toObject();
|
||||||
|
if (pulled["key"].toString() != "emotes")
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const EmoteRemoveDispatch removed(dispatch,
|
||||||
|
pulled["old_value"].toObject());
|
||||||
|
|
||||||
|
if (removed.validate())
|
||||||
|
{
|
||||||
|
this->signals_.emoteRemoved.invoke(removed);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qCDebug(chatterinoSeventvEventAPI)
|
||||||
|
<< "Invalid dispatch" << dispatch.body;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SeventvEventAPI::onUserUpdate(const Dispatch &dispatch)
|
||||||
|
{
|
||||||
|
// dispatchBody: {
|
||||||
|
// updated: Array<{ key, value: Array<{key, value}> }>
|
||||||
|
// }
|
||||||
|
for (const auto updatedRef : dispatch.body["updated"].toArray())
|
||||||
|
{
|
||||||
|
auto updated = updatedRef.toObject();
|
||||||
|
if (updated["key"].toString() != "connections")
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (const auto valueRef : updated["value"].toArray())
|
||||||
|
{
|
||||||
|
auto value = valueRef.toObject();
|
||||||
|
if (value["key"].toString() != "emote_set")
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UserConnectionUpdateDispatch update(
|
||||||
|
dispatch, value, (size_t)updated["index"].toInt());
|
||||||
|
|
||||||
|
if (update.validate())
|
||||||
|
{
|
||||||
|
this->signals_.userUpdated.invoke(update);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qCDebug(chatterinoSeventvEventAPI)
|
||||||
|
<< "Invalid dispatch" << dispatch.body;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|||||||
@@ -8,14 +8,17 @@
|
|||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
struct SeventvEventAPISubscription;
|
namespace seventv::eventapi {
|
||||||
struct SeventvEventAPIDispatch;
|
struct Subscription;
|
||||||
struct SeventvEventAPIEmoteAddDispatch;
|
struct Dispatch;
|
||||||
struct SeventvEventAPIEmoteUpdateDispatch;
|
struct EmoteAddDispatch;
|
||||||
struct SeventvEventAPIEmoteRemoveDispatch;
|
struct EmoteUpdateDispatch;
|
||||||
struct SeventvEventAPIUserConnectionUpdateDispatch;
|
struct EmoteRemoveDispatch;
|
||||||
|
struct UserConnectionUpdateDispatch;
|
||||||
|
} // namespace seventv::eventapi
|
||||||
|
|
||||||
class SeventvEventAPI : public BasicPubSubManager<SeventvEventAPISubscription>
|
class SeventvEventAPI
|
||||||
|
: public BasicPubSubManager<seventv::eventapi::Subscription>
|
||||||
{
|
{
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using Signal =
|
using Signal =
|
||||||
@@ -27,10 +30,10 @@ public:
|
|||||||
std::chrono::milliseconds(25000));
|
std::chrono::milliseconds(25000));
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
Signal<SeventvEventAPIEmoteAddDispatch> emoteAdded;
|
Signal<seventv::eventapi::EmoteAddDispatch> emoteAdded;
|
||||||
Signal<SeventvEventAPIEmoteUpdateDispatch> emoteUpdated;
|
Signal<seventv::eventapi::EmoteUpdateDispatch> emoteUpdated;
|
||||||
Signal<SeventvEventAPIEmoteRemoveDispatch> emoteRemoved;
|
Signal<seventv::eventapi::EmoteRemoveDispatch> emoteRemoved;
|
||||||
Signal<SeventvEventAPIUserConnectionUpdateDispatch> userUpdated;
|
Signal<seventv::eventapi::UserConnectionUpdateDispatch> userUpdated;
|
||||||
} signals_; // NOLINT(readability-identifier-naming)
|
} signals_; // NOLINT(readability-identifier-naming)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,18 +51,23 @@ public:
|
|||||||
void unsubscribeEmoteSet(const QString &id);
|
void unsubscribeEmoteSet(const QString &id);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::shared_ptr<BasicPubSubClient<SeventvEventAPISubscription>>
|
std::shared_ptr<BasicPubSubClient<seventv::eventapi::Subscription>>
|
||||||
createClient(liveupdates::WebsocketClient &client,
|
createClient(liveupdates::WebsocketClient &client,
|
||||||
websocketpp::connection_hdl hdl) override;
|
websocketpp::connection_hdl hdl) override;
|
||||||
void onMessage(
|
void onMessage(
|
||||||
websocketpp::connection_hdl hdl,
|
websocketpp::connection_hdl hdl,
|
||||||
BasicPubSubManager<SeventvEventAPISubscription>::WebsocketMessagePtr
|
BasicPubSubManager<seventv::eventapi::Subscription>::WebsocketMessagePtr
|
||||||
msg) override;
|
msg) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void handleDispatch(const SeventvEventAPIDispatch &dispatch);
|
void handleDispatch(const seventv::eventapi::Dispatch &dispatch);
|
||||||
|
|
||||||
|
void onEmoteSetUpdate(const seventv::eventapi::Dispatch &dispatch);
|
||||||
|
void onUserUpdate(const seventv::eventapi::Dispatch &dispatch);
|
||||||
|
|
||||||
|
/** emote-set ids */
|
||||||
std::unordered_set<QString> subscribedEmoteSets_;
|
std::unordered_set<QString> subscribedEmoteSets_;
|
||||||
|
/** user ids */
|
||||||
std::unordered_set<QString> subscribedUsers_;
|
std::unordered_set<QString> subscribedUsers_;
|
||||||
std::chrono::milliseconds heartbeatInterval_;
|
std::chrono::milliseconds heartbeatInterval_;
|
||||||
};
|
};
|
||||||
|
|||||||
+13
-16
@@ -1,44 +1,42 @@
|
|||||||
#include "providers/seventv/eventapi/SeventvEventAPIClient.hpp"
|
#include "providers/seventv/eventapi/Client.hpp"
|
||||||
|
|
||||||
#include "providers/seventv/eventapi/SeventvEventAPISubscription.hpp"
|
#include "providers/seventv/eventapi/Subscription.hpp"
|
||||||
#include "providers/twitch/PubSubHelpers.hpp"
|
#include "providers/twitch/PubSubHelpers.hpp"
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino::seventv::eventapi {
|
||||||
|
|
||||||
SeventvEventAPIClient::SeventvEventAPIClient(
|
Client::Client(liveupdates::WebsocketClient &websocketClient,
|
||||||
liveupdates::WebsocketClient &websocketClient,
|
liveupdates::WebsocketHandle handle,
|
||||||
liveupdates::WebsocketHandle handle,
|
std::chrono::milliseconds heartbeatInterval)
|
||||||
std::chrono::milliseconds heartbeatInterval)
|
: BasicPubSubClient<Subscription>(websocketClient, std::move(handle))
|
||||||
: BasicPubSubClient<SeventvEventAPISubscription>(websocketClient,
|
|
||||||
std::move(handle))
|
|
||||||
, lastHeartbeat_(std::chrono::steady_clock::now())
|
, lastHeartbeat_(std::chrono::steady_clock::now())
|
||||||
, heartbeatInterval_(heartbeatInterval)
|
, heartbeatInterval_(heartbeatInterval)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void SeventvEventAPIClient::onConnectionEstablished()
|
void Client::onConnectionEstablished()
|
||||||
{
|
{
|
||||||
this->lastHeartbeat_.store(std::chrono::steady_clock::now(),
|
this->lastHeartbeat_.store(std::chrono::steady_clock::now(),
|
||||||
std::memory_order_release);
|
std::memory_order_release);
|
||||||
this->checkHeartbeat();
|
this->checkHeartbeat();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SeventvEventAPIClient::setHeartbeatInterval(int intervalMs)
|
void Client::setHeartbeatInterval(int intervalMs)
|
||||||
{
|
{
|
||||||
qCDebug(chatterinoSeventvEventAPI)
|
qCDebug(chatterinoSeventvEventAPI)
|
||||||
<< "Setting expected heartbeat interval to" << intervalMs << "ms";
|
<< "Setting expected heartbeat interval to" << intervalMs << "ms";
|
||||||
this->heartbeatInterval_ = std::chrono::milliseconds(intervalMs);
|
this->heartbeatInterval_ = std::chrono::milliseconds(intervalMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SeventvEventAPIClient::handleHeartbeat()
|
void Client::handleHeartbeat()
|
||||||
{
|
{
|
||||||
this->lastHeartbeat_.store(std::chrono::steady_clock::now(),
|
this->lastHeartbeat_.store(std::chrono::steady_clock::now(),
|
||||||
std::memory_order_release);
|
std::memory_order_release);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SeventvEventAPIClient::checkHeartbeat()
|
void Client::checkHeartbeat()
|
||||||
{
|
{
|
||||||
// Following the heartbeat docs, a connection is dead
|
// Following the heartbeat docs, a connection is dead
|
||||||
// after three missed heartbeats.
|
// after three missed heartbeats.
|
||||||
@@ -54,8 +52,7 @@ void SeventvEventAPIClient::checkHeartbeat()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto self = std::dynamic_pointer_cast<SeventvEventAPIClient>(
|
auto self = std::dynamic_pointer_cast<Client>(this->shared_from_this());
|
||||||
this->shared_from_this());
|
|
||||||
|
|
||||||
runAfter(this->websocketClient_.get_io_service(), this->heartbeatInterval_,
|
runAfter(this->websocketClient_.get_io_service(), this->heartbeatInterval_,
|
||||||
[self](auto) {
|
[self](auto) {
|
||||||
@@ -67,4 +64,4 @@ void SeventvEventAPIClient::checkHeartbeat()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino::seventv::eventapi
|
||||||
+13
-9
@@ -2,18 +2,22 @@
|
|||||||
|
|
||||||
#include "providers/liveupdates/BasicPubSubClient.hpp"
|
#include "providers/liveupdates/BasicPubSubClient.hpp"
|
||||||
// this needs to be included for the specialization
|
// this needs to be included for the specialization
|
||||||
// of std::hash for SeventvEventAPISubscription
|
// of std::hash for Subscription
|
||||||
#include "providers/seventv/eventapi/SeventvEventAPISubscription.hpp"
|
#include "providers/seventv/eventapi/Subscription.hpp"
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
class SeventvEventAPI;
|
||||||
|
|
||||||
class SeventvEventAPIClient
|
} // namespace chatterino
|
||||||
: public BasicPubSubClient<SeventvEventAPISubscription>
|
|
||||||
|
namespace chatterino::seventv::eventapi {
|
||||||
|
|
||||||
|
class Client : public BasicPubSubClient<Subscription>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SeventvEventAPIClient(liveupdates::WebsocketClient &websocketClient,
|
Client(liveupdates::WebsocketClient &websocketClient,
|
||||||
liveupdates::WebsocketHandle handle,
|
liveupdates::WebsocketHandle handle,
|
||||||
std::chrono::milliseconds heartbeatInterval);
|
std::chrono::milliseconds heartbeatInterval);
|
||||||
|
|
||||||
void setHeartbeatInterval(int intervalMs);
|
void setHeartbeatInterval(int intervalMs);
|
||||||
void handleHeartbeat();
|
void handleHeartbeat();
|
||||||
@@ -29,7 +33,7 @@ private:
|
|||||||
// This will be set once on the welcome message.
|
// This will be set once on the welcome message.
|
||||||
std::chrono::milliseconds heartbeatInterval_;
|
std::chrono::milliseconds heartbeatInterval_;
|
||||||
|
|
||||||
friend class SeventvEventAPI;
|
friend SeventvEventAPI;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino::seventv::eventapi
|
||||||
+18
-21
@@ -1,21 +1,20 @@
|
|||||||
#include "providers/seventv/eventapi/SeventvEventAPIDispatch.hpp"
|
#include "providers/seventv/eventapi/Dispatch.hpp"
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino::seventv::eventapi {
|
||||||
|
|
||||||
SeventvEventAPIDispatch::SeventvEventAPIDispatch(QJsonObject obj)
|
Dispatch::Dispatch(QJsonObject obj)
|
||||||
: type(magic_enum::enum_cast<SeventvEventAPISubscriptionType>(
|
: type(magic_enum::enum_cast<SubscriptionType>(
|
||||||
obj["type"].toString().toStdString())
|
obj["type"].toString().toStdString())
|
||||||
.value_or(SeventvEventAPISubscriptionType::INVALID))
|
.value_or(SubscriptionType::INVALID))
|
||||||
, body(obj["body"].toObject())
|
, body(obj["body"].toObject())
|
||||||
, id(this->body["id"].toString())
|
, id(this->body["id"].toString())
|
||||||
, actorName(this->body["actor"].toObject()["display_name"].toString())
|
, actorName(this->body["actor"].toObject()["display_name"].toString())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
SeventvEventAPIEmoteAddDispatch::SeventvEventAPIEmoteAddDispatch(
|
EmoteAddDispatch::EmoteAddDispatch(const Dispatch &dispatch, QJsonObject emote)
|
||||||
const SeventvEventAPIDispatch &dispatch, QJsonObject emote)
|
|
||||||
: emoteSetID(dispatch.id)
|
: emoteSetID(dispatch.id)
|
||||||
, actorName(dispatch.actorName)
|
, actorName(dispatch.actorName)
|
||||||
, emoteJson(std::move(emote))
|
, emoteJson(std::move(emote))
|
||||||
@@ -23,7 +22,7 @@ SeventvEventAPIEmoteAddDispatch::SeventvEventAPIEmoteAddDispatch(
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SeventvEventAPIEmoteAddDispatch::validate() const
|
bool EmoteAddDispatch::validate() const
|
||||||
{
|
{
|
||||||
bool validValues =
|
bool validValues =
|
||||||
!this->emoteSetID.isEmpty() && !this->emoteJson.isEmpty();
|
!this->emoteSetID.isEmpty() && !this->emoteJson.isEmpty();
|
||||||
@@ -43,8 +42,8 @@ bool SeventvEventAPIEmoteAddDispatch::validate() const
|
|||||||
emoteData.contains("owner");
|
emoteData.contains("owner");
|
||||||
}
|
}
|
||||||
|
|
||||||
SeventvEventAPIEmoteRemoveDispatch::SeventvEventAPIEmoteRemoveDispatch(
|
EmoteRemoveDispatch::EmoteRemoveDispatch(const Dispatch &dispatch,
|
||||||
const SeventvEventAPIDispatch &dispatch, QJsonObject emote)
|
QJsonObject emote)
|
||||||
: emoteSetID(dispatch.id)
|
: emoteSetID(dispatch.id)
|
||||||
, actorName(dispatch.actorName)
|
, actorName(dispatch.actorName)
|
||||||
, emoteName(emote["name"].toString())
|
, emoteName(emote["name"].toString())
|
||||||
@@ -52,15 +51,15 @@ SeventvEventAPIEmoteRemoveDispatch::SeventvEventAPIEmoteRemoveDispatch(
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SeventvEventAPIEmoteRemoveDispatch::validate() const
|
bool EmoteRemoveDispatch::validate() const
|
||||||
{
|
{
|
||||||
return !this->emoteSetID.isEmpty() && !this->emoteName.isEmpty() &&
|
return !this->emoteSetID.isEmpty() && !this->emoteName.isEmpty() &&
|
||||||
!this->emoteID.isEmpty();
|
!this->emoteID.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
SeventvEventAPIEmoteUpdateDispatch::SeventvEventAPIEmoteUpdateDispatch(
|
EmoteUpdateDispatch::EmoteUpdateDispatch(const Dispatch &dispatch,
|
||||||
const SeventvEventAPIDispatch &dispatch, QJsonObject oldValue,
|
QJsonObject oldValue,
|
||||||
QJsonObject value)
|
QJsonObject value)
|
||||||
: emoteSetID(dispatch.id)
|
: emoteSetID(dispatch.id)
|
||||||
, actorName(dispatch.actorName)
|
, actorName(dispatch.actorName)
|
||||||
, emoteID(value["id"].toString())
|
, emoteID(value["id"].toString())
|
||||||
@@ -69,17 +68,15 @@ SeventvEventAPIEmoteUpdateDispatch::SeventvEventAPIEmoteUpdateDispatch(
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SeventvEventAPIEmoteUpdateDispatch::validate() const
|
bool EmoteUpdateDispatch::validate() const
|
||||||
{
|
{
|
||||||
return !this->emoteSetID.isEmpty() && !this->emoteID.isEmpty() &&
|
return !this->emoteSetID.isEmpty() && !this->emoteID.isEmpty() &&
|
||||||
!this->oldEmoteName.isEmpty() && !this->emoteName.isEmpty() &&
|
!this->oldEmoteName.isEmpty() && !this->emoteName.isEmpty() &&
|
||||||
this->oldEmoteName != this->emoteName;
|
this->oldEmoteName != this->emoteName;
|
||||||
}
|
}
|
||||||
|
|
||||||
SeventvEventAPIUserConnectionUpdateDispatch::
|
UserConnectionUpdateDispatch::UserConnectionUpdateDispatch(
|
||||||
SeventvEventAPIUserConnectionUpdateDispatch(
|
const Dispatch &dispatch, const QJsonObject &update, size_t connectionIndex)
|
||||||
const SeventvEventAPIDispatch &dispatch, const QJsonObject &update,
|
|
||||||
size_t connectionIndex)
|
|
||||||
: userID(dispatch.id)
|
: userID(dispatch.id)
|
||||||
, actorName(dispatch.actorName)
|
, actorName(dispatch.actorName)
|
||||||
, oldEmoteSetID(update["old_value"].toObject()["id"].toString())
|
, oldEmoteSetID(update["old_value"].toObject()["id"].toString())
|
||||||
@@ -88,10 +85,10 @@ SeventvEventAPIUserConnectionUpdateDispatch::
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SeventvEventAPIUserConnectionUpdateDispatch::validate() const
|
bool UserConnectionUpdateDispatch::validate() const
|
||||||
{
|
{
|
||||||
return !this->userID.isEmpty() && !this->oldEmoteSetID.isEmpty() &&
|
return !this->userID.isEmpty() && !this->oldEmoteSetID.isEmpty() &&
|
||||||
!this->emoteSetID.isEmpty();
|
!this->emoteSetID.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino::seventv::eventapi
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "providers/seventv/eventapi/Subscription.hpp"
|
||||||
|
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace chatterino::seventv::eventapi {
|
||||||
|
|
||||||
|
// https://github.com/SevenTV/EventAPI/tree/ca4ff15cc42b89560fa661a76c5849047763d334#message-payload
|
||||||
|
struct Dispatch {
|
||||||
|
SubscriptionType type;
|
||||||
|
QJsonObject body;
|
||||||
|
QString id;
|
||||||
|
// it's okay for this to be empty
|
||||||
|
QString actorName;
|
||||||
|
|
||||||
|
Dispatch(QJsonObject obj);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EmoteAddDispatch {
|
||||||
|
QString emoteSetID;
|
||||||
|
QString actorName;
|
||||||
|
QJsonObject emoteJson;
|
||||||
|
QString emoteID;
|
||||||
|
|
||||||
|
EmoteAddDispatch(const Dispatch &dispatch, QJsonObject emote);
|
||||||
|
|
||||||
|
bool validate() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EmoteRemoveDispatch {
|
||||||
|
QString emoteSetID;
|
||||||
|
QString actorName;
|
||||||
|
QString emoteName;
|
||||||
|
QString emoteID;
|
||||||
|
|
||||||
|
EmoteRemoveDispatch(const Dispatch &dispatch, QJsonObject emote);
|
||||||
|
|
||||||
|
bool validate() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EmoteUpdateDispatch {
|
||||||
|
QString emoteSetID;
|
||||||
|
QString actorName;
|
||||||
|
QString emoteID;
|
||||||
|
QString oldEmoteName;
|
||||||
|
QString emoteName;
|
||||||
|
|
||||||
|
EmoteUpdateDispatch(const Dispatch &dispatch, QJsonObject oldValue,
|
||||||
|
QJsonObject value);
|
||||||
|
|
||||||
|
bool validate() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UserConnectionUpdateDispatch {
|
||||||
|
QString userID;
|
||||||
|
QString actorName;
|
||||||
|
QString oldEmoteSetID;
|
||||||
|
QString emoteSetID;
|
||||||
|
size_t connectionIndex;
|
||||||
|
|
||||||
|
UserConnectionUpdateDispatch(const Dispatch &dispatch,
|
||||||
|
const QJsonObject &update,
|
||||||
|
size_t connectionIndex);
|
||||||
|
|
||||||
|
bool validate() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace chatterino::seventv::eventapi
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#include "providers/seventv/eventapi/Message.hpp"
|
||||||
|
|
||||||
|
namespace chatterino::seventv::eventapi {
|
||||||
|
|
||||||
|
Message::Message(QJsonObject _json)
|
||||||
|
: data(_json["d"].toObject())
|
||||||
|
, op(Opcode(_json["op"].toInt()))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace chatterino::seventv::eventapi
|
||||||
+9
-10
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "providers/seventv/eventapi/SeventvEventAPISubscription.hpp"
|
#include "providers/seventv/eventapi/Subscription.hpp"
|
||||||
|
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
#include <magic_enum.hpp>
|
#include <magic_enum.hpp>
|
||||||
@@ -8,27 +8,26 @@
|
|||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino::seventv::eventapi {
|
||||||
|
|
||||||
struct SeventvEventAPIMessage {
|
struct Message {
|
||||||
QJsonObject data;
|
QJsonObject data;
|
||||||
|
|
||||||
SeventvEventAPIOpcode op;
|
Opcode op;
|
||||||
|
|
||||||
SeventvEventAPIMessage(QJsonObject _json);
|
Message(QJsonObject _json);
|
||||||
|
|
||||||
template <class InnerClass>
|
template <class InnerClass>
|
||||||
boost::optional<InnerClass> toInner();
|
boost::optional<InnerClass> toInner();
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class InnerClass>
|
template <class InnerClass>
|
||||||
boost::optional<InnerClass> SeventvEventAPIMessage::toInner()
|
boost::optional<InnerClass> Message::toInner()
|
||||||
{
|
{
|
||||||
return InnerClass{this->data};
|
return InnerClass{this->data};
|
||||||
}
|
}
|
||||||
|
|
||||||
static boost::optional<SeventvEventAPIMessage> parseSeventvEventAPIBaseMessage(
|
static boost::optional<Message> parseBaseMessage(const QString &blob)
|
||||||
const QString &blob)
|
|
||||||
{
|
{
|
||||||
QJsonDocument jsonDoc(QJsonDocument::fromJson(blob.toUtf8()));
|
QJsonDocument jsonDoc(QJsonDocument::fromJson(blob.toUtf8()));
|
||||||
|
|
||||||
@@ -37,7 +36,7 @@ static boost::optional<SeventvEventAPIMessage> parseSeventvEventAPIBaseMessage(
|
|||||||
return boost::none;
|
return boost::none;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SeventvEventAPIMessage(jsonDoc.object());
|
return Message(jsonDoc.object());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino::seventv::eventapi
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "providers/seventv/eventapi/SeventvEventAPISubscription.hpp"
|
|
||||||
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
namespace chatterino {
|
|
||||||
|
|
||||||
// https://github.com/SevenTV/EventAPI/tree/ca4ff15cc42b89560fa661a76c5849047763d334#message-payload
|
|
||||||
struct SeventvEventAPIDispatch {
|
|
||||||
SeventvEventAPISubscriptionType type;
|
|
||||||
QJsonObject body;
|
|
||||||
QString id;
|
|
||||||
// it's okay for this to be empty
|
|
||||||
QString actorName;
|
|
||||||
|
|
||||||
SeventvEventAPIDispatch(QJsonObject obj);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SeventvEventAPIEmoteAddDispatch {
|
|
||||||
QString emoteSetID;
|
|
||||||
QString actorName;
|
|
||||||
QJsonObject emoteJson;
|
|
||||||
QString emoteID;
|
|
||||||
|
|
||||||
SeventvEventAPIEmoteAddDispatch(const SeventvEventAPIDispatch &dispatch,
|
|
||||||
QJsonObject emote);
|
|
||||||
|
|
||||||
bool validate() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SeventvEventAPIEmoteRemoveDispatch {
|
|
||||||
QString emoteSetID;
|
|
||||||
QString actorName;
|
|
||||||
QString emoteName;
|
|
||||||
QString emoteID;
|
|
||||||
|
|
||||||
SeventvEventAPIEmoteRemoveDispatch(const SeventvEventAPIDispatch &dispatch,
|
|
||||||
QJsonObject emote);
|
|
||||||
|
|
||||||
bool validate() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SeventvEventAPIEmoteUpdateDispatch {
|
|
||||||
QString emoteSetID;
|
|
||||||
QString actorName;
|
|
||||||
QString emoteID;
|
|
||||||
QString oldEmoteName;
|
|
||||||
QString emoteName;
|
|
||||||
|
|
||||||
SeventvEventAPIEmoteUpdateDispatch(const SeventvEventAPIDispatch &dispatch,
|
|
||||||
QJsonObject oldValue, QJsonObject value);
|
|
||||||
|
|
||||||
bool validate() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SeventvEventAPIUserConnectionUpdateDispatch {
|
|
||||||
QString userID;
|
|
||||||
QString actorName;
|
|
||||||
QString oldEmoteSetID;
|
|
||||||
QString emoteSetID;
|
|
||||||
size_t connectionIndex;
|
|
||||||
|
|
||||||
SeventvEventAPIUserConnectionUpdateDispatch(
|
|
||||||
const SeventvEventAPIDispatch &dispatch, const QJsonObject &update,
|
|
||||||
size_t connectionIndex);
|
|
||||||
|
|
||||||
bool validate() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace chatterino
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
#include "providers/seventv/eventapi/SeventvEventAPIMessage.hpp"
|
|
||||||
|
|
||||||
namespace chatterino {
|
|
||||||
|
|
||||||
SeventvEventAPIMessage::SeventvEventAPIMessage(QJsonObject _json)
|
|
||||||
: data(_json["d"].toObject())
|
|
||||||
, op(SeventvEventAPIOpcode(_json["op"].toInt()))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace chatterino
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
#include "providers/seventv/eventapi/SeventvEventAPISubscription.hpp"
|
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QJsonObject>
|
|
||||||
|
|
||||||
#include <tuple>
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
using namespace chatterino;
|
|
||||||
|
|
||||||
const char *typeToString(SeventvEventAPISubscriptionType type)
|
|
||||||
{
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case SeventvEventAPISubscriptionType::UpdateEmoteSet:
|
|
||||||
return "emote_set.update";
|
|
||||||
case SeventvEventAPISubscriptionType::UpdateUser:
|
|
||||||
return "user.update";
|
|
||||||
default:
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject createDataJson(const char *typeName, const QString &condition)
|
|
||||||
{
|
|
||||||
QJsonObject data;
|
|
||||||
data["type"] = typeName;
|
|
||||||
{
|
|
||||||
QJsonObject conditionObj;
|
|
||||||
conditionObj["object_id"] = condition;
|
|
||||||
data["condition"] = conditionObj;
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace chatterino {
|
|
||||||
|
|
||||||
bool SeventvEventAPISubscription::operator==(
|
|
||||||
const SeventvEventAPISubscription &rhs) const
|
|
||||||
{
|
|
||||||
return std::tie(this->condition, this->type) ==
|
|
||||||
std::tie(rhs.condition, rhs.type);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SeventvEventAPISubscription::operator!=(
|
|
||||||
const SeventvEventAPISubscription &rhs) const
|
|
||||||
{
|
|
||||||
return !(rhs == *this);
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray SeventvEventAPISubscription::encodeSubscribe() const
|
|
||||||
{
|
|
||||||
const auto *typeName = typeToString(this->type);
|
|
||||||
QJsonObject root;
|
|
||||||
root["op"] = (int)SeventvEventAPIOpcode::Subscribe;
|
|
||||||
root["d"] = createDataJson(typeName, this->condition);
|
|
||||||
return QJsonDocument(root).toJson();
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray SeventvEventAPISubscription::encodeUnsubscribe() const
|
|
||||||
{
|
|
||||||
const auto *typeName = typeToString(this->type);
|
|
||||||
QJsonObject root;
|
|
||||||
root["op"] = (int)SeventvEventAPIOpcode::Unsubscribe;
|
|
||||||
root["d"] = createDataJson(typeName, this->condition);
|
|
||||||
return QJsonDocument(root).toJson();
|
|
||||||
}
|
|
||||||
|
|
||||||
QDebug &operator<<(QDebug &dbg, const SeventvEventAPISubscription &subscription)
|
|
||||||
{
|
|
||||||
dbg << "SeventvEventAPISubscription{ condition:" << subscription.condition
|
|
||||||
<< "type:" << (int)subscription.type << '}';
|
|
||||||
return dbg;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace chatterino
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <magic_enum.hpp>
|
|
||||||
#include <QByteArray>
|
|
||||||
#include <QHash>
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
namespace chatterino {
|
|
||||||
|
|
||||||
// https://github.com/SevenTV/EventAPI/tree/ca4ff15cc42b89560fa661a76c5849047763d334#subscription-types
|
|
||||||
enum class SeventvEventAPISubscriptionType {
|
|
||||||
UpdateEmoteSet,
|
|
||||||
UpdateUser,
|
|
||||||
|
|
||||||
INVALID,
|
|
||||||
};
|
|
||||||
|
|
||||||
// https://github.com/SevenTV/EventAPI/tree/ca4ff15cc42b89560fa661a76c5849047763d334#opcodes
|
|
||||||
enum class SeventvEventAPIOpcode {
|
|
||||||
Dispatch = 0,
|
|
||||||
Hello = 1,
|
|
||||||
Heartbeat = 2,
|
|
||||||
Reconnect = 4,
|
|
||||||
Ack = 5,
|
|
||||||
Error = 6,
|
|
||||||
EndOfStream = 7,
|
|
||||||
Identify = 33,
|
|
||||||
Resume = 34,
|
|
||||||
Subscribe = 35,
|
|
||||||
Unsubscribe = 36,
|
|
||||||
Signal = 37,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SeventvEventAPISubscription {
|
|
||||||
bool operator==(const SeventvEventAPISubscription &rhs) const;
|
|
||||||
bool operator!=(const SeventvEventAPISubscription &rhs) const;
|
|
||||||
QString condition;
|
|
||||||
SeventvEventAPISubscriptionType type;
|
|
||||||
|
|
||||||
QByteArray encodeSubscribe() const;
|
|
||||||
QByteArray encodeUnsubscribe() const;
|
|
||||||
|
|
||||||
friend QDebug &operator<<(QDebug &dbg,
|
|
||||||
const SeventvEventAPISubscription &subscription);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace chatterino
|
|
||||||
|
|
||||||
template <>
|
|
||||||
constexpr magic_enum::customize::customize_t magic_enum::customize::enum_name<
|
|
||||||
chatterino::SeventvEventAPISubscriptionType>(
|
|
||||||
chatterino::SeventvEventAPISubscriptionType value) noexcept
|
|
||||||
{
|
|
||||||
switch (value)
|
|
||||||
{
|
|
||||||
case chatterino::SeventvEventAPISubscriptionType::UpdateEmoteSet:
|
|
||||||
return "emote_set.update";
|
|
||||||
case chatterino::SeventvEventAPISubscriptionType::UpdateUser:
|
|
||||||
return "user.update";
|
|
||||||
|
|
||||||
default:
|
|
||||||
return default_tag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace std {
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct hash<chatterino::SeventvEventAPISubscription> {
|
|
||||||
size_t operator()(const chatterino::SeventvEventAPISubscription &sub) const
|
|
||||||
{
|
|
||||||
return (size_t)qHash(sub.condition, qHash((int)sub.type));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace std
|
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
#include "providers/seventv/eventapi/Subscription.hpp"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
|
||||||
|
#include <tuple>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using namespace chatterino::seventv::eventapi;
|
||||||
|
|
||||||
|
const char *typeToString(SubscriptionType type)
|
||||||
|
{
|
||||||
|
return magic_enum::enum_name(type).data();
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject createDataJson(const char *typeName, const Condition &condition)
|
||||||
|
{
|
||||||
|
QJsonObject data;
|
||||||
|
data["type"] = typeName;
|
||||||
|
data["condition"] = std::visit(
|
||||||
|
[](const auto &c) {
|
||||||
|
return c.encode();
|
||||||
|
},
|
||||||
|
condition);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace chatterino::seventv::eventapi {
|
||||||
|
|
||||||
|
bool Subscription::operator==(const Subscription &rhs) const
|
||||||
|
{
|
||||||
|
return std::tie(this->condition, this->type) ==
|
||||||
|
std::tie(rhs.condition, rhs.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Subscription::operator!=(const Subscription &rhs) const
|
||||||
|
{
|
||||||
|
return !(rhs == *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray Subscription::encodeSubscribe() const
|
||||||
|
{
|
||||||
|
const auto *typeName = typeToString(this->type);
|
||||||
|
QJsonObject root;
|
||||||
|
root["op"] = (int)Opcode::Subscribe;
|
||||||
|
root["d"] = createDataJson(typeName, this->condition);
|
||||||
|
return QJsonDocument(root).toJson();
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray Subscription::encodeUnsubscribe() const
|
||||||
|
{
|
||||||
|
const auto *typeName = typeToString(this->type);
|
||||||
|
QJsonObject root;
|
||||||
|
root["op"] = (int)Opcode::Unsubscribe;
|
||||||
|
root["d"] = createDataJson(typeName, this->condition);
|
||||||
|
return QJsonDocument(root).toJson();
|
||||||
|
}
|
||||||
|
|
||||||
|
QDebug &operator<<(QDebug &dbg, const Subscription &subscription)
|
||||||
|
{
|
||||||
|
std::visit(
|
||||||
|
[&](const auto &cond) {
|
||||||
|
dbg << "Subscription{ condition:" << cond
|
||||||
|
<< "type:" << magic_enum::enum_name(subscription.type).data()
|
||||||
|
<< '}';
|
||||||
|
},
|
||||||
|
subscription.condition);
|
||||||
|
return dbg;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectIDCondition::ObjectIDCondition(QString objectID)
|
||||||
|
: objectID(std::move(objectID))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject ObjectIDCondition::encode() const
|
||||||
|
{
|
||||||
|
QJsonObject obj;
|
||||||
|
obj["object_id"] = this->objectID;
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ObjectIDCondition::operator==(const ObjectIDCondition &rhs) const
|
||||||
|
{
|
||||||
|
return this->objectID == rhs.objectID;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ObjectIDCondition::operator!=(const ObjectIDCondition &rhs) const
|
||||||
|
{
|
||||||
|
return !(*this == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
QDebug &operator<<(QDebug &dbg, const ObjectIDCondition &condition)
|
||||||
|
{
|
||||||
|
dbg << "{ objectID:" << condition.objectID << "}";
|
||||||
|
return dbg;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace chatterino::seventv::eventapi
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <magic_enum.hpp>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
namespace chatterino::seventv::eventapi {
|
||||||
|
|
||||||
|
// https://github.com/SevenTV/EventAPI/tree/ca4ff15cc42b89560fa661a76c5849047763d334#subscription-types
|
||||||
|
enum class SubscriptionType {
|
||||||
|
UpdateEmoteSet,
|
||||||
|
UpdateUser,
|
||||||
|
|
||||||
|
INVALID,
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://github.com/SevenTV/EventAPI/tree/ca4ff15cc42b89560fa661a76c5849047763d334#opcodes
|
||||||
|
enum class Opcode {
|
||||||
|
Dispatch = 0,
|
||||||
|
Hello = 1,
|
||||||
|
Heartbeat = 2,
|
||||||
|
Reconnect = 4,
|
||||||
|
Ack = 5,
|
||||||
|
Error = 6,
|
||||||
|
EndOfStream = 7,
|
||||||
|
Identify = 33,
|
||||||
|
Resume = 34,
|
||||||
|
Subscribe = 35,
|
||||||
|
Unsubscribe = 36,
|
||||||
|
Signal = 37,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ObjectIDCondition {
|
||||||
|
ObjectIDCondition(QString objectID);
|
||||||
|
|
||||||
|
QString objectID;
|
||||||
|
|
||||||
|
QJsonObject encode() const;
|
||||||
|
|
||||||
|
friend QDebug &operator<<(QDebug &dbg, const ObjectIDCondition &condition);
|
||||||
|
bool operator==(const ObjectIDCondition &rhs) const;
|
||||||
|
bool operator!=(const ObjectIDCondition &rhs) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
using Condition = std::variant<ObjectIDCondition>;
|
||||||
|
|
||||||
|
struct Subscription {
|
||||||
|
bool operator==(const Subscription &rhs) const;
|
||||||
|
bool operator!=(const Subscription &rhs) const;
|
||||||
|
Condition condition;
|
||||||
|
SubscriptionType type;
|
||||||
|
|
||||||
|
QByteArray encodeSubscribe() const;
|
||||||
|
QByteArray encodeUnsubscribe() const;
|
||||||
|
|
||||||
|
friend QDebug &operator<<(QDebug &dbg, const Subscription &subscription);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace chatterino::seventv::eventapi
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr magic_enum::customize::customize_t magic_enum::customize::enum_name<
|
||||||
|
chatterino::seventv::eventapi::SubscriptionType>(
|
||||||
|
chatterino::seventv::eventapi::SubscriptionType value) noexcept
|
||||||
|
{
|
||||||
|
using chatterino::seventv::eventapi::SubscriptionType;
|
||||||
|
switch (value)
|
||||||
|
{
|
||||||
|
case SubscriptionType::UpdateEmoteSet:
|
||||||
|
return "emote_set.update";
|
||||||
|
case SubscriptionType::UpdateUser:
|
||||||
|
return "user.update";
|
||||||
|
|
||||||
|
default:
|
||||||
|
return default_tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct hash<chatterino::seventv::eventapi::ObjectIDCondition> {
|
||||||
|
size_t operator()(
|
||||||
|
const chatterino::seventv::eventapi::ObjectIDCondition &c) const
|
||||||
|
{
|
||||||
|
return (size_t)qHash(c.objectID);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct hash<chatterino::seventv::eventapi::Subscription> {
|
||||||
|
size_t operator()(
|
||||||
|
const chatterino::seventv::eventapi::Subscription &sub) const
|
||||||
|
{
|
||||||
|
const size_t conditionHash =
|
||||||
|
std::hash<chatterino::seventv::eventapi::Condition>{}(
|
||||||
|
sub.condition);
|
||||||
|
return (size_t)qHash(conditionHash, qHash((int)sub.type));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace std
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
#include "providers/bttv/BttvLiveUpdates.hpp"
|
#include "providers/bttv/BttvLiveUpdates.hpp"
|
||||||
#include "providers/bttv/liveupdates/BttvLiveUpdateMessages.hpp"
|
#include "providers/bttv/liveupdates/BttvLiveUpdateMessages.hpp"
|
||||||
#include "providers/RecentMessagesApi.hpp"
|
#include "providers/RecentMessagesApi.hpp"
|
||||||
#include "providers/seventv/eventapi/SeventvEventAPIDispatch.hpp"
|
#include "providers/seventv/eventapi/Dispatch.hpp"
|
||||||
#include "providers/seventv/SeventvEmotes.hpp"
|
#include "providers/seventv/SeventvEmotes.hpp"
|
||||||
#include "providers/seventv/SeventvEventAPI.hpp"
|
#include "providers/seventv/SeventvEventAPI.hpp"
|
||||||
#include "providers/twitch/api/Helix.hpp"
|
#include "providers/twitch/api/Helix.hpp"
|
||||||
@@ -121,16 +121,6 @@ TwitchChannel::TwitchChannel(const QString &name)
|
|||||||
this->loadRecentMessagesReconnect();
|
this->loadRecentMessagesReconnect();
|
||||||
});
|
});
|
||||||
|
|
||||||
this->destroyed.connect([this]() {
|
|
||||||
getApp()->twitch->dropSeventvChannel(this->seventvUserID_,
|
|
||||||
this->seventvEmoteSetID_);
|
|
||||||
|
|
||||||
if (getApp()->twitch->bttvLiveUpdates)
|
|
||||||
{
|
|
||||||
getApp()->twitch->bttvLiveUpdates->partChannel(this->roomId());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this->messageRemovedFromStart.connect([this](MessagePtr &msg) {
|
this->messageRemovedFromStart.connect([this](MessagePtr &msg) {
|
||||||
if (msg->replyThread)
|
if (msg->replyThread)
|
||||||
{
|
{
|
||||||
@@ -169,6 +159,17 @@ TwitchChannel::TwitchChannel(const QString &name)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TwitchChannel::~TwitchChannel()
|
||||||
|
{
|
||||||
|
getApp()->twitch->dropSeventvChannel(this->seventvUserID_,
|
||||||
|
this->seventvEmoteSetID_);
|
||||||
|
|
||||||
|
if (getApp()->twitch->bttvLiveUpdates)
|
||||||
|
{
|
||||||
|
getApp()->twitch->bttvLiveUpdates->partChannel(this->roomId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TwitchChannel::initialize()
|
void TwitchChannel::initialize()
|
||||||
{
|
{
|
||||||
this->fetchDisplayName();
|
this->fetchDisplayName();
|
||||||
@@ -691,7 +692,7 @@ void TwitchChannel::removeBttvEmote(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TwitchChannel::addSeventvEmote(
|
void TwitchChannel::addSeventvEmote(
|
||||||
const SeventvEventAPIEmoteAddDispatch &dispatch)
|
const seventv::eventapi::EmoteAddDispatch &dispatch)
|
||||||
{
|
{
|
||||||
if (!SeventvEmotes::addEmote(this->seventvEmotes_, dispatch))
|
if (!SeventvEmotes::addEmote(this->seventvEmotes_, dispatch))
|
||||||
{
|
{
|
||||||
@@ -703,7 +704,7 @@ void TwitchChannel::addSeventvEmote(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TwitchChannel::updateSeventvEmote(
|
void TwitchChannel::updateSeventvEmote(
|
||||||
const SeventvEventAPIEmoteUpdateDispatch &dispatch)
|
const seventv::eventapi::EmoteUpdateDispatch &dispatch)
|
||||||
{
|
{
|
||||||
if (!SeventvEmotes::updateEmote(this->seventvEmotes_, dispatch))
|
if (!SeventvEmotes::updateEmote(this->seventvEmotes_, dispatch))
|
||||||
{
|
{
|
||||||
@@ -717,7 +718,7 @@ void TwitchChannel::updateSeventvEmote(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TwitchChannel::removeSeventvEmote(
|
void TwitchChannel::removeSeventvEmote(
|
||||||
const SeventvEventAPIEmoteRemoveDispatch &dispatch)
|
const seventv::eventapi::EmoteRemoveDispatch &dispatch)
|
||||||
{
|
{
|
||||||
auto removed = SeventvEmotes::removeEmote(this->seventvEmotes_, dispatch);
|
auto removed = SeventvEmotes::removeEmote(this->seventvEmotes_, dispatch);
|
||||||
if (!removed)
|
if (!removed)
|
||||||
@@ -730,7 +731,7 @@ void TwitchChannel::removeSeventvEmote(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TwitchChannel::updateSeventvUser(
|
void TwitchChannel::updateSeventvUser(
|
||||||
const SeventvEventAPIUserConnectionUpdateDispatch &dispatch)
|
const seventv::eventapi::UserConnectionUpdateDispatch &dispatch)
|
||||||
{
|
{
|
||||||
if (dispatch.connectionIndex != this->seventvUserTwitchConnectionIndex_)
|
if (dispatch.connectionIndex != this->seventvUserTwitchConnectionIndex_)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -49,11 +49,15 @@ class FfzEmotes;
|
|||||||
class BttvEmotes;
|
class BttvEmotes;
|
||||||
struct BttvLiveUpdateEmoteUpdateAddMessage;
|
struct BttvLiveUpdateEmoteUpdateAddMessage;
|
||||||
struct BttvLiveUpdateEmoteRemoveMessage;
|
struct BttvLiveUpdateEmoteRemoveMessage;
|
||||||
|
|
||||||
class SeventvEmotes;
|
class SeventvEmotes;
|
||||||
struct SeventvEventAPIEmoteAddDispatch;
|
namespace seventv::eventapi {
|
||||||
struct SeventvEventAPIEmoteUpdateDispatch;
|
struct EmoteAddDispatch;
|
||||||
struct SeventvEventAPIEmoteRemoveDispatch;
|
struct EmoteUpdateDispatch;
|
||||||
struct SeventvEventAPIUserConnectionUpdateDispatch;
|
struct EmoteRemoveDispatch;
|
||||||
|
struct UserConnectionUpdateDispatch;
|
||||||
|
} // namespace seventv::eventapi
|
||||||
|
|
||||||
struct ChannelPointReward;
|
struct ChannelPointReward;
|
||||||
class MessageThread;
|
class MessageThread;
|
||||||
struct CheerEmoteSet;
|
struct CheerEmoteSet;
|
||||||
@@ -98,6 +102,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
explicit TwitchChannel(const QString &channelName);
|
explicit TwitchChannel(const QString &channelName);
|
||||||
|
~TwitchChannel() override;
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
|
|
||||||
@@ -149,14 +154,16 @@ public:
|
|||||||
void removeBttvEmote(const BttvLiveUpdateEmoteRemoveMessage &message);
|
void removeBttvEmote(const BttvLiveUpdateEmoteRemoveMessage &message);
|
||||||
|
|
||||||
/** Adds a 7TV channel emote to this channel. */
|
/** Adds a 7TV channel emote to this channel. */
|
||||||
void addSeventvEmote(const SeventvEventAPIEmoteAddDispatch &dispatch);
|
void addSeventvEmote(const seventv::eventapi::EmoteAddDispatch &dispatch);
|
||||||
/** Updates a 7TV channel emote's name in this channel */
|
/** Updates a 7TV channel emote's name in this channel */
|
||||||
void updateSeventvEmote(const SeventvEventAPIEmoteUpdateDispatch &dispatch);
|
void updateSeventvEmote(
|
||||||
|
const seventv::eventapi::EmoteUpdateDispatch &dispatch);
|
||||||
/** Removes a 7TV channel emote from this channel */
|
/** Removes a 7TV channel emote from this channel */
|
||||||
void removeSeventvEmote(const SeventvEventAPIEmoteRemoveDispatch &dispatch);
|
void removeSeventvEmote(
|
||||||
|
const seventv::eventapi::EmoteRemoveDispatch &dispatch);
|
||||||
/** Updates the current 7TV user. Currently, only the emote-set is updated. */
|
/** Updates the current 7TV user. Currently, only the emote-set is updated. */
|
||||||
void updateSeventvUser(
|
void updateSeventvUser(
|
||||||
const SeventvEventAPIUserConnectionUpdateDispatch &dispatch);
|
const seventv::eventapi::UserConnectionUpdateDispatch &dispatch);
|
||||||
|
|
||||||
// Update the channel's 7TV information (the channel's 7TV user ID and emote set ID)
|
// Update the channel's 7TV information (the channel's 7TV user ID and emote set ID)
|
||||||
void updateSeventvData(const QString &newUserID,
|
void updateSeventvData(const QString &newUserID,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#include "messages/Message.hpp"
|
#include "messages/Message.hpp"
|
||||||
#include "messages/MessageBuilder.hpp"
|
#include "messages/MessageBuilder.hpp"
|
||||||
#include "providers/bttv/BttvLiveUpdates.hpp"
|
#include "providers/bttv/BttvLiveUpdates.hpp"
|
||||||
#include "providers/seventv/eventapi/SeventvEventAPISubscription.hpp"
|
#include "providers/seventv/eventapi/Subscription.hpp"
|
||||||
#include "providers/seventv/SeventvEventAPI.hpp"
|
#include "providers/seventv/SeventvEventAPI.hpp"
|
||||||
#include "providers/twitch/api/Helix.hpp"
|
#include "providers/twitch/api/Helix.hpp"
|
||||||
#include "providers/twitch/ChannelPointReward.hpp"
|
#include "providers/twitch/ChannelPointReward.hpp"
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
#include "providers/seventv/SeventvEventAPI.hpp"
|
#include "providers/seventv/SeventvEventAPI.hpp"
|
||||||
|
|
||||||
#include "providers/seventv/eventapi/SeventvEventAPIClient.hpp"
|
#include "providers/seventv/eventapi/Client.hpp"
|
||||||
#include "providers/seventv/eventapi/SeventvEventAPIDispatch.hpp"
|
#include "providers/seventv/eventapi/Dispatch.hpp"
|
||||||
#include "providers/seventv/eventapi/SeventvEventAPIMessage.hpp"
|
#include "providers/seventv/eventapi/Message.hpp"
|
||||||
|
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
using namespace chatterino;
|
using namespace chatterino;
|
||||||
|
using namespace chatterino::seventv::eventapi;
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
const QString EMOTE_SET_A = "60b39e943e203cc169dfc106";
|
const QString EMOTE_SET_A = "60b39e943e203cc169dfc106";
|
||||||
@@ -21,10 +22,10 @@ TEST(SeventvEventAPI, AllEvents)
|
|||||||
auto *eventAPI = new SeventvEventAPI(host, std::chrono::milliseconds(1000));
|
auto *eventAPI = new SeventvEventAPI(host, std::chrono::milliseconds(1000));
|
||||||
eventAPI->start();
|
eventAPI->start();
|
||||||
|
|
||||||
boost::optional<SeventvEventAPIEmoteAddDispatch> addDispatch;
|
boost::optional<EmoteAddDispatch> addDispatch;
|
||||||
boost::optional<SeventvEventAPIEmoteUpdateDispatch> updateDispatch;
|
boost::optional<EmoteUpdateDispatch> updateDispatch;
|
||||||
boost::optional<SeventvEventAPIEmoteRemoveDispatch> removeDispatch;
|
boost::optional<EmoteRemoveDispatch> removeDispatch;
|
||||||
boost::optional<SeventvEventAPIUserConnectionUpdateDispatch> userDispatch;
|
boost::optional<UserConnectionUpdateDispatch> userDispatch;
|
||||||
|
|
||||||
eventAPI->signals_.emoteAdded.connect([&](const auto &d) {
|
eventAPI->signals_.emoteAdded.connect([&](const auto &d) {
|
||||||
addDispatch = d;
|
addDispatch = d;
|
||||||
|
|||||||
Reference in New Issue
Block a user