progress 2

This commit is contained in:
ouwou
2020-11-23 20:34:09 -05:00
parent deb482a8db
commit 0b8c83eaa1
19 changed files with 700 additions and 271 deletions

View File

@@ -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() {
@@ -291,11 +420,97 @@ flags INTEGER,
premium INTEGER,
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;
}
@@ -311,17 +526,105 @@ REPLACE INTO users VALUES (
constexpr const char *get_user = R"(
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)