Now tracks and caches all (I think) required data

This commit is contained in:
Jack Bond-Preston 2016-08-05 02:27:46 +01:00
parent 1b2ea3c6bf
commit 47de861f45
8 changed files with 718 additions and 116 deletions

View File

@ -3,8 +3,8 @@
#include <boost/algorithm/string.hpp>
#include "APIHelper.hpp"
#include "data_structures/User.hpp"
#include "Logger.hpp"
#include "data_structures/GuildMember.hpp"
extern std::string bot_token;
@ -64,34 +64,314 @@ void GatewayHandler::on_dispatch(json decoded, client &c, websocketpp::connectio
json data = decoded["d"];
if (event_name == "READY") {
on_event_ready(data);
}
else if (event_name == "GUILD_CREATE") {
on_event_guild_create(data);
}
else if (event_name == "GUILD_UPDATE") {
on_event_guild_update(data);
}
else if (event_name == "GUILD_DELETE") {
on_event_guild_delete(data);
}
else if (event_name == "GUILD_MEMBER_ADD") {
on_event_guild_member_add(data);
}
else if (event_name == "GUILD_MEMBER_UPDATE") {
on_event_guild_member_update(data);
}
else if (event_name == "GUILD_MEMBER_REMOVE") {
on_event_guild_member_remove(data);
}
else if (event_name == "GUILD_ROLE_CREATE") {
on_event_guild_role_create(data);
}
else if (event_name == "GUILD_ROLE_UPDATE") {
on_event_guild_role_update(data);
}
else if (event_name == "GUILD_ROLE_DELETE") {
on_event_guild_role_delete(data);
}
else if (event_name == "CHANNEL_CREATE") {
on_event_channel_create(data);
}
else if (event_name == "CHANNEL_UPDATE") {
on_event_channel_update(data);
}
else if (event_name == "CHANNEL_DELETE") {
on_event_channel_delete(data);
}
else if (event_name == "MESSAGE_CREATE") {
on_event_message_create(data);
}
}
void GatewayHandler::on_event_ready(json data) {
user_object.load_from_json(data["user"]);
Logger::write("Sign-on confirmed. (@" + user_object.username + "#" + user_object.discriminator + ")", Logger::LogLevel::Info);
}
else if (event_name == "GUILD_CREATE") {
std::string guild_id = data["id"];
guilds[guild_id] = std::make_unique<DiscordObjects::Guild>(data);
Logger::write("Loaded guild: " + guilds[guild_id]->name, Logger::LogLevel::Debug);
void GatewayHandler::on_event_guild_create(json data) {
guilds[data["id"]] = DiscordObjects::Guild(data);
DiscordObjects::Guild &guild = guilds[data["id"]];
Logger::write("Loaded guild " + guild.id + ", now in " + std::to_string(guilds.size()) + " guild(s)", Logger::LogLevel::Info);
int channels_added = 0, roles_added = 0, members_added = 0;
for (json channel : data["channels"]) {
std::string channel_id = channel["id"];
channel["guild_id"] = guild_id;
// create channel obj, add to overall channel list
channels[channel_id] = std::make_shared<DiscordObjects::Channel>(channel);
// add ptr to said channel list to guild's channel list
guilds[guild_id]->channels.push_back(std::shared_ptr<DiscordObjects::Channel>(channels[channel_id]));
channel["guild_id"] = guild.id;
channels[channel_id] = DiscordObjects::Channel(channel);
guilds[guild.id].channels.push_back(&channels[channel_id]);
channels_added++;
}
for (json role : data["roles"]) {
std::string role_id = role["id"];
roles[role_id] = DiscordObjects::Role(role);
guilds[guild.id].roles.push_back(&roles[role_id]);
roles_added++;
}
for (json member : data["members"]) {
std::string user_id = member["user"]["id"];
auto it = users.find(user_id);
if (it == users.end()) { // new user
users[user_id] = DiscordObjects::User(member["user"]);
}
users[user_id].guilds.push_back(guild.id);
DiscordObjects::GuildMember guild_member(member, &users[user_id]);
for (std::string role_id : member["roles"]) {
guild_member.roles.push_back(&roles[role_id]);
}
if (v8_instances.count(guild_id) == 0) {
v8_instances[guild_id] = std::make_unique<V8Instance>(ah);
Logger::write("Created v8 instance for guild " + guild_id, Logger::LogLevel::Debug);
guilds[guild.id].members.push_back(guild_member);
}
Logger::write("Loaded " + std::to_string(guilds.size()) + " guild(s)", Logger::LogLevel::Info);
if (v8_instances.count(guild.id) == 0) {
v8_instances[guild.id] = std::make_unique<V8Instance>(ah);
Logger::write("Created v8 instance for guild " + guild.id, Logger::LogLevel::Debug);
}
else if (event_name == "TYPING_START") {}
else if (event_name == "MESSAGE_CREATE") {
Logger::write("Loaded " + std::to_string(channels_added) + " channels, " + std::to_string(roles_added)
+ " roles and " + std::to_string(members_added) + " members to guild " + guild.id, Logger::LogLevel::Debug);
}
void GatewayHandler::on_event_guild_update(json data) {
std::string guild_id = data["id"];
guilds[guild_id].load_from_json(data);
Logger::write("Updated guild " + guild_id, Logger::LogLevel::Debug);
}
void GatewayHandler::on_event_guild_delete(json data) {
std::string guild_id = data["id"];
bool unavailable = data.value("unavailable", false);
if (unavailable) {
Logger::write("Guild " + guild_id + " has become unavailable", Logger::LogLevel::Info);
guilds[guild_id].unavailable = true;
} else {
int channels_removed = 0;
for (auto it = channels.cbegin(); it != channels.cend();) {
if (it->second.guild_id == guild_id) {
channels.erase(it++);
channels_removed++;
} else {
++it;
}
}
guilds.erase(guilds.find(guild_id));
Logger::write("Guild " + guild_id + " and " + std::to_string(channels_removed) + " channels removed", Logger::LogLevel::Info);
}
}
void GatewayHandler::on_event_guild_member_add(json data) {
std::string guild_id = data["guild_id"];
std::string user_id = data["user"]["id"];
auto it = users.find(user_id);
if (it == users.end()) { // new user
users[user_id] = DiscordObjects::User(data["user"]);
}
users[user_id].guilds.push_back(guild_id);
DiscordObjects::GuildMember guild_member(data, &users[user_id]);
for (std::string role_id : data["roles"]) {
guild_member.roles.push_back(&roles[role_id]);
}
guilds[guild_id].members.push_back(guild_member);
Logger::write("Added new member " + guild_member.user->id + " to guild " + guild_id, Logger::LogLevel::Debug);
}
void GatewayHandler::on_event_guild_member_update(json data) {
std::cout << data.dump(4) << std::endl;
std::string user_id = data["user"]["id"];
DiscordObjects::Guild &guild = guilds[data["guild_id"]];
auto it = std::find_if(guild.members.begin(), guild.members.begin(), [user_id](const DiscordObjects::GuildMember &gm) {
return gm.user->id == user_id;
});
if (it != guild.members.end()) {
bool nick_changed = false;
size_t roles_change = 0;
std::string nick = data.value("nick", it->nick);
if (it->nick != nick) {
it->nick = nick;
nick_changed = true;
}
roles_change = it->roles.size();
it->roles.clear(); // reset and re-fill, changing the differences is probably more expensive anyway.
for (std::string role_id : data["roles"]) {
it->roles.push_back(&roles[role_id]);
}
roles_change = it->roles.size() - roles_change;
std::string debug_string = "Updated member " + user_id + " of guild " + guild.id;
if (nick_changed) debug_string += ". Nick changed to " + nick;
if (roles_change != 0) debug_string += ". No. of roles changed by " + std::to_string(roles_change);
debug_string += ".";
Logger::write(debug_string, Logger::LogLevel::Debug);
}
else {
Logger::write("Tried to update member " + user_id + " (of guild " + guild.id + ") who does not exist.", Logger::LogLevel::Warning);
}
}
void GatewayHandler::on_event_guild_member_remove(json data) {
DiscordObjects::Guild &guild = guilds[data["guild_id"]];
std::string user_id = data["user"]["id"];
auto it = std::find_if(guild.members.begin(), guild.members.begin(), [user_id](const DiscordObjects::GuildMember &gm) {
return gm.user->id == user_id;
});
if (it != guilds[guild.id].members.end()) {
guild.members.erase(it);
DiscordObjects::User &user = users[user_id];
user.guilds.erase(std::remove(user.guilds.begin(), user.guilds.end(), user.id));
if (user.guilds.size() == 0) {
users.erase(users.find(user_id));
Logger::write("User " + user_id + " removed from guild " + guild.id + " and no longer visible, deleted.", Logger::LogLevel::Debug);
}
else {
Logger::write("User " + user_id + " removed from guild " + guild.id, Logger::LogLevel::Debug);
}
}
else {
Logger::write("Tried to remove guild member " + user_id + " which doesn't exist", Logger::LogLevel::Warning);
}
}
void GatewayHandler::on_event_guild_role_create(json data) {
std::string role_id = data["role"]["id"];
std::string guild_id = data["guild_id"];
roles[role_id] = DiscordObjects::Role(data["role"]);
guilds[guild_id].roles.push_back(&roles[role_id]);
Logger::write("Created role " + role_id + " on guild " + guild_id, Logger::LogLevel::Debug);
}
void GatewayHandler::on_event_guild_role_update(json data) {
std::string role_id = data["role"]["id"];
roles[role_id].load_from_json(data["role"]);
}
void GatewayHandler::on_event_guild_role_delete(json data) {
std::string role_id = data["role_id"];
auto it = roles.find(role_id);
if (it != roles.end()) {
DiscordObjects::Role &role = roles[role_id];
DiscordObjects::Guild &guild = guilds[data["guild_id"]];
auto check_lambda = [role_id](const DiscordObjects::Role *r) {
return r->id == role_id;
};
auto it2 = std::find_if(guild.roles.begin(), guild.roles.end(), check_lambda);
if (it2 != guild.roles.end()) {
guild.roles.erase(it2);
}
else {
Logger::write("Tried to delete role " + role_id + " from guild " + guild.id + " but it doesn't exist there", Logger::LogLevel::Warning);
}
roles.erase(it);
Logger::write("Deleted role " + role_id + " (guild " + guild.id + ").", Logger::LogLevel::Debug);
}
else {
Logger::write("Tried to delete role " + role_id + " but it doesn't exist.", Logger::LogLevel::Warning);
}
}
void GatewayHandler::on_event_channel_create(json data) {
std::string channel_id = data["id"];
std::string guild_id = data["guild_id"];
channels[channel_id] = DiscordObjects::Channel(data);
Logger::write("Added channel " + channel_id + " to channel list. Now " + std::to_string(channels.size()) + " channels stored", Logger::LogLevel::Debug);
guilds[guild_id].channels.push_back(&channels[channel_id]);
Logger::write("Added channel " + channel_id + " to guild " + guild_id + "'s list. Now " + std::to_string(guilds[guild_id].channels.size()) + " channels stored", Logger::LogLevel::Debug);
}
void GatewayHandler::on_event_channel_update(json data) {
std::cout << "Update: " << data.dump(4) << std::endl;
std::string channel_id = data["id"];
auto it = channels.find(channel_id);
if (it == channels.end()) {
Logger::write("Got channel update for channel " + channel_id + " that doesn't exist. Creating channel instead.", Logger::LogLevel::Warning);
on_event_channel_create(data);
} else {
channels[channel_id].load_from_json(data);
Logger::write("Updated channel " + channel_id, Logger::LogLevel::Debug);
}
}
void GatewayHandler::on_event_channel_delete(json data) {
std::cout << "Delete: " << data.dump(4) << std::endl;
std::string channel_id = data["id"];
std::string guild_id = data["guild_id"];
auto it = channels.find(channel_id);
if (it == channels.end()) {
Logger::write("Tried to delete channel " + channel_id + " which doesn't exist", Logger::LogLevel::Warning);
}
else {
auto it2 = std::find_if(guilds[guild_id].channels.begin(), guilds[guild_id].channels.begin(), [channel_id](const DiscordObjects::Channel *c) {
return c->id == channel_id;
});
guilds[guild_id].channels.erase(it2);
Logger::write("Removed channel " + channel_id + " from guild " + guild_id + "'s list. Now "
+ std::to_string(guilds[guild_id].channels.size()) + " channels stored", Logger::LogLevel::Debug);
channels.erase(it);
Logger::write("Removed channel " + channel_id + " from channel list. Now " + std::to_string(channels.size()) + " channels stored.", Logger::LogLevel::Debug);
}
}
void GatewayHandler::on_event_message_create(json data) {
std::string message = data["content"];
auto channel = channels[data["channel_id"]];
@ -105,7 +385,7 @@ void GatewayHandler::on_dispatch(json decoded, client &c, websocketpp::connectio
int delay = 8;
if (words.size() > 3) {
ah->send_message(channel->id, ":exclamation: Invalid arguments!");
ah->send_message(channel.id, ":exclamation: Invalid arguments!");
return;
}
else if (words.size() > 1) {
@ -115,12 +395,12 @@ void GatewayHandler::on_dispatch(json decoded, client &c, websocketpp::connectio
help += "\\`trivia **stop**: stops the ongoing game.\n";
help += "\\`trivia **help**: prints this message\n";
ah->send_message(channel->id, help);
ah->send_message(channel.id, help);
return;
}
else if (words[1] == "stop" || words[1] == "s") {
if (games.find(channel->id) != games.end()) {
delete_game(channel->id);
if (games.find(channel.id) != games.end()) {
delete_game(channel.id);
return;
}
}
@ -132,30 +412,30 @@ void GatewayHandler::on_dispatch(json decoded, client &c, websocketpp::connectio
}
}
catch (std::invalid_argument e) {
ah->send_message(channel->id, ":exclamation: Invalid arguments!");
ah->send_message(channel.id, ":exclamation: Invalid arguments!");
return;
}
}
}
games[channel->id] = std::make_unique<TriviaGame>(this, ah, channel->id, questions, delay);
games[channel->id]->start();
games[channel.id] = std::make_unique<TriviaGame>(this, ah, channel.id, questions, delay);
games[channel.id]->start();
}
else if (words[0] == "`guilds") {
std::string m = "Guild List:\n";
for (auto &gu : guilds) {
m += "> " + gu.second->name + " (" + gu.second->id + ") Channels: " + std::to_string(gu.second->channels.size()) + "\n";
m += "> " + gu.second.name + " (" + gu.second.id + ") Channels: " + std::to_string(gu.second.channels.size()) + "\n";
}
ah->send_message(channel->id, m);
ah->send_message(channel.id, m);
}
else if (words[0] == "`info") {
ah->send_message(channel->id, ":information_source: trivia-bot by Jack. <http://github.com/jackb-p/TriviaDiscord>");
ah->send_message(channel.id, ":information_source: trivia-bot by Jack. <http://github.com/jackb-p/TriviaDiscord>");
}
else if (words[0] == "`js" && message.length() > 4) {
std::string js = message.substr(4);
auto it = v8_instances.find(channel->guild_id);
auto it = v8_instances.find(channel.guild_id);
if (it != v8_instances.end() && js.length() > 0) {
it->second->exec_js(js, channel->id);
it->second->exec_js(js, channel.id);
}
}
else if (words[0] == "`createjs" && message.length() > 8) {
@ -164,30 +444,101 @@ void GatewayHandler::on_dispatch(json decoded, client &c, websocketpp::connectio
if (seperator_loc != std::string::npos) {
std::string command_name = args.substr(0, seperator_loc);
std::string script = args.substr(seperator_loc + 1);
int result = command_helper->insert_command(channel->guild_id, command_name, script);
int result = command_helper->insert_command(channel.guild_id, command_name, script);
switch (result) {
case 0:
ah->send_message(channel->id, ":warning: Error!"); break;
ah->send_message(channel.id, ":warning: Error!"); break;
case 1:
ah->send_message(channel->id, ":new: Command `" + command_name + "` successfully created."); break;
ah->send_message(channel.id, ":new: Command `" + command_name + "` successfully created."); break;
case 2:
ah->send_message(channel->id, ":arrow_heading_up: Command `" + command_name + "` successfully updated."); break;
ah->send_message(channel.id, ":arrow_heading_up: Command `" + command_name + "` successfully updated."); break;
}
}
}
else if (words[0] == "`shutdown" && sender.id == "82232146579689472") { // it me
ah->send_message(channel->id, ":zzz: Goodbye!");
c.close(hdl, websocketpp::close::status::going_away, "`shutdown command used.");
ah->send_message(channel.id, ":zzz: Goodbye!");
// TODO: without needing c, hdl - c.close(hdl, websocketpp::close::status::going_away, "`shutdown command used.");
}
else if (command_helper->get_command(channel->guild_id, words[0], custom_command)) {
auto it = v8_instances.find(channel->guild_id);
else if (words[0] == "`debug") {
if (words[1] == "channel" && words.size() == 3) {
auto it = channels.find(words[2]);
if (it != channels.end()) {
ah->send_message(channel.id, it->second.to_debug_string());
}
else {
ah->send_message(channel.id, ":question: Unrecognised channel.");
}
}
else if (words[1] == "guild" && words.size() == 3) {
auto it = guilds.find(words[2]);
if (it != guilds.end()) {
ah->send_message(channel.id, it->second.to_debug_string());
}
else {
ah->send_message(channel.id, ":question: Unrecognised guild.");
}
}
else if (words[1] == "member" && words.size() == 4) {
auto it = guilds.find(words[2]);
if (it != guilds.end()) {
std::string user_id = words[3];
auto it2 = std::find_if(it->second.members.begin(), it->second.members.end(), [user_id](const DiscordObjects::GuildMember &gm) {
return user_id == gm.user->id;
});
if (it2 != it->second.members.end()) {
ah->send_message(channel.id, it2->to_debug_string());
}
else {
ah->send_message(channel.id, ":question: Unrecognised user.");
}
}
else {
ah->send_message(channel.id, ":question: Unrecognised guild.");
}
}
else if (words[1] == "role" && words.size() == 3) {
auto it = roles.find(words[2]);
if (it != roles.end()) {
ah->send_message(channel.id, it->second.to_debug_string());
}
else {
ah->send_message(channel.id, ":question: Unrecognised role.");
}
}
else if (words[1] == "role" && words.size() == 4) {
std::string role_name = words[3];
auto it = guilds.find(words[2]);
if (it != guilds.end()) {
auto check_lambda = [role_name](DiscordObjects::Role *r) {
return role_name == r->name;
};
auto it2 = std::find_if(it->second.roles.begin(), it->second.roles.end(), check_lambda);
if (it2 != it->second.roles.end()) {
ah->send_message(channel.id, (*it2)->to_debug_string());
}
else {
ah->send_message(channel.id, ":question: Unrecognised role.");
}
}
else {
ah->send_message(channel.id, ":question: Unrecognised guild.");
}
}
else {
ah->send_message(channel.id, ":question: Unknown parameters.");
}
}
else if (command_helper->get_command(channel.guild_id, words[0], custom_command)) {
auto it = v8_instances.find(channel.guild_id);
if (it != v8_instances.end() && custom_command.script.length() > 0) {
it->second->exec_js(custom_command.script, channel->id);
it->second->exec_js(custom_command.script, channel.id);
}
}
else if (games.find(channel->id) != games.end()) { // message received in channel with ongoing game
games[channel->id]->handle_answer(message, sender);
}
else if (games.find(channel.id) != games.end()) { // message received in channel with ongoing game
games[channel.id]->handle_answer(message, sender);
}
}

View File

@ -14,6 +14,7 @@
#include "data_structures/User.hpp"
#include "data_structures/Guild.hpp"
#include "data_structures/Channel.hpp"
#include "data_structures/Role.hpp"
typedef websocketpp::client<websocketpp::config::asio_tls_client> client;
using json = nlohmann::json;
@ -58,6 +59,27 @@ private:
int last_seq;
int heartbeat_interval;
void on_event_ready(json data);
/* guild events */
void on_event_guild_create(json data); // https://discordapp.com/developers/docs/topics/gateway#guild-create
void on_event_guild_update(json data); // https://discordapp.com/developers/docs/topics/gateway#guild-update
void on_event_guild_delete(json data); // https://discordapp.com/developers/docs/topics/gateway#guild-delete
void on_event_guild_member_add(json data); // https://discordapp.com/developers/docs/topics/gateway#guild-member-add
void on_event_guild_member_update(json data); // https://discordapp.com/developers/docs/topics/gateway#guild-member-update
void on_event_guild_member_remove(json data); // https://discordapp.com/developers/docs/topics/gateway#guild-member-remove
void on_event_guild_role_create(json data); // https://discordapp.com/developers/docs/topics/gateway#guild-role-create
void on_event_guild_role_update(json data); // https://discordapp.com/developers/docs/topics/gateway#guild-role-update
void on_event_guild_role_delete(json data); // https://discordapp.com/developers/docs/topics/gateway#guild-role-delete
/* channel events */
void on_event_channel_create(json data); // https://discordapp.com/developers/docs/topics/gateway#channel-create
void on_event_channel_update(json data); // https://discordapp.com/developers/docs/topics/gateway#channel-update
void on_event_channel_delete(json data); // https://discordapp.com/developers/docs/topics/gateway#channel-delete
/* message events */
void on_event_message_create(json data); // https://discordapp.com/developers/docs/topics/gateway#message-create
const int protocol_version = 5;
// bot's user obj
@ -65,10 +87,11 @@ private:
std::unique_ptr<CommandHelper> command_helper;
// <id, ptr to data>
std::map<std::string, std::unique_ptr<DiscordObjects::Guild>> guilds;
// channels pointers are shared pointers, held here but also in guild objects
std::map<std::string, std::shared_ptr<DiscordObjects::Channel>> channels;
/* <id, obj> */
std::map<std::string, DiscordObjects::Guild> guilds;
std::map<std::string, DiscordObjects::Channel> channels;
std::map<std::string, DiscordObjects::User> users;
std::map<std::string, DiscordObjects::Role> roles;
// <channel_id, game obj>
std::map<std::string, std::unique_ptr<TriviaGame>> games;

View File

@ -34,13 +34,13 @@ int main(int argc, char *argv[]) {
conn.start(uri);
}
catch (const std::exception &e) {
Logger::write(e.what(), Logger::LogLevel::Severe);
Logger::write("std exception: " + std::string(e.what()), Logger::LogLevel::Severe);
}
catch (websocketpp::lib::error_code e) {
Logger::write(e.message(), Logger::LogLevel::Severe);
Logger::write("websocketpp exception: " + e.message(), Logger::LogLevel::Severe);
}
catch (...) {
Logger::write("Other exception.", Logger::LogLevel::Severe);
Logger::write("other exception.", Logger::LogLevel::Severe);
}
v8::V8::Dispose();
@ -51,5 +51,8 @@ int main(int argc, char *argv[]) {
Logger::write("Cleaned up", Logger::LogLevel::Info);
std::cout << "Press enter to exit" << std::endl;
std::getchar();
return 0;
}

View File

@ -32,6 +32,7 @@ namespace DiscordObjects {
Channel(json data);
void load_from_json(json data);
std::string to_debug_string();
bool operator==(Channel rhs);
@ -73,6 +74,19 @@ namespace DiscordObjects {
user_limit = data.value("user_limit", -1);
}
inline std::string Channel::to_debug_string() {
return "**__Channel " + id + "__**"
+ "\n**guild_id:** " + guild_id
+ "\n**name:** " + name
+ "\n**type:** " + type
+ "\n**position:** " + std::to_string(position)
+ "\n**is_private:** " + std::to_string(is_private)
+ "\n**topic:** " + (topic == "" ? "[empty]" : topic)
+ "\n**last_message_id:** " + last_message_id
+ "\n**bitrate:** " + std::to_string(bitrate)
+ "\n**user_limit:** " + std::to_string(user_limit);
}
inline bool Channel::operator==(Channel rhs) {
return id == rhs.id && id != "null";
}

View File

@ -1,13 +1,15 @@
#ifndef BOT_DATA__STRUCTURES_Guild
#define BOT_DATA__STRUCTURES_Guild
#ifndef BOT_DATA__STRUCTURES_GUILD
#define BOT_DATA__STRUCTURES_GUILD
#include <string>
#include <memory>
#include <vector>
#include "../json/json.hpp"
#include "Channel.hpp"
#include "User.hpp"
#include "Role.hpp"
#include "GuildMember.hpp"
using json = nlohmann::json;
@ -48,6 +50,7 @@ namespace DiscordObjects {
Guild(json data);
void load_from_json(json data);
std::string to_debug_string();
bool operator==(Guild rhs);
@ -62,13 +65,15 @@ namespace DiscordObjects {
// bool embed_enabled;
// std::string embed_channel_id;
int verification_level;
// TODO: Implement all guil fields
// TODO: Implement all guild fields
// std::vector<?> voice_states
// std::vector<?> roles
// std::vector<?> emojis
// std::vector<?> features
bool unavailable;
std::vector<std::shared_ptr<Channel>> channels;
std::vector<Channel *> channels;
std::vector<GuildMember> members;
std::vector<Role *> roles;
//std::vector<std::unique_ptr<DiscordObjects::User>> users;
};
@ -93,6 +98,23 @@ namespace DiscordObjects {
afk_channel_id = data.value("afk_channel_id", "null");
afk_timeout = data.value("afk_timeout", -1);
verification_level = data.value("verification_level", -1);
unavailable = data.value("unavailable", false);
}
inline std::string Guild::to_debug_string() {
return "**__Guild " + id + "__**"
+ "\n**name:** " + name
+ "\n**icon:** " + icon
+ "\n**splash:** " + splash
+ "\n**owner_id:** " + owner_id
+ "\n**region:** " + region
+ "\n**afk_channel_id:** " + afk_channel_id
+ "\n**afk_timeout:** " + std::to_string(afk_timeout)
+ "\n**verification_level:** " + std::to_string(verification_level)
+ "\n**unavailable:** " + std::to_string(unavailable)
+ "\n**channels:** " + std::to_string(channels.size())
+ "\n**roles:** " + std::to_string(roles.size())
+ "\n**members:** " + std::to_string(members.size());
}
inline bool Guild::operator==(Guild rhs) {

View File

@ -0,0 +1,68 @@
#ifndef BOT_DATA__STRUCTURES_GUILDMEMBER
#define BOT_DATA__STRUCTURES_GUILDMEMBER
#include <string>
#include <vector>
#include "../json/json.hpp"
#include "User.hpp"
#include "Role.hpp"
namespace DiscordObjects {
class GuildMember {
public:
GuildMember();
GuildMember(json data, User *user);
void load_from_json(json data);
std::string to_debug_string();
bool operator==(GuildMember rhs);
User *user;
std::string nick;
std::vector<Role *> roles;
std::string joined_at; // TODO: better type
bool deaf;
bool mute;
};
inline GuildMember::GuildMember() {
user = nullptr;
nick = "null";
joined_at = "null";
deaf = false;
mute = false;
}
inline GuildMember::GuildMember(json data, User *user) {
this->user = user;
load_from_json(data);
}
inline void GuildMember::load_from_json(json data) {
nick = data.value("nick", "null");
joined_at = data.value("joined_at", "null");
deaf = data.value("deaf", false);
mute = data.value("mute", false);
}
inline std::string GuildMember::to_debug_string() {
return "**__GuildMember " + user->id + "__**"
+ "\n**mention:** <@" + user->id + "> / " + user->username + "#" + user->discriminator
+ "\n**bot:** " + std::to_string(user->bot)
+ "\n**mfa_enabled:** " + std::to_string(user->mfa_enabled)
+ "\n**avatar:** " + user->avatar
+ "\n**nick:** " + nick
+ "\n**joined_at:** " + joined_at
+ "\n**deaf:** " + std::to_string(deaf)
+ "\n**mute:** " + std::to_string(mute);
}
inline bool GuildMember::operator==(GuildMember rhs) {
return user->id == rhs.user->id;
}
}
#endif

View File

@ -0,0 +1,118 @@
#ifndef BOT_DATA__STRUCTURES_ROLE
#define BOT_DATA__STRUCTURES_ROLE
#include <string>
#include <sstream>
#include <iomanip>
#include "../json/json.hpp"
using json = nlohmann::json;
namespace DiscordObjects {
class Role {
public:
Role();
Role(json data);
void load_from_json(json data);
std::string to_debug_string();
bool operator==(Role rhs);
std::string id;
std::string name;
int colour;
bool hoist;
int position;
int permissions;
bool managed;
bool mentionable;
};
inline Role::Role() {
id = "null";
name = "null";
colour = -1;
hoist = false;
position = -1;
permissions = 0;
managed = false;
mentionable = false;
}
inline Role::Role(json data) {
load_from_json(data);
}
inline void Role::load_from_json(json data) {
id = data.value("id", "null");
name = data.value("name", "null");
colour = data.value("color", -1);
hoist = data.value("hoist", false);
position = data.value("position", -1);
permissions = data.value("permissions", 0);
managed = data.value("managed", false);
mentionable = data.value("mentionable", false);
}
inline std::string Role::to_debug_string() {
std::stringstream colour_ss;
colour_ss << std::setw(6) << std::setfill('0') << colour;
std::string colour_str = colour_ss.str();
return "**__Role " + id + "__**"
+ "\n**name:** " + name
+ "\n**colour:** #" + colour_str
+ "\n**hoist:** " + std::to_string(hoist)
+ "\n**position:** " + std::to_string(position)
+ "\n**permissions:** " + std::to_string(permissions)
+ "\n**managed:** " + std::to_string(managed)
+ "\n**mentionable:** " + std::to_string(mentionable);
}
inline bool Role::operator==(Role rhs) {
return id == rhs.id;
}
/* permission values */
enum class Permission {
CreateInstantInvite = 0x00000001, // Allows creation of instant invites
KickMembers = 0x00000002, // Allows kicking members
BanMembers = 0x00000004, // Allows banning members
Administrator = 0x00000008, // Allows all permissions and bypasses channel permission overwrites
ManageChannels = 0x00000010, // Allows management and editing of channels
ManageGuild = 0x00000020, // Allows management and editing of the guild
ReadMessages = 0x00000400, // Allows reading messages in a channel.The channel will not appear for users without this permission
SendMessages = 0x00000800, // Allows for sending messages in a channel.
SendTTSMessages = 0x00001000, // Allows for sending of / tts messages
ManageMessages = 0x00002000, // Allows for deletion of other users messages
EmbedLinks = 0x00004000, // Links sent by this user will be auto - embedded
AttachFiles = 0x00008000, // Allows for uploading images and files
ReadMessageHistory = 0x00010000, // Allows for reading of message history
MentionEveryone = 0x00020000, // Allows for using the @everyone tag to notify all users in a channel, and the @here tag to notify all online users in a channel
Connect = 0x00100000, // Allows for joining of a voice channel
Speak = 0x00200000, // Allows for speaking in a voice channel
MuteMembers = 0x00400000, // Allows for muting members in a voice channel
DeafenMembers = 0x00800000, // Allows for deafening of members in a voice channel
MoveMembers = 0x01000000, // Allows for moving of members between voice channels
UseVAD = 0x02000000, // Allows for using voice - activity - detection in a voice channel
ChangeNickname = 0x04000000, // Allows for modification of own nickname
ManageNicknames = 0x08000000, // Allows for modification of other users nicknames
ManageRoles = 0x10000000 // Allows management and editing of roles
};
/* implement bitwise operators */
inline Permission operator|(Permission lhs, Permission rhs) {
return static_cast<Permission>(static_cast<int>(lhs) | static_cast<int>(rhs));
}
inline Permission operator|=(Permission &lhs, Permission rhs) {
lhs = static_cast<Permission>(static_cast<int>(lhs) | static_cast<int>(rhs));
return lhs;
}
}
#endif

View File

@ -2,6 +2,7 @@
#define BOT_DATA__STRUCTURES_USER
#include <string>
#include <vector>
#include "../json/json.hpp"
@ -37,6 +38,8 @@ namespace DiscordObjects {
std::string avatar;
bool bot;
bool mfa_enabled;
std::vector<std::string> guilds;
};
inline User::User() {