summaryrefslogtreecommitdiff
path: root/discord
diff options
context:
space:
mode:
authorouwou <26526779+ouwou@users.noreply.github.com>2020-11-23 20:34:09 -0500
committerouwou <26526779+ouwou@users.noreply.github.com>2020-11-23 20:34:09 -0500
commit0b8c83eaa1fdb0fcb610f9181145abde3d60d803 (patch)
tree9897253c0018fb89e2acdf5f3effe2a2e8b02294 /discord
parentdeb482a8db55874a536b6efec366343280214e48 (diff)
downloadabaddon-portaudio-0b8c83eaa1fdb0fcb610f9181145abde3d60d803.tar.gz
abaddon-portaudio-0b8c83eaa1fdb0fcb610f9181145abde3d60d803.zip
progress 2
Diffstat (limited to 'discord')
-rw-r--r--discord/channel.cpp2
-rw-r--r--discord/channel.hpp2
-rw-r--r--discord/discord.cpp98
-rw-r--r--discord/discord.hpp9
-rw-r--r--discord/emoji.hpp16
-rw-r--r--discord/message.cpp72
-rw-r--r--discord/message.hpp102
-rw-r--r--discord/permissions.cpp2
-rw-r--r--discord/permissions.hpp6
-rw-r--r--discord/sticker.cpp13
-rw-r--r--discord/sticker.hpp1
-rw-r--r--discord/store.cpp475
-rw-r--r--discord/store.hpp25
13 files changed, 622 insertions, 201 deletions
diff --git a/discord/channel.cpp b/discord/channel.cpp
index b99971c..ca0f06a 100644
--- a/discord/channel.cpp
+++ b/discord/channel.cpp
@@ -42,6 +42,6 @@ void Channel::update_from_json(const nlohmann::json &j) {
JS_RD("last_pin_timestamp", LastPinTimestamp);
}
-const PermissionOverwrite *Channel::GetOverwrite(Snowflake id) const {
+std::optional<PermissionOverwrite> Channel::GetOverwrite(Snowflake id) const {
return Abaddon::Get().GetDiscordClient().GetPermissionOverwrite(ID, id);
}
diff --git a/discord/channel.hpp b/discord/channel.hpp
index 845cffb..178f8b6 100644
--- a/discord/channel.hpp
+++ b/discord/channel.hpp
@@ -39,5 +39,5 @@ struct Channel {
friend void from_json(const nlohmann::json &j, Channel &m);
void update_from_json(const nlohmann::json &j);
- const PermissionOverwrite *GetOverwrite(Snowflake id) const;
+ std::optional<PermissionOverwrite> GetOverwrite(Snowflake id) const;
};
diff --git a/discord/discord.cpp b/discord/discord.cpp
index 3584a5b..a787c70 100644
--- a/discord/discord.cpp
+++ b/discord/discord.cpp
@@ -2,9 +2,10 @@
#include <cassert>
#include "../util.hpp"
-DiscordClient::DiscordClient()
+DiscordClient::DiscordClient(bool mem_store)
: m_http(DiscordAPI)
- , m_decompress_buf(InflateChunkSize) {
+ , m_decompress_buf(InflateChunkSize)
+ , m_store(mem_store) {
m_msg_dispatch.connect(sigc::mem_fun(*this, &DiscordClient::MessageDispatch));
m_websocket.signal_message().connect(sigc::mem_fun(*this, &DiscordClient::HandleGatewayMessageRaw));
@@ -164,7 +165,7 @@ void DiscordClient::FetchMessagesInChannelBefore(Snowflake channel_id, Snowflake
});
}
-const Message *DiscordClient::GetMessage(Snowflake id) const {
+std::optional<Message> DiscordClient::GetMessage(Snowflake id) const {
return m_store.GetMessage(id);
}
@@ -176,7 +177,7 @@ std::optional<User> DiscordClient::GetUser(Snowflake id) const {
return m_store.GetUser(id);
}
-const Role *DiscordClient::GetRole(Snowflake id) const {
+std::optional<Role> DiscordClient::GetRole(Snowflake id) const {
return m_store.GetRole(id);
}
@@ -188,7 +189,7 @@ const GuildMember *DiscordClient::GetMember(Snowflake user_id, Snowflake guild_i
return m_store.GetGuildMemberData(guild_id, user_id);
}
-const PermissionOverwrite *DiscordClient::GetPermissionOverwrite(Snowflake channel_id, Snowflake id) const {
+std::optional<PermissionOverwrite> DiscordClient::GetPermissionOverwrite(Snowflake channel_id, Snowflake id) const {
return m_store.GetPermissionOverwrite(channel_id, id);
}
@@ -200,22 +201,22 @@ Snowflake DiscordClient::GetMemberHoistedRole(Snowflake guild_id, Snowflake user
auto *data = m_store.GetGuildMemberData(guild_id, user_id);
if (data == nullptr) return Snowflake::Invalid;
- std::vector<const Role *> roles;
+ std::vector<Role> roles;
for (const auto &id : data->Roles) {
- auto *role = GetRole(id);
- if (role != nullptr) {
+ const auto role = GetRole(id);
+ if (role.has_value()) {
if (role->IsHoisted || (with_color && role->Color != 0))
- roles.push_back(role);
+ roles.push_back(*role);
}
}
if (roles.size() == 0) return Snowflake::Invalid;
- std::sort(roles.begin(), roles.end(), [this](const Role *a, const Role *b) -> bool {
- return a->Position > b->Position;
+ std::sort(roles.begin(), roles.end(), [this](const Role &a, const Role &b) -> bool {
+ return a.Position > b.Position;
});
- return roles[0]->ID;
+ return roles[0].ID;
}
Snowflake DiscordClient::GetMemberHighestRole(Snowflake guild_id, Snowflake user_id) const {
@@ -226,9 +227,9 @@ Snowflake DiscordClient::GetMemberHighestRole(Snowflake guild_id, Snowflake user
if (data->Roles.size() == 1) return data->Roles[0];
return *std::max(data->Roles.begin(), data->Roles.end(), [this](const auto &a, const auto &b) -> bool {
- const auto *role_a = GetRole(*a);
- const auto *role_b = GetRole(*b);
- if (role_a == nullptr || role_b == nullptr) return false; // for some reason a Snowflake(0) sneaks into here
+ const auto role_a = GetRole(*a);
+ const auto role_b = GetRole(*b);
+ if (!role_a.has_value() || !role_b.has_value()) return false; // for some reason a Snowflake(0) sneaks into here
return role_a->Position < role_b->Position;
});
}
@@ -241,14 +242,6 @@ std::unordered_set<Snowflake> DiscordClient::GetUsersInGuild(Snowflake id) const
return std::unordered_set<Snowflake>();
}
-std::unordered_set<Snowflake> DiscordClient::GetRolesInGuild(Snowflake id) const {
- std::unordered_set<Snowflake> ret;
- const auto &roles = m_store.GetRoles();
- for (const auto &[rid, rdata] : roles)
- ret.insert(rid);
- return ret;
-}
-
std::unordered_set<Snowflake> DiscordClient::GetChannelsInGuild(Snowflake id) const {
auto it = m_guild_to_channels.find(id);
if (it != m_guild_to_channels.end())
@@ -278,14 +271,14 @@ Permission DiscordClient::ComputePermissions(Snowflake member_id, Snowflake guil
if (guild->OwnerID == member_id)
return Permission::ALL;
- const auto *everyone = GetRole(guild_id);
- if (everyone == nullptr)
+ const auto everyone = GetRole(guild_id);
+ if (!everyone.has_value())
return Permission::NONE;
Permission perms = everyone->Permissions;
for (const auto role_id : member->Roles) {
- const auto *role = GetRole(role_id);
- if (role != nullptr)
+ const auto role = GetRole(role_id);
+ if (role.has_value())
perms |= role->Permissions;
}
@@ -305,8 +298,8 @@ Permission DiscordClient::ComputeOverwrites(Permission base, Snowflake member_id
return Permission::NONE;
Permission perms = base;
- const auto *overwrite_everyone = GetPermissionOverwrite(channel_id, channel->GuildID);
- if (overwrite_everyone != nullptr) {
+ const auto overwrite_everyone = GetPermissionOverwrite(channel_id, channel->GuildID);
+ if (overwrite_everyone.has_value()) {
perms &= ~overwrite_everyone->Deny;
perms |= overwrite_everyone->Allow;
}
@@ -314,8 +307,8 @@ Permission DiscordClient::ComputeOverwrites(Permission base, Snowflake member_id
Permission allow = Permission::NONE;
Permission deny = Permission::NONE;
for (const auto role_id : member->Roles) {
- const auto *overwrite = GetPermissionOverwrite(channel_id, role_id);
- if (overwrite != nullptr) {
+ const auto overwrite = GetPermissionOverwrite(channel_id, role_id);
+ if (overwrite.has_value()) {
allow |= overwrite->Allow;
deny |= overwrite->Deny;
}
@@ -324,8 +317,8 @@ Permission DiscordClient::ComputeOverwrites(Permission base, Snowflake member_id
perms &= ~deny;
perms |= allow;
- const auto *member_overwrite = GetPermissionOverwrite(channel_id, member_id);
- if (member_overwrite != nullptr) {
+ const auto member_overwrite = GetPermissionOverwrite(channel_id, member_id);
+ if (member_overwrite.has_value()) {
perms &= ~member_overwrite->Deny;
perms |= member_overwrite->Allow;
}
@@ -338,10 +331,10 @@ bool DiscordClient::CanManageMember(Snowflake guild_id, Snowflake actor, Snowfla
if (guild != nullptr && guild->OwnerID == target) return false;
const auto actor_highest_id = GetMemberHighestRole(guild_id, actor);
const auto target_highest_id = GetMemberHighestRole(guild_id, target);
- const auto *actor_highest = GetRole(actor_highest_id);
- const auto *target_highest = GetRole(target_highest_id);
- if (actor_highest == nullptr) return false;
- if (target_highest == nullptr) return true;
+ const auto actor_highest = GetRole(actor_highest_id);
+ const auto target_highest = GetRole(target_highest_id);
+ if (!actor_highest.has_value()) return false;
+ if (!target_highest.has_value()) return true;
return actor_highest->Position > target_highest->Position;
}
@@ -581,6 +574,8 @@ void DiscordClient::ProcessNewGuild(Guild &guild) {
return;
}
+ m_store.BeginTransaction();
+
m_store.SetGuild(guild.ID, guild);
for (auto &c : guild.Channels) {
c.GuildID = guild.ID;
@@ -596,6 +591,8 @@ void DiscordClient::ProcessNewGuild(Guild &guild) {
for (auto &e : guild.Emojis)
m_store.SetEmoji(e.ID, e);
+
+ m_store.EndTransaction();
}
void DiscordClient::HandleGatewayReady(const GatewayMessage &msg) {
@@ -629,20 +626,28 @@ void DiscordClient::HandleGatewayMessageCreate(const GatewayMessage &msg) {
void DiscordClient::HandleGatewayMessageDelete(const GatewayMessage &msg) {
MessageDeleteData data = msg.Data;
- auto *cur = m_store.GetMessage(data.ID);
- if (cur != nullptr)
- cur->SetDeleted();
+ auto cur = m_store.GetMessage(data.ID);
+ if (!cur.has_value())
+ return;
+
+ cur->SetDeleted();
+ m_store.SetMessage(data.ID, *cur);
m_signal_message_delete.emit(data.ID, data.ChannelID);
}
void DiscordClient::HandleGatewayMessageDeleteBulk(const GatewayMessage &msg) {
MessageDeleteBulkData data = msg.Data;
+ m_store.BeginTransaction();
for (const auto &id : data.IDs) {
- auto *cur = m_store.GetMessage(id);
- if (cur != nullptr)
- cur->SetDeleted();
+ auto cur = m_store.GetMessage(id);
+ if (!cur.has_value())
+ return;
+
+ cur->SetDeleted();
+ m_store.SetMessage(id, *cur);
m_signal_message_delete.emit(id, data.ChannelID);
}
+ m_store.EndTransaction();
}
void DiscordClient::HandleGatewayGuildMemberUpdate(const GatewayMessage &msg) {
@@ -681,10 +686,12 @@ void DiscordClient::HandleGatewayChannelUpdate(const GatewayMessage &msg) {
void DiscordClient::HandleGatewayChannelCreate(const GatewayMessage &msg) {
Channel data = msg.Data;
+ m_store.BeginTransaction();
m_store.SetChannel(data.ID, data);
m_guild_to_channels[data.GuildID].insert(data.ID);
for (const auto &p : data.PermissionOverwrites)
m_store.SetPermissionOverwrite(data.ID, p.ID, p);
+ m_store.EndTransaction();
m_signal_channel_create.emit(data.ID);
}
@@ -717,11 +724,12 @@ void DiscordClient::HandleGatewayReconnect(const GatewayMessage &msg) {
void DiscordClient::HandleGatewayMessageUpdate(const GatewayMessage &msg) {
Snowflake id = msg.Data.at("id");
- auto *current = m_store.GetMessage(id);
- if (current == nullptr)
+ auto current = m_store.GetMessage(id);
+ if (!current.has_value())
return;
current->from_json_edited(msg.Data);
+ m_store.SetMessage(id, *current);
m_signal_message_update.emit(id, current->ChannelID);
}
diff --git a/discord/discord.hpp b/discord/discord.hpp
index c60f8ad..df7675a 100644
--- a/discord/discord.hpp
+++ b/discord/discord.hpp
@@ -55,7 +55,7 @@ public:
static const constexpr char *GatewayIdentity = "Discord";
public:
- DiscordClient();
+ DiscordClient(bool mem_store = false);
void Start();
void Stop();
bool IsStarted() const;
@@ -80,18 +80,17 @@ public:
void FetchInviteData(std::string code, std::function<void(Invite)> cb, std::function<void(bool)> err);
void FetchMessagesInChannel(Snowflake id, std::function<void(const std::vector<Snowflake> &)> cb);
void FetchMessagesInChannelBefore(Snowflake channel_id, Snowflake before_id, std::function<void(const std::vector<Snowflake> &)> cb);
- const Message *GetMessage(Snowflake id) const;
+ std::optional<Message> GetMessage(Snowflake id) const;
const Channel *GetChannel(Snowflake id) const;
+ std::optional<PermissionOverwrite> GetPermissionOverwrite(Snowflake channel_id, Snowflake id) const;
std::optional<User> GetUser(Snowflake id) const;
- const Role *GetRole(Snowflake id) const;
+ std::optional<Role> GetRole(Snowflake id) const;
const Guild *GetGuild(Snowflake id) const;
const GuildMember *GetMember(Snowflake user_id, Snowflake guild_id) const;
- const PermissionOverwrite *GetPermissionOverwrite(Snowflake channel_id, Snowflake id) const;
const Emoji *GetEmoji(Snowflake id) const;
Snowflake GetMemberHoistedRole(Snowflake guild_id, Snowflake user_id, bool with_color = false) const;
Snowflake GetMemberHighestRole(Snowflake guild_id, Snowflake user_id) const;
std::unordered_set<Snowflake> GetUsersInGuild(Snowflake id) const;
- std::unordered_set<Snowflake> GetRolesInGuild(Snowflake id) const;
std::unordered_set<Snowflake> GetChannelsInGuild(Snowflake id) const;
bool HasGuildPermission(Snowflake user_id, Snowflake guild_id, Permission perm) const;
diff --git a/discord/emoji.hpp b/discord/emoji.hpp
index e4839f2..18e69d3 100644
--- a/discord/emoji.hpp
+++ b/discord/emoji.hpp
@@ -6,14 +6,14 @@
#include "user.hpp"
struct Emoji {
- Snowflake ID; // null
- std::string Name; // null (in reactions)
- std::vector<Snowflake> Roles; // opt
- User Creator; // opt
- bool NeedsColons = false; // opt
- bool IsManaged = false; // opt
- bool IsAnimated = false; // opt
- bool IsAvailable = false; // opt
+ Snowflake ID; // null
+ std::string Name; // null (in reactions)
+ std::optional<std::vector<Snowflake>> Roles;
+ std::optional<User> Creator; // only reliable to access ID
+ std::optional<bool> NeedsColons;
+ std::optional<bool> IsManaged;
+ std::optional<bool> IsAnimated;
+ std::optional<bool> IsAvailable;
friend void from_json(const nlohmann::json &j, Emoji &m);
diff --git a/discord/message.cpp b/discord/message.cpp
index 66b806f..d0f2082 100644
--- a/discord/message.cpp
+++ b/discord/message.cpp
@@ -1,11 +1,24 @@
#include "message.hpp"
+void to_json(nlohmann::json &j, const EmbedFooterData &m) {
+ j["text"] = m.Text;
+ JS_IF("icon_url", m.IconURL);
+ JS_IF("proxy_icon_url", m.ProxyIconURL);
+}
+
void from_json(const nlohmann::json &j, EmbedFooterData &m) {
JS_D("text", m.Text);
JS_O("icon_url", m.IconURL);
JS_O("proxy_icon_url", m.ProxyIconURL);
}
+void to_json(nlohmann::json &j, const EmbedImageData &m) {
+ JS_IF("url", m.URL);
+ JS_IF("proxy_url", m.ProxyURL);
+ JS_IF("height", m.Height);
+ JS_IF("width", m.Width);
+}
+
void from_json(const nlohmann::json &j, EmbedImageData &m) {
JS_O("url", m.URL);
JS_O("proxy_url", m.ProxyURL);
@@ -13,6 +26,13 @@ void from_json(const nlohmann::json &j, EmbedImageData &m) {
JS_O("width", m.Width);
}
+void to_json(nlohmann::json &j, const EmbedThumbnailData &m) {
+ JS_IF("url", m.URL);
+ JS_IF("proxy_url", m.ProxyURL);
+ JS_IF("height", m.Height);
+ JS_IF("width", m.Width);
+}
+
void from_json(const nlohmann::json &j, EmbedThumbnailData &m) {
JS_O("url", m.URL);
JS_O("proxy_url", m.ProxyURL);
@@ -20,17 +40,35 @@ void from_json(const nlohmann::json &j, EmbedThumbnailData &m) {
JS_O("width", m.Width);
}
+void to_json(nlohmann::json &j, const EmbedVideoData &m) {
+ JS_IF("url", m.URL);
+ JS_IF("height", m.Height);
+ JS_IF("width", m.Width);
+}
+
void from_json(const nlohmann::json &j, EmbedVideoData &m) {
JS_O("url", m.URL);
JS_O("height", m.Height);
JS_O("width", m.Width);
}
+void to_json(nlohmann::json &j, const EmbedProviderData &m) {
+ JS_IF("name", m.Name);
+ JS_IF("url", m.URL);
+}
+
void from_json(const nlohmann::json &j, EmbedProviderData &m) {
JS_O("name", m.Name);
JS_ON("url", m.URL);
}
+void to_json(nlohmann::json &j, const EmbedAuthorData &m) {
+ JS_IF("name", m.Name);
+ JS_IF("url", m.URL);
+ JS_IF("icon_url", m.IconURL);
+ JS_IF("proxy_icon_url", m.ProxyIconURL);
+}
+
void from_json(const nlohmann::json &j, EmbedAuthorData &m) {
JS_O("name", m.Name);
JS_O("url", m.URL);
@@ -38,12 +76,34 @@ void from_json(const nlohmann::json &j, EmbedAuthorData &m) {
JS_O("proxy_icon_url", m.ProxyIconURL);
}
+void to_json(nlohmann::json &j, const EmbedFieldData &m) {
+ j["name"] = m.Name;
+ j["value"] = m.Value;
+ JS_IF("inline", m.Inline);
+}
+
void from_json(const nlohmann::json &j, EmbedFieldData &m) {
JS_D("name", m.Name);
JS_D("value", m.Value);
JS_O("inline", m.Inline);
}
+void to_json(nlohmann::json &j, const EmbedData &m) {
+ JS_IF("title", m.Title);
+ JS_IF("type", m.Type);
+ JS_IF("description", m.Description);
+ JS_IF("url", m.URL);
+ JS_IF("timestamp", m.Timestamp);
+ JS_IF("color", m.Color);
+ JS_IF("footer", m.Footer);
+ JS_IF("image", m.Image);
+ JS_IF("thumbnail", m.Thumbnail);
+ JS_IF("video", m.Video);
+ JS_IF("provider", m.Provider);
+ JS_IF("author", m.Author);
+ JS_IF("fields", m.Fields);
+}
+
void from_json(const nlohmann::json &j, EmbedData &m) {
JS_O("title", m.Title);
JS_O("type", m.Type);
@@ -60,6 +120,16 @@ void from_json(const nlohmann::json &j, EmbedData &m) {
JS_O("fields", m.Fields);
}
+void to_json(nlohmann::json &j, const AttachmentData &m) {
+ j["id"] = m.ID;
+ j["filename"] = m.Filename;
+ j["size"] = m.Bytes;
+ j["url"] = m.URL;
+ j["proxy_url"] = m.ProxyURL;
+ JS_IF("height", m.Height);
+ JS_IF("width", m.Width);
+}
+
void from_json(const nlohmann::json &j, AttachmentData &m) {
JS_D("id", m.ID);
JS_D("filename", m.Filename);
@@ -107,7 +177,7 @@ void from_json(const nlohmann::json &j, Message &m) {
JS_D("type", m.Type);
// JS_O("activity", m.Activity);
// JS_O("application", m.Application);
- // JS_O("message_reference", m.MessageReference);
+ JS_O("message_reference", m.MessageReference);
JS_O("flags", m.Flags);
JS_O("stickers", m.Stickers);
}
diff --git a/discord/message.hpp b/discord/message.hpp
index 629fc9f..99c58ab 100644
--- a/discord/message.hpp
+++ b/discord/message.hpp
@@ -35,89 +35,99 @@ enum class MessageFlags {
};
struct EmbedFooterData {
- std::string Text; //
- std::string IconURL; // opt
- std::string ProxyIconURL; // opt
+ std::string Text;
+ std::optional<std::string> IconURL;
+ std::optional<std::string> ProxyIconURL;
+ friend void to_json(nlohmann::json &j, const EmbedFooterData &m);
friend void from_json(const nlohmann::json &j, EmbedFooterData &m);
};
struct EmbedImageData {
- std::string URL; // opt
- std::string ProxyURL; // opt
- int Height = 0; // opt
- int Width = 0; // opt
+ std::optional<std::string> URL;
+ std::optional<std::string> ProxyURL;
+ std::optional<int> Height;
+ std::optional<int> Width;
+ friend void to_json(nlohmann::json &j, const EmbedImageData &m);
friend void from_json(const nlohmann::json &j, EmbedImageData &m);
};
struct EmbedThumbnailData {
- std::string URL; // opt
- std::string ProxyURL; // opt
- int Height = 0; // opt
- int Width = 0; // opt
+ std::optional<std::string> URL;
+ std::optional<std::string> ProxyURL;
+ std::optional<int> Height;
+ std::optional<int> Width;
+ friend void to_json(nlohmann::json &j, const EmbedThumbnailData &m);
friend void from_json(const nlohmann::json &j, EmbedThumbnailData &m);
};
struct EmbedVideoData {
- std::string URL; // opt
- int Height = 0; // opt
- int Width = 0; // opt
+ std::optional<std::string> URL;
+ std::optional<int> Height;
+ std::optional<int> Width;
+
+ friend void to_json(nlohmann::json &j, const EmbedVideoData &m);
friend void from_json(const nlohmann::json &j, EmbedVideoData &m);
};
struct EmbedProviderData {
- std::string Name; // opt
- std::string URL; // opt, null (docs wrong)
+ std::optional<std::string> Name;
+ std::optional<std::string> URL; // null
+ friend void to_json(nlohmann::json &j, const EmbedProviderData &m);
friend void from_json(const nlohmann::json &j, EmbedProviderData &m);
};
struct EmbedAuthorData {
- std::string Name; // opt
- std::string URL; // opt
- std::string IconURL; // opt
- std::string ProxyIconURL; // opt
+ std::optional<std::string> Name;
+ std::optional<std::string> URL;
+ std::optional<std::string> IconURL;
+ std::optional<std::string> ProxyIconURL;
+ friend void to_json(nlohmann::json &j, const EmbedAuthorData &m);
friend void from_json(const nlohmann::json &j, EmbedAuthorData &m);
};
struct EmbedFieldData {
- std::string Name; //
- std::string Value; //
- bool Inline = false; // opt
+ std::string Name;
+ std::string Value;
+ std::optional<bool> Inline;
+ friend void to_json(nlohmann::json &j, const EmbedFieldData &m);
friend void from_json(const nlohmann::json &j, EmbedFieldData &m);
};
struct EmbedData {
- std::string Title; // opt
- std::string Type; // opt
- std::string Description; // opt
- std::string URL; // opt
- std::string Timestamp; // opt
- int Color = -1; // opt
- EmbedFooterData Footer; // opt
- EmbedImageData Image; // opt
- EmbedThumbnailData Thumbnail; // opt
- EmbedVideoData Video; // opt
- EmbedProviderData Provider; // opt
- EmbedAuthorData Author; // opt
- std::vector<EmbedFieldData> Fields; // opt
-
+ std::optional<std::string> Title;
+ std::optional<std::string> Type;
+ std::optional<std::string> Description;
+ std::optional<std::string> URL;
+ std::optional<std::string> Timestamp;
+ std::optional<int> Color;
+ std::optional<EmbedFooterData> Footer;
+ std::optional<EmbedImageData> Image;
+ std::optional<EmbedThumbnailData> Thumbnail;
+ std::optional<EmbedVideoData> Video;
+ std::optional<EmbedProviderData> Provider;
+ std::optional<EmbedAuthorData> Author;
+ std::optional<std::vector<EmbedFieldData>> Fields;
+
+ friend void to_json(nlohmann::json &j, const EmbedData &m);
friend void from_json(const nlohmann::json &j, EmbedData &m);
};
struct AttachmentData {
- Snowflake ID; //
- std::string Filename; //
- int Bytes; //
- std::string URL; //
- std::string ProxyURL; //
- int Height = -1; // opt, null
- int Width = -1; // opt, null
-
+ Snowflake ID;
+ std::string Filename;
+ int Bytes;
+ std::string URL;
+ std::string ProxyURL;
+ std::optional<int> Height; // null
+ std::optional<int> Width; // null
+
+ friend void to_json(nlohmann::json &j, const AttachmentData &m);
friend void from_json(const nlohmann::json &j, AttachmentData &m);
};
@@ -141,7 +151,7 @@ struct Message {
std::string EditedTimestamp; // null
bool IsTTS;
bool DoesMentionEveryone;
- std::vector<User> Mentions;
+ std::vector<User> Mentions; // currently discarded in store
// std::vector<Role> MentionRoles;
// std::optional<std::vector<ChannelMentionData>> MentionChannels;
std::vector<AttachmentData> Attachments;
diff --git a/discord/permissions.cpp b/discord/permissions.cpp
index f181e13..63eeb9f 100644
--- a/discord/permissions.cpp
+++ b/discord/permissions.cpp
@@ -3,7 +3,7 @@
void from_json(const nlohmann::json &j, PermissionOverwrite &m) {
JS_D("id", m.ID);
std::string tmp;
- m.ID = j.at("type").get<int>() == 0 ? PermissionOverwrite::ROLE : PermissionOverwrite::MEMBER;
+ m.Type = j.at("type").get<int>() == 0 ? PermissionOverwrite::ROLE : PermissionOverwrite::MEMBER;
JS_D("allow", tmp);
m.Allow = static_cast<Permission>(std::stoull(tmp));
JS_D("deny", tmp);
diff --git a/discord/permissions.hpp b/discord/permissions.hpp
index 65a0daa..715883a 100644
--- a/discord/permissions.hpp
+++ b/discord/permissions.hpp
@@ -46,9 +46,9 @@ struct Bitwise<Permission> {
};
struct PermissionOverwrite {
- enum OverwriteType {
- ROLE,
- MEMBER,
+ enum OverwriteType : uint8_t {
+ ROLE = 0,
+ MEMBER = 1,
};
Snowflake ID;
diff --git a/discord/sticker.cpp b/discord/sticker.cpp
index 1d59e82..9eca852 100644
--- a/discord/sticker.cpp
+++ b/discord/sticker.cpp
@@ -1,12 +1,23 @@
#include "sticker.hpp"
+void to_json(nlohmann::json &j, const Sticker &m) {
+ j["id"] = m.ID;
+ j["pack_id"] = m.PackID;
+ j["name"] = m.Name;
+ j["description"] = m.Description;
+ JS_IF("tags", m.Tags);
+ JS_IF("asset", m.AssetHash);
+ JS_IF("preview_asset", m.PreviewAssetHash);
+ j["format_type"] = m.FormatType;
+}
+
void from_json(const nlohmann::json &j, Sticker &m) {
JS_D("id", m.ID);
JS_D("pack_id", m.PackID);
JS_D("name", m.Name);
JS_D("description", m.Description);
JS_O("tags", m.Tags);
- JS_D("asset", m.AssetHash);
+ JS_O("asset", m.AssetHash);
JS_N("preview_asset", m.PreviewAssetHash);
JS_D("format_type", m.FormatType);
}
diff --git a/discord/sticker.hpp b/discord/sticker.hpp
index e510800..e6b34e6 100644
--- a/discord/sticker.hpp
+++ b/discord/sticker.hpp
@@ -22,6 +22,7 @@ struct Sticker {
std::optional<std::string> PreviewAssetHash;
StickerFormatType FormatType;
+ friend void to_json(nlohmann::json &j, const Sticker &m);
friend void from_json(const nlohmann::json &j, Sticker &m);
std::string GetURL() const;
diff --git a/discord/store.cpp b/discord/store.cpp
index fbba477..9c9084c 100644
--- a/discord/store.cpp
+++ b/discord/store.cpp
@@ -1,10 +1,18 @@
#include "store.hpp"
+using namespace std::literals::string_literals;
+
// hopefully the casting between signed and unsigned int64 doesnt cause issues
-Store::Store() {
- m_db_path = std::filesystem::temp_directory_path() / "abaddon-store.db";
- m_db_err = sqlite3_open(m_db_path.string().c_str(), &m_db);
+Store::Store(bool mem_store) {
+ if (mem_store) {
+ m_db_path = ":memory:";
+ m_db_err = sqlite3_open(":memory:", &m_db);
+ } else {
+ m_db_path = std::filesystem::temp_directory_path() / "abaddon-store.db";
+ m_db_err = sqlite3_open(m_db_path.string().c_str(), &m_db);
+ }
+
if (m_db_err != SQLITE_OK) {
fprintf(stderr, "error opening database: %s\n", sqlite3_errstr(m_db_err));
return;
@@ -35,7 +43,8 @@ Store::~Store() {
return;
}
- std::filesystem::remove(m_db_path);
+ if (m_db_path != ":memory:")
+ std::filesystem::remove(m_db_path);
}
bool Store::IsValid() const {
@@ -43,10 +52,6 @@ bool Store::IsValid() const {
}
void Store::SetUser(Snowflake id, const User &user) {
- if ((uint64_t)id == 0) {
- printf("???: %s\n", user.Username.c_str());
- }
-
Bind(m_set_user_stmt, 1, id);
Bind(m_set_user_stmt, 2, user.Username);
Bind(m_set_user_stmt, 3, user.Discriminator);
@@ -64,8 +69,6 @@ void Store::SetUser(Snowflake id, const User &user) {
if (!RunInsert(m_set_user_stmt)) {
fprintf(stderr, "user insert failed: %s\n", sqlite3_errstr(m_db_err));
}
-
- // m_users[id] = user;
}
void Store::SetChannel(Snowflake id, const Channel &channel) {
@@ -77,11 +80,65 @@ void Store::SetGuild(Snowflake id, const Guild &guild) {
}
void Store::SetRole(Snowflake id, const Role &role) {
- m_roles[id] = role;
+ Bind(m_set_role_stmt, 1, id);
+ Bind(m_set_role_stmt, 2, role.Name);
+ Bind(m_set_role_stmt, 3, role.Color);
+ Bind(m_set_role_stmt, 4, role.IsHoisted);
+ Bind(m_set_role_stmt, 5, role.Position);
+ Bind(m_set_role_stmt, 6, static_cast<uint64_t>(role.Permissions));
+ Bind(m_set_role_stmt, 7, role.IsManaged);
+ Bind(m_set_role_stmt, 8, role.IsMentionable);
+
+ if (!RunInsert(m_set_role_stmt))
+ fprintf(stderr, "role insert failed: %s\n", sqlite3_errstr(m_db_err));
}
void Store::SetMessage(Snowflake id, const Message &message) {
- m_messages[id] = message;
+ Bind(m_set_msg_stmt, 1, id);
+ Bind(m_set_msg_stmt, 2, message.ChannelID);
+ Bind(m_set_msg_stmt, 3, message.GuildID);
+ Bind(m_set_msg_stmt, 4, message.Author.ID);
+ Bind(m_set_msg_stmt, 5, message.Content);
+ Bind(m_set_msg_stmt, 6, message.Timestamp);
+ Bind(m_set_msg_stmt, 7, message.EditedTimestamp);
+ Bind(m_set_msg_stmt, 8, message.IsTTS);
+ Bind(m_set_msg_stmt, 9, message.DoesMentionEveryone);
+ Bind(m_set_msg_stmt, 10, "[]"s); // mentions
+ {
+ std::string tmp;
+ tmp = nlohmann::json(message.Attachments).dump();
+ Bind(m_set_msg_stmt, 11, tmp);
+ }
+ {
+ std::string tmp = nlohmann::json(message.Embeds).dump();
+ Bind(m_set_msg_stmt, 12, tmp);
+ }
+ Bind(m_set_msg_stmt, 13, message.IsPinned);
+ Bind(m_set_msg_stmt, 14, message.WebhookID);
+ Bind(m_set_msg_stmt, 15, static_cast<uint64_t>(message.Type));
+
+ if (message.MessageReference.has_value()) {
+ std::string tmp = nlohmann::json(*message.MessageReference).dump();
+ Bind(m_set_msg_stmt, 16, tmp);
+ } else
+ Bind(m_set_msg_stmt, 16, nullptr);
+
+ if (message.Flags.has_value())
+ Bind(m_set_msg_stmt, 17, static_cast<uint64_t>(*message.Flags));
+ else
+ Bind(m_set_msg_stmt, 17, nullptr);
+
+ if (message.Stickers.has_value()) {
+ std::string tmp = nlohmann::json(*message.Stickers).dump();
+ Bind(m_set_msg_stmt, 18, tmp);
+ } else
+ Bind(m_set_msg_stmt, 18, nullptr);
+
+ Bind(m_set_msg_stmt, 19, message.IsDeleted());
+ Bind(m_set_msg_stmt, 20, message.IsEdited());
+
+ if (!RunInsert(m_set_msg_stmt))
+ fprintf(stderr, "message insert failed: %s\n", sqlite3_errstr(m_db_err));
}
void Store::SetGuildMemberData(Snowflake guild_id, Snowflake user_id, const GuildMember &data) {
@@ -89,17 +146,146 @@ void Store::SetGuildMemberData(Snowflake guild_id, Snowflake user_id, const Guil
}
void Store::SetPermissionOverwrite(Snowflake channel_id, Snowflake id, const PermissionOverwrite &perm) {
- m_permissions[channel_id][id] = perm;
+ Bind(m_set_perm_stmt, 1, perm.ID);
+ Bind(m_set_perm_stmt, 2, channel_id);
+ Bind(m_set_perm_stmt, 3, static_cast<int>(perm.Type));
+ Bind(m_set_perm_stmt, 4, static_cast<uint64_t>(perm.Allow));
+ Bind(m_set_perm_stmt, 5, static_cast<uint64_t>(perm.Deny));
+
+ if (!RunInsert(m_set_perm_stmt))
+ fprintf(stderr, "permission insert failed: %s\n", sqlite3_errstr(m_db_err));
}
void Store::SetEmoji(Snowflake id, const Emoji &emoji) {
+ Bind(m_set_emote_stmt, 1, id);
+ Bind(m_set_emote_stmt, 2, emoji.Name);
+
+ if (emoji.Roles.has_value())
+ Bind(m_set_emote_stmt, 3, nlohmann::json(*emoji.Roles).dump());
+ else
+ Bind(m_set_emote_stmt, 3, nullptr);
+
+ if (emoji.Creator.has_value())
+ Bind(m_set_emote_stmt, 4, emoji.Creator->ID);
+ else
+ Bind(m_set_emote_stmt, 4, nullptr);
+
+ Bind(m_set_emote_stmt, 5, emoji.NeedsColons);
+ Bind(m_set_emote_stmt, 6, emoji.IsManaged);
+ Bind(m_set_emote_stmt, 7, emoji.IsAnimated);
+ Bind(m_set_emote_stmt, 8, emoji.IsAvailable);
+
+ if (!RunInsert(m_set_emote_stmt))
+ fprintf(stderr, "emoji insert failed: %s\n", sqlite3_errstr(m_db_err));
+
m_emojis[id] = emoji;
}
+std::optional<Message> Store::GetMessage(Snowflake id) const {
+ Bind(m_get_msg_stmt, 1, id);
+ if (!FetchOne(m_get_msg_stmt)) {
+ if (m_db_err != SQLITE_DONE)
+ fprintf(stderr, "error while fetching message: %s\n", sqlite3_errstr(m_db_err));
+ Reset(m_get_msg_stmt);
+ return std::nullopt;
+ }
+
+ Message ret;
+ ret.ID = id;
+ Get(m_get_msg_stmt, 1, ret.ChannelID);
+ Get(m_get_msg_stmt, 2, ret.GuildID);
+ Get(m_get_msg_stmt, 3, ret.Author.ID); // yike
+ Get(m_get_msg_stmt, 4, ret.Content);
+ Get(m_get_msg_stmt, 5, ret.Timestamp);
+ Get(m_get_msg_stmt, 6, ret.EditedTimestamp);
+ Get(m_get_msg_stmt, 7, ret.IsTTS);
+ Get(m_get_msg_stmt, 8, ret.DoesMentionEveryone);
+ std::string tmps;
+ Get(m_get_msg_stmt, 9, tmps);
+ nlohmann::json::parse(tmps).get_to(ret.Mentions);
+ Get(m_get_msg_stmt, 10, tmps);
+ nlohmann::json::parse(tmps).get_to(ret.Attachments);
+ Get(m_get_msg_stmt, 11, tmps);
+ nlohmann::json::parse(tmps).get_to(ret.Embeds);
+ Get(m_get_msg_stmt, 12, ret.IsPinned);
+ Get(m_get_msg_stmt, 13, ret.WebhookID);
+ uint64_t tmpi;
+ Get(m_get_msg_stmt, 14, tmpi);
+ ret.Type = static_cast<MessageType>(tmpi);
+ Get(m_get_msg_stmt, 15, tmps);
+ if (tmps != "")
+ ret.MessageReference = nlohmann::json::parse(tmps).get<MessageReferenceData>();
+ Get(m_get_msg_stmt, 16, tmpi);
+ ret.Flags = static_cast<MessageFlags>(tmpi);
+ Get(m_get_msg_stmt, 17, tmps);
+ if (tmps != "")
+ ret.Stickers = nlohmann::json::parse(tmps).get<std::vector<Sticker>>();
+ bool tmpb = false;
+ Get(m_get_msg_stmt, 18, tmpb);
+ if (tmpb) ret.SetDeleted();
+ Get(m_get_msg_stmt, 19, tmpb);
+ if (tmpb) ret.SetEdited();
+
+ Reset(m_get_msg_stmt);
+
+ return std::optional<Message>(std::move(ret));
+}
+
+std::optional<PermissionOverwrite> Store::GetPermissionOverwrite(Snowflake channel_id, Snowflake id) const {
+ Bind(m_get_perm_stmt, 1, id);
+ Bind(m_get_perm_stmt, 2, channel_id);
+ if (!FetchOne(m_get_perm_stmt)) {
+ if (m_db_err != SQLITE_DONE)
+ fprintf(stderr, "error while fetching permission: %s\n", sqlite3_errstr(m_db_err));
+ Reset(m_get_perm_stmt);
+ return std::nullopt;
+ }
+
+ PermissionOverwrite ret;
+ ret.ID = id;
+ uint64_t tmp;
+ Get(m_get_perm_stmt, 2, tmp);
+ ret.Type = static_cast<PermissionOverwrite::OverwriteType>(tmp);
+ Get(m_get_perm_stmt, 3, tmp);
+ ret.Allow = static_cast<Permission>(tmp);
+ Get(m_get_perm_stmt, 4, tmp);
+ ret.Deny = static_cast<Permission>(tmp);
+
+ Reset(m_get_perm_stmt);
+
+ return std::optional<PermissionOverwrite>(std::move(ret));
+}
+
+std::optional<Role> Store::GetRole(Snowflake id) const {
+ Bind(m_get_role_stmt, 1, id);
+ if (!FetchOne(m_get_role_stmt)) {
+ if (m_db_err != SQLITE_DONE)
+ fprintf(stderr, "error while fetching role: %s\n", sqlite3_errstr(m_db_err));
+ Reset(m_get_role_stmt);
+ return std::nullopt;
+ }
+
+ Role ret;
+ ret.ID = id;
+ Get(m_get_role_stmt, 1, ret.Name);
+ Get(m_get_role_stmt, 2, ret.Color);
+ Get(m_get_role_stmt, 3, ret.IsHoisted);
+ Get(m_get_role_stmt, 4, ret.Position);
+ uint64_t tmp;
+ Get(m_get_role_stmt, 5, tmp);
+ ret.Permissions = static_cast<Permission>(tmp);
+ Get(m_get_role_stmt, 6, ret.IsManaged);
+ Get(m_get_role_stmt, 7, ret.IsMentionable);
+
+ Reset(m_get_role_stmt);
+
+ return std::optional<Role>(std::move(ret));
+}
+
std::optional<User> Store::GetUser(Snowflake id) const {
Bind(m_get_user_stmt, 1, id);
if (!FetchOne(m_get_user_stmt)) {
- if (m_db_err != SQLITE_DONE) // not an error, just means user isnt found
+ if (m_db_err != SQLITE_DONE)
fprintf(stderr, "error while fetching user info: %s\n", sqlite3_errstr(m_db_err));
Reset(m_get_user_stmt);
return std::nullopt;
@@ -153,34 +339,6 @@ const Guild *Store::GetGuild(Snowflake id) const {
return &it->second;
}
-Role *Store::GetRole(Snowflake id) {
- auto it = m_roles.find(id);
- if (it == m_roles.end())
- return nullptr;
- return &it->second;
-}
-
-const Role *Store::GetRole(Snowflake id) const {
- auto it = m_roles.find(id);
- if (it == m_roles.end())
- return nullptr;
- return &it->second;
-}
-
-Message *Store::GetMessage(Snowflake id) {
- auto it = m_messages.find(id);
- if (it == m_messages.end())
- return nullptr;
- return &it->second;
-}
-
-const Message *Store::GetMessage(Snowflake id) const {
- auto it = m_messages.find(id);
- if (it == m_messages.end())
- return nullptr;
- return &it->second;
-}
-
GuildMember *Store::GetGuildMemberData(Snowflake guild_id, Snowflake user_id) {
auto git = m_members.find(guild_id);
if (git == m_members.end())
@@ -191,16 +349,6 @@ GuildMember *Store::GetGuildMemberData(Snowflake guild_id, Snowflake user_id) {
return &mit->second;
}
-PermissionOverwrite *Store::GetPermissionOverwrite(Snowflake channel_id, Snowflake id) {
- auto cit = m_permissions.find(channel_id);
- if (cit == m_permissions.end())
- return nullptr;
- auto pit = cit->second.find(id);
- if (pit == cit->second.end())
- return nullptr;
- return &pit->second;
-}
-
Emoji *Store::GetEmoji(Snowflake id) {
auto it = m_emojis.find(id);
if (it != m_emojis.end())
@@ -218,16 +366,6 @@ const GuildMember *Store::GetGuildMemberData(Snowflake guild_id, Snowflake user_
return &mit->second;
}
-const PermissionOverwrite *Store::GetPermissionOverwrite(Snowflake channel_id, Snowflake id) const {
- auto cit = m_permissions.find(channel_id);
- if (cit == m_permissions.end())
- return nullptr;
- auto pit = cit->second.find(id);
- if (pit == cit->second.end())
- return nullptr;
- return &pit->second;
-}
-
const Emoji *Store::GetEmoji(Snowflake id) const {
auto it = m_emojis.find(id);
if (it != m_emojis.end())
@@ -250,20 +388,11 @@ const Store::channels_type &Store::GetChannels() const {
const Store::guilds_type &Store::GetGuilds() const {
return m_guilds;
}
-
-const Store::roles_type &Store::GetRoles() const {
- return m_roles;
-}
-
void Store::ClearAll() {
m_channels.clear();
m_emojis.clear();
m_guilds.clear();
m_members.clear();
- m_messages.clear();
- m_permissions.clear();
- m_roles.clear();
- m_users.clear();
}
void Store::BeginTransaction() {
@@ -293,9 +422,95 @@ pubflags INTEGER
)
)";
+ constexpr const char *create_permissions = R"(
+CREATE TABLE IF NOT EXISTS permissions (
+id INTEGER NOT NULL,
+channel_id INTEGER NOT NULL,
+type INTEGER NOT NULL,
+allow INTEGER NOT NULL,
+deny INTEGER NOT NULL
+)
+)";
+
+ constexpr const char *create_messages = R"(
+CREATE TABLE IF NOT EXISTS messages (
+id INTEGER PRIMARY KEY,
+channel_id INTEGER NOT NULL,
+guild_id INTEGER,
+author_id INTEGER NOT NULL,
+content TEXT NOT NULL,
+timestamp TEXT NOT NULL,
+edited_timestamp TEXT,
+tts BOOL NOT NULL,
+everyone BOOL NOT NULL,
+mentions TEXT NOT NULL, /* json */
+attachments TEXT NOT NULL, /* json */
+embeds TEXT NOT NULL, /* json */
+pinned BOOL,
+webhook_id INTEGER,
+type INTEGER,
+reference TEXT, /* json */
+flags INTEGER,
+stickers TEXT, /* json */
+/* extra */
+deleted BOOL,
+edited BOOL
+)
+)";
+
+ constexpr const char *create_roles = R"(
+CREATE TABLE IF NOT EXISTS roles (
+id INTEGER PRIMARY KEY,
+name TEXT NOT NULL,
+color INTEGER NOT NULL,
+hoisted BOOL NOT NULL,
+position INTEGER NOT NULL,
+permissions INTEGER NOT NULL,
+managed BOOL NOT NULL,
+mentionable BOOL NOT NULL
+)
+)";
+
+ constexpr const char *create_emojis = R"(
+CREATE TABLE IF NOT EXISTS emojis (
+id INTEGER PRIMARY KEY, /*though nullable, only custom emojis (with non-null ids) are stored*/
+name TEXT NOT NULL, /*same as id*/
+roles TEXT, /* json */
+creator_id INTEGER,
+colons BOOL,
+managed BOOL,
+animated BOOL,
+available BOOL
+)
+)";
+
m_db_err = sqlite3_exec(m_db, create_users, nullptr, nullptr, nullptr);
if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to create user table\n");
+ fprintf(stderr, "failed to create user table: %s\n", sqlite3_errstr(m_db_err));
+ return false;
+ }
+
+ m_db_err = sqlite3_exec(m_db, create_permissions, nullptr, nullptr, nullptr);
+ if (m_db_err != SQLITE_OK) {
+ fprintf(stderr, "failed to create permissions table: %s\n", sqlite3_errstr(m_db_err));
+ return false;
+ }
+
+ m_db_err = sqlite3_exec(m_db, create_messages, nullptr, nullptr, nullptr);
+ if (m_db_err != SQLITE_OK) {
+ fprintf(stderr, "failed to create messages table: %s\n", sqlite3_errstr(m_db_err));
+ return false;
+ }
+
+ m_db_err = sqlite3_exec(m_db, create_roles, nullptr, nullptr, nullptr);
+ if (m_db_err != SQLITE_OK) {
+ fprintf(stderr, "failed to create roles table: %s\n", sqlite3_errstr(m_db_err));
+ return false;
+ }
+
+ m_db_err = sqlite3_exec(m_db, create_emojis, nullptr, nullptr, nullptr);
+ if (m_db_err != SQLITE_OK) {
+ fprintf(stderr, "faile to create emojis table: %s\n", sqlite3_errstr(m_db_err));
return false;
}
@@ -313,15 +528,103 @@ REPLACE INTO users VALUES (
SELECT * FROM users WHERE id = ?
)";
+ constexpr const char *set_perm = R"(
+REPLACE INTO permissions VALUES (
+ ?, ?, ?, ?, ?
+)
+)";
+
+ constexpr const char *get_perm = R"(
+SELECT * FROM permissions WHERE id = ? AND channel_id = ?
+)";
+
+ constexpr const char *set_msg = R"(
+REPLACE INTO messages VALUES (
+ ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
+)
+)";
+
+ constexpr const char *get_msg = R"(
+SELECT * FROM messages WHERE id = ?
+)";
+
+ constexpr const char *set_role = R"(
+REPLACE INTO roles VALUES (
+ ?, ?, ?, ?, ?, ?, ?, ?
+)
+)";
+
+ constexpr const char *get_role = R"(
+SELECT * FROM roles WHERE id = ?
+)";
+
+ constexpr const char *set_emoji = R"(
+REPLACE INTO emojis VALUES (
+ ?, ?, ?, ?, ?, ?, ?, ?
+)
+)";
+
+ constexpr const char *get_emoji = R"(
+SELECT * FROM emojis WHERE id = ?
+)";
+
m_db_err = sqlite3_prepare_v2(m_db, set_user, -1, &m_set_user_stmt, nullptr);
if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to prepare set user statement\n");
+ fprintf(stderr, "failed to prepare set user statement: %s\n", sqlite3_errstr(m_db_err));
return false;
}
m_db_err = sqlite3_prepare_v2(m_db, get_user, -1, &m_get_user_stmt, nullptr);
if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to prepare get user statement\n");
+ fprintf(stderr, "failed to prepare get user statement: %s\n", sqlite3_errstr(m_db_err));
+ return false;
+ }
+
+ m_db_err = sqlite3_prepare_v2(m_db, set_perm, -1, &m_set_perm_stmt, nullptr);
+ if (m_db_err != SQLITE_OK) {
+ fprintf(stderr, "failed to prepare set permission statement: %s\n", sqlite3_errstr(m_db_err));
+ return false;
+ }
+
+ m_db_err = sqlite3_prepare_v2(m_db, get_perm, -1, &m_get_perm_stmt, nullptr);
+ if (m_db_err != SQLITE_OK) {
+ fprintf(stderr, "failed to prepare get permission statement: %s\n", sqlite3_errstr(m_db_err));
+ return false;
+ }
+
+ m_db_err = sqlite3_prepare_v2(m_db, set_msg, -1, &m_set_msg_stmt, nullptr);
+ if (m_db_err != SQLITE_OK) {
+ fprintf(stderr, "failed to prepare set message statement: %s\n", sqlite3_errstr(m_db_err));
+ return false;
+ }
+
+ m_db_err = sqlite3_prepare_v2(m_db, get_msg, -1, &m_get_msg_stmt, nullptr);
+ if (m_db_err != SQLITE_OK) {
+ fprintf(stderr, "failed to prepare get message statement: %s\n", sqlite3_errstr(m_db_err));
+ return false;
+ }
+
+ m_db_err = sqlite3_prepare_v2(m_db, set_role, -1, &m_set_role_stmt, nullptr);
+ if (m_db_err != SQLITE_OK) {
+ fprintf(stderr, "failed to prepare set role statement: %s\n", sqlite3_errstr(m_db_err));
+ return false;
+ }
+
+ m_db_err = sqlite3_prepare_v2(m_db, get_role, -1, &m_get_role_stmt, nullptr);
+ if (m_db_err != SQLITE_OK) {
+ fprintf(stderr, "failed to prepare get role statement: %s\n", sqlite3_errstr(m_db_err));
+ return false;
+ }
+
+ m_db_err = sqlite3_prepare_v2(m_db, set_emoji, -1, &m_set_emote_stmt, nullptr);
+ if (m_db_err != SQLITE_OK) {
+ fprintf(stderr, "failed to prepare set emoji statement: %s\n", sqlite3_errstr(m_db_err));
+ return false;
+ }
+
+ m_db_err = sqlite3_prepare_v2(m_db, get_emoji, -1, &m_get_emote_stmt, nullptr);
+ if (m_db_err != SQLITE_OK) {
+ fprintf(stderr, "failed to prepare get emoji statement: %s\n", sqlite3_errstr(m_db_err));
return false;
}
@@ -331,6 +634,14 @@ SELECT * FROM users WHERE id = ?
void Store::Cleanup() {
sqlite3_finalize(m_set_user_stmt);
sqlite3_finalize(m_get_user_stmt);
+ sqlite3_finalize(m_set_perm_stmt);
+ sqlite3_finalize(m_get_perm_stmt);
+ sqlite3_finalize(m_set_msg_stmt);
+ sqlite3_finalize(m_get_msg_stmt);
+ sqlite3_finalize(m_set_role_stmt);
+ sqlite3_finalize(m_get_role_stmt);
+ sqlite3_finalize(m_set_emote_stmt);
+ sqlite3_finalize(m_get_emote_stmt);
}
void Store::Bind(sqlite3_stmt *stmt, int index, int num) const {
@@ -348,7 +659,7 @@ void Store::Bind(sqlite3_stmt *stmt, int index, uint64_t num) const {
}
void Store::Bind(sqlite3_stmt *stmt, int index, const std::string &str) const {
- m_db_err = sqlite3_bind_text(stmt, index, str.c_str(), -1, nullptr);
+ m_db_err = sqlite3_bind_blob(stmt, index, str.c_str(), str.length(), SQLITE_TRANSIENT);
if (m_db_err != SQLITE_OK) {
fprintf(stderr, "error binding index %d: %s\n", index, sqlite3_errstr(m_db_err));
}
@@ -361,10 +672,16 @@ void Store::Bind(sqlite3_stmt *stmt, int index, bool val) const {
}
}
+void Store::Bind(sqlite3_stmt *stmt, int index, std::nullptr_t) const {
+ m_db_err = sqlite3_bind_null(stmt, index);
+ if (m_db_err != SQLITE_OK) {
+ fprintf(stderr, "error binding index %d: %s\n", index, sqlite3_errstr(m_db_err));
+ }
+}
+
bool Store::RunInsert(sqlite3_stmt *stmt) {
m_db_err = sqlite3_step(stmt);
- sqlite3_reset(stmt);
- sqlite3_clear_bindings(stmt);
+ Reset(stmt);
return m_db_err == SQLITE_DONE;
}
@@ -377,6 +694,10 @@ void Store::Get(sqlite3_stmt *stmt, int index, int &out) const {
out = sqlite3_column_int(stmt, index);
}
+void Store::Get(sqlite3_stmt *stmt, int index, uint64_t &out) const {
+ out = sqlite3_column_int64(stmt, index);
+}
+
void Store::Get(sqlite3_stmt *stmt, int index, std::string &out) const {
const unsigned char *ptr = sqlite3_column_text(stmt, index);
if (ptr == nullptr)
diff --git a/discord/store.hpp b/discord/store.hpp
index c0cd6b9..3332d70 100644
--- a/discord/store.hpp
+++ b/discord/store.hpp
@@ -12,7 +12,7 @@
class Store {
public:
- Store();
+ Store(bool mem_store = false);
~Store();
bool IsValid() const;
@@ -30,18 +30,15 @@ public:
Channel *GetChannel(Snowflake id);
Guild *GetGuild(Snowflake id);
- Role *GetRole(Snowflake id);
- Message *GetMessage(Snowflake id);
GuildMember *GetGuildMemberData(Snowflake guild_id, Snowflake user_id);
- PermissionOverwrite *GetPermissionOverwrite(Snowflake channel_id, Snowflake id);
Emoji *GetEmoji(Snowflake id);
+ std::optional<Message> GetMessage(Snowflake id) const;
+ std::optional<PermissionOverwrite> GetPermissionOverwrite(Snowflake channel_id, Snowflake id) const;
+ std::optional<Role> GetRole(Snowflake id) const;
std::optional<User> GetUser(Snowflake id) const;
const Channel *GetChannel(Snowflake id) const;
const Guild *GetGuild(Snowflake id) const;
- const Role *GetRole(Snowflake id) const;
- const Message *GetMessage(Snowflake id) const;
const GuildMember *GetGuildMemberData(Snowflake guild_id, Snowflake user_id) const;
- const PermissionOverwrite *GetPermissionOverwrite(Snowflake channel_id, Snowflake id) const;
const Emoji *GetEmoji(Snowflake id) const;
void ClearGuild(Snowflake id);
@@ -58,7 +55,6 @@ public:
const channels_type &GetChannels() const;
const guilds_type &GetGuilds() const;
- const roles_type &GetRoles() const;
void ClearAll();
@@ -66,13 +62,9 @@ public:
void EndTransaction();
private:
- users_type m_users;
channels_type m_channels;
guilds_type m_guilds;
- roles_type m_roles;
- messages_type m_messages;
members_type m_members;
- permission_overwrites_type m_permissions;
emojis_type m_emojis;
bool CreateTables();
@@ -85,6 +77,7 @@ private:
void Bind(sqlite3_stmt *stmt, int index, uint64_t num) const;
void Bind(sqlite3_stmt *stmt, int index, const std::string &str) const;
void Bind(sqlite3_stmt *stmt, int index, bool val) const;
+ void Bind(sqlite3_stmt *stmt, int index, std::nullptr_t) const;
bool RunInsert(sqlite3_stmt *stmt);
bool FetchOne(sqlite3_stmt *stmt) const;
template<typename T>
@@ -101,6 +94,14 @@ private:
mutable int m_db_err;
mutable sqlite3_stmt *m_set_user_stmt;
mutable sqlite3_stmt *m_get_user_stmt;
+ mutable sqlite3_stmt *m_set_perm_stmt;
+ mutable sqlite3_stmt *m_get_perm_stmt;
+ mutable sqlite3_stmt *m_set_msg_stmt;
+ mutable sqlite3_stmt *m_get_msg_stmt;
+ mutable sqlite3_stmt *m_set_role_stmt;
+ mutable sqlite3_stmt *m_get_role_stmt;
+ mutable sqlite3_stmt *m_set_emote_stmt;
+ mutable sqlite3_stmt *m_get_emote_stmt;
};
template<typename T>