show status indicators in member list, change some other shit with presences

This commit is contained in:
ouwou
2021-01-26 02:40:50 -05:00
parent e6c159659d
commit dabfefafd9
15 changed files with 344 additions and 59 deletions

View File

@@ -100,9 +100,17 @@ void to_json(nlohmann::json &j, const ActivityData &m) {
JS_IF("flags", m.Flags);
}
void from_json(const nlohmann::json &j, PresenceData &m) {
JS_N("activities", m.Activities);
JS_D("status", m.Status);
}
void to_json(nlohmann::json &j, const PresenceData &m) {
j["activities"] = m.Activities;
j["status"] = m.Status;
j["afk"] = m.IsAFK;
j["since"] = m.Since;
JS_IF("afk", m.IsAFK);
if (m.Since.has_value())
j["since"] = *m.Since;
else
j["since"] = 0;
}

View File

@@ -5,6 +5,13 @@
#include "json.hpp"
#include "snowflake.hpp"
enum class PresenceStatus : uint8_t {
Online,
Offline,
Idle,
DND,
};
enum class ActivityType : int {
Game = 0,
Streaming = 1,
@@ -28,8 +35,8 @@ struct Bitwise<ActivityFlags> {
};
struct ActivityTimestamps {
std::optional<std::string> Start; // opt
std::optional<std::string> End; // opt
std::optional<int> Start;
std::optional<int> End;
friend void from_json(const nlohmann::json &j, ActivityTimestamps &m);
friend void to_json(nlohmann::json &j, const ActivityTimestamps &m);
@@ -94,8 +101,9 @@ struct ActivityData {
struct PresenceData {
std::vector<ActivityData> Activities; // null (but never sent as such)
std::string Status;
bool IsAFK;
int Since = 0;
std::optional<bool> IsAFK;
std::optional<int> Since;
friend void from_json(const nlohmann::json &j, PresenceData &m);
friend void to_json(nlohmann::json &j, const PresenceData &m);
};

View File

@@ -401,13 +401,26 @@ void DiscordClient::BanUser(Snowflake user_id, Snowflake guild_id) {
m_http.MakePUT("/guilds/" + std::to_string(guild_id) + "/bans/" + std::to_string(user_id), "{}", [](auto) {});
}
void DiscordClient::UpdateStatus(const std::string &status, bool is_afk, const ActivityData &obj) {
void DiscordClient::UpdateStatus(PresenceStatus status, bool is_afk) {
UpdateStatusMessage msg;
msg.Presence.Status = status;
msg.Presence.IsAFK = is_afk;
msg.Presence.Activities.push_back(obj);
msg.Status = status;
msg.IsAFK = is_afk;
m_websocket.Send(nlohmann::json(msg));
// fake message cuz we dont receive messages for ourself
m_user_to_status[m_user_data.ID] = status;
m_signal_presence_update.emit(m_user_data.ID, status);
}
void DiscordClient::UpdateStatus(PresenceStatus status, bool is_afk, const ActivityData &obj) {
UpdateStatusMessage msg;
msg.Status = status;
msg.IsAFK = is_afk;
msg.Activities.push_back(obj);
m_websocket.Send(nlohmann::json(msg));
m_user_to_status[m_user_data.ID] = status;
m_signal_presence_update.emit(m_user_data.ID, status);
}
void DiscordClient::CreateDM(Snowflake user_id) {
@@ -589,6 +602,14 @@ void DiscordClient::SetUserAgent(std::string agent) {
m_websocket.SetUserAgent(agent);
}
std::optional<PresenceStatus> DiscordClient::GetUserStatus(Snowflake id) const {
auto it = m_user_to_status.find(id);
if (it != m_user_to_status.end())
return it->second;
return std::nullopt;
}
void DiscordClient::HandleGatewayMessageRaw(std::string str) {
// handles multiple zlib compressed messages, calling HandleGatewayMessage when a full message is received
std::vector<uint8_t> buf(str.begin(), str.end());
@@ -882,11 +903,27 @@ void DiscordClient::HandleGatewayGuildMemberUpdate(const GatewayMessage &msg) {
void DiscordClient::HandleGatewayPresenceUpdate(const GatewayMessage &msg) {
PresenceUpdateMessage data = msg.Data;
auto cur = m_store.GetUser(data.User.at("id").get<Snowflake>());
const auto user_id = data.User.at("id").get<Snowflake>();
auto cur = m_store.GetUser(user_id);
if (cur.has_value()) {
UserData::update_from_json(data.User, *cur);
cur->update_from_json(data.User);
m_store.SetUser(cur->ID, *cur);
}
PresenceStatus e;
if (data.StatusMessage == "online")
e = PresenceStatus::Online;
else if (data.StatusMessage == "offline")
e = PresenceStatus::Offline;
else if (data.StatusMessage == "idle")
e = PresenceStatus::Idle;
else if (data.StatusMessage == "dnd")
e = PresenceStatus::DND;
m_user_to_status[user_id] = e;
m_signal_presence_update.emit(user_id, e);
}
void DiscordClient::HandleGatewayChannelDelete(const GatewayMessage &msg) {
@@ -1178,6 +1215,17 @@ void DiscordClient::HandleGatewayGuildMemberListUpdate(const GatewayMessage &msg
m_store.SetUser(member->User.ID, member->User);
AddUserToGuild(member->User.ID, data.GuildID);
m_store.SetGuildMember(data.GuildID, member->User.ID, member->GetAsMemberData());
if (member->Presence.has_value()) {
const auto &s = member->Presence->Status;
if (s == "online")
m_user_to_status[member->User.ID] = PresenceStatus::Online;
else if (s == "offline")
m_user_to_status[member->User.ID] = PresenceStatus::Offline;
else if (s == "idle")
m_user_to_status[member->User.ID] = PresenceStatus::Idle;
else if (s == "dnd")
m_user_to_status[member->User.ID] = PresenceStatus::DND;
}
}
}
}
@@ -1476,3 +1524,7 @@ DiscordClient::type_signal_invite_create DiscordClient::signal_invite_create() {
DiscordClient::type_signal_invite_delete DiscordClient::signal_invite_delete() {
return m_signal_invite_delete;
}
DiscordClient::type_signal_presence_update DiscordClient::signal_presence_update() {
return m_signal_presence_update;
}

View File

@@ -105,7 +105,8 @@ public:
void LeaveGuild(Snowflake id);
void KickUser(Snowflake user_id, Snowflake guild_id);
void BanUser(Snowflake user_id, Snowflake guild_id); // todo: reason, delete messages
void UpdateStatus(const std::string &status, bool is_afk, const ActivityData &obj);
void UpdateStatus(PresenceStatus status, bool is_afk);
void UpdateStatus(PresenceStatus status, bool is_afk, const ActivityData &obj);
void CreateDM(Snowflake user_id);
std::optional<Snowflake> FindDM(Snowflake user_id); // wont find group dms
void AddReaction(Snowflake id, Glib::ustring param);
@@ -132,6 +133,8 @@ public:
void UpdateToken(std::string token);
void SetUserAgent(std::string agent);
std::optional<PresenceStatus> GetUserStatus(Snowflake id) const;
private:
static const constexpr int InflateChunkSize = 0x10000;
std::vector<uint8_t> m_compressed_buf;
@@ -192,6 +195,8 @@ private:
std::unordered_map<Snowflake, std::unordered_set<Snowflake>> m_guild_to_channels;
std::unordered_map<Snowflake, PresenceStatus> m_user_to_status;
UserData m_user_data;
UserSettings m_user_settings;
@@ -246,6 +251,7 @@ public:
typedef sigc::signal<void, Snowflake, Snowflake> type_signal_guild_ban_add; // guild id, user id
typedef sigc::signal<void, InviteData> type_signal_invite_create;
typedef sigc::signal<void, InviteDeleteObject> type_signal_invite_delete;
typedef sigc::signal<void, Snowflake, PresenceStatus> type_signal_presence_update;
typedef sigc::signal<void, bool, GatewayCloseCode> type_signal_disconnected; // bool true if reconnecting
typedef sigc::signal<void> type_signal_connected;
@@ -271,6 +277,7 @@ public:
type_signal_guild_ban_add signal_guild_ban_add();
type_signal_invite_create signal_invite_create();
type_signal_invite_delete signal_invite_delete(); // safe to assume guild id is set
type_signal_presence_update signal_presence_update();
type_signal_disconnected signal_disconnected();
type_signal_connected signal_connected();
@@ -297,6 +304,7 @@ protected:
type_signal_guild_ban_add m_signal_guild_ban_add;
type_signal_invite_create m_signal_invite_create;
type_signal_invite_delete m_signal_invite_delete;
type_signal_presence_update m_signal_presence_update;
type_signal_disconnected m_signal_disconnected;
type_signal_connected m_signal_connected;
};

View File

@@ -44,6 +44,7 @@ void from_json(const nlohmann::json &j, GuildMemberListUpdateMessage::MemberItem
JS_N("hoisted_role", m.HoistedRole);
JS_ON("premium_since", m.PremiumSince);
JS_ON("nick", m.Nickname);
JS_ON("presence", m.Presence);
m.m_member_data = j;
}
@@ -85,7 +86,24 @@ void to_json(nlohmann::json &j, const LazyLoadRequestMessage &m) {
void to_json(nlohmann::json &j, const UpdateStatusMessage &m) {
j["op"] = GatewayOp::UpdateStatus;
j["d"] = m.Presence;
j["d"] = nlohmann::json::object();
j["d"]["since"] = m.Since;
j["d"]["activities"] = m.Activities;
j["d"]["afk"] = m.IsAFK;
switch (m.Status) {
case PresenceStatus::Online:
j["d"]["status"] = "online";
break;
case PresenceStatus::Offline:
j["d"]["status"] = "offline";
break;
case PresenceStatus::Idle:
j["d"]["status"] = "idle";
break;
case PresenceStatus::DND:
j["d"]["status"] = "dnd";
break;
}
}
void from_json(const nlohmann::json &j, ReadyEventData &m) {
@@ -170,7 +188,7 @@ void from_json(const nlohmann::json &j, GuildMemberUpdateMessage &m) {
JS_D("joined_at", m.JoinedAt);
}
void from_json(const nlohmann::json &j, ClientStatus &m) {
void from_json(const nlohmann::json &j, ClientStatusData &m) {
JS_O("desktop", m.Desktop);
JS_O("mobile", m.Mobile);
JS_O("web", m.Web);
@@ -180,8 +198,8 @@ void from_json(const nlohmann::json &j, PresenceUpdateMessage &m) {
m.User = j.at("user");
JS_O("guild_id", m.GuildID);
JS_D("status", m.StatusMessage);
// JS_D("activities", m.Activities);
JS_D("client_status", m.Status);
JS_D("activities", m.Activities);
JS_D("client_status", m.ClientStatus);
}
void to_json(nlohmann::json &j, const CreateDMObject &m) {

View File

@@ -129,15 +129,15 @@ struct GuildMemberListUpdateMessage {
};
struct MemberItem : Item {
UserData User; //
std::vector<Snowflake> Roles; //
// PresenceData Presence; //
UserData User;
std::vector<Snowflake> Roles;
std::optional<PresenceData> Presence;
std::string PremiumSince; // opt
std::string Nickname; // opt
bool IsMuted; //
std::string JoinedAt; //
std::string HoistedRole; // null
bool IsDefeaned; //
bool IsMuted;
std::string JoinedAt;
std::string HoistedRole; // null
bool IsDefeaned;
GuildMember GetAsMemberData() const;
@@ -177,7 +177,10 @@ struct LazyLoadRequestMessage {
};
struct UpdateStatusMessage {
PresenceData Presence;
int Since = 0;
std::vector<ActivityData> Activities;
PresenceStatus Status;
bool IsAFK = false;
friend void to_json(nlohmann::json &j, const UpdateStatusMessage &m);
};
@@ -278,20 +281,20 @@ struct GuildMemberUpdateMessage {
friend void from_json(const nlohmann::json &j, GuildMemberUpdateMessage &m);
};
struct ClientStatus {
std::string Desktop; // opt
std::string Mobile; // opt
std::string Web; // opt
struct ClientStatusData {
std::optional<std::string> Desktop;
std::optional<std::string> Mobile;
std::optional<std::string> Web;
friend void from_json(const nlohmann::json &j, ClientStatus &m);
friend void from_json(const nlohmann::json &j, ClientStatusData &m);
};
struct PresenceUpdateMessage {
nlohmann::json User; // the client updates an existing object from this data
Snowflake GuildID; // opt
std::optional<Snowflake> GuildID;
std::string StatusMessage;
// std::vector<ActivityData> Activities;
ClientStatus Status;
std::vector<ActivityData> Activities;
ClientStatusData ClientStatus;
friend void from_json(const nlohmann::json &j, PresenceUpdateMessage &m);
};

View File

@@ -68,21 +68,21 @@ void to_json(nlohmann::json &j, const UserData &m) {
JS_IF("phone", m.Phone);
}
void UserData::update_from_json(const nlohmann::json &j, UserData &m) {
JS_RD("username", m.Username);
JS_RD("discriminator", m.Discriminator);
JS_RD("avatar", m.Avatar);
JS_RD("bot", m.IsBot);
JS_RD("system", m.IsSystem);
JS_RD("mfa_enabled", m.IsMFAEnabled);
JS_RD("locale", m.Locale);
JS_RD("verified", m.IsVerified);
JS_RD("email", m.Email);
JS_RD("flags", m.Flags);
JS_RD("premium_type", m.PremiumType);
JS_RD("public_flags", m.PublicFlags);
JS_RD("desktop", m.IsDesktop);
JS_RD("mobile", m.IsMobile);
JS_RD("nsfw_allowed", m.IsNSFWAllowed);
JS_RD("phone", m.Phone);
void UserData::update_from_json(const nlohmann::json &j) {
JS_RD("username", Username);
JS_RD("discriminator", Discriminator);
JS_RD("avatar", Avatar);
JS_RD("bot", IsBot);
JS_RD("system", IsSystem);
JS_RD("mfa_enabled", IsMFAEnabled);
JS_RD("locale", Locale);
JS_RD("verified", IsVerified);
JS_RD("email", Email);
JS_RD("flags", Flags);
JS_RD("premium_type", PremiumType);
JS_RD("public_flags", PublicFlags);
JS_RD("desktop", IsDesktop);
JS_RD("mobile", IsMobile);
JS_RD("nsfw_allowed", IsNSFWAllowed);
JS_RD("phone", Phone);
}

View File

@@ -26,7 +26,7 @@ struct UserData {
friend void from_json(const nlohmann::json &j, UserData &m);
friend void to_json(nlohmann::json &j, const UserData &m);
static void update_from_json(const nlohmann::json &j, UserData &m);
void update_from_json(const nlohmann::json &j);
bool HasAvatar() const;
bool HasAnimatedAvatar() const;