DiscordCoreAPI
A Discord bot library written in C++, with custom asynchronous coroutines.
Loading...
Searching...
No Matches
MessageEntities.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/// MessageEntities.cpp - Source file for the message_data related classes and structs.
27/// May 13, 2021
28/// https://discordcoreapi.com
29/// \file MessageEntities.cpp
30
35
36namespace jsonifier {
37
38 template<> struct core<discord_core_api::message_response_base> {
40 static constexpr auto parseValue =
41 createObject("components", &value_type::components, "allowed_mentions", &value_type::allowedMentions, "embeds", &value_type::embeds, "files", &value_type::files,
42 "custom_id", &value_type::customId, "content", &value_type::content, "title", &value_type::title, "flags", &value_type::flags, "tts", &value_type::tts);
43 };
44
45 template<> struct core<discord_core_api::create_message_data> {
47 static constexpr auto parseValue =
48 createObject("components", &value_type::components, "allowed_mentions", &value_type::allowedMentions, "embeds", &value_type::embeds, "files", &value_type::files,
49 "custom_id", &value_type::customId, "content", &value_type::content, "title", &value_type::title, "flags", &value_type::flags, "tts", &value_type::tts);
50 };
51
52 template<> struct core<discord_core_api::edit_message_data> {
53 using value_type = discord_core_api::edit_message_data;
54 static constexpr auto parseValue =
55 createObject("components", &value_type::components, "allowed_mentions", &value_type::allowedMentions, "embeds", &value_type::embeds, "files", &value_type::files,
56 "custom_id", &value_type::customId, "content", &value_type::content, "title", &value_type::title, "flags", &value_type::flags, "tts", &value_type::tts);
57 };
58
59 template<> struct core<discord_core_api::delete_messages_bulk_data> {
61 static constexpr auto parseValue = createObject("messages", &value_type::messageIds);
62 };
63}
64
65namespace discord_core_api {
66
67 template<> unordered_map<jsonifier::string, unbounded_message_block<message_data>*> object_collector<message_data>::objectsBuffersMap{};
68
69 template<> object_collector<message_data>::object_collector() {
70 collectorId = jsonifier::toString(std::chrono::duration_cast<milliseconds>(hrclock::now().time_since_epoch()).count());
71 object_collector::objectsBuffersMap[collectorId] = &objectsBuffer;
72 };
73
74 template<> void object_collector<message_data>::run(std::coroutine_handle<
76 int64_t startingTime = static_cast<int64_t>(std::chrono::duration_cast<milliseconds>(hrclock::now().time_since_epoch()).count());
77 int64_t elapsedTime{};
78 while (elapsedTime < msToCollectFor && !coroHandle.promise().stopRequested()) {
79 message_data message{};
80 waitForTimeToPass<message_data>(objectsBuffer, message, static_cast<uint64_t>(msToCollectFor - static_cast<uint64_t>(elapsedTime)));
81 if (filteringFunction(message)) {
82 objectReturnData.objects.emplace_back(message);
83 }
84 if (static_cast<int32_t>(objectReturnData.objects.size()) >= quantityOfObjectsToCollect) {
85 break;
86 }
87
88 elapsedTime = std::chrono::duration_cast<milliseconds>(hrclock::now().time_since_epoch()).count() - startingTime;
89 }
90 }
91
92 template<> co_routine<object_collector<message_data>::object_collector_return_data, false> object_collector<message_data>::collectObjects(int32_t quantityToCollect,
93 int32_t msToCollectForNew, object_filter<message_data> filteringFunctionNew) {
94 auto coroHandle = co_await newThreadAwaitable<object_collector_return_data, false>();
95 quantityOfObjectsToCollect = quantityToCollect;
96 filteringFunction = filteringFunctionNew;
97 msToCollectFor = msToCollectForNew;
98
99 run(coroHandle);
100 co_return objectReturnData;
101 }
102
103 template<> object_collector<message_data>::~object_collector() {
104 if (object_collector::objectsBuffersMap.contains(collectorId)) {
105 object_collector::objectsBuffersMap.erase(collectorId);
106 }
107 };
108
109 create_message_data::create_message_data(const snowflake channelIdNew) {
110 channelId = channelIdNew;
111 }
112
113 create_message_data::create_message_data(respond_to_input_event_data dataPackage) {
114 channelId = dataPackage.channelId;
115 addAllowedMentions(dataPackage.allowedMentions);
116 for (auto& value: dataPackage.components) {
117 components.emplace_back(value);
118 }
119 addContent(dataPackage.content);
120 for (auto& value: dataPackage.embeds) {
121 embeds.emplace_back(value);
122 }
123 tts = dataPackage.tts;
124 }
125
126 create_message_data::create_message_data(message_data dataPackage) {
127 channelId = dataPackage.channelId;
128 messageReference.channelId = dataPackage.channelId;
129 messageReference.messageId = dataPackage.id;
130 messageReference.guildId = dataPackage.guildId;
131 tts = dataPackage.tts;
132 }
133
134 create_message_data::create_message_data(input_event_data dataPackage) {
135 channelId = dataPackage.getChannelData().id;
136 }
137
138 send_dmdata::send_dmdata(respond_to_input_event_data dataPackage) {
139 targetUserId = dataPackage.targetUserId;
140 addAllowedMentions(dataPackage.allowedMentions);
141 for (auto& value: dataPackage.components) {
142 components.emplace_back(value);
143 }
144 addContent(dataPackage.content);
145 for (auto& value: dataPackage.embeds) {
146 embeds.emplace_back(value);
147 }
148 channelId = dataPackage.targetUserId;
149 tts = dataPackage.tts;
150 }
151
152 edit_message_data::edit_message_data(input_event_data dataPackage) {
153 channelId = dataPackage.getChannelData().id;
154 messageId = dataPackage.getMessageData().id;
155 }
156
157 edit_message_data::edit_message_data(respond_to_input_event_data dataPackage) {
158 allowedMentions = dataPackage.allowedMentions;
159 channelId = dataPackage.channelId;
160 messageId = dataPackage.messageId;
161 for (auto& value: dataPackage.components) {
162 components.emplace_back(value);
163 }
164 content = dataPackage.content;
165 for (auto& value: dataPackage.embeds) {
166 embeds.emplace_back(value);
167 }
168 }
169
170 delete_message_data::delete_message_data(const message_data& messageToDelete) {
171 channelId = messageToDelete.channelId;
172 timeStamp = messageToDelete.timeStamp;
173 messageId = messageToDelete.id;
174 }
175
176 void messages::initialize(discord_core_internal::https_client* client) {
177 messages::httpsClient = client;
178 }
179
181 discord_core_internal::https_workload_data workload{ discord_core_internal::https_workload_type::Get_Messages };
182 co_await newThreadAwaitable<jsonifier::vector<message_data>>();
183 workload.workloadClass = discord_core_internal::https_workload_class::Get;
184 workload.relativePath = "/channels/" + dataPackage.channelId + "/messages";
185 if (dataPackage.aroundThisId != 0) {
186 workload.relativePath += "?around=" + dataPackage.aroundThisId;
187 if (dataPackage.limit != 0) {
188 workload.relativePath += "&limit=" + jsonifier::toString(dataPackage.limit);
189 } else {
190 workload.relativePath += "&limit=1";
191 }
192 } else if (dataPackage.beforeThisId != 0) {
193 workload.relativePath += "?before=" + dataPackage.beforeThisId;
194 if (dataPackage.limit != 0) {
195 workload.relativePath += "&limit=" + jsonifier::toString(dataPackage.limit);
196 } else {
197 workload.relativePath += "&limit=1";
198 }
199 } else if (dataPackage.afterThisId != 0) {
200 workload.relativePath += "?after=" + dataPackage.afterThisId;
201 if (dataPackage.limit != 0) {
202 workload.relativePath += "&limit=" + jsonifier::toString(dataPackage.limit);
203 } else {
204 workload.relativePath += "&limit=1";
205 }
206 } else {
207 if (dataPackage.limit != 0) {
208 workload.relativePath += "?limit=" + jsonifier::toString(dataPackage.limit);
209 } else {
210 workload.relativePath += "&limit=1";
211 }
212 }
213 workload.callStack = "messages::getMessagesAsync()";
214 jsonifier::vector<message_data> returnData{};
215 messages::httpsClient->submitWorkloadAndGetResult(std::move(workload), returnData);
216 co_return returnData;
217 }
218
220 discord_core_internal::https_workload_data workload{ discord_core_internal::https_workload_type::Get_Message };
221 co_await newThreadAwaitable<message_data>();
222 workload.workloadClass = discord_core_internal::https_workload_class::Get;
223 workload.relativePath = "/channels/" + dataPackage.channelId + "/messages/" + dataPackage.id;
224 workload.callStack = "messages::getMessageAsync()";
225 message_data returnData{};
226 messages::httpsClient->submitWorkloadAndGetResult(std::move(workload), returnData);
227 co_return returnData;
228 }
229
231 discord_core_internal::https_workload_data workload{ discord_core_internal::https_workload_type::Post_Message };
232 co_await newThreadAwaitable<message_data>();
233 workload.workloadClass = discord_core_internal::https_workload_class::Post;
234 workload.relativePath = "/channels/" + dataPackage.channelId + "/messages";
235 if (dataPackage.files.size() > 0) {
236 workload.payloadType = discord_core_internal::payload_type::Multipart_Form;
237 parser.serializeJson<true>(dataPackage, workload.content);
238 } else {
239 parser.serializeJson<true>(dataPackage, workload.content);
240 }
241 workload.callStack = "messages::createMessageAsync()";
242 message_data returnData{};
243 messages::httpsClient->submitWorkloadAndGetResult(std::move(workload), returnData);
244 co_return returnData;
245 }
246
248 discord_core_internal::https_workload_data workload{ discord_core_internal::https_workload_type::Crosspost_Message };
249 co_await newThreadAwaitable<message_data>();
250 workload.workloadClass = discord_core_internal::https_workload_class::Post;
251 workload.relativePath = "/channels/" + dataPackage.channelId + "/messages/" + dataPackage.messageId + "/crosspost";
252 workload.callStack = "messages::crosspostMessageAsync()";
253 message_data returnData{};
254 messages::httpsClient->submitWorkloadAndGetResult(std::move(workload), returnData);
255 co_return returnData;
256 }
257
259 discord_core_internal::https_workload_data workload{ discord_core_internal::https_workload_type::Patch_Message };
260 co_await newThreadAwaitable<message_data>();
261 workload.workloadClass = discord_core_internal::https_workload_class::Patch;
262 workload.relativePath = "/channels/" + dataPackage.channelId + "/messages/" + dataPackage.messageId;
263 if (dataPackage.files.size() > 0) {
264 workload.payloadType = discord_core_internal::payload_type::Multipart_Form;
265 parser.serializeJson<true>(dataPackage, workload.content);
266 } else {
267 parser.serializeJson<true>(dataPackage, workload.content);
268 }
269 workload.callStack = "messages::editMessageAsync()";
270 message_data returnData{};
271 messages::httpsClient->submitWorkloadAndGetResult(std::move(workload), returnData);
272 co_return returnData;
273 }
274
276 discord_core_internal::https_workload_data workload{};
277 bool hasTimeElapsedNew = dataPackage.timeStamp.hasTimeElapsed(14, 0, 0);
278 if (!hasTimeElapsedNew) {
279 workload = discord_core_internal::https_workload_type::Delete_Message;
280 } else {
281 workload = discord_core_internal::https_workload_type::Delete_Message_Old;
282 }
283 co_await newThreadAwaitable<void>();
284 if (dataPackage.timeDelay > 0) {
285 std::this_thread::sleep_for(milliseconds{ dataPackage.timeDelay });
286 }
287 workload.workloadClass = discord_core_internal::https_workload_class::Delete;
288 workload.relativePath = "/channels/" + dataPackage.channelId + "/messages/" + dataPackage.messageId;
289 workload.callStack = "messages::deleteMessageAsync()";
290 if (dataPackage.reason != "") {
291 workload.headersToInsert["x-audit-log-reason"] = dataPackage.reason;
292 }
293 messages::httpsClient->submitWorkloadAndGetResult(std::move(workload));
294 co_return;
295 }
296
298 discord_core_internal::https_workload_data workload{ discord_core_internal::https_workload_type::Bulk_Delete_Messages };
299 co_await newThreadAwaitable<void>();
300 workload.workloadClass = discord_core_internal::https_workload_class::Post;
301 workload.relativePath = "/channels/" + dataPackage.channelId + "/messages/bulk-delete";
302 parser.serializeJson<true>(dataPackage, workload.content);
303 if (dataPackage.reason != "") {
304 workload.headersToInsert["x-audit-log-reason"] = dataPackage.reason;
305 }
306 messages::httpsClient->submitWorkloadAndGetResult(std::move(workload));
307 co_return;
308 }
309
311 discord_core_internal::https_workload_data workload{ discord_core_internal::https_workload_type::Get_Pinned_Messages };
312 co_await newThreadAwaitable<jsonifier::vector<message_data>>();
313 workload.workloadClass = discord_core_internal::https_workload_class::Get;
314 workload.relativePath = "/channels/" + dataPackage.channelId + "/pins";
315 workload.callStack = "messages::getPinnedMessagesAsync()";
316 jsonifier::vector<message_data> returnData{};
317 messages::httpsClient->submitWorkloadAndGetResult(std::move(workload), returnData);
318 co_return returnData;
319 }
320
322 discord_core_internal::https_workload_data workload{ discord_core_internal::https_workload_type::Put_Pin_Message };
323 co_await newThreadAwaitable<void>();
324 workload.workloadClass = discord_core_internal::https_workload_class::Put;
325 workload.relativePath = "/channels/" + dataPackage.channelId + "/pins/" + dataPackage.messageId;
326 workload.callStack = "messages::pinMessageAsync()";
327 if (dataPackage.reason != "") {
328 workload.headersToInsert["x-audit-log-reason"] = dataPackage.reason;
329 }
330 messages::httpsClient->submitWorkloadAndGetResult(std::move(workload));
331 co_return;
332 }
333
335 discord_core_internal::https_workload_data workload{ discord_core_internal::https_workload_type::Delete_Pin_Message };
336 co_await newThreadAwaitable<void>();
337 workload.workloadClass = discord_core_internal::https_workload_class::Delete;
338 workload.relativePath = "/channels/" + dataPackage.channelId + "/pins/" + dataPackage.messageId;
339 workload.callStack = "messages::unpinMessageAsync()";
340 if (dataPackage.reason != "") {
341 workload.headersToInsert["x-audit-log-reason"] = dataPackage.reason;
342 }
343 messages::httpsClient->submitWorkloadAndGetResult(std::move(workload));
344 co_return;
345 }
346
347 discord_core_internal::https_client* messages::httpsClient{};
348}
A co_routine - representing a potentially asynchronous operation/function.
Definition: CoRoutine.hpp:83
Data structure representing a single message_data.
Message response base, for responding to messages.
message_response_base & addContent(jsonifier::string_view dataPackage)
For setting the message content in a response.
message_response_base & addAllowedMentions(const allowed_mentions_data dataPackage)
For setting the allowable mentions in a response.
static co_routine< void > pinMessageAsync(const pin_message_data dataPackage)
Pins a message to a given channel.
static co_routine< void > deleteMessagesBulkAsync(const delete_messages_bulk_data dataPackage)
Deletes a collection of messages.
static co_routine< message_data > getMessageAsync(const get_message_data dataPackage)
Collects a message from the discord servers.
static co_routine< void > unpinMessageAsync(const unpin_message_data dataPackage)
Unpins a message from a given channel.
static co_routine< message_data > crosspostMessageAsync(const crosspost_message_data dataPackage)
Crossposts a message from a news channel_data to the following channels.
static co_routine< message_data > editMessageAsync(const edit_message_data dataPackage)
Edit a message.
static co_routine< void > deleteMessageAsync(const delete_message_data dataPackage)
Deletes a message.
static co_routine< jsonifier::vector< message_data > > getPinnedMessagesAsync(const get_pinned_messages_data dataPackage)
Collects a collection of pinned messages from the discord servers.
static co_routine< jsonifier::vector< message_data > > getMessagesAsync(const get_messages_data dataPackage)
Collects a collection of message from the discord servers.
static co_routine< message_data > createMessageAsync(const create_message_data dataPackage)
Creates a new message_data.
co_routine< object_collector_return_data, false > collectObjects(int32_t quantityToCollect, int32_t msToCollectForNew, object_filter< value_type > filteringFunctionNew)
Begin waiting for objects.
uint64_t id
The snowflake id.
Definition: Base.hpp:811
bool hasTimeElapsed(int64_t days, int64_t hours, int64_t minutes) const
Checks if a certain time duration has elapsed.
Definition: Base.hpp:407
The main namespace for the forward-facing interfaces.
snowflake messageId
snowflake of the message to be crossposted.
snowflake channelId
channel_data within which to crosspost the message from.
snowflake messageId
The message snowflake of the message to delete.
snowflake channelId
The channel snowflake of the message to delete.
jsonifier::string reason
The reason for deleting the message_data.
int32_t timeDelay
Number of milliseconds to wait before deleting the message_data.
time_stamp timeStamp
The created-at timeStamp of the original message.
For deleting a bulk of messages.
snowflake channelId
channel_data within which to delete the messages.
jsonifier::string reason
The reason for deleting the messages.
snowflake id
The id of the message to collect.
snowflake channelId
The channel_data from which to collect the message_data.
For getting a collection of messages.
snowflake aroundThisId
Around this id.
snowflake afterThisId
After this id.
snowflake beforeThisId
Before this id.
int32_t limit
Limit of messages to collect.
snowflake channelId
channel_data from which to collect the messages.
For getting a collection of pinned messages.
snowflake channelId
The channel_data from which to collect pinned messages.
snowflake guildId
snowflake of the guild that the referenced message was sent in.
snowflake messageId
snowflake of the message to reference.
snowflake channelId
snowflake of the channel_data that the referenced message was sent in.
For pinning a single message_data.
snowflake messageId
The message which you would like to pin.
snowflake channelId
The channel_data within which to pin the message_data.
jsonifier::string reason
Reason for pinning this message_data.
For unpinning a single message_data.
jsonifier::string reason
Reason for pinning this message_data.
snowflake channelId
The channel_data within which to unpin the message_data.
snowflake messageId
The message which you would like to unpin.