Now tracks and caches all (I think) required data
This commit is contained in:
parent
1b2ea3c6bf
commit
47de861f45
@ -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,131 +64,482 @@ void GatewayHandler::on_dispatch(json decoded, client &c, websocketpp::connectio
|
||||
json data = decoded["d"];
|
||||
|
||||
if (event_name == "READY") {
|
||||
user_object.load_from_json(data["user"]);
|
||||
|
||||
Logger::write("Sign-on confirmed. (@" + user_object.username + "#" + user_object.discriminator + ")", Logger::LogLevel::Info);
|
||||
on_event_ready(data);
|
||||
}
|
||||
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);
|
||||
|
||||
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]));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
Logger::write("Loaded " + std::to_string(guilds.size()) + " guild(s)", Logger::LogLevel::Info);
|
||||
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 == "TYPING_START") {}
|
||||
else if (event_name == "MESSAGE_CREATE") {
|
||||
std::string message = data["content"];
|
||||
auto channel = channels[data["channel_id"]];
|
||||
on_event_message_create(data);
|
||||
}
|
||||
}
|
||||
|
||||
DiscordObjects::User sender(data["author"]);
|
||||
void GatewayHandler::on_event_ready(json data) {
|
||||
user_object.load_from_json(data["user"]);
|
||||
|
||||
std::vector<std::string> words;
|
||||
boost::split(words, message, boost::is_any_of(" "));
|
||||
Command custom_command;
|
||||
if (words[0] == "`trivia" || words[0] == "`t") {
|
||||
int questions = 10;
|
||||
int delay = 8;
|
||||
Logger::write("Sign-on confirmed. (@" + user_object.username + "#" + user_object.discriminator + ")", Logger::LogLevel::Info);
|
||||
}
|
||||
|
||||
if (words.size() > 3) {
|
||||
ah->send_message(channel->id, ":exclamation: Invalid arguments!");
|
||||
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;
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
guilds[guild.id].members.push_back(guild_member);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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"]];
|
||||
|
||||
DiscordObjects::User sender(data["author"]);
|
||||
|
||||
std::vector<std::string> words;
|
||||
boost::split(words, message, boost::is_any_of(" "));
|
||||
Command custom_command;
|
||||
if (words[0] == "`trivia" || words[0] == "`t") {
|
||||
int questions = 10;
|
||||
int delay = 8;
|
||||
|
||||
if (words.size() > 3) {
|
||||
ah->send_message(channel.id, ":exclamation: Invalid arguments!");
|
||||
return;
|
||||
}
|
||||
else if (words.size() > 1) {
|
||||
if (words[1] == "help" || words[1] == "h") {
|
||||
std::string help = "**Base command \\`t[rivia]**. Arguments:\n";
|
||||
help += "\\`trivia **{x}** **{y}**: Makes the game last **x** number of questions, optionally sets the time interval between hints to **y** seconds\n";
|
||||
help += "\\`trivia **stop**: stops the ongoing game.\n";
|
||||
help += "\\`trivia **help**: prints this message\n";
|
||||
|
||||
ah->send_message(channel.id, help);
|
||||
return;
|
||||
}
|
||||
else if(words.size() > 1) {
|
||||
if (words[1] == "help" || words[1] == "h") {
|
||||
std::string help = "**Base command \\`t[rivia]**. Arguments:\n";
|
||||
help += "\\`trivia **{x}** **{y}**: Makes the game last **x** number of questions, optionally sets the time interval between hints to **y** seconds\n";
|
||||
help += "\\`trivia **stop**: stops the ongoing game.\n";
|
||||
help += "\\`trivia **help**: prints this message\n";
|
||||
|
||||
ah->send_message(channel->id, help);
|
||||
else if (words[1] == "stop" || words[1] == "s") {
|
||||
if (games.find(channel.id) != games.end()) {
|
||||
delete_game(channel.id);
|
||||
return;
|
||||
}
|
||||
else if (words[1] == "stop" || words[1] == "s") {
|
||||
if (games.find(channel->id) != games.end()) {
|
||||
delete_game(channel->id);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
try {
|
||||
questions = std::stoi(words[1]);
|
||||
if (words.size() == 3) {
|
||||
delay = std::stoi(words[2]);
|
||||
}
|
||||
}
|
||||
catch (std::invalid_argument e) {
|
||||
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();
|
||||
}
|
||||
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";
|
||||
}
|
||||
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>");
|
||||
}
|
||||
else if (words[0] == "`js" && message.length() > 4) {
|
||||
std::string js = message.substr(4);
|
||||
auto it = v8_instances.find(channel.guild_id);
|
||||
if (it != v8_instances.end() && js.length() > 0) {
|
||||
it->second->exec_js(js, channel.id);
|
||||
}
|
||||
}
|
||||
else if (words[0] == "`createjs" && message.length() > 8) {
|
||||
std::string args = message.substr(10);
|
||||
size_t seperator_loc = args.find("|");
|
||||
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);
|
||||
switch (result) {
|
||||
case 0:
|
||||
ah->send_message(channel.id, ":warning: Error!"); break;
|
||||
case 1:
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (words[0] == "`shutdown" && sender.id == "82232146579689472") { // it me
|
||||
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 (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 {
|
||||
try {
|
||||
questions = std::stoi(words[1]);
|
||||
if (words.size() == 3) {
|
||||
delay = std::stoi(words[2]);
|
||||
}
|
||||
}
|
||||
catch (std::invalid_argument e) {
|
||||
ah->send_message(channel->id, ":exclamation: Invalid arguments!");
|
||||
return;
|
||||
}
|
||||
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];
|
||||
|
||||
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";
|
||||
}
|
||||
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>");
|
||||
}
|
||||
else if (words[0] == "`js" && message.length() > 4) {
|
||||
std::string js = message.substr(4);
|
||||
auto it = v8_instances.find(channel->guild_id);
|
||||
if (it != v8_instances.end() && js.length() > 0) {
|
||||
it->second->exec_js(js, channel->id);
|
||||
}
|
||||
}
|
||||
else if (words[0] == "`createjs" && message.length() > 8) {
|
||||
std::string args = message.substr(10);
|
||||
size_t seperator_loc = args.find("|");
|
||||
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);
|
||||
switch (result) {
|
||||
case 0:
|
||||
ah->send_message(channel->id, ":warning: Error!"); break;
|
||||
case 1:
|
||||
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;
|
||||
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 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.");
|
||||
}
|
||||
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);
|
||||
else {
|
||||
ah->send_message(channel.id, ":question: Unrecognised guild.");
|
||||
}
|
||||
}
|
||||
else if (games.find(channel->id) != games.end()) { // message received in channel with ongoing game
|
||||
games[channel->id]->handle_answer(message, sender);
|
||||
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);
|
||||
}
|
||||
}
|
||||
else if (games.find(channel.id) != games.end()) { // message received in channel with ongoing game
|
||||
games[channel.id]->handle_answer(message, sender);
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayHandler::identify(client &c, websocketpp::connection_hdl &hdl) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
@ -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";
|
||||
}
|
||||
|
@ -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) {
|
||||
|
68
TriviaBot/bot/data_structures/GuildMember.hpp
Normal file
68
TriviaBot/bot/data_structures/GuildMember.hpp
Normal 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
|
118
TriviaBot/bot/data_structures/Role.hpp
Normal file
118
TriviaBot/bot/data_structures/Role.hpp
Normal 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
|
@ -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() {
|
||||
|
Loading…
Reference in New Issue
Block a user