mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2025-07-01 14:37:10 +02:00
Basic Discord library layout.
Foundation for the discord library bindings. To be gradually exposed to the script.
This commit is contained in:
77
vendor/DPP/src/dpp/auditlog.cpp
vendored
Normal file
77
vendor/DPP/src/dpp/auditlog.cpp
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/auditlog.h>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
namespace dpp {
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
auditlog::auditlog()
|
||||
{
|
||||
}
|
||||
|
||||
auditlog::~auditlog() {
|
||||
}
|
||||
|
||||
auditlog& auditlog::fill_from_json(nlohmann::json* j) {
|
||||
for (auto & ai : (*j)["audit_log_entries"]) {
|
||||
audit_entry ae;
|
||||
ae.id = SnowflakeNotNull(&ai, "id");
|
||||
ae.event = (audit_type)Int8NotNull(&ai, "action_type");
|
||||
ae.user_id = SnowflakeNotNull(&ai, "user_id");
|
||||
ae.target_id = SnowflakeNotNull(&ai, "target_id");
|
||||
ae.reason = StringNotNull(&ai, "reason");
|
||||
if (j->find("changes") != j->end()) {
|
||||
auto &c = ai["changes"];
|
||||
for (auto & change : c) {
|
||||
audit_change ac;
|
||||
ac.key = StringNotNull(&change, "key");
|
||||
if (change.find("new_value") != change.end()) {
|
||||
ac.new_value = change["new_value"].dump();
|
||||
}
|
||||
if (change.find("old_value") != change.end()) {
|
||||
ac.old_value = change["old_value"].dump();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (j->find("options") != j->end()) {
|
||||
auto &o = ai["options"];
|
||||
audit_extra opts;
|
||||
opts.channel_id = SnowflakeNotNull(&o, "channel_id");
|
||||
opts.count = StringNotNull(&o, "count");
|
||||
opts.delete_member_days = StringNotNull(&o, "delete_member_days");
|
||||
opts.id = SnowflakeNotNull(&o, "id");
|
||||
opts.members_removed = StringNotNull(&o, "members_removed");
|
||||
opts.message_id = SnowflakeNotNull(&o, "message_id");
|
||||
opts.role_name = StringNotNull(&o, "role_name");
|
||||
opts.type = StringNotNull(&o, "type");
|
||||
ae.options = opts;
|
||||
}
|
||||
this->entries.push_back(ae);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
52
vendor/DPP/src/dpp/ban.cpp
vendored
Normal file
52
vendor/DPP/src/dpp/ban.cpp
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/ban.h>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
namespace dpp {
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
ban::ban() : user_id(0)
|
||||
{
|
||||
}
|
||||
|
||||
ban::~ban() {
|
||||
}
|
||||
|
||||
ban& ban::fill_from_json(nlohmann::json* j) {
|
||||
reason = StringNotNull(j, "reason");
|
||||
if (j->find("user") != j->end()) {
|
||||
json & user = (*j)["user"];
|
||||
user_id = SnowflakeNotNull(&user, "id");
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string ban::build_json() const {
|
||||
/* This is an unused stub, because sending a ban is simple as a user id and a reason */
|
||||
return "{}";
|
||||
}
|
||||
|
||||
};
|
||||
|
161
vendor/DPP/src/dpp/cache.cpp
vendored
Normal file
161
vendor/DPP/src/dpp/cache.cpp
vendored
Normal file
@ -0,0 +1,161 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <mutex>
|
||||
#include <iostream>
|
||||
#include <variant>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/guild.h>
|
||||
|
||||
namespace dpp {
|
||||
|
||||
std::unordered_map<managed*, time_t> deletion_queue;
|
||||
std::mutex deletion_mutex;
|
||||
|
||||
#define cache_helper(type, cache_name, setter, getter, counter) \
|
||||
cache* cache_name = nullptr; \
|
||||
type * setter (snowflake id) { \
|
||||
return cache_name ? ( type * ) cache_name ->find(id) : nullptr; \
|
||||
} \
|
||||
cache* getter () { \
|
||||
if (! cache_name ) { \
|
||||
cache_name = new cache(); \
|
||||
} \
|
||||
return cache_name ; \
|
||||
} \
|
||||
uint64_t counter () { \
|
||||
return ( cache_name ? cache_name ->count() : 0 ); \
|
||||
}
|
||||
|
||||
|
||||
/* Because other threads and systems may run for a short while after an event is received, we don't immediately
|
||||
* delete pointers when objects are replaced. We put them into a queue, and periodically delete pointers in the
|
||||
* queue. This also rehashes unordered_maps to ensure they free their memory.
|
||||
*/
|
||||
void garbage_collection() {
|
||||
time_t now = time(NULL);
|
||||
bool repeat = false;
|
||||
{
|
||||
std::lock_guard<std::mutex> delete_lock(deletion_mutex);
|
||||
do {
|
||||
repeat = false;
|
||||
for (auto g = deletion_queue.begin(); g != deletion_queue.end(); ++g) {
|
||||
if (now > g->second + 60) {
|
||||
delete g->first;
|
||||
deletion_queue.erase(g);
|
||||
repeat = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (repeat);
|
||||
if (deletion_queue.size() == 0) {
|
||||
deletion_queue = {};
|
||||
}
|
||||
}
|
||||
dpp::get_user_cache()->rehash();
|
||||
dpp::get_channel_cache()->rehash();
|
||||
dpp::get_guild_cache()->rehash();
|
||||
dpp::get_role_cache()->rehash();
|
||||
dpp::get_emoji_cache()->rehash();
|
||||
}
|
||||
|
||||
cache::cache() {
|
||||
cache_map = new cache_container();
|
||||
}
|
||||
|
||||
cache::~cache() {
|
||||
delete cache_map;
|
||||
}
|
||||
|
||||
uint64_t cache::count() {
|
||||
std::lock_guard<std::mutex> lock(this->cache_mutex);
|
||||
return cache_map->size();
|
||||
}
|
||||
|
||||
std::mutex& cache::get_mutex() {
|
||||
return this->cache_mutex;
|
||||
}
|
||||
|
||||
cache_container& cache::get_container() {
|
||||
return *(this->cache_map);
|
||||
}
|
||||
|
||||
void cache::store(managed* object) {
|
||||
if (!object) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(this->cache_mutex);
|
||||
auto existing = cache_map->find(object->id);
|
||||
if (existing == cache_map->end()) {
|
||||
(*cache_map)[object->id] = object;
|
||||
} else if (object != existing->second) {
|
||||
/* Flag old pointer for deletion and replace */
|
||||
std::lock_guard<std::mutex> delete_lock(deletion_mutex);
|
||||
deletion_queue[existing->second] = time(NULL);
|
||||
(*cache_map)[object->id] = object;
|
||||
}
|
||||
}
|
||||
|
||||
size_t cache::bytes() {
|
||||
std::lock_guard<std::mutex> lock(cache_mutex);
|
||||
return sizeof(this) + (cache_map->bucket_count() * sizeof(size_t));
|
||||
}
|
||||
|
||||
void cache::rehash() {
|
||||
std::lock_guard<std::mutex> lock(cache_mutex);
|
||||
cache_container* n = new cache_container();
|
||||
n->reserve(cache_map->size());
|
||||
for (auto t = cache_map->begin(); t != cache_map->end(); ++t) {
|
||||
n->insert(*t);
|
||||
}
|
||||
delete cache_map;
|
||||
cache_map = n;
|
||||
}
|
||||
|
||||
void cache::remove(managed* object) {
|
||||
if (!object) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(cache_mutex);
|
||||
std::lock_guard<std::mutex> delete_lock(deletion_mutex);
|
||||
auto existing = cache_map->find(object->id);
|
||||
if (existing != cache_map->end()) {
|
||||
cache_map->erase(existing);
|
||||
deletion_queue[object] = time(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
managed* cache::find(snowflake id) {
|
||||
std::lock_guard<std::mutex> lock(cache_mutex);
|
||||
auto r = cache_map->find(id);
|
||||
if (r != cache_map->end()) {
|
||||
return r->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
cache_helper(user, user_cache, find_user, get_user_cache, get_user_count);
|
||||
cache_helper(channel, channel_cache, find_channel, get_channel_cache, get_channel_count);
|
||||
cache_helper(role, role_cache, find_role, get_role_cache, get_role_count);
|
||||
cache_helper(guild, guild_cache, find_guild, get_guild_cache, get_guild_count);
|
||||
cache_helper(emoji, emoji_cache, find_emoji, get_emoji_cache, get_emoji_count);
|
||||
|
||||
};
|
245
vendor/DPP/src/dpp/channel.cpp
vendored
Normal file
245
vendor/DPP/src/dpp/channel.cpp
vendored
Normal file
@ -0,0 +1,245 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/guild.h>
|
||||
#include <dpp/user.h>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp {
|
||||
|
||||
thread_member& thread_member::fill_from_json(nlohmann::json* j) {
|
||||
SetSnowflakeNotNull(j, "id", this->thread_id);
|
||||
SetSnowflakeNotNull(j, "user_id", this->user_id);
|
||||
SetTimestampNotNull(j, "join_timestamp", this->joined);
|
||||
SetInt32NotNull(j, "flags", this->flags);
|
||||
return *this;
|
||||
}
|
||||
|
||||
channel::channel() :
|
||||
managed(),
|
||||
flags(0),
|
||||
guild_id(0),
|
||||
position(0),
|
||||
last_message_id(0),
|
||||
user_limit(0),
|
||||
rate_limit_per_user(0),
|
||||
owner_id(0),
|
||||
parent_id(0),
|
||||
last_pin_timestamp(0),
|
||||
message_count(0),
|
||||
member_count(0)
|
||||
{
|
||||
}
|
||||
|
||||
channel::~channel()
|
||||
{
|
||||
}
|
||||
|
||||
bool channel::is_nsfw() const {
|
||||
return flags & dpp::c_nsfw;
|
||||
}
|
||||
|
||||
bool channel::is_text_channel() const {
|
||||
return flags & dpp::c_text;
|
||||
}
|
||||
|
||||
bool channel::is_dm() const {
|
||||
return flags & dpp::c_dm;
|
||||
}
|
||||
|
||||
bool channel::is_voice_channel() const {
|
||||
return flags & dpp::c_voice;
|
||||
}
|
||||
|
||||
bool channel::is_group_dm() const {
|
||||
return (flags & (dpp::c_dm | dpp::c_group)) == (dpp::c_dm | dpp::c_group);
|
||||
}
|
||||
|
||||
bool channel::is_category() const {
|
||||
return flags & dpp::c_category;
|
||||
}
|
||||
|
||||
bool channel::is_stage_channel() const {
|
||||
return (flags & dpp::c_stage) == dpp::c_stage;
|
||||
}
|
||||
|
||||
bool channel::is_news_channel() const {
|
||||
/* Important: Stage/News overlap to pack more values in a byte */
|
||||
return !is_stage_channel() && (flags & dpp::c_news);
|
||||
}
|
||||
|
||||
bool channel::is_store_channel() const {
|
||||
/* Important: Stage/Store overlap to pack more values in a byte */
|
||||
return !is_stage_channel() && (flags & dpp::c_store);
|
||||
}
|
||||
|
||||
channel& channel::fill_from_json(json* j) {
|
||||
this->id = SnowflakeNotNull(j, "id");
|
||||
SetSnowflakeNotNull(j, "guild_id", this->guild_id);
|
||||
SetInt16NotNull(j, "position", this->position);
|
||||
SetStringNotNull(j, "name", this->name);
|
||||
SetStringNotNull(j, "topic", this->topic);
|
||||
SetSnowflakeNotNull(j, "last_message_id", this->last_message_id);
|
||||
SetInt8NotNull(j, "user_limit", this->user_limit);
|
||||
SetInt16NotNull(j, "rate_limit_per_user", this->rate_limit_per_user);
|
||||
SetSnowflakeNotNull(j, "owner_id", this->owner_id);
|
||||
SetSnowflakeNotNull(j, "parent_id", this->parent_id);
|
||||
//this->last_pin_timestamp
|
||||
uint8_t type = Int8NotNull(j, "type");
|
||||
this->flags |= BoolNotNull(j, "nsfw") ? dpp::c_nsfw : 0;
|
||||
this->flags |= (type == GUILD_TEXT) ? dpp::c_text : 0;
|
||||
this->flags |= (type == GUILD_VOICE) ? dpp::c_voice : 0;
|
||||
this->flags |= (type == DM) ? dpp::c_dm : 0;
|
||||
this->flags |= (type == GROUP_DM) ? (dpp::c_group | dpp::c_dm) : 0;
|
||||
this->flags |= (type == GUILD_CATEGORY) ? dpp::c_category : 0;
|
||||
this->flags |= (type == GUILD_NEWS) ? dpp::c_news : 0;
|
||||
this->flags |= (type == GUILD_STORE) ? dpp::c_store : 0;
|
||||
this->flags |= (type == GUILD_STAGE) ? dpp::c_stage : 0;
|
||||
this->flags |= (type == GUILD_NEWS_THREAD) ? dpp::c_news_thread : 0;
|
||||
this->flags |= (type == GUILD_PUBLIC_THREAD) ? dpp::c_public_thread : 0;
|
||||
this->flags |= (type == GUILD_PRIVATE_THREAD) ? dpp::c_private_thread : 0;
|
||||
|
||||
if (j->find("recipients") != j->end()) {
|
||||
recipients = {};
|
||||
for (auto & r : (*j)["recipients"]) {
|
||||
recipients.push_back(from_string<uint64_t>(r["id"].get<std::string>(), std::dec));
|
||||
}
|
||||
}
|
||||
|
||||
if (j->find("permission_overwrites") != j->end()) {
|
||||
permission_overwrites = {};
|
||||
for (auto & overwrite : (*j)["permission_overwrites"]) {
|
||||
permission_overwrite po;
|
||||
po.id = SnowflakeNotNull(&overwrite, "id");
|
||||
po.allow = SnowflakeNotNull(&overwrite, "allow");
|
||||
po.deny = SnowflakeNotNull(&overwrite, "deny");
|
||||
po.type = Int8NotNull(&overwrite, "type");
|
||||
permission_overwrites.push_back(po);
|
||||
}
|
||||
}
|
||||
|
||||
if (type == GUILD_NEWS_THREAD || type == GUILD_PUBLIC_THREAD || type == GUILD_PRIVATE_THREAD) {
|
||||
SetInt8NotNull(j, "message_count", this->message_count);
|
||||
SetInt8NotNull(j, "memeber_count", this->member_count);
|
||||
dpp::thread_metadata metadata;
|
||||
auto json_metadata = (*j)["thread_metadata"];
|
||||
metadata.archived = BoolNotNull(&json_metadata, "archived");
|
||||
metadata.archive_timestamp = TimestampNotNull(&json_metadata, "archive_timestamp");
|
||||
metadata.auto_archive_duration = Int16NotNull(&json_metadata, "auto_archive_duration");
|
||||
metadata.locked = BoolNotNull(&json_metadata, "locked");
|
||||
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string channel::build_json(bool with_id) const {
|
||||
json j;
|
||||
if (with_id) {
|
||||
j["id"] = std::to_string(id);
|
||||
}
|
||||
j["guild_id"] = std::to_string(guild_id);
|
||||
j["position"] = position;
|
||||
j["name"] = name;
|
||||
j["topic"] = topic;
|
||||
if (is_voice_channel()) {
|
||||
j["user_limit"] = user_limit;
|
||||
j["rate_limit_per_user"] = rate_limit_per_user;
|
||||
}
|
||||
if (!is_dm()) {
|
||||
if (parent_id) {
|
||||
j["parent_id"] = parent_id;
|
||||
}
|
||||
if (is_text_channel()) {
|
||||
j["type"] = GUILD_TEXT;
|
||||
} else if (is_voice_channel()) {
|
||||
j["type"] = GUILD_VOICE;
|
||||
} else if (is_category()) {
|
||||
j["type"] = GUILD_CATEGORY;
|
||||
} else if (is_stage_channel()) {
|
||||
/* Order is important, as GUILD_STAGE overlaps NEWS and STORE */
|
||||
j["type"] = GUILD_STAGE;
|
||||
} else if (is_news_channel()) {
|
||||
j["type"] = GUILD_NEWS;
|
||||
} else if (is_store_channel()) {
|
||||
j["type"] = GUILD_STORE;
|
||||
}
|
||||
j["nsfw"] = is_nsfw();
|
||||
} else {
|
||||
if (is_group_dm()) {
|
||||
j["type"] = GROUP_DM;
|
||||
} else {
|
||||
j["type"] = DM;
|
||||
}
|
||||
}
|
||||
|
||||
return j.dump();
|
||||
}
|
||||
|
||||
uint64_t channel::get_user_permissions(const user* member) const
|
||||
{
|
||||
if (member == nullptr)
|
||||
return 0;
|
||||
|
||||
guild* g = dpp::find_guild(guild_id);
|
||||
if (g == nullptr)
|
||||
return 0;
|
||||
|
||||
return g->permission_overwrites(g->base_permissions(member), member, this);
|
||||
}
|
||||
|
||||
std::map<snowflake, guild_member*> channel::get_members() {
|
||||
std::map<snowflake, guild_member*> rv;
|
||||
guild* g = dpp::find_guild(guild_id);
|
||||
if (g) {
|
||||
for (auto m = g->members.begin(); m != g->members.end(); ++m) {
|
||||
user* u = dpp::find_user(m->second.user_id);
|
||||
if (u) {
|
||||
if (get_user_permissions(u) & p_view_channel) {
|
||||
rv[m->second.user_id] = &(m->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
std::map<snowflake, voicestate> channel::get_voice_members() {
|
||||
std::map<snowflake, voicestate> rv;
|
||||
guild* g = dpp::find_guild(guild_id);
|
||||
if (g) {
|
||||
for (auto & m : g->voice_members) {
|
||||
if (m.second.channel_id == this->id) {
|
||||
rv[m.second.user_id] = m.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
1943
vendor/DPP/src/dpp/cluster.cpp
vendored
Normal file
1943
vendor/DPP/src/dpp/cluster.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
360
vendor/DPP/src/dpp/commandhandler.cpp
vendored
Normal file
360
vendor/DPP/src/dpp/commandhandler.cpp
vendored
Normal file
@ -0,0 +1,360 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/commandhandler.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/cluster.h>
|
||||
#include <dpp/dispatcher.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <fmt/format.h>
|
||||
#include <sstream>
|
||||
|
||||
namespace dpp {
|
||||
|
||||
param_info::param_info(parameter_type t, bool o, const std::string &d, const std::map<std::string, std::string> &opts) : type(t), optional(o), description(d), choices(opts)
|
||||
{
|
||||
}
|
||||
|
||||
commandhandler::commandhandler(cluster* o, bool auto_hook_events, snowflake application_id) : slash_commands_enabled(false), owner(o), app_id(application_id)
|
||||
{
|
||||
if (!application_id && o->me.id) {
|
||||
app_id = o->me.id;
|
||||
}
|
||||
if (auto_hook_events) {
|
||||
o->on_interaction_create([this](const dpp::interaction_create_t &event) {
|
||||
this->route(event);
|
||||
});
|
||||
o->on_message_create([this](const dpp::message_create_t & event) {
|
||||
this->route(*event.msg);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
commandhandler& commandhandler::set_owner(cluster* o)
|
||||
{
|
||||
owner = o;
|
||||
return *this;
|
||||
}
|
||||
|
||||
commandhandler::~commandhandler()
|
||||
{
|
||||
}
|
||||
|
||||
commandhandler& commandhandler::add_prefix(const std::string &prefix)
|
||||
{
|
||||
prefixes.push_back(prefix);
|
||||
if (prefix == "/") {
|
||||
if (!slash_commands_enabled) {
|
||||
/* Register existing slash commands */
|
||||
slash_commands_enabled = true;
|
||||
} else {
|
||||
slash_commands_enabled = true;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
commandhandler& commandhandler::add_command(const std::string &command, const parameter_registration_t ¶meters, command_handler handler, const std::string &description, snowflake guild_id)
|
||||
{
|
||||
command_info_t i;
|
||||
i.func = handler;
|
||||
i.guild_id = guild_id;
|
||||
i.parameters = parameters;
|
||||
commands[lowercase(command)] = i;
|
||||
if (slash_commands_enabled) {
|
||||
if (this->app_id == 0) {
|
||||
if (owner->me.id == 0) {
|
||||
throw dpp::exception("Command handler not ready (i don't know my application ID)");
|
||||
} else {
|
||||
this->app_id = owner->me.id;
|
||||
}
|
||||
}
|
||||
dpp::slashcommand newcommand;
|
||||
/* Create a new global command on ready event */
|
||||
newcommand.set_name(lowercase(command)).set_description(description).set_application_id(this->app_id);
|
||||
|
||||
for (auto& parameter : parameters) {
|
||||
command_option_type cot;
|
||||
switch (parameter.second.type) {
|
||||
case pt_boolean:
|
||||
cot = co_boolean;
|
||||
break;
|
||||
case pt_integer:
|
||||
cot = co_integer;
|
||||
break;
|
||||
case pt_string:
|
||||
cot = co_string;
|
||||
break;
|
||||
case pt_user:
|
||||
cot = co_user;
|
||||
break;
|
||||
case pt_role:
|
||||
cot = co_role;
|
||||
break;
|
||||
case pt_channel:
|
||||
cot = co_channel;
|
||||
break;
|
||||
}
|
||||
|
||||
command_option opt(cot, parameter.first, parameter.second.description, !parameter.second.optional);
|
||||
if (!parameter.second.choices.empty()) {
|
||||
for (auto& c : parameter.second.choices) {
|
||||
opt.add_choice(dpp::command_option_choice(c.second, c.first));
|
||||
}
|
||||
}
|
||||
newcommand.add_option(opt);
|
||||
}
|
||||
/* Register the command */
|
||||
if (guild_id) {
|
||||
owner->guild_command_create(newcommand, guild_id, [command, this](const dpp::confirmation_callback_t &callback) {
|
||||
if (callback.is_error()) {
|
||||
this->owner->log(dpp::ll_error, fmt::format("Failed to register guild slash command '{}': {}", command, callback.http_info.body));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
owner->global_command_create(newcommand, [command, this](const dpp::confirmation_callback_t &callback) {
|
||||
if (callback.is_error()) {
|
||||
this->owner->log(dpp::ll_error, fmt::format("Failed to register global slash command '{}': {}", command, callback.http_info.body));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool commandhandler::string_has_prefix(std::string &str)
|
||||
{
|
||||
size_t str_length = utility::utf8len(str);
|
||||
for (auto& p : prefixes) {
|
||||
size_t prefix_length = utility::utf8len(p);
|
||||
if (utility::utf8substr(str, 0, prefix_length) == p) {
|
||||
str.erase(str.begin(), str.begin() + prefix_length);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void commandhandler::route(const dpp::message& msg)
|
||||
{
|
||||
std::string msg_content = msg.content;
|
||||
if (string_has_prefix(msg_content)) {
|
||||
/* Put the string into stringstream to parse parameters at spaces.
|
||||
* We use stringstream as it handles multiple spaces etc nicely.
|
||||
*/
|
||||
std::stringstream ss(msg_content);
|
||||
std::string command;
|
||||
ss >> command;
|
||||
/* Prefixed command, the prefix was removed */
|
||||
auto found_cmd = commands.find(lowercase(command));
|
||||
if (found_cmd != commands.end()) {
|
||||
/* Filter out guild specific commands that are not for the current guild */
|
||||
if (found_cmd->second.guild_id && found_cmd->second.guild_id != msg.guild_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
parameter_list_t call_params;
|
||||
|
||||
/* Command found; parse parameters */
|
||||
for (auto& p : found_cmd->second.parameters) {
|
||||
command_parameter param;
|
||||
|
||||
/* Check for end of stream */
|
||||
if (!ss) {
|
||||
/* If it's an optional param, we dont care */
|
||||
if (!p.second.optional) {
|
||||
/* Trigger missing parameter handler? */
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch (p.second.type) {
|
||||
case pt_string: {
|
||||
std::string x;
|
||||
ss >> x;
|
||||
param = x;
|
||||
}
|
||||
break;
|
||||
case pt_role: {
|
||||
std::string x;
|
||||
ss >> x;
|
||||
if (x.length() > 4 && x[0] == '<' && x[1] == '&') {
|
||||
snowflake rid = from_string<uint64_t>(x.substr(2, x.length() - 1), std::dec);
|
||||
role* r = dpp::find_role(rid);
|
||||
if (r) {
|
||||
param = *r;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case pt_channel: {
|
||||
std::string x;
|
||||
ss >> x;
|
||||
if (x.length() > 4 && x[0] == '<' && x[1] == '#') {
|
||||
snowflake cid = from_string<uint64_t>(x.substr(2, x.length() - 1), std::dec);
|
||||
channel* c = dpp::find_channel(cid);
|
||||
if (c) {
|
||||
param = *c;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case pt_user: {
|
||||
std::string x;
|
||||
ss >> x;
|
||||
if (x.length() > 4 && x[0] == '<' && x[1] == '@') {
|
||||
snowflake uid = from_string<uint64_t>(x.substr(2, x.length() - 1), std::dec);
|
||||
user* u = dpp::find_user(uid);
|
||||
if (u) {
|
||||
param = *u;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case pt_integer: {
|
||||
int32_t x = 0;
|
||||
ss >> x;
|
||||
param = x;
|
||||
}
|
||||
case pt_boolean: {
|
||||
std::string x;
|
||||
bool y = false;
|
||||
ss >> x;
|
||||
x = lowercase(x);
|
||||
if (x == "yes" || x == "1" || x == "true") {
|
||||
y = true;
|
||||
}
|
||||
param = y;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Add parameter to the list */
|
||||
call_params.push_back(std::make_pair(p.first, param));
|
||||
}
|
||||
|
||||
/* Call command handler */
|
||||
command_source source;
|
||||
source.command_id = 0;
|
||||
source.guild_id = msg.guild_id;
|
||||
source.channel_id = msg.channel_id;
|
||||
source.issuer = msg.author;
|
||||
found_cmd->second.func(command, call_params, source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void commandhandler::route(const interaction_create_t & event)
|
||||
{
|
||||
/* We don't need to check for prefixes here, slash command interactions
|
||||
* dont have prefixes at all.
|
||||
*/
|
||||
command_interaction cmd = std::get<command_interaction>(event.command.data);
|
||||
auto found_cmd = commands.find(lowercase(cmd.name));
|
||||
if (found_cmd != commands.end()) {
|
||||
/* Command found; parse parameters */
|
||||
parameter_list_t call_params;
|
||||
for (auto& p : found_cmd->second.parameters) {
|
||||
command_parameter param;
|
||||
const command_value& slash_parameter = event.get_parameter(p.first);
|
||||
|
||||
if (p.second.optional && slash_parameter.valueless_by_exception()) {
|
||||
/* Missing optional parameter, skip this */
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
switch (p.second.type) {
|
||||
case pt_string: {
|
||||
std::string s = std::get<std::string>(slash_parameter);
|
||||
param = s;
|
||||
}
|
||||
break;
|
||||
case pt_role: {
|
||||
snowflake rid = std::get<snowflake>(slash_parameter);
|
||||
role* r = dpp::find_role(rid);
|
||||
if (r) {
|
||||
param = *r;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case pt_channel: {
|
||||
snowflake cid = std::get<snowflake>(slash_parameter);
|
||||
channel* c = dpp::find_channel(cid);
|
||||
if (c) {
|
||||
param = *c;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case pt_user: {
|
||||
snowflake uid = std::get<snowflake>(slash_parameter);
|
||||
user* u = dpp::find_user(uid);
|
||||
if (u) {
|
||||
param = *u;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case pt_integer: {
|
||||
int32_t i = std::get<int32_t>(slash_parameter);
|
||||
param = i;
|
||||
}
|
||||
case pt_boolean: {
|
||||
bool b = std::get<bool>(slash_parameter);
|
||||
param = b;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (const std::bad_variant_access& e) {
|
||||
/* Missing optional parameter, skip this */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Add parameter to the list */
|
||||
call_params.push_back(std::make_pair(p.first, param));
|
||||
}
|
||||
|
||||
/* Call command handler */
|
||||
command_source source;
|
||||
source.command_id = event.command.id;
|
||||
source.command_token = event.command.token;
|
||||
source.guild_id = event.command.guild_id;
|
||||
source.channel_id = event.command.channel_id;
|
||||
source.issuer = (user*)&event.command.usr;
|
||||
found_cmd->second.func(cmd.name, call_params, source);
|
||||
}
|
||||
}
|
||||
|
||||
void commandhandler::reply(const dpp::message &m, command_source source)
|
||||
{
|
||||
dpp::message msg = m;
|
||||
msg.guild_id = source.guild_id;
|
||||
msg.channel_id = source.channel_id;
|
||||
if (!source.command_token.empty() && source.command_id) {
|
||||
owner->interaction_response_create(source.command_id, source.command_token, dpp::interaction_response(ir_channel_message_with_source, msg));
|
||||
} else {
|
||||
owner->message_create(msg);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
625
vendor/DPP/src/dpp/discordclient.cpp
vendored
Normal file
625
vendor/DPP/src/dpp/discordclient.cpp
vendored
Normal file
@ -0,0 +1,625 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/cluster.h>
|
||||
#include <thread>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <fmt/format.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#define PATH_UNCOMPRESSED "/?v=" DISCORD_API_VERSION "&encoding=json"
|
||||
#define PATH_COMPRESSED "/?v=" DISCORD_API_VERSION "&encoding=json&compress=zlib-stream"
|
||||
#define DECOMP_BUFFER_SIZE 512 * 1024
|
||||
|
||||
namespace dpp {
|
||||
|
||||
/* This is an internal class, defined externally as just a forward declaration for an opaque pointer.
|
||||
* This is because we don't want an external dependency on zlib's headers
|
||||
*/
|
||||
class zlibcontext {
|
||||
public:
|
||||
z_stream d_stream;
|
||||
};
|
||||
|
||||
discord_client::discord_client(dpp::cluster* _cluster, uint32_t _shard_id, uint32_t _max_shards, const std::string &_token, uint32_t _intents, bool comp)
|
||||
: websocket_client(DEFAULT_GATEWAY, "443", comp ? PATH_COMPRESSED : PATH_UNCOMPRESSED),
|
||||
creator(_cluster),
|
||||
shard_id(_shard_id),
|
||||
max_shards(_max_shards),
|
||||
token(_token),
|
||||
last_heartbeat(time(NULL)),
|
||||
heartbeat_interval(0),
|
||||
reconnects(0),
|
||||
resumes(0),
|
||||
last_seq(0),
|
||||
sessionid(""),
|
||||
intents(_intents),
|
||||
runner(nullptr),
|
||||
compressed(comp),
|
||||
decompressed_total(0),
|
||||
decomp_buffer(nullptr),
|
||||
ready(false),
|
||||
ping_start(0.0),
|
||||
websocket_ping(0.0)
|
||||
{
|
||||
zlib = new zlibcontext();
|
||||
Connect();
|
||||
}
|
||||
|
||||
discord_client::~discord_client()
|
||||
{
|
||||
if (runner) {
|
||||
runner->join();
|
||||
delete runner;
|
||||
}
|
||||
delete zlib;
|
||||
}
|
||||
|
||||
uint64_t discord_client::get_decompressed_bytes_in()
|
||||
{
|
||||
return decompressed_total;
|
||||
}
|
||||
|
||||
void discord_client::SetupZLib()
|
||||
{
|
||||
if (compressed) {
|
||||
zlib->d_stream.zalloc = (alloc_func)0;
|
||||
zlib->d_stream.zfree = (free_func)0;
|
||||
zlib->d_stream.opaque = (voidpf)0;
|
||||
if (inflateInit(&(zlib->d_stream)) != Z_OK) {
|
||||
throw dpp::exception("Can't initialise stream compression!");
|
||||
}
|
||||
this->decomp_buffer = new unsigned char[DECOMP_BUFFER_SIZE];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void discord_client::EndZLib()
|
||||
{
|
||||
if (compressed) {
|
||||
inflateEnd(&(zlib->d_stream));
|
||||
if (this->decomp_buffer) {
|
||||
delete[] this->decomp_buffer;
|
||||
this->decomp_buffer = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void discord_client::ThreadRun()
|
||||
{
|
||||
SetupZLib();
|
||||
do {
|
||||
bool error = false;
|
||||
ready = false;
|
||||
message_queue.clear();
|
||||
ssl_client::read_loop();
|
||||
ssl_client::close();
|
||||
EndZLib();
|
||||
SetupZLib();
|
||||
do {
|
||||
error = false;
|
||||
try {
|
||||
ssl_client::Connect();
|
||||
websocket_client::Connect();
|
||||
}
|
||||
catch (const std::exception &e) {
|
||||
log(dpp::ll_error, std::string("Error establishing connection, retry in 5 seconds: ") + e.what());
|
||||
ssl_client::close();
|
||||
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||
error = true;
|
||||
}
|
||||
} while (error);
|
||||
} while(true);
|
||||
}
|
||||
|
||||
void discord_client::Run()
|
||||
{
|
||||
this->runner = new std::thread(&discord_client::ThreadRun, this);
|
||||
this->thread_id = runner->native_handle();
|
||||
}
|
||||
|
||||
bool discord_client::HandleFrame(const std::string &buffer)
|
||||
{
|
||||
std::string& data = (std::string&)buffer;
|
||||
|
||||
/* gzip compression is a special case */
|
||||
if (compressed) {
|
||||
/* Check that we have a complete compressed frame */
|
||||
if ((uint8_t)buffer[buffer.size() - 4] == 0x00 && (uint8_t)buffer[buffer.size() - 3] == 0x00 && (uint8_t)buffer[buffer.size() - 2] == 0xFF
|
||||
&& (uint8_t)buffer[buffer.size() - 1] == 0xFF) {
|
||||
/* Decompress buffer */
|
||||
decompressed.clear();
|
||||
zlib->d_stream.next_in = (Bytef *)buffer.c_str();
|
||||
zlib->d_stream.avail_in = buffer.size();
|
||||
do {
|
||||
int have = 0;
|
||||
zlib->d_stream.next_out = (Bytef*)decomp_buffer;
|
||||
zlib->d_stream.avail_out = DECOMP_BUFFER_SIZE;
|
||||
int ret = inflate(&(zlib->d_stream), Z_NO_FLUSH);
|
||||
have = DECOMP_BUFFER_SIZE - zlib->d_stream.avail_out;
|
||||
switch (ret)
|
||||
{
|
||||
case Z_NEED_DICT:
|
||||
case Z_STREAM_ERROR:
|
||||
this->Error(6000);
|
||||
this->close();
|
||||
return true;
|
||||
break;
|
||||
case Z_DATA_ERROR:
|
||||
this->Error(6001);
|
||||
this->close();
|
||||
return true;
|
||||
break;
|
||||
case Z_MEM_ERROR:
|
||||
this->Error(6002);
|
||||
this->close();
|
||||
return true;
|
||||
break;
|
||||
case Z_OK:
|
||||
this->decompressed.append((const char*)decomp_buffer, have);
|
||||
this->decompressed_total += have;
|
||||
break;
|
||||
default:
|
||||
/* Stub */
|
||||
break;
|
||||
}
|
||||
} while (zlib->d_stream.avail_out == 0);
|
||||
data = decompressed;
|
||||
} else {
|
||||
/* No complete compressed frame yet */
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
log(dpp::ll_trace, fmt::format("R: {}", data));
|
||||
json j;
|
||||
|
||||
try {
|
||||
j = json::parse(data);
|
||||
}
|
||||
catch (const std::exception &e) {
|
||||
log(dpp::ll_error, fmt::format("discord_client::HandleFrame {} [{}]", e.what(), data));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (j.find("s") != j.end() && !j["s"].is_null()) {
|
||||
last_seq = j["s"].get<uint64_t>();
|
||||
}
|
||||
|
||||
if (j.find("op") != j.end()) {
|
||||
uint32_t op = j["op"];
|
||||
|
||||
switch (op) {
|
||||
case 9:
|
||||
/* Reset session state and fall through to 10 */
|
||||
op = 10;
|
||||
log(dpp::ll_debug, fmt::format("Failed to resume session {}, will reidentify", sessionid));
|
||||
this->sessionid = "";
|
||||
this->last_seq = 0;
|
||||
/* No break here, falls through to state 10 to cause a reidentify */
|
||||
case 10:
|
||||
/* Need to check carefully for the existence of this before we try to access it! */
|
||||
if (j.find("d") != j.end() && j["d"].find("heartbeat_interval") != j["d"].end() && !j["d"]["heartbeat_interval"].is_null()) {
|
||||
this->heartbeat_interval = j["d"]["heartbeat_interval"].get<uint32_t>();
|
||||
}
|
||||
|
||||
if (last_seq && !sessionid.empty()) {
|
||||
/* Resume */
|
||||
log(dpp::ll_debug, fmt::format("Resuming session {} with seq={}", sessionid, last_seq));
|
||||
json obj = {
|
||||
{ "op", 6 },
|
||||
{ "d", {
|
||||
{"token", this->token },
|
||||
{"session_id", this->sessionid },
|
||||
{"seq", this->last_seq }
|
||||
}
|
||||
}
|
||||
};
|
||||
this->write(obj.dump());
|
||||
resumes++;
|
||||
} else {
|
||||
/* Full connect */
|
||||
while (time(NULL) < creator->last_identify + 5) {
|
||||
uint32_t wait = (creator->last_identify + 5) - time(NULL);
|
||||
log(dpp::ll_debug, fmt::format("Waiting {} seconds before identifying for session...", wait));
|
||||
std::this_thread::sleep_for(std::chrono::seconds(wait));
|
||||
}
|
||||
log(dpp::ll_debug, "Connecting new session...");
|
||||
json obj = {
|
||||
{ "op", 2 },
|
||||
{
|
||||
"d",
|
||||
{
|
||||
{ "token", this->token },
|
||||
{ "properties",
|
||||
{
|
||||
{ "$os", "Linux" },
|
||||
{ "$browser", "D++" },
|
||||
{ "$device", "D++" }
|
||||
}
|
||||
},
|
||||
{ "shard", json::array({ shard_id, max_shards }) },
|
||||
{ "compress", false },
|
||||
{ "large_threshold", 250 }
|
||||
}
|
||||
}
|
||||
};
|
||||
if (this->intents) {
|
||||
obj["d"]["intents"] = this->intents;
|
||||
}
|
||||
this->write(obj.dump());
|
||||
this->connect_time = creator->last_identify = time(NULL);
|
||||
reconnects++;
|
||||
}
|
||||
this->last_heartbeat_ack = time(nullptr);
|
||||
websocket_ping = 0;
|
||||
break;
|
||||
case 0: {
|
||||
std::string event = j.find("t") != j.end() && !j["t"].is_null() ? j["t"] : "";
|
||||
|
||||
HandleEvent(event, j, data);
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
log(dpp::ll_debug, fmt::format("Reconnection requested, closing socket {}", sessionid));
|
||||
message_queue.clear();
|
||||
|
||||
shutdown(sfd, 2);
|
||||
#ifdef _WIN32
|
||||
if (sfd >= 0 && sfd < FD_SETSIZE) {
|
||||
closesocket(sfd);
|
||||
}
|
||||
#else
|
||||
::close(sfd);
|
||||
#endif
|
||||
|
||||
break;
|
||||
/* Heartbeat ack */
|
||||
case 11:
|
||||
this->last_heartbeat_ack = time(nullptr);
|
||||
websocket_ping = utility::time_f() - ping_start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
dpp::utility::uptime discord_client::get_uptime()
|
||||
{
|
||||
return dpp::utility::uptime(time(NULL) - connect_time);
|
||||
}
|
||||
|
||||
bool discord_client::is_connected()
|
||||
{
|
||||
return (this->GetState() == CONNECTED) && (this->ready);
|
||||
}
|
||||
|
||||
void discord_client::Error(uint32_t errorcode)
|
||||
{
|
||||
std::map<uint32_t, std::string> errortext = {
|
||||
{ 1000, "Socket shutdown" },
|
||||
{ 1001, "Client is leaving" },
|
||||
{ 1002, "Endpoint received a malformed frame" },
|
||||
{ 1003, "Endpoint received an unsupported frame" },
|
||||
{ 1004, "Reserved code" },
|
||||
{ 1005, "Expected close status, received none" },
|
||||
{ 1006, "No close code frame has been receieved" },
|
||||
{ 1007, "Endpoint received inconsistent message (e.g. malformed UTF-8)" },
|
||||
{ 1008, "Generic error" },
|
||||
{ 1009, "Endpoint won't process large frame" },
|
||||
{ 1010, "Client wanted an extension which server did not negotiate" },
|
||||
{ 1011, "Internal server error while operating" },
|
||||
{ 1012, "Server/service is restarting" },
|
||||
{ 1013, "Temporary server condition forced blocking client's request" },
|
||||
{ 1014, "Server acting as gateway received an invalid response" },
|
||||
{ 1015, "Transport Layer Security handshake failure" },
|
||||
{ 4000, "Unknown error" },
|
||||
{ 4001, "Unknown opcode" },
|
||||
{ 4002, "Decode error" },
|
||||
{ 4003, "Not authenticated" },
|
||||
{ 4004, "Authentication failed" },
|
||||
{ 4005, "Already authenticated" },
|
||||
{ 4007, "Invalid seq" },
|
||||
{ 4008, "Rate limited" },
|
||||
{ 4009, "Session timed out" },
|
||||
{ 4010, "Invalid shard" },
|
||||
{ 4011, "Sharding required" },
|
||||
{ 4012, "Invalid API version" },
|
||||
{ 4013, "Invalid intent(s)" },
|
||||
{ 4014, "Disallowed intent(s)" },
|
||||
{ 6000, "ZLib Stream Error" },
|
||||
{ 6001, "ZLib Data Error" },
|
||||
{ 6002, "ZLib Memory Error" },
|
||||
{ 6666, "Hell freezing over" }
|
||||
};
|
||||
std::string error = "Unknown error";
|
||||
auto i = errortext.find(errorcode);
|
||||
if (i != errortext.end()) {
|
||||
error = i->second;
|
||||
}
|
||||
log(dpp::ll_warning, fmt::format("OOF! Error from underlying websocket: {}: {}", errorcode, error));
|
||||
}
|
||||
|
||||
void discord_client::log(dpp::loglevel severity, const std::string &msg) const
|
||||
{
|
||||
if (creator->dispatch.log) {
|
||||
/* Pass to user if theyve hooked the event */
|
||||
dpp::log_t logmsg(nullptr, msg);
|
||||
logmsg.severity = severity;
|
||||
logmsg.message = msg;
|
||||
creator->dispatch.log(logmsg);
|
||||
}
|
||||
}
|
||||
|
||||
void discord_client::QueueMessage(const std::string &j, bool to_front)
|
||||
{
|
||||
std::lock_guard<std::mutex> locker(queue_mutex);
|
||||
if (to_front) {
|
||||
message_queue.push_front(j);
|
||||
} else {
|
||||
message_queue.push_back(j);
|
||||
}
|
||||
}
|
||||
|
||||
void discord_client::ClearQueue()
|
||||
{
|
||||
std::lock_guard<std::mutex> locker(queue_mutex);
|
||||
message_queue.clear();
|
||||
}
|
||||
|
||||
size_t discord_client::GetQueueSize()
|
||||
{
|
||||
std::lock_guard<std::mutex> locker(queue_mutex);
|
||||
return message_queue.size();
|
||||
}
|
||||
|
||||
void discord_client::one_second_timer()
|
||||
{
|
||||
|
||||
websocket_client::one_second_timer();
|
||||
|
||||
/* Every minute, rehash all containers from first shard.
|
||||
* We can't just get shard with the id 0 because this won't
|
||||
* work on a clustered environment
|
||||
*/
|
||||
auto shards = creator->get_shards();
|
||||
auto first_iter = shards.begin();
|
||||
if (first_iter != shards.end()) {
|
||||
dpp::discord_client* first_shard = first_iter->second;
|
||||
if ((time(NULL) % 60) == 0 && first_shard == this) {
|
||||
dpp::garbage_collection();
|
||||
}
|
||||
}
|
||||
|
||||
/* This all only triggers if we are connected (have completed websocket, and received READY or RESUMED) */
|
||||
if (this->is_connected()) {
|
||||
|
||||
/* If we stopped getting heartbeat acknowledgements, this means the connections is dead.
|
||||
* This can happen to TCP connections which is why we have heartbeats in the first place.
|
||||
* Miss two ACKS, forces a reconnection.
|
||||
*/
|
||||
if ((time(nullptr) - this->last_heartbeat_ack) > heartbeat_interval * 2) {
|
||||
log(dpp::ll_warning, fmt::format("Missed heartbeat ACK, forcing reconnection to session {}", sessionid));
|
||||
message_queue.clear();
|
||||
|
||||
shutdown(sfd, 2);
|
||||
#ifdef _WIN32
|
||||
if (sfd >= 0 && sfd < FD_SETSIZE) {
|
||||
closesocket(sfd);
|
||||
}
|
||||
#else
|
||||
::close(sfd);
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Rate limit outbound messages, 1 every odd second, 2 every even second */
|
||||
for (int x = 0; x < (time(NULL) % 2) + 1; ++x) {
|
||||
std::lock_guard<std::mutex> locker(queue_mutex);
|
||||
if (message_queue.size()) {
|
||||
std::string message = message_queue.front();
|
||||
message_queue.pop_front();
|
||||
/* Checking here with .find() saves us having to deserialise the json
|
||||
* to find pings in our queue. The assumption is that the format of the
|
||||
* ping isn't going to change.
|
||||
*/
|
||||
if (message.find("\"op\":1}") != std::string::npos) {
|
||||
ping_start = utility::time_f();
|
||||
}
|
||||
this->write(message);
|
||||
}
|
||||
}
|
||||
|
||||
/* Send pings (heartbeat opcodes) before each interval. We send them slightly more regular than expected,
|
||||
* just to be safe.
|
||||
*/
|
||||
if (this->heartbeat_interval && this->last_seq) {
|
||||
/* Check if we're due to emit a heartbeat */
|
||||
if (time(NULL) > last_heartbeat + ((heartbeat_interval / 1000.0) * 0.75)) {
|
||||
QueueMessage(json({{"op", 1}, {"d", last_seq}}).dump(), true);
|
||||
last_heartbeat = time(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t discord_client::get_guild_count() {
|
||||
uint64_t total = 0;
|
||||
dpp::cache* c = dpp::get_guild_cache();
|
||||
dpp::cache_container& gc = c->get_container();
|
||||
/* IMPORTANT: We must lock the container to iterate it */
|
||||
std::lock_guard<std::mutex> lock(c->get_mutex());
|
||||
for (auto g = gc.begin(); g != gc.end(); ++g) {
|
||||
dpp::guild* gp = (dpp::guild*)g->second;
|
||||
if (gp->shard_id == this->shard_id) {
|
||||
total++;
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
uint64_t discord_client::get_member_count() {
|
||||
uint64_t total = 0;
|
||||
dpp::cache* c = dpp::get_guild_cache();
|
||||
dpp::cache_container& gc = c->get_container();
|
||||
/* IMPORTANT: We must lock the container to iterate it */
|
||||
std::lock_guard<std::mutex> lock(c->get_mutex());
|
||||
for (auto g = gc.begin(); g != gc.end(); ++g) {
|
||||
dpp::guild* gp = (dpp::guild*)g->second;
|
||||
if (gp->shard_id == this->shard_id) {
|
||||
if (creator->cache_policy.user_policy == dpp::cp_aggressive) {
|
||||
/* We can use actual member count if we are using full user caching */
|
||||
total += gp->members.size();
|
||||
} else {
|
||||
/* Otherwise we use approximate guild member counts from guild_create */
|
||||
total += gp->member_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
uint64_t discord_client::get_channel_count() {
|
||||
uint64_t total = 0;
|
||||
dpp::cache* c = dpp::get_guild_cache();
|
||||
dpp::cache_container& gc = c->get_container();
|
||||
/* IMPORTANT: We must lock the container to iterate it */
|
||||
std::lock_guard<std::mutex> lock(c->get_mutex());
|
||||
for (auto g = gc.begin(); g != gc.end(); ++g) {
|
||||
dpp::guild* gp = (dpp::guild*)g->second;
|
||||
if (gp->shard_id == this->shard_id) {
|
||||
total += gp->channels.size();
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
void discord_client::connect_voice(snowflake guild_id, snowflake channel_id) {
|
||||
#ifdef HAVE_VOICE
|
||||
std::lock_guard<std::mutex> lock(voice_mutex);
|
||||
if (connecting_voice_channels.find(guild_id) == connecting_voice_channels.end()) {
|
||||
connecting_voice_channels[guild_id] = new voiceconn(this, channel_id);
|
||||
/* Once sent, this expects two events (in any order) on the websocket:
|
||||
* VOICE_SERVER_UPDATE and VOICE_STATUS_UPDATE
|
||||
*/
|
||||
log(ll_debug, fmt::format("Sending op 4, guild {}", guild_id));
|
||||
QueueMessage(json({
|
||||
{ "op", 4 },
|
||||
{ "d", {
|
||||
{ "guild_id", std::to_string(guild_id) },
|
||||
{ "channel_id", std::to_string(channel_id) },
|
||||
{ "self_mute", false },
|
||||
{ "self_deaf", false },
|
||||
}
|
||||
}
|
||||
}).dump(), false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void discord_client::disconnect_voice(snowflake guild_id) {
|
||||
#ifdef HAVE_VOICE
|
||||
std::lock_guard<std::mutex> lock(voice_mutex);
|
||||
auto v = connecting_voice_channels.find(guild_id);
|
||||
if (v != connecting_voice_channels.end()) {
|
||||
log(ll_debug, fmt::format("Disconnecting voice, guild: {}", guild_id));
|
||||
QueueMessage(json({
|
||||
{ "op", 4 },
|
||||
{ "d", {
|
||||
{ "guild_id", std::to_string(guild_id) },
|
||||
{ "channel_id", json::value_t::null },
|
||||
{ "self_mute", false },
|
||||
{ "self_deaf", false },
|
||||
}
|
||||
}
|
||||
}).dump(), false);
|
||||
delete v->second;
|
||||
v->second = nullptr;
|
||||
connecting_voice_channels.erase(v);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
voiceconn* discord_client::get_voice(snowflake guild_id) {
|
||||
#ifdef HAVE_VOICE
|
||||
std::lock_guard<std::mutex> lock(voice_mutex);
|
||||
auto v = connecting_voice_channels.find(guild_id);
|
||||
if (v != connecting_voice_channels.end()) {
|
||||
return v->second;
|
||||
}
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
voiceconn::voiceconn(discord_client* o, snowflake _channel_id) : creator(o), channel_id(_channel_id), voiceclient(nullptr) {
|
||||
}
|
||||
|
||||
bool voiceconn::is_ready() {
|
||||
return (!websocket_hostname.empty() && !session_id.empty() && !token.empty());
|
||||
}
|
||||
|
||||
bool voiceconn::is_active() {
|
||||
return voiceclient != nullptr;
|
||||
}
|
||||
|
||||
void voiceconn::disconnect() {
|
||||
if (this->is_active()) {
|
||||
voiceclient->terminating = true;
|
||||
voiceclient->close();
|
||||
delete voiceclient;
|
||||
voiceclient = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
voiceconn::~voiceconn() {
|
||||
this->disconnect();
|
||||
}
|
||||
|
||||
void voiceconn::connect(snowflake guild_id) {
|
||||
if (this->is_ready() && !this->is_active()) {
|
||||
/* This is wrapped in a thread because instantiating discord_voice_client can initiate a blocking SSL_connect() */
|
||||
auto t = std::thread([guild_id, this]() {
|
||||
try {
|
||||
this->creator->log(ll_debug, fmt::format("Connecting voice for guild {} channel {}", guild_id, this->channel_id));
|
||||
this->voiceclient = new discord_voice_client(creator->creator, this->channel_id, guild_id, this->token, this->session_id, this->websocket_hostname);
|
||||
/* Note: Spawns thread! */
|
||||
this->voiceclient->Run();
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
this->creator->log(ll_error, fmt::format("Can't connect to voice websocket (guild_id: {}, channel_id: {}): {}", guild_id, this->channel_id, e.what()));
|
||||
}
|
||||
});
|
||||
t.detach();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
325
vendor/DPP/src/dpp/discordevents.cpp
vendored
Normal file
325
vendor/DPP/src/dpp/discordevents.cpp
vendored
Normal file
@ -0,0 +1,325 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#define _XOPEN_SOURCE
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <fmt/format.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <time.h>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
char* strptime(const char* s, const char* f, struct tm* tm) {
|
||||
std::istringstream input(s);
|
||||
input.imbue(std::locale(setlocale(LC_ALL, nullptr)));
|
||||
input >> std::get_time(tm, f);
|
||||
if (input.fail()) {
|
||||
return const_cast< char* >("");
|
||||
}
|
||||
return (char*)(s + input.tellg());
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace dpp {
|
||||
|
||||
uint64_t SnowflakeNotNull(const json* j, const char *keyname) {
|
||||
/* Snowflakes are a special case. Pun intended.
|
||||
* Because discord drinks the javascript kool-aid, they have to send 64 bit integers as strings as js can't deal with them
|
||||
* even though we can. So, all snowflakes are sent and received wrapped as string values and must be read by nlohmann::json
|
||||
* as string types, then converted from string to uint64_t. Checks for existence of the value, and that it is a string containing
|
||||
* a number. If not, then this function returns 0.
|
||||
*/
|
||||
auto k = j->find(keyname);
|
||||
if (k != j->end()) {
|
||||
return !k->is_null() && k->is_string() ? strtoull(k->get<std::string>().c_str(), nullptr, 10) : 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SetSnowflakeNotNull(const json* j, const char *keyname, uint64_t &v) {
|
||||
auto k = j->find(keyname);
|
||||
if (k != j->end()) {
|
||||
v = !k->is_null() && k->is_string() ? strtoull(k->get<std::string>().c_str(), nullptr, 10) : 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string StringNotNull(const json* j, const char *keyname) {
|
||||
/* Returns empty string if the value is not a string, or is null or not defined */
|
||||
auto k = j->find(keyname);
|
||||
if (k != j->end()) {
|
||||
return !k->is_null() && k->is_string() ? k->get<std::string>() : "";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
void SetStringNotNull(const json* j, const char *keyname, std::string &v) {
|
||||
/* Returns empty string if the value is not a string, or is null or not defined */
|
||||
auto k = j->find(keyname);
|
||||
if (k != j->end()) {
|
||||
v = !k->is_null() && k->is_string() ? k->get<std::string>() : "";
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t Int64NotNull(const json* j, const char *keyname) {
|
||||
auto k = j->find(keyname);
|
||||
if (k != j->end()) {
|
||||
return !k->is_null() && !k->is_string() ? k->get<uint64_t>() : 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SetInt64NotNull(const json* j, const char *keyname, uint64_t &v) {
|
||||
auto k = j->find(keyname);
|
||||
if (k != j->end()) {
|
||||
v = !k->is_null() && !k->is_string() ? k->get<uint64_t>() : 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t Int32NotNull(const json* j, const char *keyname) {
|
||||
auto k = j->find(keyname);
|
||||
if (k != j->end()) {
|
||||
return !k->is_null() && !k->is_string() ? k->get<uint32_t>() : 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SetInt32NotNull(const json* j, const char *keyname, uint32_t &v) {
|
||||
auto k = j->find(keyname);
|
||||
if (k != j->end()) {
|
||||
v = !k->is_null() && !k->is_string() ? k->get<uint32_t>() : 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t Int16NotNull(const json* j, const char *keyname) {
|
||||
auto k = j->find(keyname);
|
||||
if (k != j->end()) {
|
||||
return !k->is_null() && !k->is_string() ? k->get<uint16_t>() : 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SetInt16NotNull(const json* j, const char *keyname, uint16_t &v) {
|
||||
auto k = j->find(keyname);
|
||||
if (k != j->end()) {
|
||||
v = !k->is_null() && !k->is_string() ? k->get<uint16_t>() : 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t Int8NotNull(const json* j, const char *keyname) {
|
||||
auto k = j->find(keyname);
|
||||
if (k != j->end()) {
|
||||
return !k->is_null() && !k->is_string() ? k->get<uint8_t>() : 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SetInt8NotNull(const json* j, const char *keyname, uint8_t &v) {
|
||||
auto k = j->find(keyname);
|
||||
if (k != j->end()) {
|
||||
v = !k->is_null() && !k->is_string() ? k->get<uint8_t>() : 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool BoolNotNull(const json* j, const char *keyname) {
|
||||
auto k = j->find(keyname);
|
||||
if (k != j->end()) {
|
||||
return !k->is_null() ? (k->get<bool>() == true) : false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void SetBoolNotNull(const json* j, const char *keyname, bool &v) {
|
||||
auto k = j->find(keyname);
|
||||
if (k != j->end()) {
|
||||
v = !k->is_null() ? (k->get<bool>() == true) : false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string base64_encode(unsigned char const* buf, unsigned int buffer_length) {
|
||||
/* Quick and dirty base64 encode */
|
||||
static const char to_base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
size_t ret_size = buffer_length + 2;
|
||||
|
||||
ret_size = 4 * ret_size / 3;
|
||||
|
||||
std::string ret;
|
||||
ret.reserve(ret_size);
|
||||
|
||||
for (unsigned int i=0; i<ret_size/4; ++i)
|
||||
{
|
||||
size_t index = i*3;
|
||||
unsigned char b3[3];
|
||||
b3[0] = buf[index+0];
|
||||
b3[1] = buf[index+1];
|
||||
b3[2] = buf[index+2];
|
||||
|
||||
ret.push_back(to_base64[ ((b3[0] & 0xfc) >> 2) ]);
|
||||
ret.push_back(to_base64[ ((b3[0] & 0x03) << 4) + ((b3[1] & 0xf0) >> 4) ]);
|
||||
ret.push_back(to_base64[ ((b3[1] & 0x0f) << 2) + ((b3[2] & 0xc0) >> 6) ]);
|
||||
ret.push_back(to_base64[ ((b3[2] & 0x3f)) ]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
time_t TimestampNotNull(const json* j, const char* keyname)
|
||||
{
|
||||
/* Parses discord ISO 8061 timestamps to time_t, accounting for local time adjustment.
|
||||
* Note that discord timestamps contain a decimal seconds part, which time_t and struct tm
|
||||
* can't handle. We strip these out.
|
||||
*/
|
||||
time_t retval = 0;
|
||||
if (j->find(keyname) != j->end() && !(*j)[keyname].is_null() && (*j)[keyname].is_string()) {
|
||||
tm timestamp = {};
|
||||
std::string timedate = (*j)[keyname].get<std::string>();
|
||||
if (timedate.find('+') != std::string::npos && timedate.find('.') != std::string::npos) {
|
||||
std::string tzpart = timedate.substr(timedate.find('+'), timedate.length());
|
||||
timedate = timedate.substr(0, timedate.find('.')) + tzpart ;
|
||||
strptime(timedate.substr(0, 19).c_str(), "%FT%TZ%z", ×tamp);
|
||||
timestamp.tm_isdst = 0;
|
||||
retval = mktime(×tamp);
|
||||
} else {
|
||||
strptime(timedate.substr(0, 19).c_str(), "%F %T", ×tamp);
|
||||
retval = mktime(×tamp);
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void SetTimestampNotNull(const json* j, const char* keyname, time_t &v)
|
||||
{
|
||||
/* Parses discord ISO 8061 timestamps to time_t, accounting for local time adjustment.
|
||||
* Note that discord timestamps contain a decimal seconds part, which time_t and struct tm
|
||||
* can't handle. We strip these out.
|
||||
*/
|
||||
time_t retval = 0;
|
||||
if (j->find(keyname) != j->end() && !(*j)[keyname].is_null() && (*j)[keyname].is_string()) {
|
||||
tm timestamp = {};
|
||||
std::string timedate = (*j)[keyname].get<std::string>();
|
||||
if (timedate.find('+') != std::string::npos && timedate.find('.') != std::string::npos) {
|
||||
std::string tzpart = timedate.substr(timedate.find('+'), timedate.length());
|
||||
timedate = timedate.substr(0, timedate.find('.')) + tzpart ;
|
||||
strptime(timedate.substr(0, 19).c_str(), "%FT%TZ%z", ×tamp);
|
||||
timestamp.tm_isdst = 0;
|
||||
retval = mktime(×tamp);
|
||||
} else {
|
||||
strptime(timedate.substr(0, 19).c_str(), "%F %T", ×tamp);
|
||||
retval = mktime(×tamp);
|
||||
}
|
||||
v = retval;
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::string, dpp::events::event*> eventmap = {
|
||||
{ "__LOG__", new dpp::events::logger() },
|
||||
{ "GUILD_CREATE", new dpp::events::guild_create() },
|
||||
{ "GUILD_UPDATE", new dpp::events::guild_update() },
|
||||
{ "GUILD_DELETE", new dpp::events::guild_delete() },
|
||||
{ "GUILD_MEMBER_UPDATE", new dpp::events::guild_member_update() },
|
||||
{ "RESUMED", new dpp::events::resumed() },
|
||||
{ "READY", new dpp::events::ready() },
|
||||
{ "CHANNEL_CREATE", new dpp::events::channel_create() },
|
||||
{ "CHANNEL_UPDATE", new dpp::events::channel_update() },
|
||||
{ "CHANNEL_DELETE", new dpp::events::channel_delete() },
|
||||
{ "PRESENCE_UPDATE", new dpp::events::presence_update() },
|
||||
{ "TYPING_START", new dpp::events::typing_start() },
|
||||
{ "MESSAGE_CREATE", new dpp::events::message_create() },
|
||||
{ "MESSAGE_UPDATE", new dpp::events::message_update() },
|
||||
{ "MESSAGE_DELETE", new dpp::events::message_delete() },
|
||||
{ "MESSAGE_DELETE_BULK", new dpp::events::message_delete_bulk() },
|
||||
{ "MESSAGE_REACTION_ADD", new dpp::events::message_reaction_add() },
|
||||
{ "MESSAGE_REACTION_REMOVE", new dpp::events::message_reaction_remove() },
|
||||
{ "MESSAGE_REACTION_REMOVE_ALL", new dpp::events::message_reaction_remove_all() },
|
||||
{ "MESSAGE_REACTION_REMOVE_EMOJI", new dpp::events::message_reaction_remove_emoji() },
|
||||
{ "CHANNEL_PINS_UPDATE", new dpp::events::channel_pins_update() },
|
||||
{ "GUILD_BAN_ADD", new dpp::events::guild_ban_add() },
|
||||
{ "GUILD_BAN_REMOVE", new dpp::events::guild_ban_remove() },
|
||||
{ "GUILD_EMOJIS_UPDATE", new dpp::events::guild_emojis_update() },
|
||||
{ "GUILD_INTEGRATIONS_UPDATE", new dpp::events::guild_integrations_update() },
|
||||
{ "INTEGRATION_CREATE", new dpp::events::integration_create() },
|
||||
{ "INTEGRATION_UPDATE", new dpp::events::integration_update() },
|
||||
{ "INTEGRATION_DELETE", new dpp::events::integration_delete() },
|
||||
{ "GUILD_MEMBER_ADD", new dpp::events::guild_member_add() },
|
||||
{ "GUILD_MEMBER_REMOVE", new dpp::events::guild_member_remove() },
|
||||
{ "GUILD_MEMBERS_CHUNK", new dpp::events::guild_members_chunk() },
|
||||
{ "GUILD_ROLE_CREATE", new dpp::events::guild_role_create() },
|
||||
{ "GUILD_ROLE_UPDATE", new dpp::events::guild_role_update() },
|
||||
{ "GUILD_ROLE_DELETE", new dpp::events::guild_role_delete() },
|
||||
{ "VOICE_STATE_UPDATE", new dpp::events::voice_state_update() },
|
||||
{ "VOICE_SERVER_UPDATE", new dpp::events::voice_server_update() },
|
||||
{ "WEBHOOKS_UPDATE", new dpp::events::webhooks_update() },
|
||||
{ "INVITE_CREATE", new dpp::events::invite_create() },
|
||||
{ "INVITE_DELETE", new dpp::events::invite_delete() },
|
||||
{ "APPLICATION_COMMAND_CREATE", new dpp::events::application_command_create() },
|
||||
{ "APPLICATION_COMMAND_UPDATE", new dpp::events::application_command_update() },
|
||||
{ "APPLICATION_COMMAND_DELETE", new dpp::events::application_command_delete() },
|
||||
{ "INTERACTION_CREATE", new dpp::events::interaction_create() },
|
||||
{ "USER_UPDATE", new dpp::events::user_update() },
|
||||
{ "GUILD_JOIN_REQUEST_DELETE", new dpp::events::guild_join_request_delete() },
|
||||
{ "STAGE_INSTANCE_CREATE", new dpp::events::stage_instance_create() },
|
||||
{ "STAGE_INSTANCE_DELETE", new dpp::events::stage_instance_delete() },
|
||||
{ "THREAD_CREATE", new dpp::events::thread_create() },
|
||||
{ "THREAD_UPDATE", new dpp::events::thread_update() },
|
||||
{ "THREAD_DELETE", new dpp::events::thread_delete() },
|
||||
{ "THREAD_LIST_SYNC", new dpp::events::thread_list_sync() },
|
||||
{ "THREAD_MEMBER_UPDATE", new dpp::events::thread_member_update() },
|
||||
{ "THREAD_MEMBERS_UPDATE", new dpp::events::thread_members_update() },
|
||||
{ "GUILD_APPLICATION_COMMAND_COUNTS_UPDATE", nullptr },
|
||||
{ "GUILD_STICKERS_UPDATE", new dpp::events::guild_stickers_update() },
|
||||
{ "APPLICATION_COMMAND_PERMISSIONS_UPDATE", nullptr },
|
||||
};
|
||||
|
||||
void discord_client::HandleEvent(const std::string &event, json &j, const std::string &raw)
|
||||
{
|
||||
auto ev_iter = eventmap.find(event);
|
||||
if (ev_iter != eventmap.end()) {
|
||||
/* A handler with nullptr is silently ignored. We don't plan to make a handler for it
|
||||
* so this usually some user-only thing thats crept into the API and shown to bots
|
||||
* that we dont care about.
|
||||
*/
|
||||
if (ev_iter->second != nullptr) {
|
||||
ev_iter->second->handle(this, j, raw);
|
||||
}
|
||||
} else {
|
||||
log(dpp::ll_debug, fmt::format("Unhandled event: {}, {}", event, j.dump()));
|
||||
}
|
||||
}
|
||||
|
||||
};
|
747
vendor/DPP/src/dpp/discordvoiceclient.cpp
vendored
Normal file
747
vendor/DPP/src/dpp/discordvoiceclient.cpp
vendored
Normal file
@ -0,0 +1,747 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
#include <dpp/discordvoiceclient.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/cluster.h>
|
||||
#include <thread>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <fmt/format.h>
|
||||
#include <zlib.h>
|
||||
|
||||
namespace dpp {
|
||||
|
||||
std::string external_ip;
|
||||
|
||||
/**
|
||||
* @brief Represents an RTP packet. Size should always be exactly 12.
|
||||
*/
|
||||
struct rtp_header {
|
||||
uint16_t constant;
|
||||
uint16_t sequence;
|
||||
uint32_t timestamp;
|
||||
uint32_t ssrc;
|
||||
|
||||
rtp_header(uint16_t _seq, uint32_t _ts, uint32_t _ssrc) : constant(htons(0x8078)), sequence(htons(_seq)), timestamp(htonl(_ts)), ssrc(htonl(_ssrc)) {
|
||||
}
|
||||
};
|
||||
|
||||
bool discord_voice_client::sodium_initialised = false;
|
||||
|
||||
discord_voice_client::discord_voice_client(dpp::cluster* _cluster, snowflake _channel_id, snowflake _server_id, const std::string &_token, const std::string &_session_id, const std::string &_host)
|
||||
: websocket_client(_host.substr(0, _host.find(":")), _host.substr(_host.find(":") + 1, _host.length()), "/?v=4"),
|
||||
creator(_cluster),
|
||||
channel_id(_channel_id),
|
||||
server_id(_server_id),
|
||||
token(_token),
|
||||
last_heartbeat(time(NULL)),
|
||||
heartbeat_interval(0),
|
||||
sessionid(_session_id),
|
||||
runner(nullptr),
|
||||
terminating(false),
|
||||
fd(-1),
|
||||
secret_key(nullptr),
|
||||
sequence(0),
|
||||
timestamp(0),
|
||||
sending(false),
|
||||
paused(false),
|
||||
tracks(0)
|
||||
{
|
||||
#if HAVE_VOICE
|
||||
if (!discord_voice_client::sodium_initialised) {
|
||||
if (sodium_init() < 0) {
|
||||
throw dpp::exception("discord_voice_client::discord_voice_client; sodium_init() failed");
|
||||
}
|
||||
int opusError = 0;
|
||||
encoder = opus_encoder_create(48000, 2, OPUS_APPLICATION_VOIP, &opusError);
|
||||
if (opusError) {
|
||||
throw dpp::exception(fmt::format("discord_voice_client::discord_voice_client; opus_encoder_create() failed: {}", opusError));
|
||||
}
|
||||
opusError = 0;
|
||||
decoder = opus_decoder_create(48000, 2, &opusError);
|
||||
if (opusError) {
|
||||
throw dpp::exception(fmt::format("discord_voice_client::discord_voice_client; opus_decoder_create() failed: {}", opusError));
|
||||
}
|
||||
repacketizer = opus_repacketizer_create();
|
||||
discord_voice_client::sodium_initialised = true;
|
||||
}
|
||||
Connect();
|
||||
#endif
|
||||
}
|
||||
|
||||
discord_voice_client::~discord_voice_client()
|
||||
{
|
||||
if (runner) {
|
||||
this->terminating = true;
|
||||
runner->join();
|
||||
delete runner;
|
||||
runner = nullptr;
|
||||
}
|
||||
#if HAVE_VOICE
|
||||
if (encoder) {
|
||||
opus_encoder_destroy(encoder);
|
||||
encoder = nullptr;
|
||||
}
|
||||
if (decoder) {
|
||||
opus_decoder_destroy(decoder);
|
||||
decoder = nullptr;
|
||||
}
|
||||
if (repacketizer) {
|
||||
opus_repacketizer_destroy(repacketizer);
|
||||
repacketizer = nullptr;
|
||||
}
|
||||
#endif
|
||||
if (secret_key) {
|
||||
delete[] secret_key;
|
||||
secret_key = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool discord_voice_client::is_ready() {
|
||||
return secret_key != nullptr;
|
||||
}
|
||||
|
||||
bool discord_voice_client::is_playing() {
|
||||
std::lock_guard<std::mutex> lock(this->stream_mutex);
|
||||
return (!this->outbuf.empty());
|
||||
}
|
||||
|
||||
void discord_voice_client::ThreadRun()
|
||||
{
|
||||
do {
|
||||
ssl_client::read_loop();
|
||||
ssl_client::close();
|
||||
if (!terminating) {
|
||||
ssl_client::Connect();
|
||||
websocket_client::Connect();
|
||||
}
|
||||
} while(!terminating);
|
||||
}
|
||||
|
||||
void discord_voice_client::Run()
|
||||
{
|
||||
this->runner = new std::thread(&discord_voice_client::ThreadRun, this);
|
||||
this->thread_id = runner->native_handle();
|
||||
}
|
||||
|
||||
int discord_voice_client::UDPSend(const char* data, size_t length)
|
||||
{
|
||||
memset(&servaddr, 0, sizeof(servaddr));
|
||||
servaddr.sin_family = AF_INET;
|
||||
servaddr.sin_port = htons(this->port);
|
||||
servaddr.sin_addr.s_addr = inet_addr(this->ip.c_str());
|
||||
return sendto(this->fd, data, length, 0, (const struct sockaddr*)&servaddr, sizeof(sockaddr_in));
|
||||
}
|
||||
|
||||
int discord_voice_client::UDPRecv(char* data, size_t max_length)
|
||||
{
|
||||
struct sockaddr sa;
|
||||
socklen_t sl;
|
||||
return recvfrom(this->fd, data, max_length, 0, (struct sockaddr*)&sa, &sl);
|
||||
}
|
||||
|
||||
bool discord_voice_client::HandleFrame(const std::string &data)
|
||||
{
|
||||
log(dpp::ll_trace, fmt::format("R: {}", data));
|
||||
json j;
|
||||
|
||||
try {
|
||||
j = json::parse(data);
|
||||
}
|
||||
catch (const std::exception &e) {
|
||||
log(dpp::ll_error, fmt::format("discord_voice_client::HandleFrame {} [{}]", e.what(), data));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (j.find("op") != j.end()) {
|
||||
uint32_t op = j["op"];
|
||||
|
||||
switch (op) {
|
||||
/* Voice resume */
|
||||
case 9:
|
||||
log(ll_debug, "Voice connection resumed");
|
||||
break;
|
||||
/* Voice HELLO */
|
||||
case 8: {
|
||||
if (j.find("d") != j.end() && j["d"].find("heartbeat_interval") != j["d"].end() && !j["d"]["heartbeat_interval"].is_null()) {
|
||||
this->heartbeat_interval = j["d"]["heartbeat_interval"].get<uint32_t>();
|
||||
}
|
||||
|
||||
if (modes.size()) {
|
||||
log(dpp::ll_debug, "Resuming voice session...");
|
||||
json obj = {
|
||||
{ "op", 7 },
|
||||
{
|
||||
"d",
|
||||
{
|
||||
{ "server_id", std::to_string(this->server_id) },
|
||||
{ "session_id", this->sessionid },
|
||||
{ "token", this->token },
|
||||
}
|
||||
}
|
||||
};
|
||||
this->write(obj.dump());
|
||||
} else {
|
||||
log(dpp::ll_debug, "Connecting new voice session...");
|
||||
json obj = {
|
||||
{ "op", 0 },
|
||||
{
|
||||
"d",
|
||||
{
|
||||
{ "user_id", creator->me.id },
|
||||
{ "server_id", std::to_string(this->server_id) },
|
||||
{ "session_id", this->sessionid },
|
||||
{ "token", this->token },
|
||||
}
|
||||
}
|
||||
};
|
||||
this->write(obj.dump());
|
||||
}
|
||||
this->connect_time = time(NULL);
|
||||
}
|
||||
break;
|
||||
/* Session description */
|
||||
case 4: {
|
||||
json &d = j["d"];
|
||||
secret_key = new uint8_t[32];
|
||||
size_t ofs = 0;
|
||||
for (auto & c : d["secret_key"]) {
|
||||
*(secret_key + ofs) = (uint8_t)c;
|
||||
ofs++;
|
||||
if (ofs > 31) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (creator->dispatch.voice_ready) {
|
||||
voice_ready_t rdy(nullptr, data);
|
||||
rdy.voice_client = this;
|
||||
rdy.voice_channel_id = this->channel_id;
|
||||
creator->dispatch.voice_ready(rdy);
|
||||
}
|
||||
}
|
||||
break;
|
||||
/* Voice ready */
|
||||
case 2: {
|
||||
/* Video stream stuff comes in this frame too, but we can't use it (YET!) */
|
||||
json &d = j["d"];
|
||||
this->ip = d["ip"].get<std::string>();
|
||||
this->port = d["port"].get<uint16_t>();
|
||||
this->ssrc = d["ssrc"].get<uint64_t>();
|
||||
// Modes
|
||||
for (auto & m : d["modes"]) {
|
||||
this->modes.push_back(m.get<std::string>());
|
||||
}
|
||||
log(ll_debug, fmt::format("Voice websocket established; UDP endpoint: {}:{} [ssrc={}] with {} modes", ip, port, ssrc, modes.size()));
|
||||
|
||||
external_ip = discover_ip();
|
||||
|
||||
int newfd = -1;
|
||||
if ((newfd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) {
|
||||
|
||||
sockaddr_in servaddr;
|
||||
memset(&servaddr, 0, sizeof(sockaddr_in));
|
||||
servaddr.sin_family = AF_INET;
|
||||
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
servaddr.sin_port = htons(0);
|
||||
|
||||
if (bind(newfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {
|
||||
throw dpp::exception("Can't bind() client UDP socket");
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
u_long mode = 1;
|
||||
int result = ioctlsocket(newfd, FIONBIO, &mode);
|
||||
if (result != NO_ERROR)
|
||||
throw dpp::exception("Can't switch socket to non-blocking mode!");
|
||||
#else
|
||||
int ofcmode;
|
||||
ofcmode = fcntl(newfd, F_GETFL, 0);
|
||||
ofcmode |= O_NDELAY;
|
||||
if (fcntl(newfd, F_SETFL, ofcmode)) {
|
||||
throw dpp::exception("Can't switch socket to non-blocking mode!");
|
||||
}
|
||||
#endif
|
||||
/* Hook select() in the ssl_client to add a new file descriptor */
|
||||
this->fd = newfd;
|
||||
this->custom_writeable_fd = std::bind(&discord_voice_client::WantWrite, this);
|
||||
this->custom_readable_fd = std::bind(&discord_voice_client::WantRead, this);
|
||||
this->custom_writeable_ready = std::bind(&discord_voice_client::WriteReady, this);
|
||||
this->custom_readable_ready = std::bind(&discord_voice_client::ReadReady, this);
|
||||
|
||||
int bound_port = 0;
|
||||
struct sockaddr_in sin;
|
||||
socklen_t len = sizeof(sin);
|
||||
if (getsockname(this->fd, (struct sockaddr *)&sin, &len) > -1) {
|
||||
bound_port = ntohs(sin.sin_port);
|
||||
}
|
||||
|
||||
log(ll_debug, fmt::format("External IP address: {}", external_ip));
|
||||
|
||||
this->write(json({
|
||||
{ "op", 1 },
|
||||
{ "d", {
|
||||
{ "protocol", "udp" },
|
||||
{ "data", {
|
||||
{ "address", external_ip },
|
||||
{ "port", bound_port },
|
||||
{ "mode", "xsalsa20_poly1305" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}).dump());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void discord_voice_client::pause_audio(bool pause) {
|
||||
this->paused = pause;
|
||||
}
|
||||
|
||||
bool discord_voice_client::is_paused() {
|
||||
return this->paused;
|
||||
}
|
||||
|
||||
float discord_voice_client::get_secs_remaining() {
|
||||
std::lock_guard<std::mutex> lock(this->stream_mutex);
|
||||
/* Audio stream sends one packet every 60ms which means there are 16.666 packets per second */
|
||||
return (outbuf.size() / 16.666666);
|
||||
}
|
||||
|
||||
dpp::utility::uptime discord_voice_client::get_remaining() {
|
||||
float fp_secs = get_secs_remaining();
|
||||
return dpp::utility::uptime((time_t)ceil(fp_secs));
|
||||
}
|
||||
|
||||
void discord_voice_client::stop_audio() {
|
||||
std::lock_guard<std::mutex> lock(this->stream_mutex);
|
||||
outbuf.clear();
|
||||
}
|
||||
|
||||
void discord_voice_client::Send(const char* packet, size_t len) {
|
||||
std::lock_guard<std::mutex> lock(this->stream_mutex);
|
||||
outbuf.push_back(std::string(packet, len));
|
||||
}
|
||||
|
||||
void discord_voice_client::ReadReady()
|
||||
{
|
||||
/* XXX Decoding of voice not currently supported.
|
||||
* Audio stream will always be a nullptr until then.
|
||||
* See: https://github.com/discord/discord-api-docs/issues/365
|
||||
* See also: https://github.com/discord/discord-api-docs/issues/1337
|
||||
*/
|
||||
uint8_t buffer[65535];
|
||||
int r = this->UDPRecv((char*)buffer, sizeof(buffer));
|
||||
if (r > 0 && creator->dispatch.voice_receive) {
|
||||
voice_receive_t vr(nullptr, std::string((const char*)buffer, r));
|
||||
vr.voice_client = this;
|
||||
vr.audio = nullptr;
|
||||
vr.audio_size = 0;
|
||||
creator->dispatch.voice_receive(vr);
|
||||
}
|
||||
}
|
||||
|
||||
void discord_voice_client::WriteReady()
|
||||
{
|
||||
bool call_event = false;
|
||||
bool track_marker_found = false;
|
||||
uint64_t bufsize = 0;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(this->stream_mutex);
|
||||
if (!this->paused && outbuf.size()) {
|
||||
|
||||
if (outbuf[0].size() == 2 && ((uint16_t)(*(outbuf[0].data()))) == AUDIO_TRACK_MARKER) {
|
||||
outbuf.erase(outbuf.begin());
|
||||
track_marker_found = true;
|
||||
if (tracks > 0)
|
||||
tracks--;
|
||||
}
|
||||
if (outbuf.size()) {
|
||||
if (this->UDPSend(outbuf[0].data(), outbuf[0].length()) == outbuf[0].length()) {
|
||||
outbuf.erase(outbuf.begin());
|
||||
call_event = true;
|
||||
bufsize = outbuf.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (call_event) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(60));
|
||||
if (creator->dispatch.voice_buffer_send) {
|
||||
voice_buffer_send_t snd(nullptr, "");
|
||||
snd.buffer_size = bufsize;
|
||||
snd.voice_client = this;
|
||||
creator->dispatch.voice_buffer_send(snd);
|
||||
}
|
||||
}
|
||||
if (track_marker_found) {
|
||||
if (creator->dispatch.voice_track_marker) {
|
||||
voice_track_marker_t vtm(nullptr, "");
|
||||
vtm.voice_client = this;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(this->stream_mutex);
|
||||
if (track_meta.size()) {
|
||||
vtm.track_meta = track_meta[0];
|
||||
track_meta.erase(track_meta.begin());
|
||||
}
|
||||
}
|
||||
creator->dispatch.voice_track_marker(vtm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dpp::utility::uptime discord_voice_client::get_uptime()
|
||||
{
|
||||
return dpp::utility::uptime(time(NULL) - connect_time);
|
||||
}
|
||||
|
||||
bool discord_voice_client::is_connected()
|
||||
{
|
||||
return (this->GetState() == CONNECTED);
|
||||
}
|
||||
|
||||
int discord_voice_client::WantWrite() {
|
||||
std::lock_guard<std::mutex> lock(this->stream_mutex);
|
||||
if (!this->paused && outbuf.size()) {
|
||||
return fd;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int discord_voice_client::WantRead() {
|
||||
return fd;
|
||||
}
|
||||
|
||||
void discord_voice_client::Error(uint32_t errorcode)
|
||||
{
|
||||
std::map<uint32_t, std::string> errortext = {
|
||||
{ 1000, "Socket shutdown" },
|
||||
{ 1001, "Client is leaving" },
|
||||
{ 1002, "Endpoint received a malformed frame" },
|
||||
{ 1003, "Endpoint received an unsupported frame" },
|
||||
{ 1004, "Reserved code" },
|
||||
{ 1005, "Expected close status, received none" },
|
||||
{ 1006, "No close code frame has been receieved" },
|
||||
{ 1007, "Endpoint received inconsistent message (e.g. malformed UTF-8)" },
|
||||
{ 1008, "Generic error" },
|
||||
{ 1009, "Endpoint won't process large frame" },
|
||||
{ 1010, "Client wanted an extension which server did not negotiate" },
|
||||
{ 1011, "Internal server error while operating" },
|
||||
{ 1012, "Server/service is restarting" },
|
||||
{ 1013, "Temporary server condition forced blocking client's request" },
|
||||
{ 1014, "Server acting as gateway received an invalid response" },
|
||||
{ 1015, "Transport Layer Security handshake failure" },
|
||||
{ 4001, "Unknown opcode" },
|
||||
{ 4002, "Failed to decode payload" },
|
||||
{ 4003, "Not authenticated" },
|
||||
{ 4004, "Authentication failed" },
|
||||
{ 4005, "Already authenticated" },
|
||||
{ 4006, "Session no longer valid" },
|
||||
{ 4009, "Session timeout" },
|
||||
{ 4011, "Server not found" },
|
||||
{ 4012, "Unknown protocol" },
|
||||
{ 4014, "Disconnected" },
|
||||
{ 4015, "Voice server crashed" },
|
||||
{ 4016, "Unknown encryption mode" }
|
||||
};
|
||||
std::string error = "Unknown error";
|
||||
auto i = errortext.find(errorcode);
|
||||
if (i != errortext.end()) {
|
||||
error = i->second;
|
||||
}
|
||||
log(dpp::ll_warning, fmt::format("Voice session error: {} on channel {}: {}", errorcode, channel_id, error));
|
||||
|
||||
/* Errors 4004...4016 except 4014 are fatal and cause termination of the voice session */
|
||||
if (errorcode >= 4003 && errorcode != 4014) {
|
||||
stop_audio();
|
||||
this->terminating = true;
|
||||
log(dpp::ll_error, "This is a non-recoverable error, giving up on voice connection");
|
||||
}
|
||||
}
|
||||
|
||||
void discord_voice_client::log(dpp::loglevel severity, const std::string &msg)
|
||||
{
|
||||
creator->log(severity, msg);
|
||||
}
|
||||
|
||||
void discord_voice_client::QueueMessage(const std::string &j, bool to_front)
|
||||
{
|
||||
std::lock_guard<std::mutex> locker(queue_mutex);
|
||||
if (to_front) {
|
||||
message_queue.push_front(j);
|
||||
} else {
|
||||
message_queue.push_back(j);
|
||||
}
|
||||
}
|
||||
|
||||
void discord_voice_client::ClearQueue()
|
||||
{
|
||||
std::lock_guard<std::mutex> locker(queue_mutex);
|
||||
message_queue.clear();
|
||||
}
|
||||
|
||||
size_t discord_voice_client::GetQueueSize()
|
||||
{
|
||||
std::lock_guard<std::mutex> locker(queue_mutex);
|
||||
return message_queue.size();
|
||||
}
|
||||
|
||||
const std::vector<std::string> discord_voice_client::get_marker_metadata() {
|
||||
std::lock_guard<std::mutex> locker(queue_mutex);
|
||||
return track_meta;
|
||||
}
|
||||
|
||||
void discord_voice_client::one_second_timer()
|
||||
{
|
||||
if (terminating) {
|
||||
throw dpp::exception("Terminating voice connection");
|
||||
}
|
||||
/* Rate limit outbound messages, 1 every odd second, 2 every even second */
|
||||
if (this->GetState() == CONNECTED) {
|
||||
for (int x = 0; x < (time(NULL) % 2) + 1; ++x) {
|
||||
std::lock_guard<std::mutex> locker(queue_mutex);
|
||||
if (message_queue.size()) {
|
||||
std::string message = message_queue.front();
|
||||
message_queue.pop_front();
|
||||
this->write(message);
|
||||
}
|
||||
}
|
||||
|
||||
if (this->heartbeat_interval) {
|
||||
/* Check if we're due to emit a heartbeat */
|
||||
if (time(NULL) > last_heartbeat + ((heartbeat_interval / 1000.0) * 0.75)) {
|
||||
QueueMessage(json({{"op", 3}, {"d", rand()}}).dump(), true);
|
||||
last_heartbeat = time(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t discord_voice_client::encode(uint8_t *input, size_t inDataSize, uint8_t *output, size_t &outDataSize)
|
||||
{
|
||||
#if HAVE_VOICE
|
||||
outDataSize = 0;
|
||||
int mEncFrameBytes = 11520;
|
||||
int mEncFrameSize = 2880;
|
||||
if (0 == (inDataSize % mEncFrameBytes)) {
|
||||
bool isOk = true;
|
||||
size_t cur = 0;
|
||||
uint8_t *out = encode_buffer;
|
||||
|
||||
memset(out, 0, sizeof(encode_buffer));
|
||||
repacketizer = opus_repacketizer_init(repacketizer);
|
||||
for (size_t i = 0; i < (inDataSize / mEncFrameBytes); ++ i) {
|
||||
const opus_int16* pcm = (opus_int16*)(input + i * mEncFrameBytes);
|
||||
int ret = opus_encode(encoder, pcm, mEncFrameSize, out, 65536);
|
||||
if (ret > 0) {
|
||||
int retval = opus_repacketizer_cat(repacketizer, out, ret);
|
||||
if (retval != OPUS_OK) {
|
||||
isOk = false;
|
||||
log(ll_warning, fmt::format("opus_repacketizer_cat(): {}", opus_strerror(retval)));
|
||||
break;
|
||||
}
|
||||
out += ret;
|
||||
cur += ret;
|
||||
} else {
|
||||
isOk = false;
|
||||
log(ll_warning, fmt::format("opus_encode(): {}", opus_strerror(ret)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isOk) {
|
||||
int ret = opus_repacketizer_out(repacketizer, output, 65536);
|
||||
if (ret > 0) {
|
||||
outDataSize = ret;
|
||||
} else {
|
||||
log(ll_warning, fmt::format("opus_repacketizer_out(): {}", opus_strerror(ret)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw dpp::exception(fmt::format("Invalid input data length: {}, must be n times of {}", inDataSize, mEncFrameBytes));
|
||||
}
|
||||
#endif
|
||||
return outDataSize;
|
||||
}
|
||||
|
||||
void discord_voice_client::insert_marker(const std::string& metadata) {
|
||||
/* Insert a track marker. A track marker is a single 16 bit value of 0xFFFF.
|
||||
* This is too small to be a valid RTP packet so the send function knows not
|
||||
* to actually send it, and instead to skip it
|
||||
*/
|
||||
uint16_t tm = AUDIO_TRACK_MARKER;
|
||||
Send((const char*)&tm, sizeof(uint16_t));
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(this->stream_mutex);
|
||||
track_meta.push_back(metadata);
|
||||
tracks++;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t discord_voice_client::get_tracks_remaining() {
|
||||
std::lock_guard<std::mutex> lock(this->stream_mutex);
|
||||
if (outbuf.size() == 0)
|
||||
return 0;
|
||||
else
|
||||
return tracks + 1;
|
||||
}
|
||||
|
||||
void discord_voice_client::skip_to_next_marker() {
|
||||
std::lock_guard<std::mutex> lock(this->stream_mutex);
|
||||
/* Keep popping the first entry off the outbuf until the first entry is a track marker */
|
||||
while (outbuf.size() && outbuf[0].size() != sizeof(uint16_t) && ((uint16_t)(*(outbuf[0].data()))) != AUDIO_TRACK_MARKER) {
|
||||
outbuf.erase(outbuf.begin());
|
||||
}
|
||||
if (outbuf.size()) {
|
||||
/* Remove the actual track marker out of the buffer */
|
||||
outbuf.erase(outbuf.begin());
|
||||
}
|
||||
if (tracks > 0)
|
||||
tracks--;
|
||||
if (track_meta.size()) {
|
||||
track_meta.erase(track_meta.begin());
|
||||
}
|
||||
}
|
||||
|
||||
void discord_voice_client::send_audio(uint16_t* audio_data, const size_t length, bool use_opus) {
|
||||
#if HAVE_VOICE
|
||||
|
||||
const size_t max_frame_bytes = 11520;
|
||||
uint8_t pad[max_frame_bytes] = { 0 };
|
||||
if (length > max_frame_bytes && use_opus) {
|
||||
std::string s_audio_data((const char*)audio_data, length);
|
||||
while (s_audio_data.length() > max_frame_bytes) {
|
||||
std::string packet(s_audio_data.substr(0, max_frame_bytes));
|
||||
s_audio_data.erase(s_audio_data.begin(), s_audio_data.begin() + max_frame_bytes);
|
||||
if (packet.size() < max_frame_bytes) {
|
||||
packet.resize(max_frame_bytes, 0);
|
||||
}
|
||||
send_audio((uint16_t*)packet.data(), max_frame_bytes, use_opus);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int frameSize = 2880;
|
||||
opus_int32 encodedAudioMaxLength = length;
|
||||
std::vector<uint8_t> encodedAudioData(encodedAudioMaxLength);
|
||||
size_t encodedAudioLength = encodedAudioMaxLength;
|
||||
if (use_opus) {
|
||||
encodedAudioLength = this->encode((uint8_t*)audio_data, length, encodedAudioData.data(), encodedAudioLength);
|
||||
} else {
|
||||
}
|
||||
|
||||
++sequence;
|
||||
const int headerSize = 12;
|
||||
const int nonceSize = 24;
|
||||
rtp_header header(sequence, timestamp, ssrc);
|
||||
|
||||
int8_t nonce[nonceSize];
|
||||
std::memcpy(nonce, &header, sizeof(header));
|
||||
std::memset(nonce + sizeof(header), 0, sizeof(nonce) - sizeof(header));
|
||||
|
||||
std::vector<uint8_t> audioDataPacket(sizeof(header) + encodedAudioLength + crypto_secretbox_MACBYTES);
|
||||
std::memcpy(audioDataPacket.data(), &header, sizeof(header));
|
||||
|
||||
crypto_secretbox_easy(audioDataPacket.data() + sizeof(header), encodedAudioData.data(), encodedAudioLength, (const unsigned char*)nonce, secret_key);
|
||||
|
||||
Send((const char*)audioDataPacket.data(), audioDataPacket.size());
|
||||
timestamp += frameSize;
|
||||
|
||||
if (!this->sending) {
|
||||
this->QueueMessage(json({
|
||||
{"op", 5},
|
||||
{"d", {
|
||||
{"speaking", 1},
|
||||
{"delay", 0},
|
||||
{"ssrc", ssrc}
|
||||
}}
|
||||
}).dump(), true);
|
||||
sending = true;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string discord_voice_client::discover_ip() {
|
||||
SOCKET newfd = -1;
|
||||
unsigned char packet[74] = { 0 };
|
||||
(*(uint16_t*)(packet)) = htons(0x01);
|
||||
(*(uint16_t*)(packet + 2)) = htons(70);
|
||||
(*(uint32_t*)(packet + 4)) = htonl(this->ssrc);
|
||||
if ((newfd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) {
|
||||
sockaddr_in servaddr;
|
||||
socklen_t sl = sizeof(servaddr);
|
||||
memset(&servaddr, 0, sizeof(sockaddr_in));
|
||||
servaddr.sin_family = AF_INET;
|
||||
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
servaddr.sin_port = htons(0);
|
||||
if (bind(newfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {
|
||||
log(ll_warning, "Could not bind socket for IP discovery");
|
||||
return "";
|
||||
}
|
||||
memset(&servaddr, 0, sizeof(servaddr));
|
||||
servaddr.sin_family = AF_INET;
|
||||
servaddr.sin_port = htons(this->port);
|
||||
servaddr.sin_addr.s_addr = inet_addr(this->ip.c_str());
|
||||
if (::connect(newfd, (const struct sockaddr*)&servaddr, sizeof(sockaddr_in)) < 0) {
|
||||
log(ll_warning, "Could not connect socket for IP discovery");
|
||||
return "";
|
||||
}
|
||||
if (send(newfd, (const char*)packet, 74, 0) == -1) {
|
||||
log(ll_warning, "Could not send packet for IP discovery");
|
||||
return "";
|
||||
}
|
||||
if (recv(newfd, (char*)packet, 74, 0) == -1) {
|
||||
log(ll_warning, "Could not receive packet for IP discovery");
|
||||
return "";
|
||||
}
|
||||
|
||||
shutdown(newfd, 2);
|
||||
#ifdef _WIN32
|
||||
if (newfd >= 0 && newfd < FD_SETSIZE) {
|
||||
closesocket(newfd);
|
||||
}
|
||||
#else
|
||||
::close(newfd);
|
||||
#endif
|
||||
|
||||
//utility::debug_dump(packet, 74);
|
||||
return std::string((const char*)(packet + 8));
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
155
vendor/DPP/src/dpp/dispatcher.cpp
vendored
Normal file
155
vendor/DPP/src/dpp/dispatcher.cpp
vendored
Normal file
@ -0,0 +1,155 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/slashcommand.h>
|
||||
#include <dpp/dispatcher.h>
|
||||
#include <dpp/cluster.h>
|
||||
#include <fmt/format.h>
|
||||
#include <variant>
|
||||
|
||||
#define event_ctor(a, b) a::a(discord_client* client, const std::string &raw) : b(client, raw) {}
|
||||
|
||||
namespace dpp {
|
||||
|
||||
event_dispatch_t::event_dispatch_t(discord_client* client, const std::string &raw) : from(client), raw_event(raw)
|
||||
{
|
||||
}
|
||||
|
||||
void interaction_create_t::reply(interaction_response_type t, const message & m) const
|
||||
{
|
||||
from->creator->interaction_response_create(this->command.id, this->command.token, dpp::interaction_response(t, m));
|
||||
}
|
||||
|
||||
void interaction_create_t::reply(interaction_response_type t, const std::string & mt) const
|
||||
{
|
||||
this->reply(t, dpp::message(this->command.channel_id, mt, mt_application_command));
|
||||
}
|
||||
|
||||
void interaction_create_t::get_original_response(command_completion_event_t callback) const
|
||||
{
|
||||
from->creator->post_rest(API_PATH "/webhooks", std::to_string(command.application_id), command.token + "/messages/@original", m_get, "", [callback](json &j, const http_request_completion_t& http) {
|
||||
if (callback) {
|
||||
callback(confirmation_callback_t("message", message().fill_from_json(&j), http));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void interaction_create_t::edit_response(const message & m) const
|
||||
{
|
||||
from->creator->interaction_response_edit(this->command.token, m);
|
||||
}
|
||||
|
||||
void interaction_create_t::edit_response(const std::string & mt) const
|
||||
{
|
||||
this->edit_response(dpp::message(this->command.channel_id, mt, mt_application_command));
|
||||
}
|
||||
|
||||
const command_value& interaction_create_t::get_parameter(const std::string& name) const
|
||||
{
|
||||
/* Dummy STATIC return value for unknown options so we arent returning a value off the stack */
|
||||
static command_value dummy_value = {};
|
||||
const command_interaction& ci = std::get<command_interaction>(command.data);
|
||||
for (auto i = ci.options.begin(); i != ci.options.end(); ++i) {
|
||||
if (i->name == name) {
|
||||
return i->value;
|
||||
}
|
||||
}
|
||||
return dummy_value;
|
||||
}
|
||||
|
||||
const command_value& button_click_t::get_parameter(const std::string& name) const
|
||||
{
|
||||
/* Buttons don't have parameters, so override this */
|
||||
static command_value dummy_b_value = {};
|
||||
return dummy_b_value;
|
||||
}
|
||||
|
||||
const command_value& select_click_t::get_parameter(const std::string& name) const
|
||||
{
|
||||
/* Selects don't have parameters, so override this */
|
||||
static command_value dummy_b_value = {};
|
||||
return dummy_b_value;
|
||||
}
|
||||
|
||||
/* Standard default constructors that call the parent constructor, for events */
|
||||
event_ctor(guild_join_request_delete_t, event_dispatch_t);
|
||||
event_ctor(stage_instance_create_t, event_dispatch_t);
|
||||
event_ctor(stage_instance_delete_t, event_dispatch_t);
|
||||
event_ctor(log_t, event_dispatch_t);
|
||||
event_ctor(voice_state_update_t, event_dispatch_t);
|
||||
event_ctor(interaction_create_t, event_dispatch_t);
|
||||
event_ctor(button_click_t, interaction_create_t);
|
||||
event_ctor(select_click_t, interaction_create_t);
|
||||
event_ctor(guild_delete_t, event_dispatch_t);
|
||||
event_ctor(channel_delete_t, event_dispatch_t);
|
||||
event_ctor(channel_update_t, event_dispatch_t);
|
||||
event_ctor(ready_t, event_dispatch_t);
|
||||
event_ctor(message_delete_t, event_dispatch_t);
|
||||
event_ctor(application_command_delete_t, event_dispatch_t);
|
||||
event_ctor(application_command_create_t, event_dispatch_t);
|
||||
event_ctor(resumed_t, event_dispatch_t);
|
||||
event_ctor(guild_role_create_t, event_dispatch_t);
|
||||
event_ctor(typing_start_t, event_dispatch_t);
|
||||
event_ctor(message_reaction_add_t, event_dispatch_t);
|
||||
event_ctor(message_reaction_remove_t, event_dispatch_t);
|
||||
event_ctor(guild_create_t, event_dispatch_t);
|
||||
event_ctor(channel_create_t, event_dispatch_t);
|
||||
event_ctor(message_reaction_remove_emoji_t, event_dispatch_t);
|
||||
event_ctor(message_delete_bulk_t, event_dispatch_t);
|
||||
event_ctor(guild_role_update_t, event_dispatch_t);
|
||||
event_ctor(guild_role_delete_t, event_dispatch_t);
|
||||
event_ctor(channel_pins_update_t, event_dispatch_t);
|
||||
event_ctor(message_reaction_remove_all_t, event_dispatch_t);
|
||||
event_ctor(voice_server_update_t, event_dispatch_t);
|
||||
event_ctor(guild_emojis_update_t, event_dispatch_t);
|
||||
event_ctor(presence_update_t, event_dispatch_t);
|
||||
event_ctor(webhooks_update_t, event_dispatch_t);
|
||||
event_ctor(guild_member_add_t, event_dispatch_t);
|
||||
event_ctor(invite_delete_t, event_dispatch_t);
|
||||
event_ctor(guild_update_t, event_dispatch_t);
|
||||
event_ctor(guild_integrations_update_t, event_dispatch_t);
|
||||
event_ctor(guild_member_update_t, event_dispatch_t);
|
||||
event_ctor(application_command_update_t, event_dispatch_t);
|
||||
event_ctor(invite_create_t, event_dispatch_t);
|
||||
event_ctor(message_update_t, event_dispatch_t);
|
||||
event_ctor(user_update_t, event_dispatch_t);
|
||||
event_ctor(message_create_t, event_dispatch_t);
|
||||
event_ctor(guild_ban_add_t, event_dispatch_t);
|
||||
event_ctor(guild_ban_remove_t, event_dispatch_t);
|
||||
event_ctor(integration_create_t, event_dispatch_t);
|
||||
event_ctor(integration_update_t, event_dispatch_t);
|
||||
event_ctor(integration_delete_t, event_dispatch_t);
|
||||
event_ctor(guild_member_remove_t, event_dispatch_t);
|
||||
event_ctor(guild_members_chunk_t, event_dispatch_t);
|
||||
event_ctor(thread_create_t, event_dispatch_t);
|
||||
event_ctor(thread_update_t, event_dispatch_t);
|
||||
event_ctor(thread_delete_t, event_dispatch_t);
|
||||
event_ctor(thread_list_sync_t, event_dispatch_t);
|
||||
event_ctor(thread_member_update_t, event_dispatch_t);
|
||||
event_ctor(thread_members_update_t, event_dispatch_t);
|
||||
event_ctor(voice_buffer_send_t, event_dispatch_t);
|
||||
event_ctor(voice_user_talking_t, event_dispatch_t);
|
||||
event_ctor(voice_ready_t, event_dispatch_t);
|
||||
event_ctor(voice_receive_t, event_dispatch_t);
|
||||
event_ctor(voice_track_marker_t, event_dispatch_t);
|
||||
event_ctor(guild_stickers_update_t, event_dispatch_t);
|
||||
|
||||
};
|
64
vendor/DPP/src/dpp/dtemplate.cpp
vendored
Normal file
64
vendor/DPP/src/dpp/dtemplate.cpp
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/dtemplate.h>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp {
|
||||
|
||||
dtemplate::dtemplate() : code(""), name(""), description(""), usage_count(0), creator_id(0), source_guild_id(0)
|
||||
{
|
||||
}
|
||||
|
||||
dtemplate::~dtemplate() {
|
||||
}
|
||||
|
||||
|
||||
dtemplate& dtemplate::fill_from_json(nlohmann::json* j) {
|
||||
code = StringNotNull(j, "code");
|
||||
name = StringNotNull(j, "name");
|
||||
description = StringNotNull(j, "description");
|
||||
usage_count = Int32NotNull(j, "usage_count");
|
||||
creator_id = SnowflakeNotNull(j, "creator_id");
|
||||
created_at = TimestampNotNull(j, "created_at");
|
||||
updated_at = TimestampNotNull(j, "updated_at");
|
||||
source_guild_id = SnowflakeNotNull(j, "source_guild_id");
|
||||
is_dirty = BoolNotNull(j, "is_dirty");
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string dtemplate::build_json() const {
|
||||
json j({
|
||||
{"code", code},
|
||||
{"name", name},
|
||||
{"description", description},
|
||||
{"usage_count", usage_count},
|
||||
{"creator_id", creator_id},
|
||||
{"updated_at", updated_at},
|
||||
{"source_guild_id", source_guild_id,
|
||||
"is_dirty", is_dirty}
|
||||
});
|
||||
return j.dump();
|
||||
}
|
||||
|
||||
};
|
116
vendor/DPP/src/dpp/emoji.cpp
vendored
Normal file
116
vendor/DPP/src/dpp/emoji.cpp
vendored
Normal file
@ -0,0 +1,116 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/emoji.h>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/dispatcher.h>
|
||||
|
||||
namespace dpp {
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
emoji::emoji() : managed(), user_id(0), flags(0), image_data(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
emoji::emoji(const std::string n, const snowflake i, const uint8_t f)
|
||||
: managed(i), user_id(0), flags(f), image_data(nullptr), name(n)
|
||||
{
|
||||
}
|
||||
|
||||
emoji::~emoji() {
|
||||
if (image_data) {
|
||||
delete image_data;
|
||||
}
|
||||
}
|
||||
|
||||
emoji& emoji::fill_from_json(nlohmann::json* j) {
|
||||
id = SnowflakeNotNull(j, "id");
|
||||
name = StringNotNull(j, "name");
|
||||
if (j->find("user") != j->end()) {
|
||||
json & user = (*j)["user"];
|
||||
user_id = SnowflakeNotNull(&user, "id");
|
||||
}
|
||||
if (BoolNotNull(j, "require_colons"))
|
||||
flags |= e_require_colons;
|
||||
if (BoolNotNull(j, "managed"))
|
||||
flags |= e_managed;
|
||||
if (BoolNotNull(j, "animated"))
|
||||
flags |= e_animated;
|
||||
if (BoolNotNull(j, "available"))
|
||||
flags |= e_available;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string emoji::build_json(bool with_id) const {
|
||||
json j;
|
||||
if (with_id) {
|
||||
j["id"] = std::to_string(id);
|
||||
}
|
||||
j["name"] = name;
|
||||
if (image_data) {
|
||||
j["image"] = *image_data;
|
||||
}
|
||||
return j.dump();
|
||||
}
|
||||
|
||||
bool emoji::requires_colons() const {
|
||||
return flags & e_require_colons;
|
||||
}
|
||||
|
||||
bool emoji::is_managed() const {
|
||||
return flags & e_managed;
|
||||
}
|
||||
|
||||
bool emoji::is_animated() const {
|
||||
return flags & e_animated;
|
||||
}
|
||||
|
||||
bool emoji::is_available() const {
|
||||
return flags & e_available;
|
||||
}
|
||||
|
||||
emoji& emoji::load_image(const std::string &image_blob, image_type type) {
|
||||
static std::map<image_type, std::string> mimetypes = {
|
||||
{ i_gif, "image/gif" },
|
||||
{ i_jpg, "image/jpeg" },
|
||||
{ i_png, "image/png" }
|
||||
};
|
||||
if (image_blob.size() > MAX_EMOJI_SIZE) {
|
||||
throw dpp::exception("Emoji file exceeds discord limit of 256 kilobytes");
|
||||
}
|
||||
if (image_data) {
|
||||
/* If there's already image data defined, free the old data, to prevent a memory leak */
|
||||
delete image_data;
|
||||
}
|
||||
image_data = new std::string("data:" + mimetypes[type] + ";base64," + base64_encode((unsigned char const*)image_blob.data(), image_blob.length()));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string emoji::format() const
|
||||
{
|
||||
return id ? (name + ":" + std::to_string(id)) : name;
|
||||
}
|
||||
|
||||
};
|
||||
|
48
vendor/DPP/src/dpp/events/application_command_create.cpp
vendored
Normal file
48
vendor/DPP/src/dpp/events/application_command_create.cpp
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
#include <dpp/discord.h>
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void application_command_create::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
}
|
||||
|
||||
}};
|
48
vendor/DPP/src/dpp/events/application_command_delete.cpp
vendored
Normal file
48
vendor/DPP/src/dpp/events/application_command_delete.cpp
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void application_command_delete::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
}
|
||||
|
||||
}};
|
48
vendor/DPP/src/dpp/events/application_command_update.cpp
vendored
Normal file
48
vendor/DPP/src/dpp/events/application_command_update.cpp
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void application_command_update::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
}
|
||||
|
||||
}};
|
75
vendor/DPP/src/dpp/events/channel_create.cpp
vendored
Normal file
75
vendor/DPP/src/dpp/events/channel_create.cpp
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <fmt/format.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void channel_create::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
json& d = j["d"];
|
||||
|
||||
dpp::channel* c = dpp::find_channel(SnowflakeNotNull(&d, "id"));
|
||||
if (!c) {
|
||||
c = new dpp::channel();
|
||||
}
|
||||
c->fill_from_json(&d);
|
||||
dpp::get_channel_cache()->store(c);
|
||||
if (c->recipients.size()) {
|
||||
for (auto & u : c->recipients) {
|
||||
client->log(dpp::ll_debug, fmt::format("Got a DM channel {} for user {}", c->id, u));
|
||||
client->creator->set_dm_channel(u, c->id);
|
||||
}
|
||||
}
|
||||
dpp::guild* g = dpp::find_guild(c->guild_id);
|
||||
if (g) {
|
||||
g->channels.push_back(c->id);
|
||||
|
||||
if (client->creator->dispatch.channel_create) {
|
||||
dpp::channel_create_t cc(client, raw);
|
||||
cc.created = c;
|
||||
cc.creating_guild = g;
|
||||
client->creator->dispatch.channel_create(cc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
69
vendor/DPP/src/dpp/events/channel_delete.cpp
vendored
Normal file
69
vendor/DPP/src/dpp/events/channel_delete.cpp
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void channel_delete::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
json& d = j["d"];
|
||||
dpp::channel* c = dpp::find_channel(SnowflakeNotNull(&d, "id"));
|
||||
if (c) {
|
||||
dpp::guild* g = dpp::find_guild(c->guild_id);
|
||||
if (g) {
|
||||
auto gc = std::find(g->channels.begin(), g->channels.end(), c->id);
|
||||
if (gc != g->channels.end()) {
|
||||
g->channels.erase(gc);
|
||||
}
|
||||
|
||||
if (client->creator->dispatch.channel_delete) {
|
||||
dpp::channel_delete_t cd(client, raw);
|
||||
cd.deleted = c;
|
||||
cd.deleting_guild = g;
|
||||
client->creator->dispatch.channel_delete(cd);
|
||||
}
|
||||
}
|
||||
dpp::get_channel_cache()->remove(c);
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
61
vendor/DPP/src/dpp/events/channel_pins_update.cpp
vendored
Normal file
61
vendor/DPP/src/dpp/events/channel_pins_update.cpp
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void channel_pins_update::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
|
||||
if (client->creator->dispatch.channel_pins_update) {
|
||||
json& d = j["d"];
|
||||
dpp::channel_pins_update_t cpu(client, raw);
|
||||
cpu.pin_channel = dpp::find_channel(SnowflakeNotNull(&d, "channel_id"));
|
||||
cpu.pin_guild = dpp::find_guild(SnowflakeNotNull(&d, "guild_id"));
|
||||
cpu.timestamp = TimestampNotNull(&d, "last_pin_timestamp");
|
||||
|
||||
client->creator->dispatch.channel_pins_update(cpu);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}};
|
59
vendor/DPP/src/dpp/events/channel_update.cpp
vendored
Normal file
59
vendor/DPP/src/dpp/events/channel_update.cpp
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void channel_update::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
json& d = j["d"];
|
||||
dpp::channel* c = dpp::find_channel(from_string<uint64_t>(d["id"].get<std::string>(), std::dec));
|
||||
if (c) {
|
||||
c->fill_from_json(&d);
|
||||
if (client->creator->dispatch.channel_update) {
|
||||
dpp::channel_update_t cu(client, raw);
|
||||
cu.updated = c;
|
||||
cu.updating_guild = dpp::find_guild(c->guild_id);
|
||||
client->creator->dispatch.channel_update(cu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
57
vendor/DPP/src/dpp/events/guild_ban_add.cpp
vendored
Normal file
57
vendor/DPP/src/dpp/events/guild_ban_add.cpp
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void guild_ban_add::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
if (client->creator->dispatch.guild_ban_add) {
|
||||
json &d = j["d"];
|
||||
dpp::guild_ban_add_t gba(client, raw);
|
||||
gba.banning_guild = dpp::find_guild(SnowflakeNotNull(&d, "guild_id"));
|
||||
gba.banned = dpp::user().fill_from_json(&(d["user"]));
|
||||
client->creator->dispatch.guild_ban_add(gba);
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
57
vendor/DPP/src/dpp/events/guild_ban_remove.cpp
vendored
Normal file
57
vendor/DPP/src/dpp/events/guild_ban_remove.cpp
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void guild_ban_remove::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
if (client->creator->dispatch.guild_ban_remove) {
|
||||
json &d = j["d"];
|
||||
dpp::guild_ban_remove_t gbr(client, raw);
|
||||
gbr.unbanning_guild = dpp::find_guild(SnowflakeNotNull(&d, "guild_id"));
|
||||
gbr.unbanned = dpp::user().fill_from_json(&(d["user"]));
|
||||
client->creator->dispatch.guild_ban_remove(gbr);
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
149
vendor/DPP/src/dpp/events/guild_create.cpp
vendored
Normal file
149
vendor/DPP/src/dpp/events/guild_create.cpp
vendored
Normal file
@ -0,0 +1,149 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void guild_create::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
json& d = j["d"];
|
||||
bool newguild = false;
|
||||
if (SnowflakeNotNull(&d, "id") == 0)
|
||||
return;
|
||||
dpp::guild* g = dpp::find_guild(SnowflakeNotNull(&d, "id"));
|
||||
if (!g) {
|
||||
g = new dpp::guild();
|
||||
newguild = true;
|
||||
}
|
||||
g->fill_from_json(client, &d);
|
||||
g->shard_id = client->shard_id;
|
||||
if (!g->is_unavailable() && newguild) {
|
||||
if (client->creator->cache_policy.role_policy != dpp::cp_none) {
|
||||
/* Store guild roles */
|
||||
g->roles.clear();
|
||||
g->roles.reserve(d["roles"].size());
|
||||
for (auto & role : d["roles"]) {
|
||||
dpp::role *r = dpp::find_role(SnowflakeNotNull(&role, "id"));
|
||||
if (!r) {
|
||||
r = new dpp::role();
|
||||
}
|
||||
r->fill_from_json(g->id, &role);
|
||||
dpp::get_role_cache()->store(r);
|
||||
g->roles.push_back(r->id);
|
||||
}
|
||||
}
|
||||
|
||||
/* Store guild channels */
|
||||
g->channels.clear();
|
||||
g->channels.reserve(d["channels"].size());
|
||||
for (auto & channel : d["channels"]) {
|
||||
dpp::channel* c = dpp::find_channel(SnowflakeNotNull(&channel, "id"));
|
||||
if (!c) {
|
||||
c = new dpp::channel();
|
||||
}
|
||||
c->fill_from_json(&channel);
|
||||
c->guild_id = g->id;
|
||||
dpp::get_channel_cache()->store(c);
|
||||
g->channels.push_back(c->id);
|
||||
}
|
||||
|
||||
/* Store guild threads */
|
||||
g->threads.clear();
|
||||
g->threads.reserve(d["threads"].size());
|
||||
for (auto & channel : d["threads"]) {
|
||||
g->threads.push_back(SnowflakeNotNull(&channel, "id"));
|
||||
}
|
||||
|
||||
/* Store guild members */
|
||||
if (client->creator->cache_policy.user_policy == cp_aggressive) {
|
||||
g->members.reserve(d["members"].size());
|
||||
for (auto & user : d["members"]) {
|
||||
snowflake userid = SnowflakeNotNull(&(user["user"]), "id");
|
||||
/* Only store ones we don't have already otherwise gm will leak */
|
||||
if (g->members.find(userid) == g->members.end()) {
|
||||
dpp::user* u = dpp::find_user(userid);
|
||||
if (!u) {
|
||||
u = new dpp::user();
|
||||
u->fill_from_json(&(user["user"]));
|
||||
dpp::get_user_cache()->store(u);
|
||||
} else {
|
||||
u->refcount++;
|
||||
}
|
||||
dpp::guild_member gm;
|
||||
gm.fill_from_json(&(user["user"]), g->id, userid);
|
||||
g->members[userid] = gm;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (client->creator->cache_policy.emoji_policy != dpp::cp_none) {
|
||||
/* Store emojis */
|
||||
g->emojis.reserve(d["emojis"].size());
|
||||
g->emojis = {};
|
||||
for (auto & emoji : d["emojis"]) {
|
||||
dpp::emoji* e = dpp::find_emoji(SnowflakeNotNull(&emoji, "id"));
|
||||
if (!e) {
|
||||
e = new dpp::emoji();
|
||||
e->fill_from_json(&emoji);
|
||||
dpp::get_emoji_cache()->store(e);
|
||||
}
|
||||
g->emojis.push_back(e->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
dpp::get_guild_cache()->store(g);
|
||||
if (newguild && g->id && (client->intents & dpp::i_guild_members)) {
|
||||
if (client->creator->cache_policy.user_policy == cp_aggressive) {
|
||||
json chunk_req = json({{"op", 8}, {"d", {{"guild_id",std::to_string(g->id)},{"query",""},{"limit",0}}}});
|
||||
if (client->intents & dpp::i_guild_presences) {
|
||||
chunk_req["d"]["presences"] = true;
|
||||
}
|
||||
client->QueueMessage(chunk_req.dump());
|
||||
}
|
||||
}
|
||||
|
||||
if (client->creator->dispatch.guild_create) {
|
||||
dpp::guild_create_t gc(client, raw);
|
||||
gc.created = g;
|
||||
client->creator->dispatch.guild_create(gc);
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
98
vendor/DPP/src/dpp/events/guild_delete.cpp
vendored
Normal file
98
vendor/DPP/src/dpp/events/guild_delete.cpp
vendored
Normal file
@ -0,0 +1,98 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void guild_delete::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
json& d = j["d"];
|
||||
dpp::guild* g = dpp::find_guild(SnowflakeNotNull(&d, "id"));
|
||||
if (g) {
|
||||
if (!BoolNotNull(&d, "unavailable")) {
|
||||
dpp::get_guild_cache()->remove(g);
|
||||
if (client->creator->cache_policy.emoji_policy != dpp::cp_none) {
|
||||
for (auto & ee : g->emojis) {
|
||||
dpp::emoji* fe = dpp::find_emoji(ee);
|
||||
if (fe) {
|
||||
dpp::get_emoji_cache()->remove(fe);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (client->creator->cache_policy.role_policy != dpp::cp_none) {
|
||||
for (auto & rr : g->roles) {
|
||||
dpp::role* role = dpp::find_role(rr);
|
||||
if (role) {
|
||||
dpp::get_role_cache()->remove(role);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto & cc : g->channels) {
|
||||
dpp::channel* ch = dpp::find_channel(cc);
|
||||
if (ch) {
|
||||
dpp::get_channel_cache()->remove(ch);
|
||||
}
|
||||
}
|
||||
if (client->creator->cache_policy.user_policy != dpp::cp_none) {
|
||||
for (auto gm = g->members.begin(); gm != g->members.end(); ++gm) {
|
||||
dpp::user* u = dpp::find_user(gm->second.user_id);
|
||||
if (u) {
|
||||
u->refcount--;
|
||||
if (u->refcount < 1) {
|
||||
dpp::get_user_cache()->remove(u);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
g->members.clear();
|
||||
} else {
|
||||
g->flags |= dpp::g_unavailable;
|
||||
}
|
||||
|
||||
if (client->creator->dispatch.guild_delete) {
|
||||
dpp::guild_delete_t gd(client, raw);
|
||||
gd.deleted = g;
|
||||
client->creator->dispatch.guild_delete(gd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
78
vendor/DPP/src/dpp/events/guild_emojis_update.cpp
vendored
Normal file
78
vendor/DPP/src/dpp/events/guild_emojis_update.cpp
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void guild_emojis_update::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
json& d = j["d"];
|
||||
dpp::guild* g = dpp::find_guild(SnowflakeNotNull(&d, "guild_id"));
|
||||
if (g) {
|
||||
if (client->creator->cache_policy.emoji_policy != dpp::cp_none) {
|
||||
for (auto & ee : g->emojis) {
|
||||
dpp::emoji* fe = dpp::find_emoji(ee);
|
||||
if (fe) {
|
||||
dpp::get_emoji_cache()->remove(fe);
|
||||
}
|
||||
}
|
||||
g->emojis.clear();
|
||||
for (auto & emoji : d["emojis"]) {
|
||||
dpp::emoji* e = dpp::find_emoji(SnowflakeNotNull(&emoji, "id"));
|
||||
if (!e) {
|
||||
e = new dpp::emoji();
|
||||
e->fill_from_json(&emoji);
|
||||
dpp::get_emoji_cache()->store(e);
|
||||
}
|
||||
g->emojis.push_back(e->id);
|
||||
}
|
||||
}
|
||||
if (client->creator->dispatch.guild_emojis_update) {
|
||||
dpp::guild_emojis_update_t geu(client, raw);
|
||||
geu.emojis = g->emojis;
|
||||
geu.updating_guild = g;
|
||||
client->creator->dispatch.guild_emojis_update(geu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
55
vendor/DPP/src/dpp/events/guild_integrations_update.cpp
vendored
Normal file
55
vendor/DPP/src/dpp/events/guild_integrations_update.cpp
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void guild_integrations_update::handle(class discord_client* client, json &j, const std::string &raw) {
|
||||
if (client->creator->dispatch.guild_integrations_update) {
|
||||
json& d = j["d"];
|
||||
dpp::guild_integrations_update_t giu(client, raw);
|
||||
giu.updating_guild = dpp::find_guild(SnowflakeNotNull(&d, "guild_id"));
|
||||
client->creator->dispatch.guild_integrations_update(giu);
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
56
vendor/DPP/src/dpp/events/guild_join_request_delete.cpp
vendored
Normal file
56
vendor/DPP/src/dpp/events/guild_join_request_delete.cpp
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void guild_join_request_delete::handle(class discord_client* client, json &j, const std::string &raw) {
|
||||
if (client->creator->dispatch.guild_join_request_delete) {
|
||||
json& d = j["d"];
|
||||
dpp::guild_join_request_delete_t grd(client, raw);
|
||||
grd.user_id = SnowflakeNotNull(&d, "user_id");
|
||||
grd.guild_id = SnowflakeNotNull(&d, "guild_id");
|
||||
client->creator->dispatch.guild_join_request_delete(grd);
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
86
vendor/DPP/src/dpp/events/guild_member_add.cpp
vendored
Normal file
86
vendor/DPP/src/dpp/events/guild_member_add.cpp
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void guild_member_add::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
json d = j["d"];
|
||||
|
||||
dpp::guild* g = dpp::find_guild(SnowflakeNotNull(&d, "guild_id"));
|
||||
dpp::guild_member_add_t gmr(client, raw);
|
||||
if (g) {
|
||||
if (client->creator->cache_policy.user_policy == dpp::cp_none) {
|
||||
dpp::guild_member gm;
|
||||
gm.fill_from_json(&d, g->id, SnowflakeNotNull(&(d["user"]), "id"));
|
||||
gmr.added = gm;
|
||||
if (client->creator->dispatch.guild_member_add) {
|
||||
gmr.adding_guild = g;
|
||||
client->creator->dispatch.guild_member_add(gmr);
|
||||
}
|
||||
} else {
|
||||
dpp::user* u = dpp::find_user(SnowflakeNotNull(&(d["user"]), "id"));
|
||||
if (!u) {
|
||||
u = new dpp::user();
|
||||
u->fill_from_json(&(d["user"]));
|
||||
dpp::get_user_cache()->store(u);
|
||||
} else {
|
||||
u->refcount++;
|
||||
}
|
||||
dpp::guild_member gm;
|
||||
gmr.added = {};
|
||||
if (u && u->id && g->members.find(u->id) == g->members.end()) {
|
||||
gm.fill_from_json(&d, g->id, u->id);
|
||||
g->members[u->id] = gm;
|
||||
gmr.added = gm;
|
||||
} else if (u && u->id) {
|
||||
gmr.added = g->members.find(u->id)->second;
|
||||
}
|
||||
if (client->creator->dispatch.guild_member_add) {
|
||||
gmr.adding_guild = g;
|
||||
client->creator->dispatch.guild_member_add(gmr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
83
vendor/DPP/src/dpp/events/guild_member_remove.cpp
vendored
Normal file
83
vendor/DPP/src/dpp/events/guild_member_remove.cpp
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void guild_member_remove::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
json d = j["d"];
|
||||
|
||||
dpp::guild_member_remove_t gmr(client, raw);
|
||||
|
||||
gmr.removing_guild = dpp::find_guild(SnowflakeNotNull(&d, "guild_id"));
|
||||
|
||||
if (client->creator->cache_policy.user_policy == dpp::cp_none) {
|
||||
dpp::user u;
|
||||
u.fill_from_json(&(d["user"]));
|
||||
gmr.removed = &u;
|
||||
if (client->creator->dispatch.guild_member_remove)
|
||||
client->creator->dispatch.guild_member_remove(gmr);
|
||||
} else {
|
||||
|
||||
gmr.removed = dpp::find_user(SnowflakeNotNull(&(d["user"]), "id"));
|
||||
|
||||
if (client->creator->dispatch.guild_member_remove)
|
||||
client->creator->dispatch.guild_member_remove(gmr);
|
||||
|
||||
if (gmr.removing_guild && gmr.removed) {
|
||||
auto i = gmr.removing_guild->members.find(gmr.removed->id);
|
||||
if (i != gmr.removing_guild->members.end()) {
|
||||
dpp::user* u = dpp::find_user(gmr.removed->id);
|
||||
if (u) {
|
||||
u->refcount--;
|
||||
if (u->refcount < 1) {
|
||||
dpp::get_user_cache()->remove(u);
|
||||
}
|
||||
}
|
||||
gmr.removing_guild->members.erase(i);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
78
vendor/DPP/src/dpp/events/guild_member_update.cpp
vendored
Normal file
78
vendor/DPP/src/dpp/events/guild_member_update.cpp
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void guild_member_update::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
json& d = j["d"];
|
||||
dpp::guild* g = dpp::find_guild(from_string<uint64_t>(d["guild_id"].get<std::string>(), std::dec));
|
||||
if (client->creator->cache_policy.user_policy == dpp::cp_none) {
|
||||
dpp::user u;
|
||||
u.fill_from_json(&(d["user"]));
|
||||
if (g && client->creator->dispatch.guild_member_update) {
|
||||
dpp::guild_member_update_t gmu(client, raw);
|
||||
gmu.updating_guild = g;
|
||||
guild_member m;
|
||||
auto& user = d;//d["user"]; // d contains roles and other member stuff already
|
||||
m.fill_from_json(&user, g->id, u.id);
|
||||
gmu.updated = m;
|
||||
client->creator->dispatch.guild_member_update(gmu);
|
||||
}
|
||||
} else {
|
||||
dpp::user* u = dpp::find_user(from_string<uint64_t>(d["user"]["id"].get<std::string>(), std::dec));
|
||||
if (g && u) {
|
||||
auto& user = d;//d["user"]; // d contains roles and other member stuff already
|
||||
guild_member m;
|
||||
m.fill_from_json(&user, g->id, u->id);
|
||||
g->members[u->id] = m;
|
||||
|
||||
if (client->creator->dispatch.guild_member_update) {
|
||||
dpp::guild_member_update_t gmu(client, raw);
|
||||
gmu.updating_guild = g;
|
||||
gmu.updated = m;
|
||||
client->creator->dispatch.guild_member_update(gmu);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
79
vendor/DPP/src/dpp/events/guild_members_chunk.cpp
vendored
Normal file
79
vendor/DPP/src/dpp/events/guild_members_chunk.cpp
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void guild_members_chunk::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
json &d = j["d"];
|
||||
dpp::guild_member_map um;
|
||||
dpp::guild* g = dpp::find_guild(SnowflakeNotNull(&d, "guild_id"));
|
||||
if (g) {
|
||||
/* Store guild members */
|
||||
if (client->creator->cache_policy.user_policy == cp_aggressive) {
|
||||
for (auto & userrec : d["members"]) {
|
||||
json & userspart = userrec["user"];
|
||||
dpp::user* u = dpp::find_user(SnowflakeNotNull(&userspart, "id"));
|
||||
if (!u) {
|
||||
u = new dpp::user();
|
||||
u->fill_from_json(&userspart);
|
||||
dpp::get_user_cache()->store(u);
|
||||
}
|
||||
if (g->members.find(u->id) == g->members.end()) {
|
||||
dpp::guild_member gm;
|
||||
gm.fill_from_json(&userrec, g->id, u->id);
|
||||
g->members[u->id] = gm;
|
||||
if (client->creator->dispatch.guild_members_chunk)
|
||||
um[u->id] = gm;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (client->creator->dispatch.guild_members_chunk) {
|
||||
dpp::guild_members_chunk_t gmc(client, raw);
|
||||
gmc.adding = g;
|
||||
gmc.members = &um;
|
||||
client->creator->dispatch.guild_members_chunk(gmc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
79
vendor/DPP/src/dpp/events/guild_role_create.cpp
vendored
Normal file
79
vendor/DPP/src/dpp/events/guild_role_create.cpp
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void guild_role_create::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
json &d = j["d"];
|
||||
dpp::guild* g = dpp::find_guild(SnowflakeNotNull(&d, "guild_id"));
|
||||
if (g) {
|
||||
if (client->creator->cache_policy.role_policy == dpp::cp_none) {
|
||||
json &role = d["role"];
|
||||
dpp::role r;
|
||||
r.fill_from_json(g->id, &role);
|
||||
if (client->creator->dispatch.guild_role_create) {
|
||||
dpp::guild_role_create_t grc(client, raw);
|
||||
grc.creating_guild = g;
|
||||
grc.created = &r;
|
||||
client->creator->dispatch.guild_role_create(grc);
|
||||
}
|
||||
} else {
|
||||
json &role = d["role"];
|
||||
dpp::role *r = dpp::find_role(SnowflakeNotNull(&role, "id"));
|
||||
if (!r) {
|
||||
r = new dpp::role();
|
||||
}
|
||||
r->fill_from_json(g->id, &role);
|
||||
dpp::get_role_cache()->store(r);
|
||||
g->roles.push_back(r->id);
|
||||
if (client->creator->dispatch.guild_role_create) {
|
||||
dpp::guild_role_create_t grc(client, raw);
|
||||
grc.creating_guild = g;
|
||||
grc.created = r;
|
||||
client->creator->dispatch.guild_role_create(grc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
80
vendor/DPP/src/dpp/events/guild_role_delete.cpp
vendored
Normal file
80
vendor/DPP/src/dpp/events/guild_role_delete.cpp
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void guild_role_delete::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
json &d = j["d"];
|
||||
dpp::guild* g = dpp::find_guild(SnowflakeNotNull(&d, "guild_id"));
|
||||
if (g) {
|
||||
if (client->creator->cache_policy.role_policy == dpp::cp_none) {
|
||||
json& role = d["role"];
|
||||
dpp::role r;
|
||||
r.fill_from_json(g->id, &d);
|
||||
if (client->creator->dispatch.guild_role_delete) {
|
||||
dpp::guild_role_delete_t grd(client, raw);
|
||||
grd.deleting_guild = g;
|
||||
grd.deleted = &r;
|
||||
client->creator->dispatch.guild_role_delete(grd);
|
||||
}
|
||||
} else {
|
||||
json& role = d["role"];
|
||||
dpp::role *r = dpp::find_role(SnowflakeNotNull(&role, "id"));
|
||||
if (r) {
|
||||
if (client->creator->dispatch.guild_role_delete) {
|
||||
dpp::guild_role_delete_t grd(client, raw);
|
||||
grd.deleting_guild = g;
|
||||
grd.deleted = r;
|
||||
client->creator->dispatch.guild_role_delete(grd);
|
||||
}
|
||||
auto i = std::find(g->roles.begin(), g->roles.end(), r->id);
|
||||
if (i != g->roles.end()) {
|
||||
g->roles.erase(i);
|
||||
}
|
||||
dpp::get_role_cache()->remove(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
76
vendor/DPP/src/dpp/events/guild_role_update.cpp
vendored
Normal file
76
vendor/DPP/src/dpp/events/guild_role_update.cpp
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void guild_role_update::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
json &d = j["d"];
|
||||
dpp::guild* g = dpp::find_guild(SnowflakeNotNull(&d, "guild_id"));
|
||||
if (g) {
|
||||
if (client->creator->cache_policy.role_policy == dpp::cp_none) {
|
||||
json& role = d["role"];
|
||||
dpp::role r;
|
||||
r.fill_from_json(g->id, &d);
|
||||
if (client->creator->dispatch.guild_role_update) {
|
||||
dpp::guild_role_update_t gru(client, raw);
|
||||
gru.updating_guild = g;
|
||||
gru.updated = &r;
|
||||
client->creator->dispatch.guild_role_update(gru);
|
||||
}
|
||||
} else {
|
||||
json& role = d["role"];
|
||||
dpp::role *r = dpp::find_role(SnowflakeNotNull(&role, "id"));
|
||||
if (r) {
|
||||
r->fill_from_json(g->id, &role);
|
||||
if (client->creator->dispatch.guild_role_update) {
|
||||
dpp::guild_role_update_t gru(client, raw);
|
||||
gru.updating_guild = g;
|
||||
gru.updated = r;
|
||||
client->creator->dispatch.guild_role_update(gru);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
64
vendor/DPP/src/dpp/events/guild_stickers_update.cpp
vendored
Normal file
64
vendor/DPP/src/dpp/events/guild_stickers_update.cpp
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void guild_stickers_update::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
json& d = j["d"];
|
||||
dpp::guild* g = dpp::find_guild(SnowflakeNotNull(&d, "guild_id"));
|
||||
if (g) {
|
||||
if (client->creator->dispatch.stickers_update) {
|
||||
dpp::guild_stickers_update_t gsu(client, raw);
|
||||
for (auto & sticker : d["stickers"]) {
|
||||
dpp::sticker s;
|
||||
s.fill_from_json(&sticker);
|
||||
gsu.stickers.push_back(s);
|
||||
}
|
||||
gsu.updating_guild = g;
|
||||
client->creator->dispatch.stickers_update(gsu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
74
vendor/DPP/src/dpp/events/guild_update.cpp
vendored
Normal file
74
vendor/DPP/src/dpp/events/guild_update.cpp
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void guild_update::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
json& d = j["d"];
|
||||
dpp::guild* g = dpp::find_guild(from_string<uint64_t>(d["id"].get<std::string>(), std::dec));
|
||||
if (g) {
|
||||
g->fill_from_json(client, &d);
|
||||
if (!g->is_unavailable()) {
|
||||
if (client->creator->cache_policy.role_policy != dpp::cp_none && d.find("roles") != d.end()) {
|
||||
for (int rc = 0; rc < g->roles.size(); ++rc) {
|
||||
dpp::role* oldrole = dpp::find_role(g->roles[rc]);
|
||||
dpp::get_role_cache()->remove(oldrole);
|
||||
}
|
||||
g->roles.clear();
|
||||
for (auto & role : d["roles"]) {
|
||||
dpp::role *r = new dpp::role();
|
||||
r->fill_from_json(g->id, &role);
|
||||
dpp::get_role_cache()->store(r);
|
||||
g->roles.push_back(r->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (client->creator->dispatch.guild_update) {
|
||||
dpp::guild_update_t gu(client, raw);
|
||||
gu.updated = g;
|
||||
client->creator->dispatch.guild_update(gu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
56
vendor/DPP/src/dpp/events/integration_create.cpp
vendored
Normal file
56
vendor/DPP/src/dpp/events/integration_create.cpp
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void integration_create::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
if (client->creator->dispatch.integration_create) {
|
||||
json& d = j["d"];
|
||||
dpp::integration_create_t ic(client, raw);
|
||||
ic.created_integration = dpp::integration().fill_from_json(&d);
|
||||
client->creator->dispatch.integration_create(ic);
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
55
vendor/DPP/src/dpp/events/integration_delete.cpp
vendored
Normal file
55
vendor/DPP/src/dpp/events/integration_delete.cpp
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void integration_delete::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
if (client->creator->dispatch.integration_delete) {
|
||||
json& d = j["d"];
|
||||
dpp::integration_delete_t id(client, raw);
|
||||
id.deleted_integration = dpp::integration().fill_from_json(&d);
|
||||
client->creator->dispatch.integration_delete(id);
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
55
vendor/DPP/src/dpp/events/integration_update.cpp
vendored
Normal file
55
vendor/DPP/src/dpp/events/integration_update.cpp
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void integration_update::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
if (client->creator->dispatch.integration_update) {
|
||||
json& d = j["d"];
|
||||
dpp::integration_update_t iu(client, raw);
|
||||
iu.updated_integration = dpp::integration().fill_from_json(&d);
|
||||
client->creator->dispatch.integration_update(iu);
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
83
vendor/DPP/src/dpp/events/interaction_create.cpp
vendored
Normal file
83
vendor/DPP/src/dpp/events/interaction_create.cpp
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void interaction_create::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
json& d = j["d"];
|
||||
dpp::interaction i;
|
||||
i.fill_from_json(&d);
|
||||
/* There are two types of interactions, component interactions and
|
||||
* slash command interactions. Both fire different library events
|
||||
* so ensure they are dispatched properly.
|
||||
*/
|
||||
if (i.type == it_application_command) {
|
||||
if (client->creator->dispatch.interaction_create) {
|
||||
dpp::interaction_create_t ic(client, raw);
|
||||
ic.command = i;
|
||||
client->creator->dispatch.interaction_create(ic);
|
||||
}
|
||||
} else if (i.type == it_component_button) {
|
||||
dpp::component_interaction bi = std::get<component_interaction>(i.data);
|
||||
if (bi.component_type == cotype_button) {
|
||||
if (client->creator->dispatch.button_click) {
|
||||
dpp::button_click_t ic(client, raw);
|
||||
ic.command = i;
|
||||
ic.custom_id = bi.custom_id;
|
||||
ic.component_type = bi.component_type;
|
||||
client->creator->dispatch.button_click(ic);
|
||||
}
|
||||
}
|
||||
if (bi.component_type == cotype_select) {
|
||||
if (client->creator->dispatch.select_click) {
|
||||
dpp::select_click_t ic(client, raw);
|
||||
ic.command = i;
|
||||
ic.custom_id = bi.custom_id;
|
||||
ic.component_type = bi.component_type;
|
||||
ic.values = bi.values;
|
||||
client->creator->dispatch.select_click(ic);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
54
vendor/DPP/src/dpp/events/invite_create.cpp
vendored
Normal file
54
vendor/DPP/src/dpp/events/invite_create.cpp
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void invite_create::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
if (client->creator->dispatch.invite_create) {
|
||||
json& d = j["d"];
|
||||
dpp::invite_create_t ci(client, raw);
|
||||
ci.created_invite = dpp::invite().fill_from_json(&d);
|
||||
client->creator->dispatch.invite_create(ci);
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
54
vendor/DPP/src/dpp/events/invite_delete.cpp
vendored
Normal file
54
vendor/DPP/src/dpp/events/invite_delete.cpp
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void invite_delete::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
if (client->creator->dispatch.invite_delete) {
|
||||
json& d = j["d"];
|
||||
dpp::invite_delete_t cd(client, raw);
|
||||
cd.deleted_invite = dpp::invite().fill_from_json(&d);
|
||||
client->creator->dispatch.invite_delete(cd);
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
54
vendor/DPP/src/dpp/events/logger.cpp
vendored
Normal file
54
vendor/DPP/src/dpp/events/logger.cpp
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void logger::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
if (client->creator->dispatch.log) {
|
||||
dpp::log_t logmsg(client, raw);
|
||||
logmsg.severity = (dpp::loglevel)from_string<uint32_t>(raw.substr(0, raw.find(';')), std::dec);
|
||||
logmsg.message = raw.substr(raw.find(';') + 1, raw.length());
|
||||
client->creator->dispatch.log(logmsg);
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
59
vendor/DPP/src/dpp/events/message_create.cpp
vendored
Normal file
59
vendor/DPP/src/dpp/events/message_create.cpp
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/dispatcher.h>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void message_create::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
|
||||
if (client->creator->dispatch.message_create) {
|
||||
json d = j["d"];
|
||||
dpp::message_create_t msg(client, raw);
|
||||
dpp::message m;
|
||||
m.fill_from_json(&d, client->creator->cache_policy);
|
||||
msg.msg = &m;
|
||||
client->creator->dispatch.message_create(msg);
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
57
vendor/DPP/src/dpp/events/message_delete.cpp
vendored
Normal file
57
vendor/DPP/src/dpp/events/message_delete.cpp
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void message_delete::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
if (client->creator->dispatch.message_delete) {
|
||||
json d = j["d"];
|
||||
dpp::message_delete_t msg(client, raw);
|
||||
dpp::message m;
|
||||
m.fill_from_json(&d);
|
||||
msg.deleted = &m;
|
||||
client->creator->dispatch.message_delete(msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}};
|
61
vendor/DPP/src/dpp/events/message_delete_bulk.cpp
vendored
Normal file
61
vendor/DPP/src/dpp/events/message_delete_bulk.cpp
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void message_delete_bulk::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
if (client->creator->dispatch.message_delete_bulk) {
|
||||
json& d = j["d"];
|
||||
dpp::message_delete_bulk_t msg(client, raw);
|
||||
msg.deleting_guild = dpp::find_guild(SnowflakeNotNull(&d, "guild_id"));
|
||||
msg.deleting_channel = dpp::find_channel(SnowflakeNotNull(&d, "channel_id"));
|
||||
msg.deleting_user = dpp::find_user(SnowflakeNotNull(&d, "user_id"));
|
||||
for (auto& m : d["ids"]) {
|
||||
msg.deleted.push_back(from_string<uint64_t>(m.get<std::string>(), std::dec));
|
||||
}
|
||||
client->creator->dispatch.message_delete_bulk(msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}};
|
61
vendor/DPP/src/dpp/events/message_reaction_add.cpp
vendored
Normal file
61
vendor/DPP/src/dpp/events/message_reaction_add.cpp
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void message_reaction_add::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
if (client->creator->dispatch.message_reaction_add) {
|
||||
json &d = j["d"];
|
||||
dpp::message_reaction_add_t mra(client, raw);
|
||||
mra.reacting_guild = dpp::find_guild(SnowflakeNotNull(&d, "guild_id"));
|
||||
mra.reacting_user = dpp::find_user(SnowflakeNotNull(&d, "user_id"));
|
||||
mra.reacting_channel = dpp::find_channel(SnowflakeNotNull(&d, "channel_id"));
|
||||
mra.message_id = SnowflakeNotNull(&d, "message_id");
|
||||
mra.reacting_emoji = dpp::find_emoji(SnowflakeNotNull(&(d["emoji"]), "id"));
|
||||
if (mra.reacting_user && mra.reacting_channel && mra.message_id) {
|
||||
client->creator->dispatch.message_reaction_add(mra);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
61
vendor/DPP/src/dpp/events/message_reaction_remove.cpp
vendored
Normal file
61
vendor/DPP/src/dpp/events/message_reaction_remove.cpp
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void message_reaction_remove::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
if (client->creator->dispatch.message_reaction_remove) {
|
||||
json &d = j["d"];
|
||||
dpp::message_reaction_remove_t mrr(client, raw);
|
||||
mrr.reacting_guild = dpp::find_guild(SnowflakeNotNull(&d, "guild_id"));
|
||||
mrr.reacting_user = dpp::find_user(SnowflakeNotNull(&d, "user_id"));
|
||||
mrr.reacting_channel = dpp::find_channel(SnowflakeNotNull(&d, "channel_id"));
|
||||
mrr.message_id = SnowflakeNotNull(&d, "message_id");
|
||||
mrr.reacting_emoji = dpp::find_emoji(SnowflakeNotNull(&(d["emoji"]), "id"));
|
||||
if (mrr.reacting_user && mrr.reacting_channel && mrr.message_id) {
|
||||
client->creator->dispatch.message_reaction_remove(mrr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
59
vendor/DPP/src/dpp/events/message_reaction_remove_all.cpp
vendored
Normal file
59
vendor/DPP/src/dpp/events/message_reaction_remove_all.cpp
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void message_reaction_remove_all::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
if (client->creator->dispatch.message_reaction_remove_all) {
|
||||
json &d = j["d"];
|
||||
dpp::message_reaction_remove_all_t mrra(client, raw);
|
||||
mrra.reacting_guild = dpp::find_guild(SnowflakeNotNull(&d, "guild_id"));
|
||||
mrra.reacting_channel = dpp::find_channel(SnowflakeNotNull(&d, "channel_id"));
|
||||
mrra.message_id = SnowflakeNotNull(&d, "message_id");
|
||||
if (mrra.reacting_channel && mrra.message_id) {
|
||||
client->creator->dispatch.message_reaction_remove_all(mrra);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
61
vendor/DPP/src/dpp/events/message_reaction_remove_emoji.cpp
vendored
Normal file
61
vendor/DPP/src/dpp/events/message_reaction_remove_emoji.cpp
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void message_reaction_remove_emoji::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
if (client->creator->dispatch.message_reaction_remove_emoji) {
|
||||
json &d = j["d"];
|
||||
dpp::message_reaction_remove_emoji_t mrre(client, raw);
|
||||
mrre.reacting_guild = dpp::find_guild(SnowflakeNotNull(&d, "guild_id"));
|
||||
mrre.reacting_channel = dpp::find_channel(SnowflakeNotNull(&d, "channel_id"));
|
||||
mrre.message_id = SnowflakeNotNull(&d, "message_id");
|
||||
mrre.reacting_emoji = dpp::find_emoji(SnowflakeNotNull(&(d["emoji"]), "id"));
|
||||
if (mrre.reacting_channel && mrre.message_id) {
|
||||
client->creator->dispatch.message_reaction_remove_emoji(mrre);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}};
|
57
vendor/DPP/src/dpp/events/message_update.cpp
vendored
Normal file
57
vendor/DPP/src/dpp/events/message_update.cpp
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void message_update::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
if (client->creator->dispatch.message_update) {
|
||||
json d = j["d"];
|
||||
dpp::message_update_t msg(client, raw);
|
||||
dpp::message m;
|
||||
m.fill_from_json(&d);
|
||||
msg.updated = &m;
|
||||
client->creator->dispatch.message_update(msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}};
|
55
vendor/DPP/src/dpp/events/presence_update.cpp
vendored
Normal file
55
vendor/DPP/src/dpp/events/presence_update.cpp
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void presence_update::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
if (client->creator->dispatch.presence_update) {
|
||||
json& d = j["d"];
|
||||
dpp::presence_update_t pu(client, raw);
|
||||
pu.rich_presence = dpp::presence().fill_from_json(&d);
|
||||
client->creator->dispatch.presence_update(pu);
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
68
vendor/DPP/src/dpp/events/ready.cpp
vendored
Normal file
68
vendor/DPP/src/dpp/events/ready.cpp
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <fmt/format.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
std::mutex protect_the_loot;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void ready::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
client->log(dpp::ll_info, fmt::format("Shard {}/{} ready!", client->shard_id, client->max_shards));
|
||||
client->sessionid = j["d"]["session_id"];
|
||||
|
||||
client->ready = true;
|
||||
|
||||
/* Mutex this to make sure multiple threads don't change it at the same time */
|
||||
{
|
||||
std::lock_guard<std::mutex> lockit(protect_the_loot);
|
||||
client->creator->me.fill_from_json(&(j["d"]["user"]));
|
||||
}
|
||||
|
||||
if (client->creator->dispatch.ready) {
|
||||
dpp::ready_t r(client, raw);
|
||||
r.session_id = client->sessionid;
|
||||
r.shard_id = client->shard_id;
|
||||
client->creator->dispatch.ready(r);
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
59
vendor/DPP/src/dpp/events/resumed.cpp
vendored
Normal file
59
vendor/DPP/src/dpp/events/resumed.cpp
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <fmt/format.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void resumed::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
client->log(dpp::ll_debug, fmt::format("Successfully resumed session id {}", client->sessionid));
|
||||
|
||||
client->ready = true;
|
||||
|
||||
if (client->creator->dispatch.resumed) {
|
||||
dpp::resumed_t r(client, raw);
|
||||
r.session_id = client->sessionid;
|
||||
r.shard_id = client->shard_id;
|
||||
client->creator->dispatch.resumed(r);
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
59
vendor/DPP/src/dpp/events/stage_instance_create.cpp
vendored
Normal file
59
vendor/DPP/src/dpp/events/stage_instance_create.cpp
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
#include <dpp/discord.h>
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void stage_instance_create::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
if (client->creator->dispatch.stage_instance_create) {
|
||||
json& d = j["d"];
|
||||
dpp::stage_instance_create_t sic(client, raw);
|
||||
sic.id = SnowflakeNotNull(&d, "id");
|
||||
sic.channel_id = SnowflakeNotNull(&d, "channel_id");
|
||||
sic.guild_id = SnowflakeNotNull(&d, "channel_id");
|
||||
sic.privacy_level = dpp::Int8NotNull(&d, "privacy_level");
|
||||
sic.topic = StringNotNull(&d, "topic");
|
||||
client->creator->dispatch.stage_instance_create(sic);
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
59
vendor/DPP/src/dpp/events/stage_instance_delete.cpp
vendored
Normal file
59
vendor/DPP/src/dpp/events/stage_instance_delete.cpp
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
#include <dpp/discord.h>
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void stage_instance_delete::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
if (client->creator->dispatch.stage_instance_delete) {
|
||||
json& d = j["d"];
|
||||
dpp::stage_instance_delete_t sid(client, raw);
|
||||
sid.id = SnowflakeNotNull(&d, "id");
|
||||
sid.channel_id = SnowflakeNotNull(&d, "channel_id");
|
||||
sid.guild_id = SnowflakeNotNull(&d, "channel_id");
|
||||
sid.privacy_level = dpp::Int8NotNull(&d, "privacy_level");
|
||||
sid.topic = StringNotNull(&d, "topic");
|
||||
client->creator->dispatch.stage_instance_delete(sid);
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
35
vendor/DPP/src/dpp/events/thread_create.cpp
vendored
Normal file
35
vendor/DPP/src/dpp/events/thread_create.cpp
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <fmt/format.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
void thread_create::handle(discord_client* client, json& j, const std::string& raw) {
|
||||
json& d = j["d"];
|
||||
|
||||
dpp::channel t;
|
||||
t.fill_from_json(&d);
|
||||
dpp::guild* g = dpp::find_guild(t.guild_id);
|
||||
if (g) {
|
||||
g->threads.push_back(t.id);
|
||||
if (client->creator->dispatch.thread_create) {
|
||||
dpp::thread_create_t tc(client, raw);
|
||||
tc.created = t;
|
||||
tc.creating_guild = g;
|
||||
client->creator->dispatch.thread_create(tc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}};
|
38
vendor/DPP/src/dpp/events/thread_delete.cpp
vendored
Normal file
38
vendor/DPP/src/dpp/events/thread_delete.cpp
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <fmt/format.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
void thread_delete::handle(discord_client* client, json& j, const std::string& raw) {
|
||||
json& d = j["d"];
|
||||
|
||||
dpp::channel t;
|
||||
t.fill_from_json(&d);
|
||||
dpp::guild* g = dpp::find_guild(t.guild_id);
|
||||
if (g) {
|
||||
auto gt = std::find(g->threads.begin(), g->threads.end(), t.id);
|
||||
if (gt != g->threads.end()) {
|
||||
g->threads.erase(gt);
|
||||
}
|
||||
if (client->creator->dispatch.thread_delete) {
|
||||
dpp::thread_delete_t tc(client, raw);
|
||||
tc.deleted = t;
|
||||
tc.deleting_guild = g;
|
||||
client->creator->dispatch.thread_delete(tc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}};
|
46
vendor/DPP/src/dpp/events/thread_list_sync.cpp
vendored
Normal file
46
vendor/DPP/src/dpp/events/thread_list_sync.cpp
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <fmt/format.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
void thread_list_sync::handle(discord_client* client, json& j, const std::string& raw) {
|
||||
json& d = j["d"];
|
||||
|
||||
dpp::guild* g = dpp::find_guild(SnowflakeNotNull(&d, "guild_id"));
|
||||
if (g) {
|
||||
/** Store thread IDs*/
|
||||
if (d.find("threads") != d.end()) {
|
||||
for (auto& t : d["threads"]) {
|
||||
g->threads.push_back(SnowflakeNotNull(&t, "id"));
|
||||
}
|
||||
}
|
||||
if (client->creator->dispatch.thread_list_sync) {
|
||||
dpp::thread_list_sync_t tls(client, raw);
|
||||
if (d.find("threads") != d.end()) {
|
||||
for (auto& t : d["threads"]) {
|
||||
tls.threads.push_back(channel().fill_from_json(&t));
|
||||
}
|
||||
}
|
||||
if (d.find("members") != d.end()) {
|
||||
for (auto& tm : d["members"]) {
|
||||
tls.members.push_back(thread_member().fill_from_json(&tm));
|
||||
}
|
||||
}
|
||||
client->creator->dispatch.thread_list_sync(tls);
|
||||
}
|
||||
}
|
||||
}
|
||||
}};
|
28
vendor/DPP/src/dpp/events/thread_member_update.cpp
vendored
Normal file
28
vendor/DPP/src/dpp/events/thread_member_update.cpp
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <fmt/format.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
void thread_member_update::handle(discord_client* client, json& j, const std::string& raw) {
|
||||
json& d = j["d"];
|
||||
if (client->creator->dispatch.thread_member_update) {
|
||||
dpp::thread_member_update_t tm(client, raw);
|
||||
tm.updated = thread_member().fill_from_json(&j);
|
||||
|
||||
client->creator->dispatch.thread_member_update(tm);
|
||||
}
|
||||
}
|
||||
}};
|
47
vendor/DPP/src/dpp/events/thread_members_update.cpp
vendored
Normal file
47
vendor/DPP/src/dpp/events/thread_members_update.cpp
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <fmt/format.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
void thread_members_update::handle(discord_client* client, json& j, const std::string& raw) {
|
||||
json& d = j["d"];
|
||||
|
||||
dpp::guild* g = dpp::find_guild(SnowflakeNotNull(&d, "guild_id"));
|
||||
if (g) {
|
||||
if (client->creator->dispatch.thread_members_update) {
|
||||
dpp::thread_members_update_t tms(client, raw);
|
||||
tms.updating_guild = g;
|
||||
SetSnowflakeNotNull(&d, "id", tms.thread_id);
|
||||
SetInt8NotNull(&d, "member_count", tms.member_count);
|
||||
if (d.find("added_members") != d.end()) {
|
||||
for (auto& tm : d["added_members"]) {
|
||||
tms.added.push_back(thread_member().fill_from_json(&tm));
|
||||
}
|
||||
}
|
||||
if (d.find("removed_member_ids") != d.end()) {
|
||||
try {
|
||||
for (auto& rm : d["removed_member_ids"]) {
|
||||
tms.removed_ids.push_back(std::stoull(static_cast<std::string>(rm)));
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
client->creator->log(dpp::ll_error, fmt::format("thread_members_update: {}", e.what()));
|
||||
}
|
||||
}
|
||||
client->creator->dispatch.thread_members_update(tms);
|
||||
}
|
||||
}
|
||||
}
|
||||
}};
|
34
vendor/DPP/src/dpp/events/thread_update.cpp
vendored
Normal file
34
vendor/DPP/src/dpp/events/thread_update.cpp
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <fmt/format.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
void thread_update::handle(discord_client* client, json& j, const std::string& raw) {
|
||||
json& d = j["d"];
|
||||
|
||||
dpp::channel t;
|
||||
t.fill_from_json(&d);
|
||||
dpp::guild* g = dpp::find_guild(t.guild_id);
|
||||
if (g) {
|
||||
if (client->creator->dispatch.thread_update) {
|
||||
dpp::thread_update_t tc(client, raw);
|
||||
tc.updated = t;
|
||||
tc.updating_guild = g;
|
||||
client->creator->dispatch.thread_update(tc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}};
|
58
vendor/DPP/src/dpp/events/typing_start.cpp
vendored
Normal file
58
vendor/DPP/src/dpp/events/typing_start.cpp
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void typing_start::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
if (client->creator->dispatch.typing_start) {
|
||||
json& d = j["d"];
|
||||
dpp::typing_start_t ts(client, raw);
|
||||
ts.typing_guild = dpp::find_guild(SnowflakeNotNull(&d, "guild_id"));
|
||||
ts.typing_channel = dpp::find_channel(SnowflakeNotNull(&d, "channel_id"));
|
||||
ts.typing_user = dpp::find_user(SnowflakeNotNull(&d, "user_id"));
|
||||
ts.timestamp = TimestampNotNull(&d, "timestamp");
|
||||
client->creator->dispatch.typing_start(ts);
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
74
vendor/DPP/src/dpp/events/user_update.cpp
vendored
Normal file
74
vendor/DPP/src/dpp/events/user_update.cpp
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void user_update::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
json& d = j["d"];
|
||||
|
||||
dpp::snowflake user_id = SnowflakeNotNull(&d, "id");
|
||||
if (user_id) {
|
||||
if (client->creator->cache_policy.user_policy != dpp::cp_none) {
|
||||
dpp::user* u = dpp::find_user(user_id);
|
||||
if (u) {
|
||||
u->fill_from_json(&d);
|
||||
}
|
||||
if (client->creator->dispatch.user_update) {
|
||||
dpp::user_update_t uu(client, raw);
|
||||
uu.updated = *u;
|
||||
client->creator->dispatch.user_update(uu);
|
||||
}
|
||||
} else {
|
||||
if (client->creator->dispatch.user_update) {
|
||||
dpp::user u;
|
||||
u.fill_from_json(&d);
|
||||
dpp::user_update_t uu(client, raw);
|
||||
uu.updated = u;
|
||||
client->creator->dispatch.user_update(uu);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
74
vendor/DPP/src/dpp/events/voice_server_update.cpp
vendored
Normal file
74
vendor/DPP/src/dpp/events/voice_server_update.cpp
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void voice_server_update::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
|
||||
json &d = j["d"];
|
||||
dpp::voice_server_update_t vsu(client, raw);
|
||||
vsu.guild_id = SnowflakeNotNull(&d, "guild_id");
|
||||
vsu.token = StringNotNull(&d, "token");
|
||||
vsu.endpoint = StringNotNull(&d, "endpoint");
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(client->voice_mutex);
|
||||
auto v = client->connecting_voice_channels.find(vsu.guild_id);
|
||||
/* Check to see if there is a connection in progress for a voice channel on this guild */
|
||||
if (v != client->connecting_voice_channels.end()) {
|
||||
if (!v->second->is_ready()) {
|
||||
v->second->token = vsu.token;
|
||||
v->second->websocket_hostname = vsu.endpoint;
|
||||
if (!v->second->is_active()) {
|
||||
v->second->connect(vsu.guild_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (client->creator->dispatch.voice_server_update) {
|
||||
client->creator->dispatch.voice_server_update(vsu);
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
83
vendor/DPP/src/dpp/events/voice_state_update.cpp
vendored
Normal file
83
vendor/DPP/src/dpp/events/voice_state_update.cpp
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void voice_state_update::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
|
||||
json& d = j["d"];
|
||||
dpp::voice_state_update_t vsu(client, raw);
|
||||
vsu.state = dpp::voicestate().fill_from_json(&d);
|
||||
vsu.state.shard = client;
|
||||
|
||||
/* Update guild voice states */
|
||||
dpp::guild* g = dpp::find_guild(vsu.state.guild_id);
|
||||
if (g) {
|
||||
if (vsu.state.channel_id == 0) {
|
||||
auto ve = g->voice_members.find(vsu.state.user_id);
|
||||
if (ve != g->voice_members.end()) {
|
||||
g->voice_members.erase(ve);
|
||||
}
|
||||
} else {
|
||||
g->voice_members[vsu.state.user_id] = vsu.state;
|
||||
}
|
||||
}
|
||||
|
||||
if (vsu.state.user_id == client->creator->me.id)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(client->voice_mutex);
|
||||
auto v = client->connecting_voice_channels.find(vsu.state.guild_id);
|
||||
/* Check to see if we have a connection to a voice channel in progress on this guild */
|
||||
if (v != client->connecting_voice_channels.end()) {
|
||||
v->second->session_id = vsu.state.session_id;
|
||||
if (v->second->is_ready() && !v->second->is_active()) {
|
||||
v->second->connect(vsu.state.guild_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (client->creator->dispatch.voice_state_update) {
|
||||
client->creator->dispatch.voice_state_update(vsu);
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
56
vendor/DPP/src/dpp/events/webhooks_update.cpp
vendored
Normal file
56
vendor/DPP/src/dpp/events/webhooks_update.cpp
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/event.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp { namespace events {
|
||||
|
||||
using namespace dpp;
|
||||
|
||||
/**
|
||||
* @brief Handle event
|
||||
*
|
||||
* @param client Websocket client (current shard)
|
||||
* @param j JSON data for the event
|
||||
* @param raw Raw JSON string
|
||||
*/
|
||||
void webhooks_update::handle(discord_client* client, json &j, const std::string &raw) {
|
||||
if (client->creator->dispatch.webhooks_update) {
|
||||
json& d = j["d"];
|
||||
dpp::webhooks_update_t wu(client, raw);
|
||||
wu.webhook_guild = dpp::find_guild(SnowflakeNotNull(&d, "guild_id"));
|
||||
wu.webhook_channel = dpp::find_channel(SnowflakeNotNull(&d, "channel_id"));
|
||||
client->creator->dispatch.webhooks_update(wu);
|
||||
}
|
||||
}
|
||||
|
||||
}};
|
469
vendor/DPP/src/dpp/guild.cpp
vendored
Normal file
469
vendor/DPP/src/dpp/guild.cpp
vendored
Normal file
@ -0,0 +1,469 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/discordclient.h>
|
||||
#include <dpp/voicestate.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
std::map<std::string, dpp::guild_flags> featuremap = {
|
||||
{"INVITE_SPLASH", dpp::g_invite_splash },
|
||||
{"VIP_REGIONS", dpp::g_vip_regions },
|
||||
{"VANITY_URL", dpp::g_vanity_url },
|
||||
{"VERIFIED", dpp::g_verified },
|
||||
{"PARTNERED", dpp::g_partnered },
|
||||
{"COMMUNITY", dpp::g_community },
|
||||
{"COMMERCE", dpp::g_commerce },
|
||||
{"NEWS", dpp::g_news },
|
||||
{"DISCOVERABLE", dpp::g_discoverable },
|
||||
{"FEATUREABLE", dpp::g_featureable },
|
||||
{"ANIMATED_ICON", dpp::g_animated_icon },
|
||||
{"BANNER", dpp::g_banner },
|
||||
{"WELCOME_SCREEN_ENABLED", dpp::g_welcome_screen_enabled },
|
||||
{"MEMBER_VERIFICATION_GATE_ENABLED", dpp::g_member_verification_gate },
|
||||
{"PREVIEW_ENABLED", dpp::g_preview_enabled }
|
||||
};
|
||||
|
||||
std::map<std::string, dpp::region> regionmap = {
|
||||
{ "brazil", dpp::r_brazil },
|
||||
{ "central-europe", dpp::r_central_europe },
|
||||
{ "hong-kong", dpp::r_hong_kong },
|
||||
{ "india", dpp::r_india },
|
||||
{ "japan", dpp::r_japan },
|
||||
{ "russia", dpp::r_russia },
|
||||
{ "singapore", dpp::r_singapore },
|
||||
{ "south-africa", dpp::r_south_africa },
|
||||
{ "sydney", dpp::r_sydney },
|
||||
{ "us-central", dpp::r_us_central },
|
||||
{ "us-east", dpp::r_us_east },
|
||||
{ "us-south", dpp::r_us_south },
|
||||
{ "us-west", dpp::r_us_west },
|
||||
{ "western-europe", dpp::r_western_europe }
|
||||
};
|
||||
|
||||
|
||||
namespace dpp {
|
||||
|
||||
guild::guild() :
|
||||
managed(),
|
||||
shard_id(0),
|
||||
flags(0),
|
||||
owner_id(0),
|
||||
voice_region(r_us_central),
|
||||
afk_channel_id(0),
|
||||
afk_timeout(0),
|
||||
widget_channel_id(0),
|
||||
verification_level(0),
|
||||
default_message_notifications(0),
|
||||
explicit_content_filter(0),
|
||||
mfa_level(0),
|
||||
application_id(0),
|
||||
system_channel_id(0),
|
||||
rules_channel_id(0),
|
||||
member_count(0),
|
||||
premium_tier(0),
|
||||
premium_subscription_count(0),
|
||||
public_updates_channel_id(0),
|
||||
max_video_channel_users(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
guild_member::guild_member() :
|
||||
joined_at(0),
|
||||
premium_since(0),
|
||||
flags(0)
|
||||
{
|
||||
}
|
||||
|
||||
guild_member& guild_member::fill_from_json(nlohmann::json* j, snowflake g_id, snowflake u_id) {
|
||||
this->guild_id = g_id;
|
||||
this->user_id = u_id;
|
||||
j->get_to(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void from_json(const nlohmann::json& j, guild_member& gm) {
|
||||
gm.nickname = StringNotNull(&j, "nick");
|
||||
gm.joined_at = TimestampNotNull(&j, "joined_at");
|
||||
gm.premium_since = TimestampNotNull(&j, "premium_since");
|
||||
|
||||
gm.roles.clear();
|
||||
if (j.contains("roles") && !j.at("roles").is_null()) {
|
||||
for (auto& role : j.at("roles")) {
|
||||
gm.roles.push_back(std::stoull(role.get<std::string>()));
|
||||
}
|
||||
}
|
||||
|
||||
gm.flags |= BoolNotNull(&j, "deaf") ? gm_deaf : 0;
|
||||
gm.flags |= BoolNotNull(&j, "mute") ? gm_mute : 0;
|
||||
gm.flags |= BoolNotNull(&j, "pending") ? gm_pending : 0;
|
||||
}
|
||||
|
||||
std::string guild_member::build_json() const {
|
||||
json j;
|
||||
if (!this->nickname.empty())
|
||||
j["nick"] = this->nickname;
|
||||
if (this->roles.size()) {
|
||||
j["roles"] = {};
|
||||
for (auto & role : roles) {
|
||||
j["roles"].push_back(std::to_string(role));
|
||||
}
|
||||
}
|
||||
if (is_muted()) {
|
||||
j["muted"] = true;
|
||||
}
|
||||
if (is_deaf()) {
|
||||
j["deaf"] = true;
|
||||
}
|
||||
return j.dump();
|
||||
}
|
||||
|
||||
bool guild_member::is_deaf() const {
|
||||
return flags & dpp::gm_deaf;
|
||||
}
|
||||
|
||||
bool guild_member::is_muted() const {
|
||||
return flags & dpp::gm_mute;
|
||||
}
|
||||
|
||||
bool guild_member::is_pending() const {
|
||||
return flags & dpp::gm_pending;
|
||||
}
|
||||
|
||||
bool guild::is_large() const {
|
||||
return this->flags & g_large;
|
||||
}
|
||||
|
||||
bool guild::is_unavailable() const {
|
||||
return this->flags & g_unavailable;
|
||||
}
|
||||
|
||||
bool guild::widget_enabled() const {
|
||||
return this->flags & g_widget_enabled;
|
||||
}
|
||||
|
||||
bool guild::has_invite_splash() const {
|
||||
return this->flags & g_invite_splash;
|
||||
}
|
||||
|
||||
bool guild::has_vip_regions() const {
|
||||
return this->flags & g_vip_regions;
|
||||
}
|
||||
|
||||
bool guild::has_vanity_url() const {
|
||||
return this->flags & g_vanity_url;
|
||||
}
|
||||
|
||||
bool guild::is_verified() const {
|
||||
return this->flags & g_verified;
|
||||
}
|
||||
|
||||
bool guild::is_partnered() const {
|
||||
return this->flags & g_partnered;
|
||||
}
|
||||
|
||||
bool guild::is_community() const {
|
||||
return this->flags & g_community;
|
||||
}
|
||||
|
||||
bool guild::has_commerce() const {
|
||||
return this->flags & g_commerce;
|
||||
}
|
||||
|
||||
bool guild::has_news() const {
|
||||
return this->flags & g_news;
|
||||
}
|
||||
|
||||
bool guild::is_discoverable() const {
|
||||
return this->flags & g_discoverable;
|
||||
}
|
||||
|
||||
bool guild::is_featureable() const {
|
||||
return this->flags & g_featureable;
|
||||
}
|
||||
|
||||
bool guild::has_animated_icon() const {
|
||||
return this->flags & g_animated_icon;
|
||||
}
|
||||
|
||||
bool guild::has_banner() const {
|
||||
return this->flags & g_banner;
|
||||
}
|
||||
|
||||
bool guild::is_welcome_screen_enabled() const {
|
||||
return this->flags & g_welcome_screen_enabled;
|
||||
}
|
||||
|
||||
bool guild::has_member_verification_gate() const {
|
||||
return this->flags & g_member_verification_gate;
|
||||
}
|
||||
|
||||
bool guild::is_preview_enabled() const {
|
||||
return this->flags & g_preview_enabled;
|
||||
}
|
||||
|
||||
bool guild::has_animated_icon_hash() const {
|
||||
return this->flags & g_has_animated_icon;
|
||||
}
|
||||
|
||||
std::string guild::build_json(bool with_id) const {
|
||||
json j;
|
||||
if (with_id) {
|
||||
j["id"] = std::to_string(id);
|
||||
}
|
||||
if (!name.empty()) {
|
||||
j["name"] = name;
|
||||
}
|
||||
j["widget_enabled"] = widget_enabled();
|
||||
if (afk_channel_id) {
|
||||
j["afk_channel_id"] = afk_channel_id;
|
||||
}
|
||||
if (afk_channel_id) {
|
||||
j["afk_timeout"] = afk_timeout;
|
||||
}
|
||||
if (widget_enabled()) {
|
||||
j["widget_channel_id"] = widget_channel_id;
|
||||
}
|
||||
j["default_message_notifications"] = default_message_notifications;
|
||||
j["explicit_content_filter"] = explicit_content_filter;
|
||||
j["mfa_level"] = mfa_level;
|
||||
if (system_channel_id) {
|
||||
j["system_channel_id"] = system_channel_id;
|
||||
}
|
||||
if (rules_channel_id) {
|
||||
j["rules_channel_id"] = rules_channel_id;
|
||||
}
|
||||
if (!vanity_url_code.empty()) {
|
||||
j["vanity_url_code"] = vanity_url_code;
|
||||
}
|
||||
if (!description.empty()) {
|
||||
j["description"] = description;
|
||||
}
|
||||
return j.dump();
|
||||
}
|
||||
|
||||
void guild::rehash_members() {
|
||||
members_container n;
|
||||
n.reserve(members.size());
|
||||
for (auto t = members.begin(); t != members.end(); ++t) {
|
||||
n.insert(*t);
|
||||
}
|
||||
members = n;
|
||||
}
|
||||
|
||||
|
||||
guild& guild::fill_from_json(discord_client* shard, nlohmann::json* d) {
|
||||
/* NOTE: This can be called by GUILD_UPDATE and also GUILD_CREATE.
|
||||
* GUILD_UPDATE sends a partial guild object, so we use Set*NotNull functions
|
||||
* for a lot of the values under the assumption they may sometimes be missing.
|
||||
*/
|
||||
this->id = SnowflakeNotNull(d, "id");
|
||||
if (d->find("unavailable") == d->end() || (*d)["unavailable"].get<bool>() == false) {
|
||||
/* Clear unavailable flag if set */
|
||||
if (this->flags & dpp::g_unavailable) {
|
||||
this->flags -= dpp::g_unavailable;
|
||||
}
|
||||
SetStringNotNull(d, "name", this->name);
|
||||
/* Special case for guild icon to allow for animated icons.
|
||||
* Animated icons start with a_ on the name, so we use this to set a flag
|
||||
* in the flags field and then just store the iconhash separately.
|
||||
*/
|
||||
std::string _icon = StringNotNull(d, "icon");
|
||||
if (!_icon.empty()) {
|
||||
if (_icon.length() > 2 && _icon.substr(0, 2) == "a_") {
|
||||
_icon = _icon.substr(2, _icon.length());
|
||||
this->flags |= g_has_animated_icon;
|
||||
}
|
||||
this->icon = _icon;
|
||||
}
|
||||
std::string _dsplash = StringNotNull(d, "discovery_splash");
|
||||
if (!_dsplash.empty()) {
|
||||
this->discovery_splash = _dsplash;
|
||||
}
|
||||
SetSnowflakeNotNull(d, "owner_id", this->owner_id);
|
||||
if (!(*d)["region"].is_null()) {
|
||||
auto r = regionmap.find((*d)["region"].get<std::string>());
|
||||
if (r != regionmap.end()) {
|
||||
this->voice_region = r->second;
|
||||
}
|
||||
}
|
||||
this->flags |= BoolNotNull(d, "large") ? dpp::g_large : 0;
|
||||
this->flags |= BoolNotNull(d, "widget_enabled") ? dpp::g_widget_enabled : 0;
|
||||
|
||||
for (auto & feature : (*d)["features"]) {
|
||||
auto f = featuremap.find(feature.get<std::string>());
|
||||
if (f != featuremap.end()) {
|
||||
this->flags |= f->second;
|
||||
}
|
||||
}
|
||||
uint8_t scf = Int8NotNull(d, "system_channel_flags");
|
||||
if (scf & 1) {
|
||||
this->flags |= dpp::g_no_join_notifications;
|
||||
}
|
||||
if (scf & 2) {
|
||||
this->flags |= dpp::g_no_boost_notifications;
|
||||
}
|
||||
|
||||
SetSnowflakeNotNull(d, "afk_channel_id", this->afk_channel_id);
|
||||
SetInt8NotNull(d, "afk_timeout", this->afk_timeout);
|
||||
SetSnowflakeNotNull(d, "widget_channel_id", this->widget_channel_id);
|
||||
SetInt8NotNull(d, "verification_level", this->verification_level);
|
||||
SetInt8NotNull(d, "default_message_notifications", this->default_message_notifications);
|
||||
SetInt8NotNull(d, "explicit_content_filter", this->explicit_content_filter);
|
||||
SetInt8NotNull(d, "mfa_level", this->mfa_level);
|
||||
SetSnowflakeNotNull(d, "application_id", this->application_id);
|
||||
SetSnowflakeNotNull(d, "system_channel_id", this->system_channel_id);
|
||||
SetSnowflakeNotNull(d, "rules_channel_id", this->rules_channel_id);
|
||||
SetInt32NotNull(d, "member_count", this->member_count);
|
||||
SetStringNotNull(d, "vanity_url_code", this->vanity_url_code);
|
||||
SetStringNotNull(d, "description", this->description);
|
||||
if (d->find("voice_states") != d->end()) {
|
||||
this->voice_members.clear();
|
||||
for (auto & vm : (*d)["voice_states"]) {
|
||||
voicestate vs;
|
||||
vs.fill_from_json(&vm);
|
||||
vs.shard = shard;
|
||||
vs.guild_id = this->id;
|
||||
this->voice_members[vs.user_id] = vs;
|
||||
}
|
||||
}
|
||||
|
||||
std::string _banner = StringNotNull(d, "banner");
|
||||
if (!_banner.empty()) {
|
||||
this->banner = _banner;
|
||||
}
|
||||
SetInt8NotNull(d, "premium_tier", this->premium_tier);
|
||||
SetInt16NotNull(d, "premium_subscription_count", this->premium_subscription_count);
|
||||
SetSnowflakeNotNull(d, "public_updates_channel_id", this->public_updates_channel_id);
|
||||
SetInt16NotNull(d, "max_video_channel_users", this->max_video_channel_users);
|
||||
} else {
|
||||
this->flags |= dpp::g_unavailable;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
guild_widget::guild_widget() : enabled(false), channel_id(0)
|
||||
{
|
||||
}
|
||||
|
||||
guild_widget& guild_widget::fill_from_json(nlohmann::json* j) {
|
||||
enabled = BoolNotNull(j, "enabled");
|
||||
channel_id = SnowflakeNotNull(j, "channel_id");
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string guild_widget::build_json() const {
|
||||
return json({{"channel_id", channel_id}, {"enabled", enabled}}).dump();
|
||||
}
|
||||
|
||||
|
||||
uint64_t guild::base_permissions(const user* member) const
|
||||
{
|
||||
if (owner_id == member->id)
|
||||
return ~0;
|
||||
|
||||
role* everyone = dpp::find_role(id);
|
||||
auto mi = members.find(member->id);
|
||||
if (mi == members.end())
|
||||
return 0;
|
||||
guild_member gm = mi->second;
|
||||
|
||||
uint64_t permissions = everyone->permissions;
|
||||
|
||||
for (auto& rid : gm.roles) {
|
||||
role* r = dpp::find_role(rid);
|
||||
permissions |= r->permissions;
|
||||
}
|
||||
|
||||
if (permissions & p_administrator)
|
||||
return ~0;
|
||||
|
||||
return permissions;
|
||||
}
|
||||
|
||||
uint64_t guild::permission_overwrites(const uint64_t base_permissions, const user* member, const channel* channel) const
|
||||
{
|
||||
if (base_permissions & p_administrator)
|
||||
return ~0;
|
||||
|
||||
int64_t permissions = base_permissions;
|
||||
for (auto it = channel->permission_overwrites.begin(); it != channel->permission_overwrites.end(); ++it) {
|
||||
if (it->id == id && it->type == ot_role) {
|
||||
permissions &= ~it->deny;
|
||||
permissions |= it->allow;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto mi = members.find(member->id);
|
||||
if (mi == members.end())
|
||||
return 0;
|
||||
guild_member gm = mi->second;
|
||||
uint64_t allow = 0;
|
||||
uint64_t deny = 0;
|
||||
|
||||
for (auto& rid : gm.roles) {
|
||||
|
||||
/* Skip \@everyone, calculated above */
|
||||
if (rid == id)
|
||||
continue;
|
||||
|
||||
for (auto it = channel->permission_overwrites.begin(); it != channel->permission_overwrites.end(); ++it) {
|
||||
if ((rid == it->id && it->type == ot_role) || (member->id == it->id && it->type == ot_member)) {
|
||||
allow |= it->allow;
|
||||
deny |= it->deny;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
permissions &= ~deny;
|
||||
permissions |= allow;
|
||||
|
||||
return permissions;
|
||||
}
|
||||
|
||||
bool guild::connect_member_voice(snowflake user_id) {
|
||||
for (auto & c : channels) {
|
||||
channel* ch = dpp::find_channel(c);
|
||||
if (!ch || (!ch->is_voice_channel() && !ch->is_stage_channel())) {
|
||||
continue;
|
||||
}
|
||||
auto vcmembers = ch->get_voice_members();
|
||||
auto vsi = vcmembers.find(user_id);
|
||||
if (vsi != vcmembers.end()) {
|
||||
if (vsi->second.shard) {
|
||||
vsi->second.shard->connect_voice(this->id, vsi->second.channel_id);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
6193
vendor/DPP/src/dpp/httplib.cpp
vendored
Normal file
6193
vendor/DPP/src/dpp/httplib.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
120
vendor/DPP/src/dpp/integration.cpp
vendored
Normal file
120
vendor/DPP/src/dpp/integration.cpp
vendored
Normal file
@ -0,0 +1,120 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/integration.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/cache.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp {
|
||||
|
||||
integration::integration() :
|
||||
managed(),
|
||||
type(i_twitch),
|
||||
role_id(0),
|
||||
user_id(0),
|
||||
expire_grace_period(0),
|
||||
flags(0),
|
||||
synced_at(0),
|
||||
subscriber_count(0)
|
||||
{
|
||||
app.id = 0;
|
||||
app.bot = nullptr;
|
||||
}
|
||||
|
||||
integration::~integration()
|
||||
{
|
||||
}
|
||||
|
||||
integration& integration::fill_from_json(nlohmann::json* j)
|
||||
{
|
||||
std::map<std::string, integration_type> type_map = {
|
||||
{ "", i_discord },
|
||||
{ "youtube", i_youtube },
|
||||
{ "twitch", i_twitch },
|
||||
{ "discord", i_discord }
|
||||
};
|
||||
this->id = SnowflakeNotNull(j, "id");
|
||||
this->name = StringNotNull(j, "name");
|
||||
this->type = type_map[StringNotNull(j, "type")];
|
||||
if (BoolNotNull(j, "enabled"))
|
||||
this->flags |= if_enabled;
|
||||
if (BoolNotNull(j, "syncing"))
|
||||
this->flags |= if_syncing;
|
||||
if (BoolNotNull(j, "enable_emoticons"))
|
||||
this->flags |= if_emoticons;
|
||||
if (BoolNotNull(j, "revoked"))
|
||||
this->flags |= if_revoked;
|
||||
if (Int8NotNull(j, "expire_behavior"))
|
||||
this->flags |= if_expire_kick;
|
||||
this->expire_grace_period = Int32NotNull(j, "expire_grace_period");
|
||||
if (j->find("user") != j->end()) {
|
||||
auto t = (*j)["user"];
|
||||
this->user_id = SnowflakeNotNull(&t, "user_id");
|
||||
}
|
||||
if (j->find("application") != j->end()) {
|
||||
auto & t = (*j)["application"];
|
||||
this->app.id = SnowflakeNotNull(&t, "id");
|
||||
if (t.find("bot") != t.end()) {
|
||||
auto & b = t["bot"];
|
||||
this->app.bot = dpp::find_user(SnowflakeNotNull(&b, "id"));
|
||||
}
|
||||
}
|
||||
this->subscriber_count = Int32NotNull(j, "subscriber_count");
|
||||
|
||||
this->account_id = StringNotNull(&((*j)["account"]), "id");
|
||||
this->account_name = StringNotNull(&((*j)["account"]), "name");
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string integration::build_json() const {
|
||||
return json({
|
||||
{ "expire_behavior", (flags & if_expire_kick) ? 1 : 0 },
|
||||
{ "expire_grace_period", expire_grace_period },
|
||||
{ "enable_emoticons", emoticons_enabled() }
|
||||
}).dump();
|
||||
}
|
||||
|
||||
bool integration::emoticons_enabled() const {
|
||||
return flags & if_emoticons;
|
||||
}
|
||||
|
||||
bool integration::is_enabled() const {
|
||||
return flags & if_enabled;
|
||||
}
|
||||
|
||||
bool integration::is_syncing() const {
|
||||
return flags & if_syncing;
|
||||
}
|
||||
|
||||
bool integration::is_revoked() const {
|
||||
return flags & if_revoked;
|
||||
}
|
||||
|
||||
bool integration::expiry_kicks_user() const {
|
||||
return flags & if_expire_kick;
|
||||
}
|
||||
|
||||
};
|
70
vendor/DPP/src/dpp/invite.cpp
vendored
Normal file
70
vendor/DPP/src/dpp/invite.cpp
vendored
Normal file
@ -0,0 +1,70 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/invite.h>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp {
|
||||
|
||||
invite::invite() : guild_id(0), channel_id(0), inviter_id(0), target_user_id(0), target_user_type(1), approximate_presence_count(0), approximate_member_count(0)
|
||||
{
|
||||
}
|
||||
|
||||
invite::~invite() {
|
||||
}
|
||||
|
||||
|
||||
invite& invite::fill_from_json(nlohmann::json* j) {
|
||||
code = StringNotNull(j, "code");
|
||||
guild_id = (j->find("guild") != j->end()) ? SnowflakeNotNull(&((*j)["guild_id"]), "id") : 0;
|
||||
channel_id = (j->find("channel") != j->end()) ? SnowflakeNotNull(&((*j)["channel"]), "id") : 0;
|
||||
inviter_id = (j->find("inviter") != j->end()) ? SnowflakeNotNull(&((*j)["inviter"]), "id") : 0;
|
||||
target_user_id = (j->find("target_user") != j->end()) ? SnowflakeNotNull(&((*j)["target_user"]), "id") : 0;
|
||||
target_user_type = Int8NotNull(j, "target_user_type");
|
||||
approximate_presence_count = Int32NotNull(j, "approximate_presence_count");
|
||||
approximate_member_count = Int32NotNull(j, "approximate_member_count");
|
||||
max_age = Int32NotNull(j, "max_age");
|
||||
max_uses = Int32NotNull(j, "max_uses");
|
||||
temporary = BoolNotNull(j, "temporary");
|
||||
unique = BoolNotNull(j, "unique");
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string invite::build_json() const {
|
||||
json j;
|
||||
if (max_age > 0)
|
||||
j["max_age"] = max_age;
|
||||
if (max_uses > 0)
|
||||
j["max_uses"] = max_uses;
|
||||
if (target_user_id > 0)
|
||||
j["target_user"] = target_user_id;
|
||||
if (target_user_type > 0)
|
||||
j["target_user_type"] = target_user_type;
|
||||
if (temporary)
|
||||
j["temporary"] = temporary;
|
||||
if (unique)
|
||||
j["unique"] = unique;
|
||||
return j.dump();
|
||||
}
|
||||
|
||||
};
|
29
vendor/DPP/src/dpp/managed.cpp
vendored
Normal file
29
vendor/DPP/src/dpp/managed.cpp
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
|
||||
namespace dpp {
|
||||
|
||||
managed::managed(const snowflake nid) : id(nid)
|
||||
{
|
||||
}
|
||||
|
||||
};
|
996
vendor/DPP/src/dpp/message.cpp
vendored
Normal file
996
vendor/DPP/src/dpp/message.cpp
vendored
Normal file
@ -0,0 +1,996 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/message.h>
|
||||
#include <dpp/user.h>
|
||||
#include <dpp/channel.h>
|
||||
#include <dpp/guild.h>
|
||||
#include <dpp/cache.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/stringops.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp {
|
||||
|
||||
component::component() : type(static_cast<component_type>(1)), label(""), style(static_cast<component_style>(1)), custom_id(""), disabled(false), min_values(-1), max_values(-1)
|
||||
{
|
||||
emoji.animated = false;
|
||||
emoji.id = 0;
|
||||
emoji.name = "";
|
||||
}
|
||||
|
||||
|
||||
component& component::fill_from_json(nlohmann::json* j) {
|
||||
type = static_cast<component_type>(Int8NotNull(j, "type"));
|
||||
if (type == cot_action_row) {
|
||||
components;
|
||||
for (json sub_component : (*j)["components"]) {
|
||||
dpp::component new_component;
|
||||
new_component.fill_from_json(&sub_component);
|
||||
components.push_back(new_component);
|
||||
}
|
||||
} else if (type == cot_button) {
|
||||
label = StringNotNull(j, "label");
|
||||
style = static_cast<component_style>(Int8NotNull(j, "style"));
|
||||
custom_id = StringNotNull(j, "custom_id");
|
||||
disabled = BoolNotNull(j, "disabled");
|
||||
} else if (type == cot_selectmenu) {
|
||||
label = "";
|
||||
custom_id = StringNotNull(j, "custom_id");
|
||||
disabled = BoolNotNull(j, "disabled");
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
component& component::add_component(const component& c)
|
||||
{
|
||||
set_type(cot_action_row);
|
||||
components.push_back(c);
|
||||
return *this;
|
||||
}
|
||||
|
||||
component& component::set_type(component_type ct)
|
||||
{
|
||||
type = ct;
|
||||
return *this;
|
||||
}
|
||||
|
||||
component& component::set_label(const std::string &l)
|
||||
{
|
||||
if (type == cot_action_row) {
|
||||
set_type(cot_button);
|
||||
}
|
||||
label = utility::utf8substr(l, 0, 80);
|
||||
return *this;
|
||||
}
|
||||
|
||||
component& component::set_style(component_style cs)
|
||||
{
|
||||
set_type(cot_button);
|
||||
style = cs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
component& component::set_url(const std::string& u)
|
||||
{
|
||||
set_type(cot_button);
|
||||
set_style(cos_link);
|
||||
url = utility::utf8substr(u, 0, 512);
|
||||
return *this;
|
||||
}
|
||||
|
||||
component& component::set_id(const std::string &id)
|
||||
{
|
||||
if (type == cot_action_row) {
|
||||
set_type(cot_button);
|
||||
}
|
||||
custom_id = utility::utf8substr(id, 0, 100);
|
||||
return *this;
|
||||
}
|
||||
|
||||
component& component::set_disabled(bool disable)
|
||||
{
|
||||
if (type == cot_action_row) {
|
||||
set_type(cot_button);
|
||||
}
|
||||
disabled = disable;
|
||||
return *this;
|
||||
}
|
||||
|
||||
component& component::set_emoji(const std::string& name, dpp::snowflake id, bool animated)
|
||||
{
|
||||
if (type == cot_action_row) {
|
||||
set_type(cot_button);
|
||||
}
|
||||
this->emoji.id = id;
|
||||
this->emoji.name = name;
|
||||
this->emoji.animated = animated;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string component::build_json() const {
|
||||
json j;
|
||||
if (type == component_type::cot_action_row) {
|
||||
j["type"] = 1;
|
||||
json new_components;
|
||||
for (component new_component : components) {
|
||||
new_components.push_back(new_component.build_json());
|
||||
}
|
||||
j["components"] = new_components;
|
||||
} else if (type == component_type::cot_button) {
|
||||
j["type"] = 2;
|
||||
j["label"] = label;
|
||||
j["style"] = int(style);
|
||||
j["custom_id"] = custom_id;
|
||||
j["disabled"] = disabled;
|
||||
} else if (type == component_type::cot_selectmenu) {
|
||||
j["type"] = 3;
|
||||
j["custom_id"] = custom_id;
|
||||
//j["disabled"] = disabled;
|
||||
if (!placeholder.empty()) {
|
||||
j["placeholder"] = placeholder;
|
||||
}
|
||||
if (min_values >= 0) {
|
||||
j["min_values"] = min_values;
|
||||
}
|
||||
if (max_values >= 0) {
|
||||
j["max_values"] = max_values;
|
||||
}
|
||||
j["options"] = json::array();
|
||||
for (auto opt : options) {
|
||||
json o;
|
||||
if (!opt.description.empty()) {
|
||||
o["description"] = opt.description;
|
||||
}
|
||||
if (!opt.label.empty()) {
|
||||
o["label"] = opt.label;
|
||||
}
|
||||
if (!opt.value.empty()) {
|
||||
o["value"] = opt.value;
|
||||
}
|
||||
if (opt.is_default) {
|
||||
o["default"] = true;
|
||||
}
|
||||
if (!opt.emoji.name.empty()) {
|
||||
o["emoji"] = json::object();
|
||||
o["emoji"]["name"] = opt.emoji.name;
|
||||
if (opt.emoji.id) {
|
||||
o["emoji"]["id"] = std::to_string(opt.emoji.id);
|
||||
}
|
||||
}
|
||||
j["options"].push_back(o);
|
||||
}
|
||||
}
|
||||
return j.dump();
|
||||
}
|
||||
|
||||
select_option::select_option() : is_default(false) {
|
||||
}
|
||||
|
||||
select_option::select_option(const std::string &_label, const std::string &_value, const std::string &_description) : is_default(false), label(_label), value(_value), description(_description) {
|
||||
}
|
||||
|
||||
select_option& select_option::set_label(const std::string &l) {
|
||||
label = dpp::utility::utf8substr(l, 0, 100);
|
||||
return *this;
|
||||
}
|
||||
|
||||
select_option& select_option::set_default(bool def) {
|
||||
is_default = def;
|
||||
return *this;
|
||||
}
|
||||
|
||||
select_option& select_option::set_value(const std::string &v) {
|
||||
value = dpp::utility::utf8substr(v, 0, 100);
|
||||
return *this;
|
||||
}
|
||||
|
||||
select_option& select_option::set_description(const std::string &d) {
|
||||
description = dpp::utility::utf8substr(d, 0, 100);
|
||||
return *this;
|
||||
}
|
||||
|
||||
select_option& select_option::set_emoji(const std::string &n, dpp::snowflake id, bool animated) {
|
||||
emoji.name = n;
|
||||
emoji.id = id;
|
||||
emoji.animated = animated;
|
||||
return *this;
|
||||
}
|
||||
|
||||
select_option& select_option::set_animated(bool anim) {
|
||||
emoji.animated = anim;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
component& component::set_placeholder(const std::string &_placeholder) {
|
||||
placeholder = dpp::utility::utf8substr(_placeholder, 0, 100);
|
||||
return *this;
|
||||
}
|
||||
|
||||
component& component::set_min_values(uint32_t _min_values) {
|
||||
min_values = _min_values;
|
||||
return *this;
|
||||
}
|
||||
|
||||
component& component::set_max_values(uint32_t _max_values) {
|
||||
max_values = _max_values;
|
||||
return *this;
|
||||
}
|
||||
|
||||
component& component::add_select_option(const select_option &option) {
|
||||
if (options.size() <= 25) {
|
||||
options.push_back(option);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
embed::~embed() {
|
||||
}
|
||||
|
||||
embed::embed() : timestamp(0), color(0) {
|
||||
}
|
||||
|
||||
message::message() : id(0), channel_id(0), guild_id(0), author(nullptr), sent(0), edited(0), flags(0),
|
||||
type(mt_default), tts(false), mention_everyone(false), pinned(false), webhook_id(0)
|
||||
{
|
||||
message_reference.channel_id = 0;
|
||||
message_reference.guild_id = 0;
|
||||
message_reference.message_id = 0;
|
||||
message_reference.fail_if_not_exists = false;
|
||||
interaction.id = 0;
|
||||
interaction.type = interaction_type::it_ping;
|
||||
interaction.usr.id = 0;
|
||||
allowed_mentions.parse_users = false;
|
||||
allowed_mentions.parse_everyone = false;
|
||||
allowed_mentions.parse_roles = false;
|
||||
/* The documentation for discord is INCORRECT. This defaults to true, and must be set to false.
|
||||
* The default ctor reflects this.
|
||||
*/
|
||||
allowed_mentions.replied_user = true;
|
||||
|
||||
}
|
||||
|
||||
message& message::set_reference(snowflake _message_id, snowflake _guild_id, snowflake _channel_id, bool fail_if_not_exists) {
|
||||
message_reference.channel_id = _channel_id;
|
||||
message_reference.guild_id = _guild_id;
|
||||
message_reference.message_id = _message_id;
|
||||
message_reference.fail_if_not_exists = fail_if_not_exists;
|
||||
return *this;
|
||||
}
|
||||
|
||||
message& message::set_allowed_mentions(bool _parse_users, bool _parse_roles, bool _parse_everyone, bool _replied_user, const std::vector<snowflake> &users, const std::vector<snowflake> &roles) {
|
||||
allowed_mentions.parse_users = _parse_users;
|
||||
allowed_mentions.parse_everyone = _parse_everyone;
|
||||
allowed_mentions.parse_roles = _parse_roles;
|
||||
allowed_mentions.replied_user = _replied_user;
|
||||
allowed_mentions.users = users;
|
||||
allowed_mentions.roles = roles;
|
||||
return *this;
|
||||
}
|
||||
|
||||
message::message(snowflake _channel_id, const std::string &_content, message_type t) : message() {
|
||||
channel_id = _channel_id;
|
||||
content = utility::utf8substr(_content, 0, 2000);
|
||||
type = t;
|
||||
}
|
||||
|
||||
message& message::add_component(const component& c)
|
||||
{
|
||||
components.push_back(c);
|
||||
return *this;
|
||||
}
|
||||
|
||||
message& message::add_embed(const embed& e)
|
||||
{
|
||||
embeds.push_back(e);
|
||||
return *this;
|
||||
}
|
||||
|
||||
message& message::set_flags(uint8_t f)
|
||||
{
|
||||
flags = f;
|
||||
return *this;
|
||||
}
|
||||
|
||||
message& message::set_type(message_type t)
|
||||
{
|
||||
type = t;
|
||||
return *this;
|
||||
}
|
||||
|
||||
message& message::set_filename(const std::string &fn)
|
||||
{
|
||||
filename = fn;
|
||||
return *this;
|
||||
}
|
||||
|
||||
message& message::set_file_content(const std::string &fc)
|
||||
{
|
||||
filecontent = fc;
|
||||
return *this;
|
||||
}
|
||||
|
||||
message& message::set_content(const std::string &c)
|
||||
{
|
||||
content = utility::utf8substr(c, 0, 2000);
|
||||
return *this;
|
||||
}
|
||||
|
||||
message::message(const std::string &_content, message_type t) : message() {
|
||||
content = utility::utf8substr(_content, 0, 2000);
|
||||
type = t;
|
||||
}
|
||||
|
||||
message::message(snowflake _channel_id, const embed& _embed) : message() {
|
||||
channel_id = _channel_id;
|
||||
embeds.push_back(_embed);
|
||||
}
|
||||
|
||||
embed::embed(json* j) : embed() {
|
||||
title = StringNotNull(j, "title");
|
||||
type = StringNotNull(j, "type");
|
||||
description = StringNotNull(j, "description");
|
||||
url = StringNotNull(j, "url");
|
||||
timestamp = TimestampNotNull(j, "timestamp");
|
||||
color = Int32NotNull(j, "color");
|
||||
if (j->find("footer") != j->end()) {
|
||||
dpp::embed_footer f;
|
||||
json& fj = (*j)["footer"];
|
||||
f.text = StringNotNull(&fj, "text");
|
||||
f.icon_url = StringNotNull(&fj, "icon_url");
|
||||
f.proxy_url = StringNotNull(&fj, "proxy_url");
|
||||
footer = f;
|
||||
}
|
||||
std::vector<std::string> type_list = { "image", "video", "thumbnail" };
|
||||
for (auto& s : type_list) {
|
||||
if (j->find(s) != j->end()) {
|
||||
embed_image curr;
|
||||
json& fi = (*j)[s];
|
||||
curr.url = StringNotNull(&fi, "url");
|
||||
curr.height = StringNotNull(&fi, "height");
|
||||
curr.width = StringNotNull(&fi, "width");
|
||||
curr.proxy_url = StringNotNull(&fi, "proxy_url");
|
||||
if (s == "image") {
|
||||
image = curr;
|
||||
} else if (s == "video") {
|
||||
video = curr;
|
||||
} else if (s == "thumbnail") {
|
||||
thumbnail = curr;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (j->find("provider") != j->end()) {
|
||||
json &p = (*j)["provider"];
|
||||
dpp::embed_provider pr;
|
||||
pr.name = StringNotNull(&p, "name");
|
||||
pr.url = StringNotNull(&p, "url");
|
||||
provider = pr;
|
||||
}
|
||||
if (j->find("author") != j->end()) {
|
||||
json &a = (*j)["author"];
|
||||
dpp::embed_author au;
|
||||
au.name = StringNotNull(&a, "name");
|
||||
au.url = StringNotNull(&a, "url");
|
||||
au.icon_url = StringNotNull(&a, "icon_url");
|
||||
au.proxy_icon_url = StringNotNull(&a, "proxy_icon_url");
|
||||
author = au;
|
||||
}
|
||||
if (j->find("fields") != j->end()) {
|
||||
json &fl = (*j)["fields"];
|
||||
for (auto & field : fl) {
|
||||
embed_field f;
|
||||
f.name = StringNotNull(&field, "name");
|
||||
f.value = StringNotNull(&field, "value");
|
||||
f.is_inline = BoolNotNull(&field, "inline");
|
||||
fields.push_back(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
embed& embed::add_field(const std::string& name, const std::string &value, bool is_inline) {
|
||||
if (fields.size() < 25) {
|
||||
embed_field f;
|
||||
f.name = utility::utf8substr(name, 0, 256);
|
||||
f.value = utility::utf8substr(value, 0, 1024);
|
||||
f.is_inline = is_inline;
|
||||
fields.push_back(f);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
embed& embed::set_author(const embed_author& a)
|
||||
{
|
||||
author = a;
|
||||
return *this;
|
||||
}
|
||||
|
||||
embed& embed::set_author(const std::string& name, const std::string& url, const std::string& icon_url) {
|
||||
dpp::embed_author a;
|
||||
a.name = utility::utf8substr(name, 0, 256);
|
||||
a.url = url;
|
||||
a.icon_url = icon_url;
|
||||
author = a;
|
||||
return *this;
|
||||
}
|
||||
|
||||
embed& embed::set_footer(const embed_footer& f) {
|
||||
footer = f;
|
||||
return *this;
|
||||
}
|
||||
|
||||
embed& embed::set_provider(const std::string& name, const std::string& url) {
|
||||
dpp::embed_provider p;
|
||||
p.name = utility::utf8substr(name, 0, 256);
|
||||
p.url = url;
|
||||
provider = p;
|
||||
return *this;
|
||||
}
|
||||
|
||||
embed& embed::set_image(const std::string& url) {
|
||||
dpp::embed_image i;
|
||||
i.url = url;
|
||||
image = i;
|
||||
return *this;
|
||||
}
|
||||
|
||||
embed& embed::set_video(const std::string& url) {
|
||||
dpp::embed_image v;
|
||||
v.url = url;
|
||||
video = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
embed& embed::set_thumbnail(const std::string& url) {
|
||||
dpp::embed_image t;
|
||||
t.url = url;
|
||||
thumbnail = t;
|
||||
return *this;
|
||||
}
|
||||
|
||||
embed& embed::set_title(const std::string &text) {
|
||||
title = utility::utf8substr(text, 0, 256);
|
||||
return *this;
|
||||
}
|
||||
|
||||
embed& embed::set_description(const std::string &text) {
|
||||
description = utility::utf8substr(text, 0, 4096);
|
||||
return *this;
|
||||
}
|
||||
|
||||
embed& embed::set_color(uint32_t col) {
|
||||
// Mask off alpha, as discord doesn't use it
|
||||
color = col & 0x00FFFFFF;
|
||||
return *this;
|
||||
}
|
||||
|
||||
embed& embed::set_url(const std::string &u) {
|
||||
url = u;
|
||||
return *this;
|
||||
}
|
||||
|
||||
embed_footer& embed_footer::set_text(const std::string& t){
|
||||
text = t;
|
||||
return *this;
|
||||
}
|
||||
|
||||
embed_footer& embed_footer::set_icon(const std::string& i){
|
||||
icon_url = i;
|
||||
return *this;
|
||||
}
|
||||
|
||||
embed_footer& embed_footer::set_proxy(const std::string& p){
|
||||
proxy_url = p;
|
||||
return *this;
|
||||
}
|
||||
|
||||
reaction::reaction() {
|
||||
count = 0;
|
||||
me = false;
|
||||
emoji_id = 0;
|
||||
}
|
||||
|
||||
reaction::reaction(json* j) {
|
||||
count = (*j)["count"];
|
||||
me = (*j)["me"];
|
||||
json emoji = (*j)["emoji"];
|
||||
emoji_id = SnowflakeNotNull(&emoji, "id");
|
||||
emoji_name = StringNotNull(&emoji, "name");
|
||||
}
|
||||
|
||||
attachment::attachment() {
|
||||
id = 0;
|
||||
size = 0;
|
||||
width = 0;
|
||||
height = 0;
|
||||
}
|
||||
|
||||
attachment::attachment(json *j) : attachment() {
|
||||
this->id = SnowflakeNotNull(j, "id");
|
||||
this->size = (*j)["size"];
|
||||
this->filename = (*j)["filename"];
|
||||
this->url = (*j)["url"];
|
||||
this->proxy_url = (*j)["proxy_url"];
|
||||
this->width = Int32NotNull(j, "width");
|
||||
this->height = Int32NotNull(j, "height");
|
||||
this->content_type = StringNotNull(j, "content_type");
|
||||
}
|
||||
|
||||
std::string message::build_json(bool with_id, bool is_interaction_response) const {
|
||||
/* This is the basics. once it works, expand on it. */
|
||||
json j({
|
||||
{"channel_id", channel_id},
|
||||
{"tts", tts},
|
||||
{"nonce", nonce},
|
||||
{"flags", flags},
|
||||
{"type", type}
|
||||
});
|
||||
|
||||
if (with_id) {
|
||||
j["id"] = std::to_string(id);
|
||||
}
|
||||
|
||||
if (!content.empty()) {
|
||||
j["content"] = content;
|
||||
}
|
||||
|
||||
/* Populate message reference */
|
||||
if (message_reference.channel_id || message_reference.guild_id || message_reference.message_id) {
|
||||
j["message_reference"] = json::object();
|
||||
if (message_reference.channel_id) {
|
||||
j["message_reference"]["channel_id"] = std::to_string(message_reference.channel_id);
|
||||
}
|
||||
if (message_reference.guild_id) {
|
||||
j["message_reference"]["guild_id"] = std::to_string(message_reference.guild_id);
|
||||
}
|
||||
if (message_reference.message_id) {
|
||||
j["message_reference"]["message_id"] = std::to_string(message_reference.message_id);
|
||||
}
|
||||
j["message_reference"]["fail_if_not_exists"] = message_reference.fail_if_not_exists;
|
||||
}
|
||||
|
||||
j["allowed_mentions"] = json::object();
|
||||
j["allowed_mentions"]["parse"] = json::array();
|
||||
if (allowed_mentions.parse_everyone || allowed_mentions.parse_roles || allowed_mentions.parse_users || !allowed_mentions.replied_user || allowed_mentions.users.size() || allowed_mentions.roles.size()) {
|
||||
if (allowed_mentions.parse_everyone) {
|
||||
j["allowed_mentions"]["parse"].push_back("everyone");
|
||||
}
|
||||
if (allowed_mentions.parse_roles) {
|
||||
j["allowed_mentions"]["parse"].push_back("roles");
|
||||
}
|
||||
if (allowed_mentions.parse_users) {
|
||||
j["allowed_mentions"]["parse"].push_back("users");
|
||||
}
|
||||
if (!allowed_mentions.replied_user) {
|
||||
j["allowed_mentions"]["replied_user"] = false;
|
||||
}
|
||||
if (allowed_mentions.users.size()) {
|
||||
j["allowed_mentions"]["users"] = json::array();
|
||||
for (auto& user : allowed_mentions.users) {
|
||||
j["allowed_mentions"]["users"].push_back(std::to_string(user));
|
||||
}
|
||||
}
|
||||
if (allowed_mentions.roles.size()) {
|
||||
j["allowed_mentions"]["roles"] = json::array();
|
||||
for (auto& role : allowed_mentions.roles) {
|
||||
j["allowed_mentions"]["roles"].push_back(std::to_string(role));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (components.size()) {
|
||||
j["components"] = json::array();
|
||||
}
|
||||
for (auto & component : components) {
|
||||
json n;
|
||||
n["type"] = cot_action_row;
|
||||
n["components"] = {};
|
||||
json sn;
|
||||
for (auto & subcomponent : component.components) {
|
||||
if (subcomponent.type == cot_button) {
|
||||
sn["type"] = subcomponent.type;
|
||||
sn["label"] = subcomponent.label;
|
||||
sn["style"] = int(subcomponent.style);
|
||||
if (subcomponent.type == cot_button && subcomponent.style != cos_link && !subcomponent.custom_id.empty()) {
|
||||
/* Links cannot have a custom id */
|
||||
sn["custom_id"] = subcomponent.custom_id;
|
||||
}
|
||||
if (subcomponent.type == cot_button && subcomponent.style == cos_link && !subcomponent.url.empty()) {
|
||||
sn["url"] = subcomponent.url;
|
||||
}
|
||||
sn["disabled"] = subcomponent.disabled;
|
||||
|
||||
if (subcomponent.emoji.id || !subcomponent.emoji.name.empty()) {
|
||||
sn["emoji"] = {};
|
||||
sn["emoji"]["animated"] = subcomponent.emoji.animated;
|
||||
}
|
||||
if (subcomponent.emoji.id) {
|
||||
sn["emoji"]["id"] = std::to_string(subcomponent.emoji.id);
|
||||
}
|
||||
if (!subcomponent.emoji.name.empty()) {
|
||||
sn["emoji"]["name"] = subcomponent.emoji.name;
|
||||
}
|
||||
} else if (subcomponent.type == cot_selectmenu) {
|
||||
|
||||
sn["type"] = subcomponent.type;
|
||||
sn["custom_id"] = subcomponent.custom_id;
|
||||
//sn["disabled"] = subcomponent.disabled;
|
||||
if (!subcomponent.placeholder.empty()) {
|
||||
sn["placeholder"] = subcomponent.placeholder;
|
||||
}
|
||||
if (subcomponent.min_values >= 0) {
|
||||
sn["min_values"] = subcomponent.min_values;
|
||||
}
|
||||
if (subcomponent.max_values >= 0) {
|
||||
sn["max_values"] = subcomponent.max_values;
|
||||
}
|
||||
sn["options"] = json::array();
|
||||
for (auto opt : subcomponent.options) {
|
||||
json o;
|
||||
if (!opt.description.empty()) {
|
||||
o["description"] = opt.description;
|
||||
}
|
||||
if (!opt.label.empty()) {
|
||||
o["label"] = opt.label;
|
||||
}
|
||||
if (!opt.value.empty()) {
|
||||
o["value"] = opt.value;
|
||||
}
|
||||
if (opt.is_default) {
|
||||
o["default"] = true;
|
||||
}
|
||||
if (!opt.emoji.name.empty()) {
|
||||
o["emoji"] = json::object();
|
||||
o["emoji"]["name"] = opt.emoji.name;
|
||||
if (opt.emoji.id) {
|
||||
o["emoji"]["id"] = std::to_string(opt.emoji.id);
|
||||
}
|
||||
if (opt.emoji.animated) {
|
||||
o["emoji"]["animated"] = true;
|
||||
}
|
||||
}
|
||||
sn["options"].push_back(o);
|
||||
}
|
||||
}
|
||||
|
||||
n["components"].push_back(sn);
|
||||
}
|
||||
j["components"].push_back(n);
|
||||
}
|
||||
if (embeds.size()) {
|
||||
j["embeds"] = json::array();
|
||||
|
||||
for (auto& embed : embeds) {
|
||||
json e;
|
||||
if (!embed.description.empty())
|
||||
e["description"] = embed.description;
|
||||
if (!embed.title.empty())
|
||||
e["title"] = embed.title;
|
||||
if (!embed.url.empty())
|
||||
e["url"] = embed.url;
|
||||
e["color"] = embed.color;
|
||||
if (embed.footer.has_value()) {
|
||||
e["footer"]["text"] = embed.footer->text;
|
||||
e["footer"]["icon_url"] = embed.footer->icon_url;
|
||||
}
|
||||
if (embed.image.has_value()) {
|
||||
e["image"]["url"] = embed.image->url;
|
||||
}
|
||||
if (embed.thumbnail.has_value()) {
|
||||
e["thumbnail"]["url"] = embed.thumbnail->url;
|
||||
}
|
||||
if (embed.author.has_value()) {
|
||||
e["author"]["name"] = embed.author->name;
|
||||
e["author"]["url"] = embed.author->url;
|
||||
e["author"]["icon_url"] = embed.author->icon_url;
|
||||
}
|
||||
if (embed.fields.size()) {
|
||||
e["fields"] = json();
|
||||
for (auto& field : embed.fields) {
|
||||
json f({ {"name", field.name}, {"value", field.value}, {"inline", field.is_inline} });
|
||||
e["fields"].push_back(f);
|
||||
}
|
||||
}
|
||||
if (embed.timestamp != 0) {
|
||||
std::ostringstream ss;
|
||||
struct tm t;
|
||||
|
||||
#ifdef _WIN32
|
||||
gmtime_s(&t, &embed.timestamp);
|
||||
#else
|
||||
gmtime_r(&embed.timestamp, &t);
|
||||
#endif
|
||||
|
||||
ss << std::put_time(&t, "%FT%TZ");
|
||||
e["timestamp"] = ss.str();
|
||||
}
|
||||
|
||||
j["embeds"].push_back(e);
|
||||
}
|
||||
}
|
||||
return j.dump();
|
||||
}
|
||||
|
||||
bool message::is_crossposted() const {
|
||||
return flags & m_crossposted;
|
||||
}
|
||||
|
||||
bool message::is_crosspost() const {
|
||||
return flags & m_is_crosspost;
|
||||
|
||||
}
|
||||
|
||||
bool message::supress_embeds() const {
|
||||
return flags & m_supress_embeds;
|
||||
}
|
||||
|
||||
bool message::is_source_message_deleted() const {
|
||||
return flags & m_source_message_deleted;
|
||||
}
|
||||
|
||||
bool message::is_urgent() const {
|
||||
return flags & m_urgent;
|
||||
}
|
||||
|
||||
bool message::is_ephemeral() const {
|
||||
return flags & m_ephemeral;
|
||||
}
|
||||
|
||||
bool message::is_loading() const {
|
||||
return flags & m_loading;
|
||||
}
|
||||
|
||||
message::~message() {
|
||||
}
|
||||
|
||||
|
||||
message& message::fill_from_json(json* d, cache_policy_t cp) {
|
||||
this->id = SnowflakeNotNull(d, "id");
|
||||
this->channel_id = SnowflakeNotNull(d, "channel_id");
|
||||
this->guild_id = SnowflakeNotNull(d, "guild_id");
|
||||
/* We didn't get a guild id. See if we can find one in the channel */
|
||||
if (guild_id == 0 && channel_id != 0) {
|
||||
dpp::channel* c = dpp::find_channel(this->channel_id);
|
||||
if (c) {
|
||||
this->guild_id = c->guild_id;
|
||||
}
|
||||
}
|
||||
this->flags = Int8NotNull(d, "flags");
|
||||
this->type = Int8NotNull(d, "type");
|
||||
this->author = nullptr;
|
||||
user* authoruser = nullptr;
|
||||
/* May be null, if its null cache it from the partial */
|
||||
if (d->find("author") != d->end()) {
|
||||
json &j_author = (*d)["author"];
|
||||
if (cp.user_policy == dpp::cp_none) {
|
||||
/* User caching off! Allocate a temp user to be deleted in destructor */
|
||||
authoruser = &self_author;
|
||||
this->author = &self_author;
|
||||
self_author.fill_from_json(&j_author);
|
||||
} else {
|
||||
/* User caching on - aggressive or lazy - create a cached user entry */
|
||||
authoruser = find_user(SnowflakeNotNull(&j_author, "id"));
|
||||
if (!authoruser) {
|
||||
/* User does not exist yet, cache the partial as a user record */
|
||||
authoruser = new user();
|
||||
authoruser->fill_from_json(&j_author);
|
||||
get_user_cache()->store(authoruser);
|
||||
}
|
||||
this->author = authoruser;
|
||||
}
|
||||
}
|
||||
if (d->find("interaction") != d->end()) {
|
||||
json& inter = (*d)["interaction"];
|
||||
interaction.id = SnowflakeNotNull(&inter, "id");
|
||||
interaction.name = StringNotNull(&inter, "name");
|
||||
interaction.type = Int8NotNull(&inter, "type");
|
||||
if (inter.contains("user") && !inter["user"].is_null()) from_json(inter["user"], interaction.usr);
|
||||
}
|
||||
if (d->find("sticker_items") != d->end()) {
|
||||
json &sub = (*d)["sticker_items"];
|
||||
for (auto & sticker_raw : sub) {
|
||||
stickers.push_back(dpp::sticker().fill_from_json(&sticker_raw));
|
||||
}
|
||||
}
|
||||
if (d->find("mentions") != d->end()) {
|
||||
json &sub = (*d)["mentions"];
|
||||
for (auto & m : sub) {
|
||||
mentions.push_back(SnowflakeNotNull(&m, "id"));
|
||||
}
|
||||
}
|
||||
if (d->find("mention_roles") != d->end()) {
|
||||
json &sub = (*d)["mention_roles"];
|
||||
for (auto & m : sub) {
|
||||
mention_roles.push_back(from_string<snowflake>(m, std::dec));
|
||||
}
|
||||
}
|
||||
if (d->find("mention_channels") != d->end()) {
|
||||
json &sub = (*d)["mention_channels"];
|
||||
for (auto & m : sub) {
|
||||
mention_channels.push_back(SnowflakeNotNull(&m, "id"));
|
||||
}
|
||||
}
|
||||
/* Fill in member record, cache uncached ones */
|
||||
guild* g = find_guild(this->guild_id);
|
||||
this->member = {};
|
||||
if (g && d->find("member") != d->end()) {
|
||||
json& mi = (*d)["member"];
|
||||
snowflake uid = SnowflakeNotNull(&(mi["user"]), "id");
|
||||
if (!uid && authoruser) {
|
||||
uid = authoruser->id;
|
||||
}
|
||||
if (cp.user_policy == dpp::cp_none) {
|
||||
/* User caching off! Just fill in directly but dont store member to guild */
|
||||
this->member.fill_from_json(&mi, g->id, uid);
|
||||
} else {
|
||||
/* User caching on, lazy or aggressive - cache the member information */
|
||||
auto thismember = g->members.find(uid);
|
||||
if (thismember == g->members.end()) {
|
||||
if (uid != 0 && authoruser) {
|
||||
guild_member gm;
|
||||
gm.fill_from_json(&mi, g->id, uid);
|
||||
g->members[authoruser->id] = gm;
|
||||
this->member = gm;
|
||||
}
|
||||
} else {
|
||||
/* Update roles etc */
|
||||
this->member = thismember->second;
|
||||
if (authoruser) {
|
||||
this->member.fill_from_json(&mi, g->id, authoruser->id);
|
||||
g->members[authoruser->id] = this->member;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (d->find("embeds") != d->end()) {
|
||||
json & el = (*d)["embeds"];
|
||||
for (auto& e : el) {
|
||||
this->embeds.push_back(embed(&e));
|
||||
}
|
||||
}
|
||||
this->content = StringNotNull(d, "content");
|
||||
this->sent = TimestampNotNull(d, "timestamp");
|
||||
this->edited = TimestampNotNull(d, "edited_timestamp");
|
||||
this->tts = BoolNotNull(d, "tts");
|
||||
this->mention_everyone = BoolNotNull(d, "mention_everyone");
|
||||
if (d->find("reactions") != d->end()) {
|
||||
json & el = (*d)["reactions"];
|
||||
for (auto& e : el) {
|
||||
this->reactions.push_back(reaction(&e));
|
||||
}
|
||||
}
|
||||
if (((*d)["nonce"]).is_string()) {
|
||||
this->nonce = StringNotNull(d, "nonce");
|
||||
} else {
|
||||
this->nonce = std::to_string(SnowflakeNotNull(d, "nonce"));
|
||||
}
|
||||
this->pinned = BoolNotNull(d, "pinned");
|
||||
this->webhook_id = SnowflakeNotNull(d, "webhook_id");
|
||||
for (auto& e : (*d)["attachments"]) {
|
||||
this->attachments.push_back(attachment(&e));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
sticker::sticker() : id(0), pack_id(0), guild_id(0), type(st_standard), format_type(sf_png), available(true), sort_value(0) {
|
||||
}
|
||||
|
||||
sticker& sticker::fill_from_json(nlohmann::json* j) {
|
||||
this->id = SnowflakeNotNull(j, "id");
|
||||
this->pack_id = SnowflakeNotNull(j, "pack_id");
|
||||
this->name = StringNotNull(j, "name");
|
||||
this->description = StringNotNull(j, "description");
|
||||
this->tags = StringNotNull(j, "tags");
|
||||
this->asset = StringNotNull(j, "asset");
|
||||
this->guild_id = SnowflakeNotNull(j, "guild_id");
|
||||
this->type = static_cast<sticker_type>(Int8NotNull(j, "type"));
|
||||
this->format_type = static_cast<sticker_format>(Int8NotNull(j, "format_type"));
|
||||
this->available = BoolNotNull(j, "available");
|
||||
this->sort_value = Int8NotNull(j, "sort_value");
|
||||
if (j->find("user") != j->end()) {
|
||||
sticker_user.fill_from_json(&((*j)["user"]));
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string sticker::build_json(bool with_id) const {
|
||||
json j;
|
||||
|
||||
if (with_id) {
|
||||
j["id"] = std::to_string(this->id);
|
||||
}
|
||||
j["pack_id"] = std::to_string(this->pack_id);
|
||||
if (this->guild_id) {
|
||||
j["guild_id"] = std::to_string(this->guild_id);
|
||||
}
|
||||
j["name"] = this->name;
|
||||
j["description"] = this->description;
|
||||
if (!this->tags.empty()) {
|
||||
j["tags"] = this->tags;
|
||||
}
|
||||
if (!this->asset.empty()) {
|
||||
j["asset"] = this->asset;
|
||||
}
|
||||
j["type"] = this->type;
|
||||
j["format_type"] = this->format_type;
|
||||
j["available"] = this->available;
|
||||
j["sort_value"] = this->sort_value;
|
||||
|
||||
return j.dump();
|
||||
}
|
||||
|
||||
sticker_pack::sticker_pack() : id(0), sku_id(0), cover_sticker_id(0), banner_asset_id(0) {
|
||||
}
|
||||
|
||||
sticker_pack& sticker_pack::fill_from_json(nlohmann::json* j) {
|
||||
this->id = SnowflakeNotNull(j, "id");
|
||||
this->sku_id = SnowflakeNotNull(j, "sku_id");
|
||||
this->cover_sticker_id = SnowflakeNotNull(j, "cover_sticker_id");
|
||||
this->banner_asset_id = SnowflakeNotNull(j, "banner_asset_id");
|
||||
this->name = StringNotNull(j, "name");
|
||||
this->description = StringNotNull(j, "description");
|
||||
if (j->find("stickers") != j->end()) {
|
||||
json & sl = (*j)["stickers"];
|
||||
for (auto& s : sl) {
|
||||
this->stickers[SnowflakeNotNull(&s, "id")] = sticker().fill_from_json(&s);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string sticker_pack::build_json(bool with_id) const {
|
||||
json j;
|
||||
if (with_id) {
|
||||
j["id"] = std::to_string(this->id);
|
||||
}
|
||||
if (sku_id) {
|
||||
j["sku_id"] = std::to_string(sku_id);
|
||||
}
|
||||
if (cover_sticker_id) {
|
||||
j["cover_sticker_id"] = std::to_string(cover_sticker_id);
|
||||
}
|
||||
if (banner_asset_id) {
|
||||
j["banner_asset_id"] = std::to_string(banner_asset_id);
|
||||
}
|
||||
j["name"] = name;
|
||||
j["description"] = description;
|
||||
j["stickers"] = json::array();
|
||||
for (auto& s : stickers) {
|
||||
j["stickers"].push_back(json::parse(s.second.build_json(with_id)));
|
||||
}
|
||||
return j.dump();
|
||||
}
|
||||
|
||||
sticker& sticker::set_filename(const std::string &fn) {
|
||||
filename = fn;
|
||||
return *this;
|
||||
}
|
||||
|
||||
sticker& sticker::set_file_content(const std::string &fc) {
|
||||
filecontent = fc;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
};
|
211
vendor/DPP/src/dpp/presence.cpp
vendored
Normal file
211
vendor/DPP/src/dpp/presence.cpp
vendored
Normal file
@ -0,0 +1,211 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/presence.h>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp {
|
||||
|
||||
activity::activity(const activity_type typ, const std::string& nam, const std::string& stat, const std::string& url_) : type(typ), name(nam), state(stat), url(url_)
|
||||
{
|
||||
}
|
||||
|
||||
presence::presence() : guild_id(0), user_id(0), flags(0)
|
||||
{
|
||||
}
|
||||
|
||||
presence::presence(presence_status status, activity_type type, const std::string& activity_description) {
|
||||
dpp::activity a;
|
||||
a.name = activity_description;
|
||||
a.type = type;
|
||||
activities.clear();
|
||||
activities.push_back(a);
|
||||
flags &= PF_CLEAR_STATUS;
|
||||
if (status == ps_online)
|
||||
flags |= p_status_online;
|
||||
else if (status == ps_idle)
|
||||
flags |= p_status_idle;
|
||||
else if (status == ps_dnd)
|
||||
flags |= p_status_dnd;
|
||||
}
|
||||
|
||||
presence::presence(presence_status status, activity a) {
|
||||
activities.clear();
|
||||
activities.push_back(std::move(a));
|
||||
flags &= PF_CLEAR_STATUS;
|
||||
if (status == ps_online)
|
||||
flags |= p_status_online;
|
||||
else if (status == ps_idle)
|
||||
flags |= p_status_idle;
|
||||
else if (status == ps_dnd)
|
||||
flags |= p_status_dnd;
|
||||
}
|
||||
|
||||
presence::~presence() {
|
||||
}
|
||||
|
||||
presence& presence::fill_from_json(nlohmann::json* j) {
|
||||
guild_id = SnowflakeNotNull(j, "guild_id");
|
||||
user_id = SnowflakeNotNull(&((*j)["user"]), "id");
|
||||
|
||||
auto f = j->find("client_status");
|
||||
if (f != j->end()) {
|
||||
|
||||
bool update_desktop = false, update_web = false, update_mobile = false;
|
||||
std::string desktop, mobile, web;
|
||||
|
||||
if (f->find("desktop") != f->end()) {
|
||||
desktop = StringNotNull(&((*j)["client_status"]), "desktop");
|
||||
update_desktop = true;
|
||||
}
|
||||
if (f->find("mobile") != f->end()) {
|
||||
mobile = StringNotNull(&((*j)["client_status"]), "mobile");
|
||||
update_mobile = true;
|
||||
}
|
||||
if (f->find("web") != f->end()) {
|
||||
web = StringNotNull(&((*j)["client_status"]), "web");
|
||||
update_web = true;
|
||||
}
|
||||
|
||||
if (update_desktop) {
|
||||
flags &= PF_CLEAR_DESKTOP;
|
||||
if (desktop == "online")
|
||||
flags |= p_desktop_online;
|
||||
else if (desktop == "idle")
|
||||
flags |= p_desktop_idle;
|
||||
else if (desktop == "dnd")
|
||||
flags |= p_desktop_dnd;
|
||||
}
|
||||
|
||||
if (update_mobile) {
|
||||
flags &= PF_CLEAR_MOBILE;
|
||||
if (mobile == "online")
|
||||
flags |= p_mobile_online;
|
||||
else if (mobile == "idle")
|
||||
flags |= p_mobile_idle;
|
||||
else if (mobile == "dnd")
|
||||
flags |= p_mobile_dnd;
|
||||
}
|
||||
|
||||
if (update_web) {
|
||||
flags &= PF_CLEAR_WEB;
|
||||
if (web == "online")
|
||||
flags |= p_web_online;
|
||||
else if (web == "idle")
|
||||
flags |= p_web_idle;
|
||||
else if (web == "dnd")
|
||||
flags |= p_web_dnd;
|
||||
}
|
||||
}
|
||||
|
||||
if (j->find("status") != j->end()) {
|
||||
flags &= PF_CLEAR_STATUS;
|
||||
std::string main = StringNotNull(j, "status");
|
||||
if (main == "online")
|
||||
flags |= p_status_online;
|
||||
else if (main == "idle")
|
||||
flags |= p_status_idle;
|
||||
else if (main == "dnd")
|
||||
flags |= p_status_dnd;
|
||||
}
|
||||
|
||||
|
||||
if (j->find("activities") != j->end()) {
|
||||
activities.clear();
|
||||
for (auto & act : (*j)["activities"]) {
|
||||
activity a;
|
||||
a.name = StringNotNull(&act, "name");
|
||||
a.state = StringNotNull(&act, "state"); // if user
|
||||
if (a.state.empty()) a.state = StringNotNull(&act, "details"); // if activity from bot, maybe?
|
||||
a.type = (activity_type)Int8NotNull(&act, "type");
|
||||
a.url = StringNotNull(&act, "url");
|
||||
a.created_at = Int64NotNull(&act, "created_at");
|
||||
if (act.find("timestamps") != act.end()) {
|
||||
a.start = Int64NotNull(&(act["timestamps"]), "start");
|
||||
a.end = Int64NotNull(&(act["timestamps"]), "end");
|
||||
}
|
||||
a.application_id = SnowflakeNotNull(&act, "application_id");
|
||||
a.flags = Int8NotNull(&act, "flags");
|
||||
|
||||
activities.push_back(a);
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string presence::build_json() const {
|
||||
std::map<presence_status, std::string> status_name_mapping = {
|
||||
{ps_online, "online"},
|
||||
{ps_offline, "offline"},
|
||||
{ps_idle, "idle"},
|
||||
{ps_dnd, "dnd"}
|
||||
};
|
||||
json j({
|
||||
|
||||
{"op", 3},
|
||||
{"d",
|
||||
{
|
||||
{ "status", status_name_mapping[status()] },
|
||||
{ "since", json::value_t::null },
|
||||
{ "afk", false }
|
||||
}
|
||||
}
|
||||
});
|
||||
if (activities.size()) {
|
||||
for(const auto& i : activities){
|
||||
json j2({
|
||||
{ "name", i.name },
|
||||
{ "type", i.type }
|
||||
});
|
||||
if (!i.url.empty()) j2["url"] = i.url;
|
||||
if (!i.state.empty()) j2["details"] = i.state; // bot activity is details, not state
|
||||
|
||||
j["d"]["activities"].push_back(j2);
|
||||
}
|
||||
/*j["d"]["game"] = json({ // use activities instead.
|
||||
{ "name", activities[0].name },
|
||||
{ "type", activities[0].type }
|
||||
});*/
|
||||
}
|
||||
|
||||
return j.dump();
|
||||
}
|
||||
|
||||
presence_status presence::desktop_status() const {
|
||||
return (presence_status)((flags >> PF_SHIFT_DESKTOP) & PF_STATUS_MASK);
|
||||
}
|
||||
|
||||
presence_status presence::web_status() const {
|
||||
return (presence_status)((flags >> PF_SHIFT_WEB) & PF_STATUS_MASK);
|
||||
}
|
||||
|
||||
presence_status presence::mobile_status() const {
|
||||
return (presence_status)((flags >> PF_SHIFT_MOBILE) & PF_STATUS_MASK);
|
||||
}
|
||||
|
||||
presence_status presence::status() const {
|
||||
return (presence_status)((flags >> PF_SHIFT_MAIN) & PF_STATUS_MASK);
|
||||
}
|
||||
|
||||
};
|
53
vendor/DPP/src/dpp/prune.cpp
vendored
Normal file
53
vendor/DPP/src/dpp/prune.cpp
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/prune.h>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
namespace dpp {
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
prune& prune::fill_from_json(nlohmann::json* j) {
|
||||
days = Int32NotNull(j, "days");
|
||||
compute_prune_count = BoolNotNull(j, "compute_prune_count");
|
||||
if (j->find("include_roles") != j->end()) {
|
||||
for (auto & r : (*j)["include_roles"]) {
|
||||
include_roles.push_back(from_string<uint64_t>(r.get<std::string>(), std::dec));
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string prune::build_json(bool with_prune_count) const {
|
||||
json j;
|
||||
for (auto & r : include_roles) {
|
||||
j["include_roles"].push_back(std::to_string(r));
|
||||
}
|
||||
if (with_prune_count) {
|
||||
j["compute_prune_count"] = compute_prune_count;
|
||||
}
|
||||
j["days"] = days;
|
||||
return j.dump();
|
||||
}
|
||||
|
||||
};
|
472
vendor/DPP/src/dpp/queues.cpp
vendored
Normal file
472
vendor/DPP/src/dpp/queues.cpp
vendored
Normal file
@ -0,0 +1,472 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <WinSock2.h>
|
||||
#include <WS2tcpip.h>
|
||||
#include <io.h>
|
||||
#pragma comment(lib,"ws2_32")
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <random>
|
||||
#include <dpp/queues.h>
|
||||
#include <dpp/cluster.h>
|
||||
#define CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
#include <dpp/httplib.h>
|
||||
#include <fmt/format.h>
|
||||
#include <dpp/stringops.h>
|
||||
|
||||
namespace dpp {
|
||||
|
||||
http_request::http_request(const std::string &_endpoint, const std::string &_parameters, http_completion_event completion, const std::string &_postdata, http_method _method, const std::string &filename, const std::string &filecontent) : endpoint(_endpoint), parameters(_parameters), complete_handler(completion), postdata(_postdata), method(_method), completed(false), file_name(filename), file_content(filecontent)
|
||||
{
|
||||
}
|
||||
|
||||
http_request::~http_request() {
|
||||
}
|
||||
|
||||
void http_request::complete(const http_request_completion_t &c) {
|
||||
/* Call completion handler only if the request has been completed */
|
||||
if (is_completed() && complete_handler)
|
||||
complete_handler(c);
|
||||
}
|
||||
|
||||
/* Fill a http_request_completion_t from a HTTP result */
|
||||
void populate_result(const std::string &url, const cluster* owner, http_request_completion_t& rv, const httplib::Result &res) {
|
||||
rv.status = res->status;
|
||||
rv.body = res->body;
|
||||
for (auto &v : res->headers) {
|
||||
rv.headers[v.first] = v.second;
|
||||
}
|
||||
rv.ratelimit_limit = from_string<uint64_t>(res->get_header_value("X-RateLimit-Limit"), std::dec);
|
||||
rv.ratelimit_remaining = from_string<uint64_t>(res->get_header_value("X-RateLimit-Remaining"), std::dec);
|
||||
rv.ratelimit_reset_after = from_string<uint64_t>(res->get_header_value("X-RateLimit-Reset-After"), std::dec);
|
||||
rv.ratelimit_bucket = res->get_header_value("X-RateLimit-Bucket");
|
||||
rv.ratelimit_global = (res->get_header_value("X-RateLimit-Global") == "true");
|
||||
if (res->get_header_value("X-RateLimit-Retry-After") != "") {
|
||||
rv.ratelimit_retry_after = from_string<uint64_t>(res->get_header_value("X-RateLimit-Retry-After"), std::dec);
|
||||
}
|
||||
if (rv.status == 429) {
|
||||
owner->log(ll_warning, fmt::format("Rate limited on endpoint {}, reset after {}s!", url, rv.ratelimit_retry_after ? rv.ratelimit_retry_after : rv.ratelimit_reset_after));
|
||||
}
|
||||
if (url != "/api/v" DISCORD_API_VERSION "/gateway/bot") { // Squelch this particular api endpoint or it generates a warning the minute we boot a cluster
|
||||
if (rv.ratelimit_global) {
|
||||
owner->log(ll_warning, fmt::format("At global rate limit on endpoint {}, reset after {}s", url, rv.ratelimit_retry_after ? rv.ratelimit_retry_after : rv.ratelimit_reset_after));
|
||||
} else if (rv.ratelimit_remaining == 1) {
|
||||
owner->log(ll_warning, fmt::format("Near endpoint {} rate limit, reset after {}s", url, rv.ratelimit_retry_after ? rv.ratelimit_retry_after : rv.ratelimit_reset_after));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns true if the request has been made */
|
||||
bool http_request::is_completed()
|
||||
{
|
||||
return completed;
|
||||
}
|
||||
|
||||
/* Execute a HTTP request */
|
||||
http_request_completion_t http_request::Run(const cluster* owner) {
|
||||
|
||||
http_request_completion_t rv;
|
||||
|
||||
httplib::Client cli("https://discord.com");
|
||||
/* This is for a reason :( - Some systems have really out of date cert stores */
|
||||
cli.enable_server_certificate_verification(false);
|
||||
cli.set_follow_location(true);
|
||||
/* TODO: Once we have a version number header, use it here */
|
||||
httplib::Headers headers = {
|
||||
{"Authorization", std::string("Bot ") + owner->token},
|
||||
{"User-Agent", "DiscordBot (https://github.com/brainboxdotcc/DPP, 0.0.1)"}
|
||||
};
|
||||
cli.set_default_headers(headers);
|
||||
|
||||
rv.ratelimit_limit = rv.ratelimit_remaining = rv.ratelimit_reset_after = rv.ratelimit_retry_after = 0;
|
||||
rv.status = 0;
|
||||
rv.ratelimit_global = false;
|
||||
|
||||
std::string _url = endpoint;
|
||||
if (!empty(parameters)) {
|
||||
_url = endpoint + "/" +parameters;
|
||||
}
|
||||
|
||||
/* Because of the design of cpp-httplib we can't create a httplib::Result once and make this code
|
||||
* shorter. We have to use "auto res = ...". This is because httplib::Result has no default constructor
|
||||
* and needs to be passed a result and some other blackboxed rammel.
|
||||
*/
|
||||
switch (method) {
|
||||
case m_get: {
|
||||
if (auto res = cli.Get(_url.c_str())) {
|
||||
populate_result(_url, owner, rv, res);
|
||||
} else {
|
||||
rv.error = (http_error)res.error();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case m_post: {
|
||||
/* POST supports post data body */
|
||||
if (!file_name.empty() && !file_content.empty()) {
|
||||
httplib::MultipartFormDataItems items = {
|
||||
{ "payload_json", postdata, "", "application/json" },
|
||||
{ "file", file_content, file_name, "application/octet-stream" }
|
||||
};
|
||||
if (auto res = cli.Post(_url.c_str(), items)) {
|
||||
populate_result(_url, owner, rv, res);
|
||||
} else {
|
||||
rv.error = (http_error)res.error();
|
||||
}
|
||||
} else {
|
||||
if (auto res = cli.Post(_url.c_str(), postdata.c_str(), "application/json")) {
|
||||
populate_result(_url, owner, rv, res);
|
||||
} else {
|
||||
rv.error = (http_error)res.error();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case m_patch: {
|
||||
if (auto res = cli.Patch(_url.c_str(), postdata.c_str(), "application/json")) {
|
||||
populate_result(_url, owner, rv, res);
|
||||
} else {
|
||||
rv.error = (http_error)res.error();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case m_put: {
|
||||
/* PUT supports post data body */
|
||||
if (auto res = cli.Put(_url.c_str(), postdata.c_str(), "application/json")) {
|
||||
populate_result(_url, owner, rv, res);
|
||||
} else {
|
||||
rv.error = (http_error)res.error();
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case m_delete: {
|
||||
if (auto res = cli.Delete(_url.c_str())) {
|
||||
populate_result(_url, owner, rv, res);
|
||||
} else {
|
||||
rv.error = (http_error)res.error();
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* Set completion flag */
|
||||
completed = true;
|
||||
return rv;
|
||||
}
|
||||
|
||||
request_queue::request_queue(const class cluster* owner) : creator(owner), terminating(false), globally_ratelimited(false), globally_limited_for(0)
|
||||
{
|
||||
in_queue_listen_sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
out_queue_listen_sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (in_queue_listen_sock == -1 || out_queue_listen_sock == -1) {
|
||||
throw dpp::exception("Can't initialise request queue sockets");
|
||||
}
|
||||
|
||||
std::mt19937 generator(time(NULL));
|
||||
std::uniform_real_distribution<double> distribution(8192, 32760);
|
||||
|
||||
in_queue_port = distribution(generator);
|
||||
out_queue_port = distribution(generator);
|
||||
|
||||
struct sockaddr_in in_server, out_server;
|
||||
in_server.sin_family = out_server.sin_family = AF_INET;
|
||||
in_server.sin_addr.s_addr = out_server.sin_addr.s_addr = htonl(0x7f000001); /* Localhost */
|
||||
in_server.sin_port = htons(in_queue_port);
|
||||
out_server.sin_port = htons(out_queue_port);
|
||||
|
||||
if ((bind(in_queue_listen_sock, (struct sockaddr *)&in_server , sizeof(in_server)) < 0) || (bind(out_queue_listen_sock, (struct sockaddr *)&out_server , sizeof(out_server)) < 0)) {
|
||||
throw dpp::exception("Can't bind request queue sockets");
|
||||
}
|
||||
/* Backlog is only 1, because we only expect our own system to connect back to this once */
|
||||
listen(in_queue_listen_sock, 1);
|
||||
listen(out_queue_listen_sock, 1);
|
||||
|
||||
in_thread = new std::thread(&request_queue::in_loop, this);
|
||||
out_thread = new std::thread(&request_queue::out_loop, this);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(250));
|
||||
|
||||
in_queue_connect_sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
out_queue_connect_sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (in_queue_connect_sock == -1 || out_queue_connect_sock == -1) {
|
||||
throw dpp::exception("Can't initialise request queue notifier sockets");
|
||||
}
|
||||
|
||||
struct sockaddr_in in_client, out_client;
|
||||
in_client.sin_addr.s_addr = out_client.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
in_client.sin_family = out_client.sin_family = AF_INET;
|
||||
in_client.sin_port = htons(in_queue_port);
|
||||
out_client.sin_port = htons(out_queue_port);
|
||||
|
||||
if ((connect(in_queue_connect_sock, (struct sockaddr *)&in_client, sizeof(in_client)) < 0) || (connect(out_queue_connect_sock, (struct sockaddr *)&out_client, sizeof(out_client)) < 0)) {
|
||||
throw dpp::exception("Can't connect notifiers");
|
||||
}
|
||||
}
|
||||
|
||||
request_queue::~request_queue()
|
||||
{
|
||||
terminating = true;
|
||||
in_thread->join();
|
||||
out_thread->join();
|
||||
delete in_thread;
|
||||
delete out_thread;
|
||||
}
|
||||
|
||||
void request_queue::in_loop()
|
||||
{
|
||||
int c = sizeof(struct sockaddr_in);
|
||||
fd_set readfds;
|
||||
timeval ts;
|
||||
char n;
|
||||
struct sockaddr_in client;
|
||||
int notifier = accept(in_queue_listen_sock, (struct sockaddr *)&client, (socklen_t*)&c);
|
||||
#ifndef _WIN32
|
||||
close(in_queue_listen_sock);
|
||||
#endif
|
||||
while (!terminating) {
|
||||
/* select for one second, waiting for new data */
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(notifier, &readfds);
|
||||
ts.tv_sec = 1;
|
||||
ts.tv_usec = 0;
|
||||
int r = select(FD_SETSIZE, &readfds, 0, 0, &ts);
|
||||
time_t now = time(nullptr);
|
||||
|
||||
if (r > 0 && FD_ISSET(notifier, &readfds)) {
|
||||
|
||||
if (recv(notifier, &n, 1, 0) > 0) {
|
||||
/* New request to be sent! */
|
||||
|
||||
if (!globally_ratelimited) {
|
||||
|
||||
std::map<std::string, std::vector<http_request*>> requests_in_copy;
|
||||
{
|
||||
/* Make a safe copy within a mutex */
|
||||
std::lock_guard<std::mutex> lock(in_mutex);
|
||||
requests_in_copy = requests_in;
|
||||
}
|
||||
|
||||
for (auto & bucket : requests_in_copy) {
|
||||
for (auto req : bucket.second) {
|
||||
|
||||
http_request_completion_t rv;
|
||||
auto currbucket = buckets.find(bucket.first);
|
||||
|
||||
if (currbucket != buckets.end()) {
|
||||
/* Theres a bucket for this request. Check its status. If the bucket says to wait,
|
||||
* skip all requests in this bucket till its ok.
|
||||
*/
|
||||
if (currbucket->second.remaining < 1) {
|
||||
uint64_t wait = (currbucket->second.retry_after ? currbucket->second.retry_after : currbucket->second.reset_after);
|
||||
if (time(NULL) > currbucket->second.timestamp + wait) {
|
||||
/* Time has passed, we can process this bucket again. send its request. */
|
||||
rv = req->Run(creator);
|
||||
} else {
|
||||
/* Time not up yet, emit signal and wait */
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
emit_in_queue_signal();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* There's limit remaining, we can just run the request */
|
||||
rv = req->Run(creator);
|
||||
}
|
||||
} else {
|
||||
/* No bucket for this endpoint yet. Just send it, and make one from its reply */
|
||||
rv = req->Run(creator);
|
||||
}
|
||||
|
||||
bucket_t newbucket;
|
||||
newbucket.limit = rv.ratelimit_limit;
|
||||
newbucket.remaining = rv.ratelimit_remaining;
|
||||
newbucket.reset_after = rv.ratelimit_reset_after;
|
||||
newbucket.retry_after = rv.ratelimit_retry_after;
|
||||
newbucket.timestamp = time(NULL);
|
||||
globally_ratelimited = rv.ratelimit_global;
|
||||
if (globally_ratelimited) {
|
||||
globally_limited_for = (newbucket.retry_after ? newbucket.retry_after : newbucket.reset_after);
|
||||
}
|
||||
buckets[req->endpoint] = newbucket;
|
||||
|
||||
/* Make a new entry in the completion list and notify */
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(out_mutex);
|
||||
http_request_completion_t* hrc = new http_request_completion_t();
|
||||
*hrc = rv;
|
||||
responses_out.push(std::make_pair(hrc, req));
|
||||
emit_out_queue_signal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(in_mutex);
|
||||
bool again = false;
|
||||
do {
|
||||
again = false;
|
||||
for (auto & bucket : requests_in) {
|
||||
for (auto req = bucket.second.begin(); req != bucket.second.end(); ++req) {
|
||||
if ((*req)->is_completed()) {
|
||||
requests_in[bucket.first].erase(req);
|
||||
again = true;
|
||||
goto out; /* Only clean way out of a nested loop */
|
||||
}
|
||||
}
|
||||
}
|
||||
out:;
|
||||
} while (again);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (globally_limited_for > 0) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(globally_limited_for));
|
||||
globally_limited_for = 0;
|
||||
}
|
||||
globally_ratelimited = false;
|
||||
emit_in_queue_signal();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
close(notifier);
|
||||
}
|
||||
|
||||
void request_queue::out_loop()
|
||||
{
|
||||
int c = sizeof(struct sockaddr_in);
|
||||
fd_set readfds;
|
||||
timeval ts;
|
||||
char n;
|
||||
struct sockaddr_in client;
|
||||
SOCKET notifier = accept(out_queue_listen_sock, (struct sockaddr *)&client, (socklen_t*)&c);
|
||||
#ifndef _WIN32
|
||||
close(out_queue_listen_sock);
|
||||
#endif
|
||||
while (!terminating) {
|
||||
|
||||
/* select for one second, waiting for new data */
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(notifier, &readfds);
|
||||
ts.tv_sec = 1;
|
||||
ts.tv_usec = 0;
|
||||
int r = select(FD_SETSIZE, &readfds, 0, 0, &ts);
|
||||
time_t now = time(nullptr);
|
||||
|
||||
if (r > 0 && FD_ISSET(notifier, &readfds)) {
|
||||
if (recv(notifier, &n, 1, 0) > 0) {
|
||||
|
||||
/* A request has been completed! */
|
||||
std::pair<http_request_completion_t*, http_request*> queue_head = {};
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(out_mutex);
|
||||
if (responses_out.size()) {
|
||||
queue_head = responses_out.front();
|
||||
responses_out.pop();
|
||||
}
|
||||
}
|
||||
|
||||
if (queue_head.first && queue_head.second) {
|
||||
queue_head.second->complete(*queue_head.first);
|
||||
}
|
||||
|
||||
/* Queue deletions for 60 seconds from now */
|
||||
responses_to_delete.insert(std::make_pair(now + 60, queue_head));
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for deletable items every second regardless of select status */
|
||||
while (responses_to_delete.size() && now >= responses_to_delete.begin()->first) {
|
||||
delete responses_to_delete.begin()->second.first;
|
||||
delete responses_to_delete.begin()->second.second;
|
||||
responses_to_delete.erase(responses_to_delete.begin());
|
||||
}
|
||||
}
|
||||
shutdown(notifier, 2);
|
||||
#ifdef _WIN32
|
||||
if (notifier >= 0 && notifier < FD_SETSIZE) {
|
||||
closesocket(notifier);
|
||||
}
|
||||
#else
|
||||
::close(notifier);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* These only need to send a byte to notify the other end of something to do. any byte will do.
|
||||
*/
|
||||
void request_queue::emit_in_queue_signal()
|
||||
{
|
||||
send(in_queue_connect_sock, "X", 1, 0);
|
||||
}
|
||||
|
||||
void request_queue::emit_out_queue_signal()
|
||||
{
|
||||
send(out_queue_connect_sock, "X", 1, 0);
|
||||
}
|
||||
|
||||
/* Post a http_request into the queue */
|
||||
void request_queue::post_request(http_request* req)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(in_mutex);
|
||||
requests_in[req->endpoint].push_back(req);
|
||||
emit_in_queue_signal();
|
||||
}
|
||||
|
||||
std::string url_encode(const std::string &value) {
|
||||
std::ostringstream escaped;
|
||||
escaped.fill('0');
|
||||
escaped << std::hex;
|
||||
|
||||
for (std::string::const_iterator i = value.begin(), n = value.end(); i != n; ++i) {
|
||||
std::string::value_type c = (*i);
|
||||
|
||||
// Keep alphanumeric and other accepted characters intact
|
||||
if (isalnum((unsigned char)c) || c == '-' || c == '_' || c == '.' || c == '~') {
|
||||
escaped << c;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Any other characters are percent-encoded
|
||||
escaped << std::uppercase;
|
||||
escaped << '%' << std::setw(2) << int((unsigned char) c);
|
||||
escaped << std::nouppercase;
|
||||
}
|
||||
|
||||
return escaped.str();
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
238
vendor/DPP/src/dpp/role.cpp
vendored
Normal file
238
vendor/DPP/src/dpp/role.cpp
vendored
Normal file
@ -0,0 +1,238 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp {
|
||||
|
||||
role::role() :
|
||||
managed(),
|
||||
guild_id(0),
|
||||
colour(0),
|
||||
position(0),
|
||||
permissions(0),
|
||||
flags(0),
|
||||
integration_id(0),
|
||||
bot_id(0)
|
||||
{
|
||||
}
|
||||
|
||||
role::~role()
|
||||
{
|
||||
}
|
||||
|
||||
role& role::fill_from_json(snowflake _guild_id, nlohmann::json* j)
|
||||
{
|
||||
this->guild_id = _guild_id;
|
||||
this->name = StringNotNull(j, "name");
|
||||
this->id = SnowflakeNotNull(j, "id");
|
||||
this->colour = Int32NotNull(j, "color");
|
||||
this->position = Int8NotNull(j, "position");
|
||||
this->permissions = SnowflakeNotNull(j, "permissions");
|
||||
this->flags |= BoolNotNull(j, "hoist") ? dpp::r_hoist : 0;
|
||||
this->flags |= BoolNotNull(j, "managed") ? dpp::r_managed : 0;
|
||||
this->flags |= BoolNotNull(j, "mentionable") ? dpp::r_mentionable : 0;
|
||||
if (j->find("tags") != j->end()) {
|
||||
auto t = (*j)["tags"];
|
||||
this->flags |= BoolNotNull(&t, "premium_subscriber") ? dpp::r_premium_subscriber : 0;
|
||||
this->bot_id = SnowflakeNotNull(&t, "bot_id");
|
||||
this->integration_id = SnowflakeNotNull(&t, "integration_id");
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string role::build_json(bool with_id) const {
|
||||
json j;
|
||||
|
||||
if (with_id) {
|
||||
j["id"] = std::to_string(id);
|
||||
}
|
||||
if (colour) {
|
||||
j["color"] = colour;
|
||||
}
|
||||
j["position"] = position;
|
||||
j["permissions"] = permissions;
|
||||
j["hoist"] = is_hoisted();
|
||||
j["mentionable"] = is_mentionable();
|
||||
|
||||
return j.dump();
|
||||
}
|
||||
|
||||
bool role::is_hoisted() const {
|
||||
return this->flags & dpp::r_hoist;
|
||||
}
|
||||
|
||||
bool role::is_mentionable() const {
|
||||
return this->flags & dpp::r_mentionable;
|
||||
}
|
||||
|
||||
bool role::is_managed() const {
|
||||
return this->flags & dpp::r_managed;
|
||||
}
|
||||
|
||||
bool role::has_create_instant_invite() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_create_instant_invite));
|
||||
}
|
||||
|
||||
bool role::has_kick_members() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_kick_members));
|
||||
}
|
||||
|
||||
bool role::has_ban_members() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_ban_members));
|
||||
}
|
||||
|
||||
bool role::has_administrator() const {
|
||||
return (this->permissions & p_administrator);
|
||||
}
|
||||
|
||||
bool role::has_manage_channels() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_manage_channels));
|
||||
}
|
||||
|
||||
bool role::has_manage_guild() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_manage_guild));
|
||||
}
|
||||
|
||||
bool role::has_add_reactions() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_add_reactions));
|
||||
}
|
||||
|
||||
bool role::has_view_audit_log() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_view_audit_log));
|
||||
}
|
||||
|
||||
bool role::has_priority_speaker() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_priority_speaker));
|
||||
}
|
||||
|
||||
bool role::has_stream() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_stream));
|
||||
}
|
||||
|
||||
bool role::has_view_channel() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_view_channel));
|
||||
}
|
||||
|
||||
bool role::has_send_messages() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_send_messages));
|
||||
}
|
||||
|
||||
bool role::has_send_tts_messages() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_send_tts_messages));
|
||||
}
|
||||
|
||||
bool role::has_manage_messages() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_manage_messages));
|
||||
}
|
||||
|
||||
bool role::has_embed_links() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_embed_links));
|
||||
}
|
||||
|
||||
bool role::has_attach_files() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_attach_files));
|
||||
}
|
||||
|
||||
bool role::has_read_message_history() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_read_message_history));
|
||||
}
|
||||
|
||||
bool role::has_mention_everyone() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_mention_everyone));
|
||||
}
|
||||
|
||||
bool role::has_use_external_emojis() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_use_external_emojis));
|
||||
}
|
||||
|
||||
bool role::has_view_guild_insights() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_view_guild_insights));
|
||||
}
|
||||
|
||||
bool role::has_connect() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_connect));
|
||||
}
|
||||
|
||||
bool role::has_speak() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_speak));
|
||||
}
|
||||
|
||||
bool role::has_mute_members() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_mute_members));
|
||||
}
|
||||
|
||||
bool role::has_deafen_members() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_deafen_members));
|
||||
}
|
||||
|
||||
bool role::has_move_members() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_move_members));
|
||||
}
|
||||
|
||||
bool role::has_use_vad() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_use_vad));
|
||||
}
|
||||
|
||||
bool role::has_change_nickname() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_change_nickname));
|
||||
}
|
||||
|
||||
bool role::has_manage_nicknames() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_manage_nicknames));
|
||||
}
|
||||
|
||||
bool role::has_manage_roles() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_manage_roles));
|
||||
}
|
||||
|
||||
bool role::has_manage_webhooks() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_manage_webhooks));
|
||||
}
|
||||
|
||||
bool role::has_manage_emojis() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_manage_emojis));
|
||||
}
|
||||
|
||||
bool role::has_use_slash_commands() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_use_slash_commands));
|
||||
}
|
||||
|
||||
bool role::has_request_to_speak() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_request_to_speak));
|
||||
}
|
||||
|
||||
bool role::has_manage_threads() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_manage_threads));
|
||||
}
|
||||
|
||||
bool role::has_use_public_threads() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_use_public_threads));
|
||||
}
|
||||
|
||||
bool role::has_use_private_threads() const {
|
||||
return ((this->permissions & p_administrator) | (this->permissions & p_use_private_threads));
|
||||
}
|
||||
};
|
332
vendor/DPP/src/dpp/slashcommand.cpp
vendored
Normal file
332
vendor/DPP/src/dpp/slashcommand.cpp
vendored
Normal file
@ -0,0 +1,332 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/slashcommand.h>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <iostream>
|
||||
|
||||
namespace dpp {
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
slashcommand::slashcommand() : managed(), default_permission(true), type(ctxm_none) {
|
||||
}
|
||||
|
||||
slashcommand::~slashcommand() {
|
||||
}
|
||||
|
||||
slashcommand& slashcommand::fill_from_json(nlohmann::json* j) {
|
||||
id = SnowflakeNotNull(j, "id");
|
||||
name = StringNotNull(j, "name");
|
||||
description = StringNotNull(j, "description");
|
||||
return *this;
|
||||
}
|
||||
|
||||
void to_json(json& j, const command_option_choice& choice) {
|
||||
j["name"] = choice.name;
|
||||
if (std::holds_alternative<int32_t>(choice.value)) {
|
||||
j["value"] = std::get<int32_t>(choice.value);
|
||||
} else if (std::holds_alternative<bool>(choice.value)) {
|
||||
j["value"] = std::get<bool>(choice.value);
|
||||
} else if (std::holds_alternative<snowflake>(choice.value)) {
|
||||
j["value"] = std::to_string(std::get<uint64_t>(choice.value));
|
||||
} else {
|
||||
j["value"] = std::get<std::string>(choice.value);
|
||||
}
|
||||
}
|
||||
|
||||
void to_json(json& j, const command_option& opt) {
|
||||
j["name"] = opt.name;
|
||||
j["description"] = opt.description;
|
||||
j["type"] = opt.type;
|
||||
j["required"] = opt.required;
|
||||
|
||||
if (opt.options.size()) {
|
||||
j["options"] = json();
|
||||
|
||||
for (const auto& opt : opt.options) {
|
||||
json jopt = opt;
|
||||
j["options"].push_back(jopt);
|
||||
}
|
||||
}
|
||||
|
||||
if (opt.choices.size()) {
|
||||
j["choices"] = json();
|
||||
|
||||
for (const auto& choice : opt.choices) {
|
||||
json jchoice = choice;
|
||||
j["choices"].push_back(jchoice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void to_json(nlohmann::json& j, const command_permission& cp) {
|
||||
j["id"] = std::to_string(cp.id);
|
||||
j["type"] = cp.type;
|
||||
j["permission"] = cp.permission;
|
||||
}
|
||||
|
||||
void to_json(nlohmann::json& j, const guild_command_permissions& gcp) {
|
||||
j["id"] = std::to_string(gcp.id);
|
||||
j["application_id"] = std::to_string(gcp.application_id);
|
||||
j["guild_id"] = std::to_string(gcp.guild_id);
|
||||
j["permissions"] = gcp.permissions;
|
||||
}
|
||||
|
||||
void to_json(json& j, const slashcommand& p) {
|
||||
j["name"] = p.name;
|
||||
|
||||
if (p.type != ctxm_user && p.type != ctxm_message) {
|
||||
j["description"] = p.description;
|
||||
}
|
||||
|
||||
/* Only send this if set to something other than ctxm_none */
|
||||
if (p.type != ctxm_none) {
|
||||
j["type"] = p.type;
|
||||
}
|
||||
|
||||
if (p.type != ctxm_user && p.type != ctxm_message) {
|
||||
if (p.options.size()) {
|
||||
j["options"] = json();
|
||||
|
||||
for (const auto& opt : p.options) {
|
||||
json jopt = opt;
|
||||
j["options"].push_back(jopt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(p.permissions.size()) {
|
||||
j["permissions"] = json();
|
||||
|
||||
for(const auto& perm : p.permissions) {
|
||||
json jperm = perm;
|
||||
j["permissions"].push_back(jperm);
|
||||
}
|
||||
}
|
||||
|
||||
j["default_permission"] = p.default_permission;
|
||||
}
|
||||
|
||||
std::string slashcommand::build_json(bool with_id) const {
|
||||
json j = *this;
|
||||
|
||||
if (with_id) {
|
||||
j["id"] = std::to_string(id);
|
||||
}
|
||||
|
||||
return j.dump();
|
||||
}
|
||||
|
||||
slashcommand& slashcommand::set_type(slashcommand_contextmenu_type t) {
|
||||
type = t;
|
||||
return *this;
|
||||
}
|
||||
|
||||
slashcommand& slashcommand::set_name(const std::string &n) {
|
||||
name = n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
slashcommand& slashcommand::set_description(const std::string &d) {
|
||||
description = d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
slashcommand& slashcommand::set_application_id(snowflake i) {
|
||||
application_id = i;
|
||||
return *this;
|
||||
}
|
||||
|
||||
slashcommand& slashcommand::add_permission(const command_permission& p) {
|
||||
this->permissions.push_back(p);
|
||||
return *this;
|
||||
}
|
||||
|
||||
slashcommand& slashcommand::disable_default_permissions() {
|
||||
this->default_permission = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
command_option_choice::command_option_choice(const std::string &n, command_value v) : name(n), value(v)
|
||||
{
|
||||
}
|
||||
|
||||
command_option::command_option(command_option_type t, const std::string &n, const std::string &d, bool r) :
|
||||
type(t), name(n), description(d), required(r)
|
||||
{
|
||||
}
|
||||
|
||||
command_option& command_option::add_choice(const command_option_choice &o)
|
||||
{
|
||||
choices.push_back(o);
|
||||
return *this;
|
||||
}
|
||||
|
||||
command_option& command_option::add_option(const command_option &o)
|
||||
{
|
||||
options.push_back(o);
|
||||
return *this;
|
||||
}
|
||||
|
||||
slashcommand& slashcommand::add_option(const command_option &o)
|
||||
{
|
||||
options.push_back(o);
|
||||
return *this;
|
||||
}
|
||||
|
||||
interaction& interaction::fill_from_json(nlohmann::json* j) {
|
||||
j->get_to(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string interaction::build_json(bool with_id) const {
|
||||
return "";
|
||||
}
|
||||
|
||||
void from_json(const nlohmann::json& j, command_data_option& cdo) {
|
||||
cdo.name = StringNotNull(&j, "name");
|
||||
cdo.type = (command_option_type)Int8NotNull(&j, "type");
|
||||
|
||||
if (j.contains("options") && !j.at("options").is_null()) {
|
||||
j.at("options").get_to(cdo.options);
|
||||
}
|
||||
|
||||
/* If there's a target ID, define it */
|
||||
if (j.contains("target_id") && !j.at("target_id").is_null()) {
|
||||
cdo.target_id = (dpp::snowflake)SnowflakeNotNull(&j, "target_id");
|
||||
}
|
||||
|
||||
if (j.contains("value") && !j.at("value").is_null()) {
|
||||
switch (cdo.type) {
|
||||
case co_boolean:
|
||||
cdo.value = j.at("value").get<bool>();
|
||||
break;
|
||||
case co_channel:
|
||||
case co_role:
|
||||
case co_user:
|
||||
cdo.value = SnowflakeNotNull(&j, "value");
|
||||
break;
|
||||
case co_integer:
|
||||
cdo.value = j.at("value").get<int32_t>();
|
||||
break;
|
||||
case co_string:
|
||||
cdo.value = j.at("value").get<std::string>();
|
||||
break;
|
||||
case co_sub_command:
|
||||
case co_sub_command_group:
|
||||
/* Silences warning on clang, handled elsewhere */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void from_json(const nlohmann::json& j, command_interaction& ci) {
|
||||
ci.id = SnowflakeNotNull(&j, "id");
|
||||
ci.name = StringNotNull(&j, "name");
|
||||
|
||||
if (j.contains("options") && !j.at("options").is_null()) {
|
||||
j.at("options").get_to(ci.options);
|
||||
}
|
||||
}
|
||||
|
||||
void from_json(const nlohmann::json& j, component_interaction& bi) {
|
||||
bi.component_type = Int8NotNull(&j, "component_type");
|
||||
bi.custom_id = StringNotNull(&j, "custom_id");
|
||||
if (bi.component_type == cotype_select && j.find("values") != j.end()) {
|
||||
/* Get values */
|
||||
for (auto& entry : j["values"]) {
|
||||
bi.values.push_back(entry.get<std::string>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void from_json(const nlohmann::json& j, interaction& i) {
|
||||
i.id = SnowflakeNotNull(&j, "id");
|
||||
i.application_id = SnowflakeNotNull(&j, "application_id");
|
||||
i.channel_id = SnowflakeNotNull(&j, "channel_id");
|
||||
i.guild_id = SnowflakeNotNull(&j, "guild_id");
|
||||
|
||||
if (j.find("message") != j.end()) {
|
||||
const json& m = j["message"];
|
||||
SetSnowflakeNotNull(&m, "id", i.message_id);
|
||||
}
|
||||
|
||||
|
||||
i.type = Int8NotNull(&j, "type");
|
||||
i.token = StringNotNull(&j, "token");
|
||||
i.version = Int8NotNull(&j, "version");
|
||||
|
||||
if (j.contains("member") && !j.at("member").is_null()) {
|
||||
j.at("member").get_to(i.member);
|
||||
if (j.at("member").contains("user") && !j.at("member").at("user").is_null()) {
|
||||
j.at("member").at("user").get_to(i.usr);
|
||||
}
|
||||
}
|
||||
|
||||
if (j.contains("data") && !j.at("data").is_null()) {
|
||||
if (i.type == it_application_command) {
|
||||
command_interaction ci;
|
||||
j.at("data").get_to(ci);
|
||||
i.data = ci;
|
||||
} else if (i.type == it_component_button) {
|
||||
component_interaction bi;
|
||||
j.at("data").get_to(bi);
|
||||
i.data = bi;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interaction_response::interaction_response() {
|
||||
msg = new message();
|
||||
}
|
||||
|
||||
interaction_response::~interaction_response() {
|
||||
delete msg;
|
||||
}
|
||||
|
||||
interaction_response::interaction_response(interaction_response_type t, const message& m) : interaction_response() {
|
||||
type = t;
|
||||
*msg = m;
|
||||
}
|
||||
|
||||
interaction_response& interaction_response::fill_from_json(nlohmann::json* j) {
|
||||
type = (interaction_response_type)Int8NotNull(j, "type");
|
||||
if (j->find("data") != j->end()) {
|
||||
msg->fill_from_json(&((*j)["data"]));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string interaction_response::build_json() const {
|
||||
json j;
|
||||
json msg_json = json::parse(msg->build_json(false, true));
|
||||
j["type"] = this->type;
|
||||
auto cid = msg_json.find("channel_id");
|
||||
if (cid != msg_json.end()) {
|
||||
msg_json.erase(cid);
|
||||
}
|
||||
j["data"] = msg_json;
|
||||
return j.dump();
|
||||
}
|
||||
|
||||
};
|
408
vendor/DPP/src/dpp/sslclient.cpp
vendored
Normal file
408
vendor/DPP/src/dpp/sslclient.cpp
vendored
Normal file
@ -0,0 +1,408 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <WinSock2.h>
|
||||
#include <WS2tcpip.h>
|
||||
#include <io.h>
|
||||
#pragma comment(lib,"ws2_32")
|
||||
#else
|
||||
#include <resolv.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef OPENSSL_SYS_WIN32
|
||||
#undef X509_NAME
|
||||
#undef X509_EXTENSIONS
|
||||
#undef X509_CERT_PAIR
|
||||
#undef PKCS7_ISSUER_AND_SERIAL
|
||||
#undef OCSP_REQUEST
|
||||
#undef OCSP_RESPONSE
|
||||
#endif
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fmt/format.h>
|
||||
#include <dpp/sslclient.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/dispatcher.h>
|
||||
|
||||
namespace dpp {
|
||||
|
||||
class opensslcontext {
|
||||
public:
|
||||
/** OpenSSL session */
|
||||
SSL* ssl;
|
||||
|
||||
/** OpenSSL context */
|
||||
SSL_CTX* ctx;
|
||||
};
|
||||
|
||||
/* You'd think that we would get better performance with a bigger buffer, but SSL frames are 16k each.
|
||||
* SSL_read in non-blocking mode will only read 16k at a time. There's no point in a bigger buffer as
|
||||
* it'd go unused.
|
||||
*/
|
||||
#define BUFSIZZ 1024 * 16
|
||||
const int ERROR_STATUS = -1;
|
||||
|
||||
ssl_client::ssl_client(const std::string &_hostname, const std::string &_port) : last_tick(time(NULL)), hostname(_hostname), port(_port), bytes_in(0), bytes_out(0)
|
||||
{
|
||||
#ifndef WIN32
|
||||
signal(SIGALRM, SIG_IGN);
|
||||
signal(SIGHUP, SIG_IGN);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGCHLD, SIG_IGN);
|
||||
signal(SIGXFSZ, SIG_IGN);
|
||||
#endif
|
||||
ssl = new opensslcontext();
|
||||
Connect();
|
||||
}
|
||||
|
||||
/* SSL Client constructor throws std::runtime_error if it can't connect to the host */
|
||||
void ssl_client::Connect()
|
||||
{
|
||||
/* Initial connection is done in blocking mode. There is a timeout on it. */
|
||||
nonblocking = false;
|
||||
const SSL_METHOD *method = TLS_client_method(); /* Create new client-method instance */
|
||||
|
||||
/* Create SSL context */
|
||||
ssl->ctx = SSL_CTX_new(method);
|
||||
if (ssl->ctx == nullptr)
|
||||
throw dpp::exception("Failed to create SSL client context!");
|
||||
|
||||
/* Create SSL session */
|
||||
ssl->ssl = SSL_new(ssl->ctx);
|
||||
if (ssl->ssl == nullptr)
|
||||
throw dpp::exception("SSL_new failed!");
|
||||
|
||||
/* Resolve hostname to IP */
|
||||
struct hostent *host;
|
||||
if ((host = gethostbyname(hostname.c_str())) == nullptr)
|
||||
throw dpp::exception(fmt::format("Couldn't resolve hostname '{}'", hostname));
|
||||
|
||||
struct addrinfo hints = {0}, *addrs;
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
int status = getaddrinfo(hostname.c_str(), port.c_str(), &hints, &addrs);
|
||||
if (status != 0)
|
||||
throw dpp::exception(fmt::format("getaddrinfo (host={}, port={}): ", hostname, port, gai_strerror(status)));
|
||||
|
||||
/* Attempt each address in turn, if there are multiple IP addresses on the hostname */
|
||||
int err;
|
||||
for (struct addrinfo *addr = addrs; addr != nullptr; addr = addr->ai_next) {
|
||||
sfd = socket(addrs->ai_family, addrs->ai_socktype, addrs->ai_protocol);
|
||||
if (sfd == ERROR_STATUS) {
|
||||
err = errno;
|
||||
continue;
|
||||
} else if (connect(sfd, addr->ai_addr, addr->ai_addrlen) == 0) {
|
||||
break;
|
||||
}
|
||||
err = errno;
|
||||
shutdown(sfd, 2);
|
||||
#ifdef _WIN32
|
||||
if (sfd >= 0 && sfd < FD_SETSIZE) {
|
||||
closesocket(sfd);
|
||||
}
|
||||
#else
|
||||
::close(sfd);
|
||||
#endif
|
||||
sfd = ERROR_STATUS;
|
||||
}
|
||||
freeaddrinfo(addrs);
|
||||
|
||||
/* Check if none of the IPs yielded a valid connection */
|
||||
if (sfd == ERROR_STATUS)
|
||||
throw dpp::exception(strerror(err));
|
||||
|
||||
/* We're good to go - hand the fd over to openssl */
|
||||
SSL_set_fd(ssl->ssl, sfd);
|
||||
|
||||
status = SSL_connect(ssl->ssl);
|
||||
if (status != 1) {
|
||||
throw dpp::exception("SSL_connect error");
|
||||
}
|
||||
|
||||
this->cipher = SSL_get_cipher(ssl->ssl);
|
||||
}
|
||||
|
||||
void ssl_client::write(const std::string &data)
|
||||
{
|
||||
/* If we are in nonblocking mode, append to the buffer,
|
||||
* otherwise just use SSL_write directly. The only time we
|
||||
* use SSL_write directly is during connection before the
|
||||
* ReadLoop is called, which allows for guaranteed simple
|
||||
* lock-step delivery e.g. for HTTP header negotiation
|
||||
*/
|
||||
if (nonblocking) {
|
||||
obuffer += data;
|
||||
} else {
|
||||
SSL_write(ssl->ssl, data.data(), data.length());
|
||||
}
|
||||
}
|
||||
|
||||
void ssl_client::one_second_timer()
|
||||
{
|
||||
}
|
||||
|
||||
std::string ssl_client::get_cipher() {
|
||||
return cipher;
|
||||
}
|
||||
|
||||
void ssl_client::log(dpp::loglevel severity, const std::string &msg) const
|
||||
{
|
||||
}
|
||||
|
||||
void ssl_client::read_loop()
|
||||
{
|
||||
/* The read loop is non-blocking using select(). This method
|
||||
* cannot read while it is waiting for write, or write while it is
|
||||
* waiting for read. This is a limitation of the openssl libraries,
|
||||
* as SSL is sent and received in low level ~16k frames which must
|
||||
* be synchronised and ordered correctly. Attempting to send while
|
||||
* we need another frame or receive while we are due to send a frame
|
||||
* would cause the protocol to break.
|
||||
*/
|
||||
int width;
|
||||
int r = 0;
|
||||
size_t ClientToServerLength = 0, ClientToServerOffset = 0;
|
||||
bool read_blocked_on_write = false, write_blocked_on_read = false,read_blocked = false;
|
||||
fd_set readfds, writefds, efds;
|
||||
char ClientToServerBuffer[BUFSIZZ], ServerToClientBuffer[BUFSIZZ];
|
||||
|
||||
/* Make the socket nonblocking */
|
||||
#ifdef _WIN32
|
||||
u_long mode = 1;
|
||||
int result = ioctlsocket(sfd, FIONBIO, &mode);
|
||||
if (result != NO_ERROR)
|
||||
throw dpp::exception("Can't switch socket to non-blocking mode!");
|
||||
#else
|
||||
int ofcmode;
|
||||
ofcmode = fcntl(sfd, F_GETFL, 0);
|
||||
ofcmode |= O_NDELAY;
|
||||
if (fcntl(sfd, F_SETFL, ofcmode)) {
|
||||
throw dpp::exception("Can't switch socket to non-blocking mode!");
|
||||
}
|
||||
#endif
|
||||
nonblocking = true;
|
||||
width = sfd + 1;
|
||||
|
||||
try {
|
||||
/* Loop until there is a socket error */
|
||||
while(true) {
|
||||
|
||||
if (last_tick != time(NULL)) {
|
||||
this->one_second_timer();
|
||||
last_tick = time(NULL);
|
||||
}
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_ZERO(&writefds);
|
||||
FD_ZERO(&efds);
|
||||
|
||||
FD_SET(sfd,&readfds);
|
||||
FD_SET(sfd,&efds);
|
||||
if (custom_readable_fd && custom_readable_fd() >= 0) {
|
||||
int cfd = custom_readable_fd();
|
||||
FD_SET(cfd, &readfds);
|
||||
FD_SET(cfd, &efds);
|
||||
}
|
||||
if (custom_writeable_fd && custom_writeable_fd() >= 0) {
|
||||
int cfd = custom_writeable_fd();
|
||||
FD_SET(cfd, &writefds);
|
||||
}
|
||||
|
||||
/* If we're waiting for a read on the socket don't try to write to the server */
|
||||
if (ClientToServerLength || obuffer.length() || read_blocked_on_write) {
|
||||
FD_SET(sfd,&writefds);
|
||||
}
|
||||
|
||||
timeval ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_usec = 50000;
|
||||
r = select(FD_SETSIZE, &readfds, &writefds, &efds, &ts);
|
||||
if (r == 0)
|
||||
continue;
|
||||
|
||||
if (custom_writeable_fd && FD_ISSET(custom_writeable_fd(), &writefds)) {
|
||||
custom_writeable_ready();
|
||||
}
|
||||
if (custom_readable_fd && FD_ISSET(custom_readable_fd(), &readfds)) {
|
||||
custom_readable_ready();
|
||||
}
|
||||
if (custom_readable_fd && FD_ISSET(custom_readable_fd(), &efds)) {
|
||||
}
|
||||
|
||||
if (FD_ISSET(sfd, &efds)) {
|
||||
this->log(dpp::ll_error, fmt::format("Error on SSL connection: {}", strerror(errno)));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now check if there's data to read */
|
||||
if((FD_ISSET(sfd,&readfds) && !write_blocked_on_read) || (read_blocked_on_write && FD_ISSET(sfd,&writefds))) {
|
||||
do {
|
||||
read_blocked_on_write = false;
|
||||
read_blocked = false;
|
||||
|
||||
r = SSL_read(ssl->ssl,ServerToClientBuffer,BUFSIZZ);
|
||||
|
||||
int e = SSL_get_error(ssl->ssl,r);
|
||||
|
||||
switch (e) {
|
||||
case SSL_ERROR_NONE:
|
||||
/* Data received, add it to the buffer */
|
||||
buffer.append(ServerToClientBuffer, r);
|
||||
this->handle_buffer(buffer);
|
||||
bytes_in += r;
|
||||
break;
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
/* End of data */
|
||||
SSL_shutdown(ssl->ssl);
|
||||
return;
|
||||
break;
|
||||
case SSL_ERROR_WANT_READ:
|
||||
read_blocked = true;
|
||||
break;
|
||||
|
||||
/* We get a WANT_WRITE if we're trying to rehandshake and we block on a write during that rehandshake.
|
||||
* We need to wait on the socket to be writeable but reinitiate the read when it is
|
||||
*/
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
read_blocked_on_write = true;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
/* We need a check for read_blocked here because SSL_pending() doesn't work properly during the
|
||||
* handshake. This check prevents a busy-wait loop around SSL_read()
|
||||
*/
|
||||
} while (SSL_pending(ssl->ssl) && !read_blocked);
|
||||
}
|
||||
|
||||
/* Check for input on the sendq */
|
||||
if (obuffer.length() && ClientToServerLength == 0) {
|
||||
memcpy(&ClientToServerBuffer, obuffer.data(), obuffer.length() > BUFSIZZ ? BUFSIZZ : obuffer.length());
|
||||
ClientToServerLength = obuffer.length() > BUFSIZZ ? BUFSIZZ : obuffer.length();
|
||||
obuffer = obuffer.substr(ClientToServerLength, obuffer.length());
|
||||
ClientToServerOffset = 0;
|
||||
}
|
||||
|
||||
/* If the socket is writeable... */
|
||||
if ((FD_ISSET(sfd,&writefds) && ClientToServerLength) || (write_blocked_on_read && FD_ISSET(sfd,&readfds))) {
|
||||
write_blocked_on_read = false;
|
||||
/* Try to write */
|
||||
r = SSL_write(ssl->ssl, ClientToServerBuffer + ClientToServerOffset, ClientToServerLength);
|
||||
|
||||
switch(SSL_get_error(ssl->ssl,r)) {
|
||||
/* We wrote something */
|
||||
case SSL_ERROR_NONE:
|
||||
ClientToServerLength -= r;
|
||||
ClientToServerOffset += r;
|
||||
bytes_out += r;
|
||||
break;
|
||||
|
||||
/* We would have blocked */
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
break;
|
||||
|
||||
/* We get a WANT_READ if we're trying to rehandshake and we block onwrite during the current connection.
|
||||
* We need to wait on the socket to be readable but reinitiate our write when it is
|
||||
*/
|
||||
case SSL_ERROR_WANT_READ:
|
||||
write_blocked_on_read = true;
|
||||
break;
|
||||
|
||||
/* Some other error */
|
||||
default:
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e) {
|
||||
log(ll_warning, fmt::format("Read loop ended: {}", e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t ssl_client::get_bytes_out()
|
||||
{
|
||||
return bytes_out;
|
||||
}
|
||||
|
||||
uint64_t ssl_client::get_bytes_in()
|
||||
{
|
||||
return bytes_in;
|
||||
}
|
||||
|
||||
bool ssl_client::handle_buffer(std::string &buffer)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void ssl_client::close()
|
||||
{
|
||||
if (ssl->ssl) {
|
||||
SSL_free(ssl->ssl);
|
||||
ssl->ssl = nullptr;
|
||||
}
|
||||
shutdown(sfd, 2);
|
||||
#ifdef _WIN32
|
||||
if (sfd >= 0 && sfd < FD_SETSIZE) {
|
||||
closesocket(sfd);
|
||||
}
|
||||
#else
|
||||
::close(sfd);
|
||||
#endif
|
||||
if (ssl->ctx) {
|
||||
SSL_CTX_free(ssl->ctx);
|
||||
ssl->ctx = nullptr;
|
||||
}
|
||||
sfd = -1;
|
||||
obuffer.clear();
|
||||
buffer.clear();
|
||||
}
|
||||
|
||||
ssl_client::~ssl_client()
|
||||
{
|
||||
this->close();
|
||||
delete ssl;
|
||||
}
|
||||
|
||||
};
|
183
vendor/DPP/src/dpp/user.cpp
vendored
Normal file
183
vendor/DPP/src/dpp/user.cpp
vendored
Normal file
@ -0,0 +1,183 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <fmt/format.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
/* A mapping of discord's flag values to our bitmap (theyre different bit positions to fit other stuff in) */
|
||||
std::map<uint32_t, dpp::user_flags> usermap = {
|
||||
{ 1 << 0, dpp::u_discord_employee },
|
||||
{ 1 << 1, dpp::u_partnered_owner },
|
||||
{ 1 << 2, dpp::u_hypesquad_events },
|
||||
{ 1 << 3, dpp::u_bughunter_1 },
|
||||
{ 1 << 6, dpp::u_house_bravery },
|
||||
{ 1 << 7, dpp::u_house_brilliance },
|
||||
{ 1 << 8, dpp::u_house_balanace },
|
||||
{ 1 << 9, dpp::u_early_supporter },
|
||||
{ 1 << 10, dpp::u_team_user },
|
||||
{ 1 << 14, dpp::u_bughunter_2 },
|
||||
{ 1 << 16, dpp::u_verified_bot },
|
||||
{ 1 << 17, dpp::u_verified_bot_dev },
|
||||
{ 1 << 18, dpp::u_certified_moderator }
|
||||
};
|
||||
|
||||
namespace dpp {
|
||||
|
||||
user::user() :
|
||||
managed(),
|
||||
discriminator(0),
|
||||
flags(0),
|
||||
refcount(1)
|
||||
{
|
||||
}
|
||||
|
||||
user::~user()
|
||||
{
|
||||
}
|
||||
|
||||
std::string user::get_avatar_url() const {
|
||||
/* XXX: Discord were supposed to change their CDN over to discord.com, they havent.
|
||||
* At some point in the future this URL *will* change!
|
||||
*/
|
||||
return fmt::format("https://cdn.discordapp.com/avatars/{}/{}{}.{}",
|
||||
this->id,
|
||||
(has_animated_icon() ? "a_" : ""),
|
||||
this->avatar.to_string(),
|
||||
(has_animated_icon() ? "gif" : "png")
|
||||
);
|
||||
}
|
||||
|
||||
bool user::is_bot() const {
|
||||
return this->flags & u_bot;
|
||||
}
|
||||
|
||||
bool user::is_system() const {
|
||||
return this->flags & u_system;
|
||||
}
|
||||
|
||||
bool user::is_mfa_enabled() const {
|
||||
return this->flags & u_mfa_enabled;
|
||||
}
|
||||
|
||||
bool user::is_verified() const {
|
||||
return this->flags & u_verified;
|
||||
}
|
||||
|
||||
bool user::has_nitro_full() const {
|
||||
return this->flags & u_nitro_full;
|
||||
}
|
||||
|
||||
bool user::has_nitro_classic() const {
|
||||
return this->flags & u_nitro_classic;
|
||||
}
|
||||
|
||||
bool user::is_discord_employee() const {
|
||||
return this->flags & u_discord_employee;
|
||||
}
|
||||
|
||||
bool user::is_partnered_owner() const {
|
||||
return this->flags & u_partnered_owner;
|
||||
}
|
||||
|
||||
bool user::has_hypesquad_events() const {
|
||||
return this->flags & u_hypesquad_events;
|
||||
}
|
||||
|
||||
bool user::is_bughunter_1() const {
|
||||
return this->flags & u_bughunter_1;
|
||||
}
|
||||
|
||||
bool user::is_house_bravery() const {
|
||||
return this->flags & u_house_bravery;
|
||||
}
|
||||
|
||||
bool user::is_house_brilliance() const {
|
||||
return this->flags & u_house_brilliance;
|
||||
}
|
||||
|
||||
bool user::is_house_balanace() const {
|
||||
return this->flags & u_house_balanace;
|
||||
}
|
||||
|
||||
bool user::is_early_supporter() const {
|
||||
return this->flags & u_early_supporter;
|
||||
}
|
||||
|
||||
bool user::is_team_user() const {
|
||||
return this->flags & u_team_user;
|
||||
}
|
||||
|
||||
bool user::is_bughunter_2() const {
|
||||
return this->flags & u_bughunter_2;
|
||||
}
|
||||
|
||||
bool user::is_verified_bot() const {
|
||||
return this->flags & u_verified_bot;
|
||||
}
|
||||
|
||||
bool user::is_verified_bot_dev() const {
|
||||
return this->flags & u_verified_bot_dev;
|
||||
}
|
||||
|
||||
bool user::is_certified_moderator() const {
|
||||
return this->flags & u_certified_moderator;
|
||||
}
|
||||
|
||||
bool user::has_animated_icon() const {
|
||||
return this->flags & u_animated_icon;
|
||||
}
|
||||
|
||||
user& user::fill_from_json(json* j) {
|
||||
j->get_to(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void from_json(const nlohmann::json& j, user& u) {
|
||||
u.id = SnowflakeNotNull(&j, "id");
|
||||
u.username = StringNotNull(&j, "username");
|
||||
|
||||
std::string av = StringNotNull(&j, "avatar");
|
||||
if (av.length() > 2 && av.substr(0, 2) == "a_") {
|
||||
av = av.substr(2, av.length());
|
||||
u.flags |= u_animated_icon;
|
||||
}
|
||||
u.avatar = av;
|
||||
|
||||
u.discriminator = SnowflakeNotNull(&j, "discriminator");
|
||||
|
||||
u.flags |= BoolNotNull(&j, "bot") ? dpp::u_bot : 0;
|
||||
u.flags |= BoolNotNull(&j, "system") ? dpp::u_system : 0;
|
||||
u.flags |= BoolNotNull(&j, "mfa_enabled") ? dpp::u_mfa_enabled : 0;
|
||||
u.flags |= BoolNotNull(&j, "verified") ? dpp::u_verified : 0;
|
||||
u.flags |= Int8NotNull(&j, "premium_type") == 1 ? dpp::u_nitro_classic : 0;
|
||||
u.flags |= Int8NotNull(&j, "premium_type") == 2 ? dpp::u_nitro_full : 0;
|
||||
uint32_t flags = Int32NotNull(&j, "flags");
|
||||
for (auto & flag : usermap) {
|
||||
if (flags & flag.first) {
|
||||
u.flags |= flag.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
274
vendor/DPP/src/dpp/utility.cpp
vendored
Normal file
274
vendor/DPP/src/dpp/utility.cpp
vendored
Normal file
@ -0,0 +1,274 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/stringops.h>
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <fmt/format.h>
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
namespace dpp {
|
||||
|
||||
namespace utility {
|
||||
|
||||
double time_f()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
auto tp = system_clock::now() + 0ns;
|
||||
return tp.time_since_epoch().count() / 1000000000.0;
|
||||
}
|
||||
|
||||
bool has_voice() {
|
||||
#if HAVE_VOICE
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string current_date_time() {
|
||||
#ifdef _WIN32
|
||||
std::time_t curr_time = time(nullptr);
|
||||
return std::ctime(&curr_time);
|
||||
#else
|
||||
auto t = std::time(nullptr);
|
||||
struct tm timedata;
|
||||
localtime_r(&t, &timedata);
|
||||
std::stringstream s;
|
||||
s << std::put_time(&timedata, "%Y-%m-%d %H:%M:%S");
|
||||
return s.str();
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string loglevel(dpp::loglevel in) {
|
||||
switch (in) {
|
||||
case dpp::ll_trace: return "TRACE";
|
||||
case dpp::ll_debug: return "DEBUG";
|
||||
case dpp::ll_info: return "INFO";
|
||||
case dpp::ll_warning: return "WARN";
|
||||
case dpp::ll_error: return "ERROR";
|
||||
case dpp::ll_critical: return "CRIT";
|
||||
default: return "???";
|
||||
}
|
||||
}
|
||||
|
||||
uptime::uptime() : days(0), hours(0), mins(0), secs(0) {
|
||||
}
|
||||
|
||||
uptime::uptime(time_t diff) : uptime() {
|
||||
days = (uint16_t)(diff / (3600 * 24));
|
||||
hours = (uint8_t)(diff % (3600 * 24) / 3600);
|
||||
mins = (uint8_t)(diff % 3600 / 60);
|
||||
secs = (uint8_t)(diff % 60);
|
||||
}
|
||||
|
||||
std::string uptime::to_string() {
|
||||
if (hours == 0 && days == 0) {
|
||||
return fmt::format("{:02d}:{:02d}", mins, secs);
|
||||
} else {
|
||||
return fmt::format("{}{:02d}:{:02d}:{:02d}", (days ? fmt::format("{} day{}, ", days, (days > 1 ? "s" : "")) : ""), hours, mins, secs);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t uptime::to_secs() {
|
||||
return secs + (mins * 60) + (hours * 60 * 60) + (days * 60 * 60 * 24);
|
||||
}
|
||||
|
||||
uint64_t uptime::to_msecs() {
|
||||
return to_secs() * 1000;
|
||||
}
|
||||
|
||||
iconhash::iconhash() : first(0), second(0) {
|
||||
}
|
||||
|
||||
void iconhash::set(const std::string &hash) {
|
||||
if (hash.empty()) { // Clear values if empty hash
|
||||
first = second = 0;
|
||||
return;
|
||||
}
|
||||
if (hash.length() != 32)
|
||||
throw std::length_error("iconhash must be exactly 32 characters in length");
|
||||
this->first = from_string<uint64_t>(hash.substr(0, 16), std::hex);
|
||||
this->second = from_string<uint64_t>(hash.substr(16, 16), std::hex);
|
||||
}
|
||||
|
||||
iconhash::iconhash(const std::string &hash) {
|
||||
set(hash);
|
||||
}
|
||||
|
||||
iconhash& iconhash::operator=(const std::string &assignment) {
|
||||
set(assignment);
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string iconhash::to_string() const {
|
||||
if (first == 0 && second == 0)
|
||||
return "";
|
||||
else
|
||||
return fmt::format("{:016x}{:016x}", this->first, this->second);
|
||||
}
|
||||
|
||||
void debug_dump(uint8_t* data, size_t length) {
|
||||
size_t addr = (size_t)data;
|
||||
size_t extra = addr % 16;
|
||||
if (extra != 0) {
|
||||
addr -= extra;
|
||||
std::cout << fmt::format("[{:016X}] : ", addr);
|
||||
}
|
||||
for (size_t n = 0; n < extra; ++n) {
|
||||
std::cout << "-- ";
|
||||
}
|
||||
for (uint8_t* ptr = data; ptr < data + length; ++ptr) {
|
||||
if (((size_t)ptr % 16) == 0) {
|
||||
std::cout << fmt::format("\n[{:016X}] : ", (size_t)ptr);
|
||||
}
|
||||
std::cout << fmt::format("{:02X} ", *ptr);
|
||||
}
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
std::string bytes(uint64_t c) {
|
||||
if (c > 1099511627776) { // 1TB
|
||||
return fmt::format("{:.2f}T", (c / 1099511627776.0));
|
||||
} else if (c > 1073741824) { // 1GB
|
||||
return fmt::format("{:.2f}G", (c / 1073741824.0));
|
||||
} else if (c > 1048576) { // 1MB
|
||||
return fmt::format("{:.2f}M", (c / 1048576.0));
|
||||
} else if (c > 1024) { // 1KB
|
||||
return fmt::format("{:.2f}K", (c / 1024.0));
|
||||
} else { // Bytes
|
||||
return std::to_string(c);
|
||||
}
|
||||
}
|
||||
|
||||
void exec(const std::string& cmd, std::vector<std::string> parameters, cmd_result_t callback) {
|
||||
#ifndef _WIN32
|
||||
auto t = std::thread([cmd, parameters, callback]() {
|
||||
std::array<char, 128> buffer;
|
||||
std::vector<std::string> my_parameters = parameters;
|
||||
std::string result;
|
||||
std::stringstream cmd_and_parameters;
|
||||
cmd_and_parameters << cmd;
|
||||
for (auto & parameter : my_parameters) {
|
||||
cmd_and_parameters << " " << std::quoted(parameter);
|
||||
}
|
||||
/* Capture stderr */
|
||||
cmd_and_parameters << " 2>&1";
|
||||
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd_and_parameters.str().c_str(), "r"), pclose);
|
||||
if (!pipe) {
|
||||
return "";
|
||||
}
|
||||
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
|
||||
result += buffer.data();
|
||||
}
|
||||
if (callback) {
|
||||
callback(result);
|
||||
}
|
||||
return "";
|
||||
});
|
||||
t.detach();
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t utf8len(const std::string &str)
|
||||
{
|
||||
size_t i = 0, iBefore = 0, count = 0;
|
||||
const char* s = str.c_str();
|
||||
if (*s == 0)
|
||||
return 0;
|
||||
|
||||
while (s[i] > 0) {
|
||||
ascii:
|
||||
i++;
|
||||
}
|
||||
|
||||
count += i - iBefore;
|
||||
|
||||
while (s[i]) {
|
||||
if (s[i] > 0) {
|
||||
iBefore = i;
|
||||
goto ascii;
|
||||
} else {
|
||||
switch (0xF0 & s[i]) {
|
||||
case 0xE0:
|
||||
i += 3;
|
||||
break;
|
||||
case 0xF0:
|
||||
i += 4;
|
||||
break;
|
||||
default:
|
||||
i += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
std::string utf8substr(const std::string& str, std::string::size_type start, std::string::size_type leng)
|
||||
{
|
||||
if (leng == 0) {
|
||||
return "";
|
||||
}
|
||||
if (start == 0 && leng >= utf8len(str)) {
|
||||
return str;
|
||||
}
|
||||
std::string::size_type i, ix, q, min = std::string::npos, max = std::string::npos;
|
||||
for (q = 0, i = 0, ix = str.length(); i < ix; i++, q++)
|
||||
{
|
||||
if (q == start)
|
||||
min = i;
|
||||
if (q <= start + leng || leng == std::string::npos)
|
||||
max = i;
|
||||
|
||||
unsigned char c = (unsigned char)str[i];
|
||||
if (c < 0x80)
|
||||
i += 0;
|
||||
else if ((c & 0xE0) == 0xC0)
|
||||
i += 1;
|
||||
else if ((c & 0xF0) == 0xE0)
|
||||
i += 2;
|
||||
else if ((c & 0xF8) == 0xF0)
|
||||
i += 3;
|
||||
else
|
||||
return ""; //invalid utf8
|
||||
}
|
||||
if (q <= start + leng || leng == std::string::npos)
|
||||
max = i;
|
||||
if (min == std::string::npos || max == std::string::npos)
|
||||
return "";
|
||||
|
||||
return str.substr(min, max);
|
||||
}
|
||||
};
|
||||
|
||||
};
|
80
vendor/DPP/src/dpp/voiceregion.cpp
vendored
Normal file
80
vendor/DPP/src/dpp/voiceregion.cpp
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/voiceregion.h>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
namespace dpp {
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
voiceregion::voiceregion() : flags(0)
|
||||
{
|
||||
}
|
||||
|
||||
voiceregion::~voiceregion() {
|
||||
}
|
||||
|
||||
voiceregion& voiceregion::fill_from_json(nlohmann::json* j) {
|
||||
id = StringNotNull(j, "id");
|
||||
name = StringNotNull(j, "id");
|
||||
if (BoolNotNull(j, "optimal"))
|
||||
flags |= v_optimal;
|
||||
if (BoolNotNull(j, "deprecated"))
|
||||
flags |= v_deprecated;
|
||||
if (BoolNotNull(j, "custom"))
|
||||
flags |= v_custom;
|
||||
if (BoolNotNull(j, "vip"))
|
||||
flags |= v_vip;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string voiceregion::build_json() const {
|
||||
return json({
|
||||
{ "id", id },
|
||||
{ "name", name },
|
||||
{ "optimal", is_optimal() },
|
||||
{ "deprecated", is_deprecated() },
|
||||
{ "custom", is_custom() },
|
||||
{ "vip", is_vip() }
|
||||
}).dump();
|
||||
}
|
||||
|
||||
bool voiceregion::is_optimal() const {
|
||||
return flags & v_optimal;
|
||||
}
|
||||
|
||||
bool voiceregion::is_deprecated() const {
|
||||
return flags & v_deprecated;
|
||||
}
|
||||
|
||||
bool voiceregion::is_custom() const {
|
||||
return flags & v_custom;
|
||||
}
|
||||
|
||||
bool voiceregion::is_vip() const {
|
||||
return flags & v_vip;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
91
vendor/DPP/src/dpp/voicestate.cpp
vendored
Normal file
91
vendor/DPP/src/dpp/voicestate.cpp
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dpp {
|
||||
|
||||
voicestate::voicestate() : shard(nullptr), guild_id(0), channel_id(0), user_id(0)
|
||||
{
|
||||
}
|
||||
|
||||
voicestate::~voicestate() {
|
||||
}
|
||||
|
||||
voicestate& voicestate::fill_from_json(nlohmann::json* j) {
|
||||
guild_id = SnowflakeNotNull(j, "guild_id");
|
||||
channel_id = SnowflakeNotNull(j, "channel_id");
|
||||
user_id = SnowflakeNotNull(j, "user_id");
|
||||
session_id = StringNotNull(j, "session_id");
|
||||
flags = 0;
|
||||
if (BoolNotNull(j, "deaf"))
|
||||
flags |= vs_deaf;
|
||||
if (BoolNotNull(j, "mute"))
|
||||
flags |= vs_mute;
|
||||
if (BoolNotNull(j, "self_mute"))
|
||||
flags |= vs_self_mute;
|
||||
if (BoolNotNull(j, "self_deaf"))
|
||||
flags |= vs_self_deaf;
|
||||
if (BoolNotNull(j, "self_stream"))
|
||||
flags |= vs_self_stream;
|
||||
if (BoolNotNull(j, "self_video"))
|
||||
flags |= vs_self_video;
|
||||
if (BoolNotNull(j, "supress"))
|
||||
flags |= vs_supress;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool voicestate::is_deaf() const {
|
||||
return flags & vs_deaf;
|
||||
}
|
||||
|
||||
bool voicestate::is_mute() const {
|
||||
return flags & vs_mute;
|
||||
}
|
||||
|
||||
bool voicestate::is_self_mute() const {
|
||||
return flags & vs_self_mute;
|
||||
}
|
||||
|
||||
bool voicestate::is_self_deaf() const {
|
||||
return flags & vs_self_deaf;
|
||||
}
|
||||
|
||||
bool voicestate::self_stream() const {
|
||||
return flags & vs_self_stream;
|
||||
}
|
||||
|
||||
bool voicestate::self_video() const {
|
||||
return flags & vs_self_video;
|
||||
}
|
||||
|
||||
bool voicestate::is_supressed() const {
|
||||
return flags & vs_supress;
|
||||
}
|
||||
|
||||
std::string voicestate::build_json() const {
|
||||
return json({}).dump();
|
||||
}
|
||||
|
||||
};
|
97
vendor/DPP/src/dpp/webhook.cpp
vendored
Normal file
97
vendor/DPP/src/dpp/webhook.cpp
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <dpp/webhook.h>
|
||||
#include <dpp/discordevents.h>
|
||||
#include <dpp/discord.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <dpp/dispatcher.h>
|
||||
|
||||
namespace dpp {
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
webhook::webhook() : managed(), type(w_incoming), guild_id(0), channel_id(0), user_id(0), application_id(0), image_data(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
webhook::~webhook() {
|
||||
if (image_data) {
|
||||
delete image_data;
|
||||
}
|
||||
}
|
||||
|
||||
webhook& webhook::fill_from_json(nlohmann::json* j) {
|
||||
id = SnowflakeNotNull(j, "id");
|
||||
type = Int8NotNull(j, "type");
|
||||
channel_id = SnowflakeNotNull(j, "channel_id");
|
||||
guild_id = SnowflakeNotNull(j, "guild_id");
|
||||
if (j->find("user") != j->end()) {
|
||||
json & user = (*j)["user"];
|
||||
user_id = SnowflakeNotNull(&user, "id");
|
||||
}
|
||||
name = StringNotNull(j, "name");
|
||||
avatar = StringNotNull(j, "name");
|
||||
token = StringNotNull(j, "token");
|
||||
application_id = SnowflakeNotNull(j, "application_id");
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string webhook::build_json(bool with_id) const {
|
||||
json j;
|
||||
if (with_id) {
|
||||
j["id"] = std::to_string(id);
|
||||
}
|
||||
j["name"] = name;
|
||||
j["type"] = type;
|
||||
if (channel_id)
|
||||
j["channel_id"] = channel_id;
|
||||
if (guild_id)
|
||||
j["guild_id"] = guild_id;
|
||||
if (!name.empty())
|
||||
j["name"] = name;
|
||||
if (image_data)
|
||||
j["avatar"] = *image_data;
|
||||
if (application_id)
|
||||
j["application_id"] = application_id;
|
||||
return j.dump();
|
||||
}
|
||||
|
||||
webhook& webhook::load_image(const std::string &image_blob, image_type type) {
|
||||
static std::map<image_type, std::string> mimetypes = {
|
||||
{ i_gif, "image/gif" },
|
||||
{ i_jpg, "image/jpeg" },
|
||||
{ i_png, "image/png" }
|
||||
};
|
||||
if (image_blob.size() > MAX_EMOJI_SIZE) {
|
||||
throw dpp::exception("Webhook icon file exceeds discord limit of 256 kilobytes");
|
||||
}
|
||||
if (image_data) {
|
||||
/* If there's already image data defined, free the old data, to prevent a memory leak */
|
||||
delete image_data;
|
||||
}
|
||||
image_data = new std::string("data:" + mimetypes[type] + ";base64," + base64_encode((unsigned char const*)image_blob.data(), image_blob.length()));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
325
vendor/DPP/src/dpp/wsclient.cpp
vendored
Normal file
325
vendor/DPP/src/dpp/wsclient.cpp
vendored
Normal file
@ -0,0 +1,325 @@
|
||||
/************************************************************************************
|
||||
*
|
||||
* D++, A Lightweight C++ library for Discord
|
||||
*
|
||||
* Copyright 2021 Craig Edwards and D++ contributors
|
||||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
************************************************************************************/
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <dpp/wsclient.h>
|
||||
#include <fmt/format.h>
|
||||
|
||||
namespace dpp {
|
||||
|
||||
const unsigned char WS_MASKBIT = (1 << 7);
|
||||
const unsigned char WS_FINBIT = (1 << 7);
|
||||
const unsigned char WS_PAYLOAD_LENGTH_MAGIC_LARGE = 126;
|
||||
const unsigned char WS_PAYLOAD_LENGTH_MAGIC_HUGE = 127;
|
||||
const size_t WS_MAX_PAYLOAD_LENGTH_SMALL = 125;
|
||||
const size_t WS_MAX_PAYLOAD_LENGTH_LARGE = 65535;
|
||||
const size_t MAXHEADERSIZE = sizeof(uint64_t) + 2;
|
||||
|
||||
websocket_client::websocket_client(const std::string &hostname, const std::string &port, const std::string &urlpath)
|
||||
: ssl_client(hostname, port),
|
||||
state(HTTP_HEADERS),
|
||||
key(fmt::format("{:16x}", time(nullptr))),
|
||||
path(urlpath)
|
||||
{
|
||||
}
|
||||
|
||||
void websocket_client::Connect()
|
||||
{
|
||||
state = HTTP_HEADERS;
|
||||
/* Send headers synchronously */
|
||||
this->write(
|
||||
fmt::format(
|
||||
|
||||
"GET {} HTTP/1.1\r\n"
|
||||
"Host: {}\r\n"
|
||||
"pragma: no-cache\r\n"
|
||||
"User-Agent: DPP/0.1\r\n"
|
||||
"Upgrade: WebSocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Sec-WebSocket-Key: {}\r\n"
|
||||
"Sec-WebSocket-Version: 13\r\n\r\n",
|
||||
|
||||
this->path, this->hostname, this->key
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
websocket_client::~websocket_client()
|
||||
{
|
||||
}
|
||||
|
||||
bool websocket_client::HandleFrame(const std::string &buffer)
|
||||
{
|
||||
/* This is a stub for classes that derive the websocket client */
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t websocket_client::FillHeader(unsigned char* outbuf, size_t sendlength, ws_opcode opcode)
|
||||
{
|
||||
size_t pos = 0;
|
||||
outbuf[pos++] = WS_FINBIT | opcode;
|
||||
|
||||
if (sendlength <= WS_MAX_PAYLOAD_LENGTH_SMALL)
|
||||
{
|
||||
outbuf[pos++] = sendlength;
|
||||
}
|
||||
else if (sendlength <= WS_MAX_PAYLOAD_LENGTH_LARGE)
|
||||
{
|
||||
outbuf[pos++] = WS_PAYLOAD_LENGTH_MAGIC_LARGE;
|
||||
outbuf[pos++] = (sendlength >> 8) & 0xff;
|
||||
outbuf[pos++] = sendlength & 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
outbuf[pos++] = WS_PAYLOAD_LENGTH_MAGIC_HUGE;
|
||||
const uint64_t len = sendlength;
|
||||
for (int i = sizeof(uint64_t)-1; i >= 0; i--)
|
||||
outbuf[pos++] = ((len >> i*8) & 0xff);
|
||||
}
|
||||
|
||||
/* Masking - We don't care about masking, but discord insists on it. We send a mask of 0x00000000 because
|
||||
* any value XOR 0 is itself, meaning we dont have to waste time and effort on this crap.
|
||||
*/
|
||||
outbuf[1] |= WS_MASKBIT;
|
||||
outbuf[pos++] = 0;
|
||||
outbuf[pos++] = 0;
|
||||
outbuf[pos++] = 0;
|
||||
outbuf[pos++] = 0;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
void websocket_client::write(const std::string &data)
|
||||
{
|
||||
if (state == HTTP_HEADERS) {
|
||||
/* Simple write */
|
||||
ssl_client::write(data);
|
||||
} else {
|
||||
unsigned char out[MAXHEADERSIZE];
|
||||
size_t s = this->FillHeader(out, data.length(), OP_TEXT);
|
||||
std::string header((const char*)out, s);
|
||||
ssl_client::write(header);
|
||||
ssl_client::write(data);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> tokenize(std::string const &in, const char* sep = "\r\n") {
|
||||
std::string::size_type b = 0;
|
||||
std::vector<std::string> result;
|
||||
|
||||
while ((b = in.find_first_not_of(sep, b)) != std::string::npos) {
|
||||
auto e = in.find(sep, b);
|
||||
result.push_back(in.substr(b, e-b));
|
||||
b = e;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool websocket_client::handle_buffer(std::string &buffer)
|
||||
{
|
||||
switch (state) {
|
||||
case HTTP_HEADERS:
|
||||
if (buffer.find("\r\n\r\n") != std::string::npos) {
|
||||
/* Got all headers, proceed to new state */
|
||||
|
||||
/* Get headers string */
|
||||
std::string headers = buffer.substr(0, buffer.find("\r\n\r\n"));
|
||||
|
||||
/* Modify buffer, remove headers section */
|
||||
buffer.erase(0, buffer.find("\r\n\r\n") + 4);
|
||||
|
||||
/* Process headers into map */
|
||||
std::vector<std::string> h = tokenize(headers);
|
||||
if (h.size()) {
|
||||
std::string status_line = h[0];
|
||||
h.erase(h.begin());
|
||||
/* HTTP/1.1 101 Switching Protocols */
|
||||
std::vector<std::string> status = tokenize(status_line, " ");
|
||||
if (status.size() >= 3 && status[1] == "101") {
|
||||
for(auto &hd : h) {
|
||||
std::string::size_type sep = hd.find(": ");
|
||||
if (sep != std::string::npos) {
|
||||
std::string key = hd.substr(0, sep);
|
||||
std::string value = hd.substr(sep + 2, hd.length());
|
||||
HTTPHeaders[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
state = CONNECTED;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CONNECTED:
|
||||
/* Process packets until we can't */
|
||||
while (this->parseheader(buffer));
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ws_state websocket_client::GetState()
|
||||
{
|
||||
return this->state;
|
||||
}
|
||||
|
||||
bool websocket_client::parseheader(std::string &data)
|
||||
{
|
||||
if (data.size() < 4) {
|
||||
/* Not enough data to form a frame yet */
|
||||
return false;
|
||||
} else {
|
||||
unsigned char opcode = data[0];
|
||||
switch (opcode & ~WS_FINBIT)
|
||||
{
|
||||
case OP_CONTINUATION:
|
||||
case OP_TEXT:
|
||||
case OP_BINARY:
|
||||
case OP_PING:
|
||||
case OP_PONG:
|
||||
{
|
||||
std::string payload;
|
||||
|
||||
unsigned char len1 = data[1];
|
||||
unsigned int payloadstartoffset = 2;
|
||||
|
||||
if (len1 & WS_MASKBIT) {
|
||||
len1 &= ~WS_MASKBIT;
|
||||
payloadstartoffset += 2;
|
||||
/* We don't handle masked data, because discord doesnt send it */
|
||||
return true;
|
||||
}
|
||||
|
||||
/* 6 bit ("small") length frame */
|
||||
uint64_t len = len1;
|
||||
|
||||
if (len1 == WS_PAYLOAD_LENGTH_MAGIC_LARGE) {
|
||||
/* 24 bit ("large") length frame */
|
||||
if (data.length() < 8) {
|
||||
/* We don't have a complete header yet */
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned char len2 = (unsigned char)data[2];
|
||||
unsigned char len3 = (unsigned char)data[3];
|
||||
len = (len2 << 8) | len3;
|
||||
|
||||
payloadstartoffset += 2;
|
||||
} else if (len1 == WS_PAYLOAD_LENGTH_MAGIC_HUGE) {
|
||||
/* 64 bit ("huge") length frame */
|
||||
if (data.length() < 10) {
|
||||
/* We don't have a complete header yet */
|
||||
return false;
|
||||
}
|
||||
len = 0;
|
||||
for (int v = 2, shift = 56; v < 10; ++v, shift -= 8) {
|
||||
unsigned char l = (unsigned char)data[v];
|
||||
len |= (uint64_t)(l & 0xff) << shift;
|
||||
}
|
||||
payloadstartoffset += 8;
|
||||
}
|
||||
|
||||
if (data.length() < payloadstartoffset + len) {
|
||||
/* We don't have a complete frame yet */
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Copy from buffer into string */
|
||||
const std::string::iterator endit = data.begin() + payloadstartoffset + len;
|
||||
for (std::string::const_iterator i = data.begin() + payloadstartoffset; i != endit; ++i) {
|
||||
const unsigned char c = (unsigned char)*i;
|
||||
payload.push_back(c);
|
||||
}
|
||||
|
||||
/* Remove this frame from the input buffer */
|
||||
data.erase(data.begin(), endit);
|
||||
|
||||
if ((opcode & ~WS_FINBIT) == OP_PING || (opcode & ~WS_FINBIT) == OP_PONG) {
|
||||
HandlePingPong((opcode & ~WS_FINBIT) == OP_PING, payload);
|
||||
} else {
|
||||
/* Pass this frame to the deriving class */
|
||||
this->HandleFrame(payload);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_CLOSE:
|
||||
{
|
||||
uint16_t error = data[2] & 0xff;
|
||||
error <<= 8;
|
||||
error |= (data[3] & 0xff);
|
||||
this->Error(error);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
this->Error(0);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void websocket_client::one_second_timer()
|
||||
{
|
||||
if (((time(NULL) % 20) == 0) && (state == CONNECTED)) {
|
||||
/* For sending pings, we send with payload */
|
||||
unsigned char out[MAXHEADERSIZE];
|
||||
std::string payload = "keepalive";
|
||||
size_t s = this->FillHeader(out, payload.length(), OP_PING);
|
||||
std::string header((const char*)out, s);
|
||||
ssl_client::write(header);
|
||||
ssl_client::write(payload);
|
||||
}
|
||||
}
|
||||
|
||||
void websocket_client::HandlePingPong(bool ping, const std::string &payload)
|
||||
{
|
||||
unsigned char out[MAXHEADERSIZE];
|
||||
if (ping) {
|
||||
/* For receving pings we echo back their payload with the type OP_PONG */
|
||||
size_t s = this->FillHeader(out, payload.length(), OP_PONG);
|
||||
std::string header((const char*)out, s);
|
||||
ssl_client::write(header);
|
||||
ssl_client::write(payload);
|
||||
}
|
||||
}
|
||||
|
||||
void websocket_client::Error(uint32_t errorcode)
|
||||
{
|
||||
}
|
||||
|
||||
void websocket_client::close()
|
||||
{
|
||||
this->state = HTTP_HEADERS;
|
||||
ssl_client::close();
|
||||
}
|
||||
|
||||
};
|
Reference in New Issue
Block a user