2024-02-22 16:09:56 -05:00
|
|
|
#include <iostream>
|
|
|
|
#include <dpp/dpp.h>
|
|
|
|
#include <cstdlib>
|
2024-02-26 10:03:34 -05:00
|
|
|
#include <utility>
|
2024-02-22 16:09:56 -05:00
|
|
|
#include <blt/std/logging.h>
|
|
|
|
#include <blt/parse/argparse.h>
|
2024-02-26 10:03:34 -05:00
|
|
|
#include <sqlite_orm/sqlite_orm.h>
|
|
|
|
#include "blt/std/types.h"
|
2024-02-26 15:40:05 -05:00
|
|
|
#include "blt/std/utility.h"
|
|
|
|
#include <curl/curl.h>
|
2024-02-26 23:25:37 -05:00
|
|
|
#include <atomic>
|
|
|
|
#include <condition_variable>
|
|
|
|
#include <mutex>
|
2024-02-25 14:05:45 -05:00
|
|
|
|
2024-02-26 15:40:05 -05:00
|
|
|
namespace sql = sqlite_orm;
|
|
|
|
|
2024-02-26 23:25:37 -05:00
|
|
|
struct server_info_t
|
|
|
|
{
|
|
|
|
blt::u32 member_count;
|
|
|
|
std::string name;
|
|
|
|
std::string description;
|
|
|
|
std::string icon;
|
|
|
|
std::string splash;
|
|
|
|
std::string discovery_splash;
|
|
|
|
std::string banner;
|
|
|
|
};
|
|
|
|
|
2024-02-26 15:40:05 -05:00
|
|
|
struct user_info_t
|
2024-02-26 10:03:34 -05:00
|
|
|
{
|
|
|
|
blt::u64 userID;
|
2024-02-26 15:40:05 -05:00
|
|
|
std::string username;
|
|
|
|
std::string global_nickname;
|
|
|
|
std::string server_name;
|
2024-02-26 10:03:34 -05:00
|
|
|
};
|
|
|
|
|
2024-02-26 15:40:05 -05:00
|
|
|
auto make_user_table()
|
2024-02-26 12:17:59 -05:00
|
|
|
{
|
2024-02-26 15:40:05 -05:00
|
|
|
return sql::make_table("users",
|
|
|
|
sql::make_column("userID", &user_info_t::userID, sql::primary_key()),
|
|
|
|
sql::make_column("username", &user_info_t::username),
|
|
|
|
sql::make_column("global_nickname", &user_info_t::global_nickname),
|
|
|
|
sql::make_column("server_name", &user_info_t::server_name));
|
|
|
|
}
|
2024-02-26 12:17:59 -05:00
|
|
|
|
2024-02-26 15:40:05 -05:00
|
|
|
using user_table_t = decltype(make_user_table());
|
|
|
|
|
|
|
|
struct user_history_t
|
2024-02-26 10:03:34 -05:00
|
|
|
{
|
|
|
|
blt::u64 userID;
|
2024-02-26 15:40:05 -05:00
|
|
|
blt::u64 time_changed;
|
|
|
|
std::string old_username;
|
|
|
|
std::string old_global_nickname;
|
|
|
|
std::string old_server_name;
|
2024-02-26 10:03:34 -05:00
|
|
|
};
|
|
|
|
|
2024-02-26 15:40:05 -05:00
|
|
|
auto make_user_history_table()
|
|
|
|
{
|
|
|
|
return sql::make_table("user_history",
|
2024-02-27 12:25:18 -05:00
|
|
|
sql::make_column("userID", &user_history_t::userID),
|
|
|
|
sql::make_column("time_changed", &user_history_t::time_changed),
|
2024-02-26 15:40:05 -05:00
|
|
|
sql::make_column("old_username", &user_history_t::old_username),
|
|
|
|
sql::make_column("old_global_nickname", &user_history_t::old_global_nickname),
|
|
|
|
sql::make_column("old_server_name", &user_history_t::old_server_name),
|
2024-02-27 12:25:18 -05:00
|
|
|
sql::foreign_key(&user_history_t::userID).references(&user_info_t::userID),
|
|
|
|
sql::primary_key(&user_history_t::userID, &user_history_t::time_changed));
|
2024-02-26 15:40:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
using user_history_table_t = decltype(make_user_history_table());
|
|
|
|
|
2024-02-26 10:03:34 -05:00
|
|
|
struct channel_info_t
|
|
|
|
{
|
|
|
|
blt::u64 channelID;
|
|
|
|
std::string channel_name;
|
|
|
|
};
|
|
|
|
|
2024-02-26 15:40:05 -05:00
|
|
|
auto make_channel_table()
|
|
|
|
{
|
|
|
|
return sql::make_table("channels",
|
|
|
|
sql::make_column("channelID", &channel_info_t::channelID, sql::primary_key()),
|
|
|
|
sql::make_column("channel_name", &channel_info_t::channel_name));
|
|
|
|
}
|
|
|
|
|
|
|
|
using channel_table_t = decltype(make_channel_table());
|
|
|
|
|
|
|
|
struct channel_history_t
|
|
|
|
{
|
|
|
|
blt::u64 channelID;
|
|
|
|
blt::u64 time_changed;
|
|
|
|
std::string old_channel_name;
|
|
|
|
};
|
|
|
|
|
|
|
|
auto make_channel_history_table()
|
|
|
|
{
|
|
|
|
return sql::make_table("channel_history",
|
2024-02-27 12:25:18 -05:00
|
|
|
sql::make_column("channelID", &channel_history_t::channelID),
|
|
|
|
sql::make_column("time_changed", &channel_history_t::time_changed),
|
2024-02-26 15:40:05 -05:00
|
|
|
sql::make_column("old_channel_name", &channel_history_t::old_channel_name),
|
2024-02-27 12:25:18 -05:00
|
|
|
sql::foreign_key(&channel_history_t::channelID).references(&channel_info_t::channelID),
|
|
|
|
sql::primary_key(&channel_history_t::channelID, &channel_history_t::time_changed));
|
2024-02-26 15:40:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
using channel_history_table_t = decltype(make_channel_history_table());
|
|
|
|
|
|
|
|
struct message_t
|
2024-02-26 10:03:34 -05:00
|
|
|
{
|
|
|
|
blt::u64 messageID;
|
|
|
|
blt::u64 channelID;
|
|
|
|
blt::u64 userID;
|
2024-02-26 15:40:05 -05:00
|
|
|
std::string content;
|
|
|
|
};
|
|
|
|
|
|
|
|
auto make_message_table()
|
|
|
|
{
|
|
|
|
return sql::make_table("messages",
|
|
|
|
sql::make_column("messageID", &message_t::messageID, sql::primary_key()),
|
|
|
|
sql::make_column("channelID", &message_t::channelID),
|
|
|
|
sql::make_column("userID", &message_t::userID),
|
|
|
|
sql::make_column("content", &message_t::content),
|
|
|
|
sql::foreign_key(&message_t::channelID).references(&channel_info_t::channelID),
|
|
|
|
sql::foreign_key(&message_t::userID).references(&user_info_t::userID));
|
|
|
|
}
|
|
|
|
|
|
|
|
using message_table_t = decltype(make_message_table());
|
|
|
|
|
|
|
|
struct attachment_t
|
|
|
|
{
|
|
|
|
blt::u64 messageID;
|
|
|
|
std::string url;
|
|
|
|
};
|
|
|
|
|
|
|
|
auto make_attachment_table()
|
|
|
|
{
|
|
|
|
return sql::make_table("attachments",
|
2024-02-27 12:25:18 -05:00
|
|
|
sql::make_column("messageID", &attachment_t::messageID),
|
|
|
|
sql::make_column("url", &attachment_t::url),
|
|
|
|
sql::foreign_key(&attachment_t::messageID).references(&message_t::messageID),
|
|
|
|
sql::primary_key(&attachment_t::messageID, &attachment_t::url));
|
2024-02-26 15:40:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
using attachment_table_t = decltype(make_attachment_table());
|
|
|
|
|
|
|
|
struct message_edits_t
|
|
|
|
{
|
|
|
|
blt::u64 messageID;
|
|
|
|
std::string old_content;
|
2024-02-26 10:03:34 -05:00
|
|
|
std::string new_content;
|
|
|
|
};
|
|
|
|
|
2024-02-26 15:40:05 -05:00
|
|
|
auto make_message_edits_table()
|
|
|
|
{
|
|
|
|
return sql::make_table("message_edits",
|
2024-02-27 12:25:18 -05:00
|
|
|
sql::make_column("messageID", &message_edits_t::messageID),
|
|
|
|
sql::make_column("old_content", &message_edits_t::old_content),
|
|
|
|
sql::make_column("new_content", &message_edits_t::new_content),
|
|
|
|
sql::foreign_key(&message_edits_t::messageID).references(&message_t::messageID),
|
|
|
|
sql::primary_key(&message_edits_t::messageID, &message_edits_t::old_content, &message_edits_t::new_content));
|
2024-02-26 15:40:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
using message_edits_table_t = decltype(make_message_edits_table());
|
|
|
|
|
2024-02-26 12:17:59 -05:00
|
|
|
struct message_deletes_t
|
|
|
|
{
|
|
|
|
blt::u64 messageID;
|
|
|
|
blt::u64 channelID;
|
2024-02-26 15:40:05 -05:00
|
|
|
std::string content;
|
2024-02-26 12:17:59 -05:00
|
|
|
};
|
|
|
|
|
2024-02-26 15:40:05 -05:00
|
|
|
auto make_message_deletes_table()
|
|
|
|
{
|
|
|
|
return sql::make_table("message_deletes",
|
2024-02-27 12:25:18 -05:00
|
|
|
sql::make_column("messageID", &message_deletes_t::messageID),
|
|
|
|
sql::make_column("channelID", &message_deletes_t::channelID),
|
2024-02-26 15:40:05 -05:00
|
|
|
sql::make_column("content", &message_deletes_t::content),
|
|
|
|
sql::foreign_key(&message_deletes_t::messageID).references(&message_t::messageID),
|
2024-02-27 12:25:18 -05:00
|
|
|
sql::foreign_key(&message_deletes_t::channelID).references(&channel_info_t::channelID),
|
|
|
|
sql::primary_key(&message_deletes_t::messageID, &message_deletes_t::channelID));
|
2024-02-26 15:40:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
using message_deletes_table_t = decltype(make_message_deletes_table());
|
|
|
|
|
|
|
|
auto make_database(std::string path)
|
|
|
|
{
|
|
|
|
return sql::make_storage(std::move(path), make_user_table(), make_user_history_table(), make_channel_table(), make_channel_history_table(),
|
|
|
|
make_message_table(), make_attachment_table(), make_message_edits_table(), make_message_deletes_table());
|
|
|
|
}
|
|
|
|
|
|
|
|
using database_type = decltype(make_database(""));
|
2024-02-26 10:03:34 -05:00
|
|
|
|
|
|
|
struct db_obj
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
blt::u64 guildID;
|
2024-02-27 12:25:18 -05:00
|
|
|
std::atomic_bool loaded_channels = false;
|
2024-02-26 15:40:05 -05:00
|
|
|
database_type db;
|
|
|
|
|
|
|
|
void ensure_channel_exists()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void ensure_user_exists()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
2024-02-26 23:25:37 -05:00
|
|
|
|
|
|
|
bool loading_complete()
|
|
|
|
{
|
2024-02-27 12:25:18 -05:00
|
|
|
return loaded_channels.load();
|
2024-02-26 23:25:37 -05:00
|
|
|
}
|
2024-02-26 15:40:05 -05:00
|
|
|
|
2024-02-26 10:03:34 -05:00
|
|
|
public:
|
2024-02-26 15:40:05 -05:00
|
|
|
explicit db_obj(blt::u64 guildID, const std::string& path): guildID(guildID), db(make_database(path + "/" + std::to_string(guildID) + "/"))
|
|
|
|
{
|
|
|
|
db.sync_schema();
|
|
|
|
}
|
2024-02-26 12:17:59 -05:00
|
|
|
|
2024-02-26 23:25:37 -05:00
|
|
|
void load(dpp::cluster& bot, const dpp::guild& guild)
|
|
|
|
{
|
2024-02-27 12:25:18 -05:00
|
|
|
bot.channels_get(guild.id, [&bot, this, &guild](const dpp::confirmation_callback_t& event) {
|
|
|
|
if (event.is_error())
|
|
|
|
{
|
|
|
|
BLT_WARN("Failed to fetch channels for guild %ld", guildID);
|
|
|
|
BLT_WARN("Cause: %s", event.get_error().human_readable.c_str());
|
|
|
|
loaded_channels = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
auto channel_map = event.get<dpp::channel_map>();
|
|
|
|
BLT_INFO("Guild '%s' channel count: %ld", guild.name.c_str(), channel_map.size());
|
|
|
|
|
|
|
|
for (const auto& channel : channel_map)
|
|
|
|
{
|
|
|
|
BLT_DEBUG("\tfetched channel id %ld with name '%s'", channel.first, channel.second.name.c_str());
|
|
|
|
}
|
|
|
|
loaded_channels = true;
|
|
|
|
});
|
2024-02-26 23:25:37 -05:00
|
|
|
|
2024-02-27 12:25:18 -05:00
|
|
|
while (!loaded_channels.load())
|
|
|
|
{}
|
2024-02-26 23:25:37 -05:00
|
|
|
|
2024-02-27 12:25:18 -05:00
|
|
|
for (const auto& member : guild.members)
|
2024-02-26 23:25:37 -05:00
|
|
|
{
|
2024-02-27 12:25:18 -05:00
|
|
|
BLT_TRACE("\tfetching user %ld -> %ld", member.first, member.second.user_id);
|
|
|
|
bot.user_get(member.first, [member, this](const dpp::confirmation_callback_t& event) {
|
|
|
|
if (event.is_error())
|
|
|
|
{
|
|
|
|
BLT_WARN("Failed to fetch user $ld for guild '%s'", member.first, guildID);
|
|
|
|
BLT_WARN("Cause: %s", event.get_error().human_readable.c_str());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
auto user = event.get<dpp::user_identified>();
|
|
|
|
|
|
|
|
BLT_DEBUG("We got user '%s' with username '%s' and global name '%s'", user.username.c_str(), user.global_name.c_str());
|
|
|
|
});
|
|
|
|
bot.guild_get_member(guildID, member.first, [&guild, member](const dpp::confirmation_callback_t& event) {
|
|
|
|
if (event.is_error())
|
|
|
|
{
|
|
|
|
BLT_WARN("Failed to fetch member %ld for guild %ld", member.first, guild.id);
|
|
|
|
BLT_WARN("Cause: %s", event.get_error().human_readable.c_str());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
auto user = event.get<dpp::guild_member>();
|
2024-02-26 23:25:37 -05:00
|
|
|
|
2024-02-27 12:25:18 -05:00
|
|
|
BLT_DEBUG("Member of guild '%s' with nickname '%s'", guild.name.c_str(), user.get_nickname().c_str());
|
2024-02-26 23:25:37 -05:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
while (!loading_complete())
|
|
|
|
{}
|
2024-02-27 12:25:18 -05:00
|
|
|
BLT_DEBUG("Finished loading guild '%s'", guild.name.c_str());
|
2024-02-26 23:25:37 -05:00
|
|
|
}
|
|
|
|
|
2024-02-26 15:40:05 -05:00
|
|
|
void commit(const user_info_t& edited)
|
2024-02-26 12:17:59 -05:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2024-02-26 15:40:05 -05:00
|
|
|
void commit(const user_history_t& edited)
|
2024-02-26 12:17:59 -05:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
2024-02-26 15:40:05 -05:00
|
|
|
|
|
|
|
void commit(const channel_info_t& channel)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void commit(const channel_history_t& channel)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void commit(const message_t& message)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void commit(const attachment_t& attachment)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void commit(const message_edits_t& edited)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void commit(const message_deletes_t& deleted)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2024-02-26 10:03:34 -05:00
|
|
|
};
|
|
|
|
|
2024-02-26 23:25:37 -05:00
|
|
|
blt::hashmap_t<blt::u64, std::unique_ptr<db_obj>> databases;
|
2024-02-26 15:40:05 -05:00
|
|
|
std::string path;
|
2024-02-26 23:25:37 -05:00
|
|
|
blt::u64 total_guilds = 0;
|
|
|
|
std::atomic_uint64_t completed_guilds = 0;
|
|
|
|
|
|
|
|
bool loading_complete()
|
|
|
|
{
|
|
|
|
return total_guilds != 0 && total_guilds == completed_guilds.load();
|
|
|
|
}
|
2024-02-22 16:09:56 -05:00
|
|
|
|
2024-02-26 12:17:59 -05:00
|
|
|
db_obj& get(blt::u64 id)
|
|
|
|
{
|
|
|
|
if (databases.find(id) == databases.end())
|
2024-02-26 23:25:37 -05:00
|
|
|
databases.insert({id, std::make_unique<db_obj>(id, path)});
|
|
|
|
return *databases.at(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename event_type>
|
|
|
|
std::function<void(const event_type& event)> wait_wrapper(std::function<void(const event_type& event)>&& func)
|
|
|
|
{
|
|
|
|
return [func](const event_type& event) {
|
|
|
|
if (!loading_complete())
|
|
|
|
return;
|
|
|
|
func(event);
|
|
|
|
};
|
2024-02-26 12:17:59 -05:00
|
|
|
}
|
|
|
|
|
2024-02-22 16:09:56 -05:00
|
|
|
int main(int argc, const char** argv)
|
|
|
|
{
|
|
|
|
blt::arg_parse parser;
|
2024-02-25 14:05:45 -05:00
|
|
|
parser.addArgument(blt::arg_builder("-t", "--token").setAction(blt::arg_action_t::STORE).setHelp("The discord bot token").build());
|
|
|
|
parser.addArgument(blt::arg_builder("-p", "--path").setAction(blt::arg_action_t::STORE).setHelp("Path to store the archive data").build());
|
2024-02-22 16:09:56 -05:00
|
|
|
|
|
|
|
auto args = parser.parse_args(argc, argv);
|
2024-02-26 15:40:05 -05:00
|
|
|
path = args.get<std::string>("path");
|
2024-02-27 12:25:18 -05:00
|
|
|
std::filesystem::create_directories(path);
|
2024-02-22 16:09:56 -05:00
|
|
|
|
2024-02-27 12:25:18 -05:00
|
|
|
dpp::cluster bot(args.get<std::string>("token"), dpp::i_default_intents | dpp::i_message_content | dpp::i_all_intents | dpp::i_guild_members);
|
2024-02-25 14:05:45 -05:00
|
|
|
|
2024-02-26 23:25:37 -05:00
|
|
|
bot.on_ready([&bot](const dpp::ready_t& event) {
|
|
|
|
if (dpp::run_once<struct fetch_active_guilds>())
|
|
|
|
{
|
|
|
|
total_guilds = event.guild_count;
|
|
|
|
for (blt::u64 server : event.guilds)
|
|
|
|
{
|
|
|
|
bot.guild_get(server, [&bot, server](const dpp::confirmation_callback_t& event) {
|
2024-02-27 12:25:18 -05:00
|
|
|
if (event.is_error())
|
|
|
|
{
|
|
|
|
BLT_WARN("Failed to fetch for guild %ld", server);
|
|
|
|
BLT_WARN("Cause: %s", event.get_error().human_readable.c_str());
|
|
|
|
return;
|
|
|
|
}
|
2024-02-26 23:25:37 -05:00
|
|
|
BLT_INFO("Fetched data for %ld ('%s')", server, event.get<dpp::guild>().name.c_str());
|
|
|
|
auto& db = get(server);
|
|
|
|
|
|
|
|
db.load(bot, event.get<dpp::guild>());
|
|
|
|
|
|
|
|
completed_guilds++;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2024-02-26 12:43:31 -05:00
|
|
|
});
|
|
|
|
|
2024-02-26 23:25:37 -05:00
|
|
|
bot.on_user_update(wait_wrapper<dpp::user_update_t>([&bot](const dpp::user_update_t& event) {
|
|
|
|
BLT_INFO("User '%s' updated in some way; global name: '%s'", event.updated.username.c_str(), event.updated.global_name.c_str());
|
|
|
|
}));
|
2024-02-26 12:43:31 -05:00
|
|
|
|
2024-02-26 23:25:37 -05:00
|
|
|
bot.on_guild_member_update(wait_wrapper<dpp::guild_member_update_t>([&bot](const dpp::guild_member_update_t& event) {
|
2024-02-26 12:43:31 -05:00
|
|
|
|
2024-02-26 23:25:37 -05:00
|
|
|
}));
|
|
|
|
|
|
|
|
bot.on_message_delete(wait_wrapper<dpp::message_delete_t>([&bot](const dpp::message_delete_t& event) {
|
2024-02-26 12:17:59 -05:00
|
|
|
BLT_DEBUG("Message %ld deleted content in %ld", event.id, event.channel_id);
|
2024-02-26 23:25:37 -05:00
|
|
|
}));
|
2024-02-22 16:09:56 -05:00
|
|
|
|
2024-02-26 23:25:37 -05:00
|
|
|
bot.on_message_delete_bulk(wait_wrapper<dpp::message_delete_bulk_t>([&bot](const dpp::message_delete_bulk_t& event) {
|
2024-02-25 14:05:45 -05:00
|
|
|
|
2024-02-26 23:25:37 -05:00
|
|
|
}));
|
2024-02-25 14:05:45 -05:00
|
|
|
|
2024-02-26 23:25:37 -05:00
|
|
|
bot.on_message_update(wait_wrapper<dpp::message_update_t>([&bot](const dpp::message_update_t& event) {
|
2024-02-26 15:40:05 -05:00
|
|
|
auto& storage = get(event.msg.guild_id);
|
|
|
|
|
2024-02-26 10:03:34 -05:00
|
|
|
BLT_INFO("%ld (from user %ld in channel %ld ['%s']) -> '%s'", event.msg.id, event.msg.author.id, event.msg.channel_id,
|
|
|
|
event.msg.author.username.c_str(), event.msg.content.c_str());
|
2024-02-26 23:25:37 -05:00
|
|
|
}));
|
2024-02-22 16:09:56 -05:00
|
|
|
|
2024-02-26 23:25:37 -05:00
|
|
|
bot.on_message_create(wait_wrapper<dpp::message_create_t>([&bot](const dpp::message_create_t& event) {
|
2024-02-23 14:37:23 -05:00
|
|
|
if (event.msg.id == bot.me.id)
|
|
|
|
return;
|
2024-02-26 15:40:05 -05:00
|
|
|
if (blt::string::starts_with(event.msg.content, "!dump"))
|
2024-02-23 14:37:23 -05:00
|
|
|
{
|
2024-02-26 15:40:05 -05:00
|
|
|
|
2024-02-23 14:37:23 -05:00
|
|
|
}
|
2024-02-26 15:40:05 -05:00
|
|
|
// auto& storage = get(event.msg.guild_id);
|
|
|
|
// storage.messages.push_back({
|
|
|
|
// event.msg.id,
|
|
|
|
// event.msg.channel_id,
|
|
|
|
// event.msg.author.id,
|
|
|
|
// event.msg.content
|
|
|
|
// });
|
|
|
|
//
|
|
|
|
// for (const dpp::attachment& attach : event.msg.attachments)
|
|
|
|
// {
|
|
|
|
// storage.attachments.push_back({event.msg.id, attach.url});
|
|
|
|
// }
|
2024-02-26 23:25:37 -05:00
|
|
|
}));
|
2024-02-22 16:22:48 -05:00
|
|
|
|
2024-02-22 16:09:56 -05:00
|
|
|
bot.start(dpp::st_wait);
|
2024-02-26 23:25:37 -05:00
|
|
|
|
2024-02-22 16:09:56 -05:00
|
|
|
return 0;
|
|
|
|
}
|