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> {
40 static constexpr auto parseValue =
41 createObject("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> {
46 static constexpr auto parseValue = createObject("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 excludedKeys.emplace("t");
59 excludedKeys.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 excludedKeys.emplace("t");
83 excludedKeys.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
201 void bot_user::updateVoiceStatus(update_voice_state_data dataPackage) {
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<true>(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<true>(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
241 void bot_user::updatePresence(update_presence_data dataPackage) {
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.excludedKeys.emplace("s");
249 for (auto& value: data.d.activities) {
250 if (value.url == "") {
251 value.excludedKeys.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<true>(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
274 co_routine<void> users::addRecipientToGroupDMAsync(const add_recipient_to_group_dmdata dataPackage) {
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<true>(dataPackage, workload.content);
280 workload.callStack = "users::addRecipientToGroupDMAsync()";
281 users::httpsClient->submitWorkloadAndGetResult(std::move(workload));
282 co_return;
283 }
284
285 co_routine<void> users::removeRecipientFromGroupDMAsync(const remove_recipient_from_group_dmdata dataPackage) {
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
295 co_routine<void> users::modifyCurrentUserVoiceStateAsync(const modify_current_user_voice_state_data dataPackage) {
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
305 co_routine<void> users::modifyUserVoiceStateAsync(const modify_user_voice_state_data dataPackage) {
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
315 co_routine<user_data> users::getCurrentUserAsync() {
316 discord_core_internal::https_workload_data workload{ discord_core_internal::https_workload_type::Get_Current_User };
317 co_await newThreadAwaitable<user_data>();
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
328 user_cache_data users::getCachedUser(const get_user_data dataPackage) {
329 if (cache.contains(dataPackage.userId)) {
330 return cache[dataPackage.userId];
331 } else {
332 return getUserAsync({ .userId = dataPackage.userId }).get();
333 }
334 }
335
336 co_routine<user_data> users::getUserAsync(const get_user_data dataPackage) {
337 discord_core_internal::https_workload_data workload{ discord_core_internal::https_workload_type::Get_User };
338 co_await newThreadAwaitable<user_data>();
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
353 co_routine<user_data> users::modifyCurrentUserAsync(const modify_current_user_data dataPackage) {
354 discord_core_internal::https_workload_data workload{ discord_core_internal::https_workload_type::Patch_Current_User };
355 co_await newThreadAwaitable<user_data>();
356 workload.workloadClass = discord_core_internal::https_workload_class::Patch;
357 workload.relativePath = "/users/@me";
358 workload.callStack = "users::modifyCurrentUserAsync()";
359 parser.serializeJson<true>(dataPackage, workload.content);
360 user_data returnData{};
361 users::httpsClient->submitWorkloadAndGetResult(std::move(workload), returnData);
362 co_return returnData;
363 }
364
365 co_routine<jsonifier::vector<connection_data>> users::getUserConnectionsAsync() {
366 discord_core_internal::https_workload_data workload{ discord_core_internal::https_workload_type::Get_User_Connections };
367 co_await newThreadAwaitable<jsonifier::vector<connection_data>>();
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
376 co_routine<application_data> users::getCurrentUserApplicationInfoAsync() {
377 discord_core_internal::https_workload_data workload{ discord_core_internal::https_workload_type::Get_Application_Info };
378 co_await newThreadAwaitable<application_data>();
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
387 co_routine<authorization_info_data> users::getCurrentUserAuthorizationInfoAsync() {
388 discord_core_internal::https_workload_data workload{ discord_core_internal::https_workload_type::Get_Authorization_Info };
389 co_await newThreadAwaitable<authorization_info_data>();
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}
A co_routine - representing a potentially asynchronous operation/function.
Definition: CoRoutine.hpp:83
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.
snowflake id
The user's id.
bool verified
Whether the email on this account has been verified.
premium_type
Premium types denote the level of premium a user has.
@ System
Is it a system integration?
The main namespace for the forward-facing interfaces.
For adding a user to a group dm.
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.
For removing a user from a group dm.
snowflake channelId
The channel_data snowflake of the dm.
For updating a user's presence.
Definition: Utilities.hpp:131
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.