SceneSwitcher/plugins/twitch/chat-connection.hpp

151 lines
3.6 KiB
C++

#pragma once
#include "channel-selection.hpp"
#include "token.hpp"
#include <condition_variable>
#include <mutex>
#include <message-buffer.hpp>
#include <QObject>
#include <websocketpp/client.hpp>
#include <websocketpp/config/asio.hpp>
#include <websocketpp/config/asio_client.hpp>
namespace advss {
using websocketpp::connection_hdl;
struct IRCMessage {
enum class Type {
MESSAGE_RECEIVED,
MESSAGE_REMOVED,
MESSAGE_CLEARED,
USER_LEAVE,
USER_JOIN,
OTHER,
UNKNOWN,
};
Type type = Type::UNKNOWN;
struct Badge {
std::string name;
bool enabled;
};
struct {
std::string badgeInfoString;
std::string badgesString;
std::vector<Badge> badges;
int bits = 0;
std::string color;
std::string displayName;
bool isUsingOnlyEmotes = false;
std::string emotesString;
bool isFirstMessage = false;
std::string id;
bool isMod = false;
std::string replyParentBody;
std::string replyParentDisplayName;
std::string replyParentId;
std::string replyParentUserId;
std::string replyParentUserLogin;
std::string rootParentId;
std::string rootParentUserLogin;
bool isSubscriber = false;
unsigned long long timestamp = 0;
unsigned long long banDuration = 0;
bool isTurbo = false;
std::string userId;
std::string userType;
bool isVIP = false;
} properties;
struct {
std::string nick;
std::string host;
} source;
struct {
std::string command;
std::variant<std::string, bool, std::vector<std::string>>
parameters;
} command;
std::string message;
};
using ChatMessageBuffer = std::shared_ptr<MessageBuffer<IRCMessage>>;
using ChatMessageDispatcher = MessageDispatcher<IRCMessage>;
class TwitchChatConnection : public QObject {
public:
~TwitchChatConnection();
static std::shared_ptr<TwitchChatConnection>
GetChatConnection(const TwitchToken &token,
const TwitchChannel &channel);
[[nodiscard]] ChatMessageBuffer RegisterForMessages();
[[nodiscard]] ChatMessageBuffer RegisterForWhispers();
void SendChatMessage(const std::string &message);
void ConnectToChat();
private:
TwitchChatConnection(const TwitchToken &token,
const TwitchChannel &channel);
void Connect();
void Disconnect();
void OnOpen(connection_hdl hdl);
void
OnMessage(connection_hdl hdl,
websocketpp::client<websocketpp::config::asio_tls_client>::
message_ptr message);
void OnClose(connection_hdl hdl);
void OnFail(connection_hdl hdl);
void Send(const std::string &msg);
void ConnectThread();
void Authenticate();
void JoinChannel(const std::string &);
void HandleJoin(const IRCMessage &);
void HandlePart(const IRCMessage &);
void HandleNewMessage(const IRCMessage &);
void HandleRemoveMessage(const IRCMessage &);
void HandleClear(const IRCMessage &);
void HandleWhisper(const IRCMessage &);
void HandleNotice(const IRCMessage &) const;
void HandleReconnect();
struct ChatMapKey {
std::string channelName;
std::string token;
bool operator<(const ChatMapKey &) const;
};
static std::map<ChatMapKey, std::weak_ptr<TwitchChatConnection>>
_chatMap;
TwitchToken _token;
TwitchChannel _channel;
std::string _joinedChannelName;
websocketpp::client<websocketpp::config::asio_tls_client> _client;
connection_hdl _connection;
std::thread _thread;
std::mutex _waitMtx;
std::mutex _connectMtx;
std::condition_variable _cv;
enum class State { DISCONNECTED, CONNECTING, CONNECTED };
std::atomic<State> _state = {State::DISCONNECTED};
std::atomic_bool _authenticated{false};
std::atomic_bool _stop{false};
std::string _url;
ChatMessageDispatcher _messageDispatcher;
ChatMessageDispatcher _whisperDispatcher;
};
} // namespace advss