DiscordCoreAPI
A Discord bot library written in C++, with custom asynchronous coroutines.
Loading...
Searching...
No Matches
UserEntities.cpp
Go to the documentation of this file.
1/*
2 MIT License
3
4 DiscordCoreAPI, A bot library for Discord, written in C++, and featuring explicit multithreading through the usage of custom, asynchronous C++ CoRoutines.
5
6 Copyright 2022, 2023 Chris M. (RealTimeChris)
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25*/
26/// UserEntities.cpp - Source file for user related classes and structs.
27/// May 13, 2021
28/// https://discordcoreapi.com
29/// \file UserEntities.cpp
30
35
36namespace jsonifier {
37
38 template<> struct core<discord_core_api::add_recipient_to_group_dmdata> {
39 using value_type = discord_core_api::add_recipient_to_group_dmdata;
40 static constexpr auto parseValue =
41 createValue("channel_id", &value_type::channelId, "access_token", &value_type::token, "nick", &value_type::nick, "user_id", &value_type::userId);
42 };
43
44 template<> struct core<discord_core_api::modify_current_user_data> {
45 using value_type = discord_core_api::modify_current_user_data;
46 static constexpr auto parseValue = createValue("username", &value_type::userName, "avatar", &value_type::avatar);
47 };
48}
49namespace discord_core_api {
50
51 namespace discord_core_internal {
52
53 websocket_message_data<update_voice_state_data>::websocket_message_data(const update_voice_state_data& other) {
54 d.channelId = other.channelId;
55 d.guildId = other.guildId;
56 d.selfDeaf = other.selfDeaf;
57 d.selfMute = other.selfMute;
58 jsonifierExcludedKeys.emplace("t");
59 jsonifierExcludedKeys.emplace("s");
60 op = 4;
61 }
62
63 websocket_message_data<update_voice_state_data>::operator etf_serializer() {
64 etf_serializer data{};
65 data["op"] = 4;
66 if (d.channelId == 0) {
67 data["d"]["channel_id"] = discord_core_internal::json_type::null_t;
68 } else {
69 data["d"]["channel_id"] = d.channelId.operator jsonifier::string();
70 }
71 data["d"]["self_deaf"] = d.selfDeaf;
72 data["d"]["self_mute"] = d.selfMute;
73 data["d"]["guild_id"] = d.guildId.operator jsonifier::string();
74 return data;
75 }
76
77 websocket_message_data<update_voice_state_data_dc>::websocket_message_data(const update_voice_state_data& other) {
78 d.channelId = nullptr;
79 d.guildId = other.guildId;
80 d.selfDeaf = other.selfDeaf;
81 d.selfMute = other.selfMute;
82 jsonifierExcludedKeys.emplace("t");
83 jsonifierExcludedKeys.emplace("s");
84 op = 4;
85 }
86
87 websocket_message_data<update_voice_state_data_dc>::operator etf_serializer() {
88 etf_serializer data{};
89 data["op"] = 4;
90 data["d"]["channel_id"] = discord_core_internal::json_type::null_t;
91 data["d"]["self_deaf"] = d.selfDeaf;
92 data["d"]["self_mute"] = d.selfMute;
93 data["d"]["guild_id"] = d.guildId.operator jsonifier::string();
94 return data;
95 }
96 }
97
98 user_cache_data& user_cache_data::operator=(const user_data& other) {
99 premiumType = static_cast<premium_type>(other.premiumType);
100 setFlagValue(user_flags::Verified, other.verified);
101 if (other.avatarDecoration != "") {
102 avatarDecoration = other.avatarDecoration;
103 }
104 if (static_cast<int64_t>(other.flags) != 0) {
105 flags = other.flags;
106 }
107 setFlagValue(user_flags::System, other.system);
108 setFlagValue(user_flags::Bot, other.bot);
109 if (other.discriminator != "") {
110 discriminator = other.discriminator;
111 }
112 if (other.accentColor != 0) {
113 accentColor = other.accentColor;
114 }
115 if (other.globalName != "") {
116 globalName = other.globalName;
117 }
118 if (other.userName != "") {
119 userName = other.userName;
120 }
121 if (other.banner != "") {
122 banner = other.banner;
123 }
124 if (other.avatar != "") {
125 avatar = other.avatar;
126 }
127 if (other.id != 0) {
128 id = other.id;
129 }
130 return *this;
131 }
132
133 user_cache_data::user_cache_data(const user_data& dataNew) {
134 *this = dataNew;
135 }
136
137 user_cache_data& user_cache_data::operator=(user_data&& other) noexcept {
138 premiumType = static_cast<premium_type>(other.premiumType);
139 if (other.avatarDecoration != "") {
140 avatarDecoration = std::move(other.avatarDecoration);
141 }
142 if (other.discriminator != "") {
143 discriminator = std::move(other.discriminator);
144 }
145 setFlagValue(user_flags::Verified, other.verified);
146 setFlagValue(user_flags::System, other.system);
147 if (other.globalName != "") {
148 globalName = std::move(other.globalName);
149 }
150 if (static_cast<int64_t>(other.flags) != 0) {
151 flags = other.flags;
152 }
153 setFlagValue(user_flags::Bot, other.bot);
154 if (other.userName != "") {
155 userName = std::move(other.userName);
156 }
157 if (other.banner != "") {
158 banner = std::move(other.banner);
159 }
160 if (other.avatar != "") {
161 avatar = std::move(other.avatar);
162 }
163 if (other.accentColor != 0) {
164 accentColor = other.accentColor;
165 }
166 if (other.id != 0) {
167 id = other.id;
168 }
169 return *this;
170 }
171
172 user_cache_data::operator user_data() {
173 discord_core_api::user_data returnData{};
174 returnData.verified = getFlagValue<user_flags>(user_flags::Verified);
175 returnData.system = getFlagValue<user_flags>(user_flags::System);
176 returnData.bot = getFlagValue<user_flags>(user_flags::Bot);
177 returnData.discriminator = discriminator;
178 returnData.globalName = globalName;
179 returnData.userName = userName;
180 returnData.avatarDecoration = avatarDecoration;
181 returnData.accentColor = accentColor;
182 returnData.avatar = avatar;
183 returnData.banner = banner;
184 returnData.flags = flags;
185 returnData.id = id;
186 return returnData;
187 }
188
189 user_cache_data::user_cache_data(user_data&& other) noexcept {
190 *this = std::move(other);
191 }
192
193 user_data::user_data(snowflake newId) {
194 id = newId;
195 }
196
197 bot_user::bot_user(user_data& dataPackage, discord_core_internal::base_socket_agent* baseSocketAgentNew) : user_data(dataPackage) {
198 baseSocketAgent = baseSocketAgentNew;
199 }
200
202 if (baseSocketAgent) {
203 jsonifier::string_base<uint8_t> string{};
204 uint64_t shardId = (dataPackage.guildId.operator const uint64_t&() >> 22) % discord_core_client::getInstance()->configManager.getTotalShardCount();
205 uint64_t basesocketAgentIndex{ shardId % discord_core_client::getInstance()->configManager.getTotalShardCount() };
206 if (dataPackage.channelId == 0) {
207 discord_core_internal::websocket_message_data<update_voice_state_data_dc> data{};
209 dcData.guildId = dataPackage.guildId;
210 dcData.selfDeaf = dataPackage.selfDeaf;
211 dcData.selfMute = dataPackage.selfMute;
212 data.d = dcData;
213 data.op = 4;
214 if (static_cast<discord_core_internal::websocket_op_code>(
215 discord_core_client::getInstance()->baseSocketAgentsMap[basesocketAgentIndex]->shardMap[shardId].dataOpCode) ==
216 discord_core_internal::websocket_op_code::Op_Binary) {
217 auto serializer = data.operator discord_core_internal::etf_serializer();
218 string = serializer.operator jsonifier::string_base<uint8_t>();
219 } else {
220 parser.serializeJson(data, string);
221 }
222 } else {
223 discord_core_internal::websocket_message_data<update_voice_state_data> data{};
224 data.d = dataPackage;
225 data.op = 4;
226 if (static_cast<discord_core_internal::websocket_op_code>(
227 discord_core_client::getInstance()->baseSocketAgentsMap[basesocketAgentIndex]->shardMap[shardId].dataOpCode) ==
228 discord_core_internal::websocket_op_code::Op_Binary) {
229 auto serializer = data.operator discord_core_internal::etf_serializer();
230 string = serializer.operator jsonifier::string_base<uint8_t>();
231 } else {
232 parser.serializeJson(data, string);
233 }
234 }
235 discord_core_client::getInstance()->baseSocketAgentsMap[basesocketAgentIndex]->shardMap[shardId].createHeader(string,
236 discord_core_client::getInstance()->baseSocketAgentsMap[basesocketAgentIndex]->shardMap[shardId].dataOpCode);
237 discord_core_client::getInstance()->baseSocketAgentsMap[basesocketAgentIndex]->shardMap[shardId].sendMessage(string, false);
238 }
239 }
240
242 if (baseSocketAgent) {
243 jsonifier::string_base<uint8_t> string{};
244 uint64_t shardId = 0;
245 uint64_t basesocketAgentIndex{};
246 discord_core_internal::websocket_message_data<update_presence_data> data{};
247 data.d = dataPackage;
248 data.jsonifierExcludedKeys.emplace("s");
249 for (auto& value: data.d.activities) {
250 if (value.url == "") {
251 value.jsonifierExcludedKeys.emplace("url");
252 }
253 }
254 data.op = 3;
255 if (static_cast<discord_core_internal::websocket_op_code>(
256 discord_core_client::getInstance()->baseSocketAgentsMap[basesocketAgentIndex]->shardMap[shardId].dataOpCode) ==
257 discord_core_internal::websocket_op_code::Op_Binary) {
258 auto serializer = data.operator discord_core_internal::etf_serializer();
259 string = serializer.operator jsonifier::string_base<uint8_t>();
260 } else {
261 parser.serializeJson(data, string);
262 }
263 discord_core_client::getInstance()->baseSocketAgentsMap[basesocketAgentIndex]->shardMap[shardId].createHeader(string,
264 discord_core_client::getInstance()->baseSocketAgentsMap[basesocketAgentIndex]->shardMap[shardId].dataOpCode);
265 discord_core_client::getInstance()->baseSocketAgentsMap[basesocketAgentIndex]->shardMap[shardId].sendMessage(string, true);
266 }
267 }
268
269 void users::initialize(discord_core_internal::https_client* client, config_manager* configManagerNew) {
270 users::doWeCacheUsersBool = configManagerNew->doWeCacheUsers();
271 users::httpsClient = client;
272 }
273
275 discord_core_internal::https_workload_data workload{ discord_core_internal::https_workload_type::Put_Recipient_To_Group_Dm };
276 co_await newThreadAwaitable<void>();
277 workload.workloadClass = discord_core_internal::https_workload_class::Put;
278 workload.relativePath = "/channels/" + dataPackage.channelId + "/recipients/" + dataPackage.userId;
279 parser.serializeJson(dataPackage, workload.content);
280 workload.callStack = "users::addRecipientToGroupDMAsync()";
281 users::httpsClient->submitWorkloadAndGetResult(std::move(workload));
282 co_return;
283 }
284
286 discord_core_internal::https_workload_data workload{ discord_core_internal::https_workload_type::Delete_Recipient_From_Group_Dm };
287 co_await newThreadAwaitable<void>();
288 workload.workloadClass = discord_core_internal::https_workload_class::Delete;
289 workload.relativePath = "/channels/" + dataPackage.channelId + "/recipients/" + dataPackage.userId;
290 workload.callStack = "users::removeRecipientToGroupDMAsync()";
291 users::httpsClient->submitWorkloadAndGetResult(std::move(workload));
292 co_return;
293 }
294
296 discord_core_internal::https_workload_data workload{ discord_core_internal::https_workload_type::Patch_Current_User_Voice_State };
297 co_await newThreadAwaitable<void>();
298 workload.workloadClass = discord_core_internal::https_workload_class::Patch;
299 workload.relativePath = "/guilds/" + dataPackage.guildId + "/voice-states/@me";
300 workload.callStack = "users::modifyCurrentUserVoiceStateAsync()";
301 users::httpsClient->submitWorkloadAndGetResult(std::move(workload));
302 co_return;
303 }
304
306 discord_core_internal::https_workload_data workload{ discord_core_internal::https_workload_type::Patch_User_Voice_State };
307 co_await newThreadAwaitable<void>();
308 workload.workloadClass = discord_core_internal::https_workload_class::Patch;
309 workload.relativePath = "/guilds/" + dataPackage.guildId + "/voice-states/" + dataPackage.userId;
310 workload.callStack = "users::modifyUserVoiceStateAsync()";
311 users::httpsClient->submitWorkloadAndGetResult(std::move(workload));
312 co_return;
313 }
314
316 discord_core_internal::https_workload_data workload{ discord_core_internal::https_workload_type::Get_Current_User };
318 workload.workloadClass = discord_core_internal::https_workload_class::Get;
319 workload.relativePath = "/users/@me";
320 workload.callStack = "users::getCurrentUserAsync()";
321 user_data returnData{};
322 users::httpsClient->submitWorkloadAndGetResult(std::move(workload), returnData);
323 auto newId = returnData.id;
324 insertUser(static_cast<user_cache_data>(returnData));
325 co_return cache[newId];
326 }
327
329 if (cache.contains(dataPackage.userId)) {
330 return cache[dataPackage.userId];
331 } else {
332 return getUserAsync({ .userId = dataPackage.userId }).get();
333 }
334 }
335
337 discord_core_internal::https_workload_data workload{ discord_core_internal::https_workload_type::Get_User };
339 workload.workloadClass = discord_core_internal::https_workload_class::Get;
340 workload.relativePath = "/users/" + dataPackage.userId;
341 workload.callStack = "users::getUserAsync()";
342 user_data data{ dataPackage.userId };
343 if (cache.contains(data.id)) {
344 data = cache[data.id];
345 }
346 users::httpsClient->submitWorkloadAndGetResult(std::move(workload), data);
347 if (doWeCacheUsersBool) {
348 insertUser(static_cast<user_cache_data>(data));
349 }
350 co_return data;
351 }
352
354 discord_core_internal::https_workload_data workload{ discord_core_internal::https_workload_type::Patch_Current_User };
356 workload.workloadClass = discord_core_internal::https_workload_class::Patch;
357 workload.relativePath = "/users/@me";
358 workload.callStack = "users::modifyCurrentUserAsync()";
359 parser.serializeJson(dataPackage, workload.content);
360 user_data returnData{};
361 users::httpsClient->submitWorkloadAndGetResult(std::move(workload), returnData);
362 co_return returnData;
363 }
364
366 discord_core_internal::https_workload_data workload{ discord_core_internal::https_workload_type::Get_User_Connections };
368 workload.workloadClass = discord_core_internal::https_workload_class::Get;
369 workload.relativePath = "/users/@me/connections";
370 workload.callStack = "users::getUserConnectionsAsync()";
371 jsonifier::vector<connection_data> returnData{};
372 users::httpsClient->submitWorkloadAndGetResult(std::move(workload), returnData);
373 co_return returnData;
374 }
375
377 discord_core_internal::https_workload_data workload{ discord_core_internal::https_workload_type::Get_Application_Info };
379 workload.workloadClass = discord_core_internal::https_workload_class::Get;
380 workload.relativePath = "/oauth2/applications/@me";
381 workload.callStack = "users::getApplicationDataAsync()";
382 application_data returnData{};
383 users::httpsClient->submitWorkloadAndGetResult(std::move(workload), returnData);
384 co_return returnData;
385 }
386
388 discord_core_internal::https_workload_data workload{ discord_core_internal::https_workload_type::Get_Authorization_Info };
390 workload.workloadClass = discord_core_internal::https_workload_class::Get;
391 workload.relativePath = "/oauth2/@me";
392 workload.callStack = "users::getCurrentUserAuthorizationInfoAsync()";
393 authorization_info_data returnData{};
394 users::httpsClient->submitWorkloadAndGetResult(std::move(workload), returnData);
395 co_return returnData;
396 }
397
398 bool users::doWeCacheUsers() {
399 return users::doWeCacheUsersBool;
400 }
401
402 discord_core_internal::https_client* users::httpsClient{};
403 object_cache<user_cache_data> users::cache{};
404 bool users::doWeCacheUsersBool{};
405}
void updateVoiceStatus(update_voice_state_data dataPackage)
Updates the bot's current voice-status. joins/leaves a channel, and/or self deafens/mutes.
void updatePresence(update_presence_data dataPackage)
Updates the bot's current activity status, to be viewed by others in the same server as the bot.
A co_routine - representing a potentially asynchronous operation/function.
A class representing a snowflake identifier with various operations.
Definition Base.hpp:701
uint64_t accentColor
The user's banner color encoded as an integer representation of hexadecimal color code.
jsonifier::string banner
The user's banner hash.
jsonifier::string avatar
The user's avatar hash.
jsonifier::string globalName
The user's global name.
jsonifier::string avatarDecoration
The user's avatar decoration hash.
user_flags flags
The public flags on a user's account.
premium_type premiumType
The type of nitro subscription on a user's account.
jsonifier::string discriminator
The user's 4-digit discord-tag identify.
jsonifier::string userName
The user's username.
static co_routine< void > addRecipientToGroupDMAsync(add_recipient_to_group_dmdata dataPackage)
Adds a chosen recipient to a group dm.
static co_routine< authorization_info_data > getCurrentUserAuthorizationInfoAsync()
Collects the authorization info associated with the current bot.
static co_routine< application_data > getCurrentUserApplicationInfoAsync()
Collects the application responseData associated with the current bot.
static co_routine< void > modifyUserVoiceStateAsync(modify_user_voice_state_data dataPackage)
Sets another user's current voice state.
static co_routine< void > removeRecipientFromGroupDMAsync(remove_recipient_from_group_dmdata dataPackage)
Removes a chosen recipient from a group dm.
static co_routine< user_data > modifyCurrentUserAsync(modify_current_user_data dataPackage)
Modifies the bot's user_data responseData.
static user_cache_data getCachedUser(get_user_data dataPackage)
Collects a given user from the library's cache.
static co_routine< void > modifyCurrentUserVoiceStateAsync(modify_current_user_voice_state_data dataPackage)
Sets the bot's current voice state.
static co_routine< user_data > getUserAsync(get_user_data dataPackage)
Collects a given user from the discord servers.
static co_routine< user_data > getCurrentUserAsync()
Collects the bot's current user_data responseData.
static co_routine< jsonifier::vector< connection_data > > getUserConnectionsAsync()
Collects the user_data's connections.
premium_type
Premium types denote the level of premium a user has.
@ System
Is it a system integration?
DCA_INLINE auto newThreadAwaitable()
An awaitable that can be used to launch the co_routine onto a new thread - as well as return the hand...
The main namespace for the forward-facing interfaces.
snowflake channelId
The channel_data snowflake of the dm.
For getting user_data responseData from the library's cache or the discord server.
snowflake userId
The id of the desired user_data.
For modifying the bot's user_data responseData.
For updating the bot's current voice state.
snowflake guildId
The guild within which to update the bot's voice state.
For modifying a user's voice state.
snowflake guildId
The guild within which you would like to modify their voice state.
snowflake userId
The user for which you would like to modify the voice state of.
snowflake channelId
The channel_data snowflake of the dm.
For updating a user's presence.
For updating the current voice state.
snowflake guildId
The id of the guild fo which we would like to establish a voice connection.
For updating the current voice state.
bool selfDeaf
Whether or not we self-deafen ourselves.
bool selfMute
Whether or not we self-mute ourselves.
snowflake channelId
snowflake of the desired voice channel_data. leave blank to disconnect.
snowflake guildId
The id of the guild fo which we would like to establish a voice connection.