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 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<DiscordCoreAPI::MessageResponseBase> {
40 static constexpr auto parseValue = objectVal("components", &ValueType::components, "allowed_mentions", &ValueType::allowedMentions, "embeds", &ValueType::embeds, "files",
41 &ValueType::files, "custom_id", &ValueType::customId, "content", &ValueType::content, "title", &ValueType::title, "flags", &ValueType::flags, "tts", &ValueType::tts);
42 };
43
44 template<> struct core<DiscordCoreAPI::CreateMessageData> {
45 using ValueType = DiscordCoreAPI::CreateMessageData;
46 static constexpr auto parseValue = objectVal("components", &ValueType::components, "allowed_mentions", &ValueType::allowedMentions, "embeds", &ValueType::embeds, "files",
47 &ValueType::files, "custom_id", &ValueType::customId, "content", &ValueType::content, "title", &ValueType::title, "flags", &ValueType::flags, "tts", &ValueType::tts);
48 };
49
50 template<> struct core<DiscordCoreAPI::EditMessageData> {
51 using ValueType = DiscordCoreAPI::EditMessageData;
52 static constexpr auto parseValue = objectVal("components", &ValueType::components, "allowed_mentions", &ValueType::allowedMentions, "embeds", &ValueType::embeds, "files",
53 &ValueType::files, "custom_id", &ValueType::customId, "content", &ValueType::content, "title", &ValueType::title, "flags", &ValueType::flags, "tts", &ValueType::tts);
54 };
55
56 template<> struct core<DiscordCoreAPI::DeleteMessagesBulkData> {
58 static constexpr auto parseValue = objectVal("messages", &ValueType::messageIds);
59 };
60}
61
62namespace DiscordCoreAPI {
63
64 template<> UnorderedMap<std::string, UnboundedMessageBlock<MessageData>*> ObjectCollector<MessageData>::objectsBuffersMap{};
65
66 template<> ObjectCollector<MessageData>::ObjectCollector() {
67 collectorId = std::to_string(std::chrono::duration_cast<Milliseconds>(HRClock::now().time_since_epoch()).count());
68 ObjectCollector::objectsBuffersMap[collectorId] = &objectsBuffer;
69 };
70
71 template<> void ObjectCollector<MessageData>::run(
73 coroHandle) {
74 int64_t startingTime = static_cast<int64_t>(std::chrono::duration_cast<Milliseconds>(HRClock::now().time_since_epoch()).count());
75 int64_t elapsedTime{};
76 while (elapsedTime < msToCollectFor && !coroHandle.promise().stopRequested()) {
77 MessageData message{};
78 waitForTimeToPass<MessageData>(objectsBuffer, message, static_cast<uint64_t>(msToCollectFor - static_cast<uint64_t>(elapsedTime)));
79 if (filteringFunction(message)) {
80 objectReturnData.objects.emplace_back(message);
81 }
82 if (static_cast<int32_t>(objectReturnData.objects.size()) >= quantityOfObjectsToCollect) {
83 break;
84 }
85
86 elapsedTime = std::chrono::duration_cast<Milliseconds>(HRClock::now().time_since_epoch()).count() - startingTime;
87 }
88 }
89
90 template<> CoRoutine<ObjectCollector<MessageData>::ObjectCollectorReturnData> ObjectCollector<MessageData>::collectObjects(int32_t quantityToCollect, int32_t msToCollectForNew,
91 ObjectFilter<MessageData> filteringFunctionNew) {
92 auto coroHandle = co_await NewThreadAwaitable<ObjectCollectorReturnData>();
93 quantityOfObjectsToCollect = quantityToCollect;
94 filteringFunction = filteringFunctionNew;
95 msToCollectFor = msToCollectForNew;
96
97 run(coroHandle);
98 co_return std::move(objectReturnData);
99 }
100
101 template<> ObjectCollector<MessageData>::~ObjectCollector() {
102 if (ObjectCollector::objectsBuffersMap.contains(collectorId)) {
103 ObjectCollector::objectsBuffersMap.erase(collectorId);
104 }
105 };
106
107 CreateMessageData::CreateMessageData(const Snowflake channelIdNew) {
108 channelId = channelIdNew;
109 }
110
111 CreateMessageData::CreateMessageData(RespondToInputEventData dataPackage) {
112 channelId = dataPackage.channelId;
113 addAllowedMentions(dataPackage.allowedMentions);
114 for (auto& value: dataPackage.components) {
115 components.emplace_back(value);
116 }
117 addContent(dataPackage.content);
118 for (auto& value: dataPackage.embeds) {
119 embeds.emplace_back(value);
120 }
121 tts = dataPackage.tts;
122 }
123
124 CreateMessageData::CreateMessageData(MessageData dataPackage) {
125 channelId = dataPackage.channelId;
126 messageReference.channelId = dataPackage.channelId;
127 messageReference.messageId = dataPackage.id;
128 messageReference.guildId = dataPackage.guildId;
129 tts = dataPackage.tts;
130 }
131
132 CreateMessageData::CreateMessageData(InputEventData dataPackage) {
133 channelId = dataPackage.getChannelData().id;
134 }
135
136 SendDMData::SendDMData(RespondToInputEventData dataPackage) {
137 targetUserId = dataPackage.targetUserId;
138 addAllowedMentions(dataPackage.allowedMentions);
139 for (auto& value: dataPackage.components) {
140 components.emplace_back(value);
141 }
142 addContent(dataPackage.content);
143 for (auto& value: dataPackage.embeds) {
144 embeds.emplace_back(value);
145 }
146 channelId = dataPackage.targetUserId;
147 tts = dataPackage.tts;
148 }
149
150 EditMessageData::EditMessageData(InputEventData dataPackage) {
151 channelId = dataPackage.getChannelData().id;
152 messageId = dataPackage.getMessageData().id;
153 }
154
155 EditMessageData::EditMessageData(RespondToInputEventData dataPackage) {
156 allowedMentions = dataPackage.allowedMentions;
157 channelId = dataPackage.channelId;
158 messageId = dataPackage.messageId;
159 for (auto& value: dataPackage.components) {
160 components.emplace_back(value);
161 }
162 content = dataPackage.content;
163 for (auto& value: dataPackage.embeds) {
164 embeds.emplace_back(value);
165 }
166 }
167
168 DeleteMessageData::DeleteMessageData(const MessageData& messageToDelete) {
169 channelId = messageToDelete.channelId;
170 timeStamp = messageToDelete.timeStamp;
171 messageId = messageToDelete.id;
172 }
173
174 void Messages::initialize(DiscordCoreInternal::HttpsClient* client) {
175 Messages::httpsClient = client;
176 }
177
179 DiscordCoreInternal::HttpsWorkloadData workload{ DiscordCoreInternal::HttpsWorkloadType::Get_Messages };
180 co_await NewThreadAwaitable<jsonifier::vector<MessageData>>();
181 workload.workloadClass = DiscordCoreInternal::HttpsWorkloadClass::Get;
182 workload.relativePath = "/channels/" + dataPackage.channelId + "/messages";
183 if (dataPackage.aroundThisId != 0) {
184 workload.relativePath += "?around=" + std::to_string(dataPackage.aroundThisId);
185 if (dataPackage.limit != 0) {
186 workload.relativePath += "&limit=" + std::to_string(dataPackage.limit);
187 } else {
188 workload.relativePath += "&limit=1";
189 }
190 } else if (dataPackage.beforeThisId != 0) {
191 workload.relativePath += "?before=" + dataPackage.beforeThisId;
192 if (dataPackage.limit != 0) {
193 workload.relativePath += "&limit=" + std::to_string(dataPackage.limit);
194 } else {
195 workload.relativePath += "&limit=1";
196 }
197 } else if (dataPackage.afterThisId != 0) {
198 workload.relativePath += "?after=" + dataPackage.afterThisId;
199 if (dataPackage.limit != 0) {
200 workload.relativePath += "&limit=" + std::to_string(dataPackage.limit);
201 } else {
202 workload.relativePath += "&limit=1";
203 }
204 } else {
205 if (dataPackage.limit != 0) {
206 workload.relativePath += "?limit=" + std::to_string(dataPackage.limit);
207 } else {
208 workload.relativePath += "&limit=1";
209 }
210 }
211 workload.callStack = "Messages::getMessagesAsync()";
212 jsonifier::vector<MessageData> returnData{};
213 Messages::httpsClient->submitWorkloadAndGetResult(std::move(workload), returnData);
214 co_return returnData;
215 }
216
218 DiscordCoreInternal::HttpsWorkloadData workload{ DiscordCoreInternal::HttpsWorkloadType::Get_Message };
219 co_await NewThreadAwaitable<MessageData>();
220 workload.workloadClass = DiscordCoreInternal::HttpsWorkloadClass::Get;
221 workload.relativePath = "/channels/" + dataPackage.channelId + "/messages/" + dataPackage.id;
222 workload.callStack = "Messages::getMessageAsync()";
223 MessageData returnData{};
224 Messages::httpsClient->submitWorkloadAndGetResult(std::move(workload), returnData);
225 co_return returnData;
226 }
227
229 DiscordCoreInternal::HttpsWorkloadData workload{ DiscordCoreInternal::HttpsWorkloadType::Post_Message };
230 co_await NewThreadAwaitable<MessageData>();
231 workload.workloadClass = DiscordCoreInternal::HttpsWorkloadClass::Post;
232 workload.relativePath = "/channels/" + dataPackage.channelId + "/messages";
233 if (dataPackage.files.size() > 0) {
234 workload.payloadType = DiscordCoreInternal::PayloadType::Multipart_Form;
235 parser.serializeJson(dataPackage, workload.content);
236 } else {
237 parser.serializeJson(dataPackage, workload.content);
238 }
239 workload.callStack = "Messages::createMessageAsync()";
240 MessageData returnData{};
241 Messages::httpsClient->submitWorkloadAndGetResult(std::move(workload), returnData);
242 co_return returnData;
243 }
244
246 DiscordCoreInternal::HttpsWorkloadData workload{ DiscordCoreInternal::HttpsWorkloadType::Crosspost_Message };
247 co_await NewThreadAwaitable<MessageData>();
248 workload.workloadClass = DiscordCoreInternal::HttpsWorkloadClass::Post;
249 workload.relativePath = "/channels/" + dataPackage.channelId + "/messages/" + dataPackage.messageId + "/crosspost";
250 workload.callStack = "Messages::crosspostMessageAsync()";
251 MessageData returnData{};
252 Messages::httpsClient->submitWorkloadAndGetResult(std::move(workload), returnData);
253 co_return returnData;
254 }
255
257 DiscordCoreInternal::HttpsWorkloadData workload{ DiscordCoreInternal::HttpsWorkloadType::Patch_Message };
258 co_await NewThreadAwaitable<MessageData>();
259 workload.workloadClass = DiscordCoreInternal::HttpsWorkloadClass::Patch;
260 workload.relativePath = "/channels/" + dataPackage.channelId + "/messages/" + dataPackage.messageId;
261 if (dataPackage.files.size() > 0) {
262 workload.payloadType = DiscordCoreInternal::PayloadType::Multipart_Form;
263 parser.serializeJson(dataPackage, workload.content);
264 } else {
265 parser.serializeJson(dataPackage, workload.content);
266 }
267 workload.callStack = "Messages::editMessageAsync()";
268 MessageData returnData{};
269 Messages::httpsClient->submitWorkloadAndGetResult(std::move(workload), returnData);
270 co_return returnData;
271 }
272
274 DiscordCoreInternal::HttpsWorkloadData workload{};
275 bool hasTimeElapsedNew = dataPackage.timeStamp.hasTimeElapsed(14, 0, 0);
276 if (!hasTimeElapsedNew) {
277 workload = DiscordCoreInternal::HttpsWorkloadType::Delete_Message;
278 } else {
279 workload = DiscordCoreInternal::HttpsWorkloadType::Delete_Message_Old;
280 }
281 co_await NewThreadAwaitable<void>();
282 if (dataPackage.timeDelay > 0) {
283 std::this_thread::sleep_for(Milliseconds{ dataPackage.timeDelay });
284 }
285 workload.workloadClass = DiscordCoreInternal::HttpsWorkloadClass::Delete;
286 workload.relativePath = "/channels/" + dataPackage.channelId + "/messages/" + dataPackage.messageId;
287 workload.callStack = "Messages::deleteMessageAsync()";
288 if (dataPackage.reason != "") {
289 workload.headersToInsert["X-Audit-Log-Reason"] = dataPackage.reason;
290 }
291 Messages::httpsClient->submitWorkloadAndGetResult(std::move(workload));
292 co_return;
293 }
294
296 DiscordCoreInternal::HttpsWorkloadData workload{ DiscordCoreInternal::HttpsWorkloadType::Bulk_Delete_Messages };
297 co_await NewThreadAwaitable<void>();
298 workload.workloadClass = DiscordCoreInternal::HttpsWorkloadClass::Post;
299 workload.relativePath = "/channels/" + dataPackage.channelId + "/messages/bulk-delete";
300 parser.serializeJson(dataPackage, workload.content);
301 if (dataPackage.reason != "") {
302 workload.headersToInsert["X-Audit-Log-Reason"] = dataPackage.reason;
303 }
304 Messages::httpsClient->submitWorkloadAndGetResult(std::move(workload));
305 co_return;
306 }
307
309 DiscordCoreInternal::HttpsWorkloadData workload{ DiscordCoreInternal::HttpsWorkloadType::Get_Pinned_Messages };
310 co_await NewThreadAwaitable<jsonifier::vector<MessageData>>();
311 workload.workloadClass = DiscordCoreInternal::HttpsWorkloadClass::Get;
312 workload.relativePath = "/channels/" + dataPackage.channelId + "/pins";
313 workload.callStack = "Messages::getPinnedMessagesAsync()";
314 jsonifier::vector<MessageData> returnData{};
315 Messages::httpsClient->submitWorkloadAndGetResult(std::move(workload), returnData);
316 co_return returnData;
317 }
318
320 DiscordCoreInternal::HttpsWorkloadData workload{ DiscordCoreInternal::HttpsWorkloadType::Put_Pin_Message };
321 co_await NewThreadAwaitable<void>();
322 workload.workloadClass = DiscordCoreInternal::HttpsWorkloadClass::Put;
323 workload.relativePath = "/channels/" + dataPackage.channelId + "/pins/" + dataPackage.messageId;
324 workload.callStack = "Messages::pinMessageAsync()";
325 if (dataPackage.reason != "") {
326 workload.headersToInsert["X-Audit-Log-Reason"] = dataPackage.reason;
327 }
328 Messages::httpsClient->submitWorkloadAndGetResult(std::move(workload));
329 co_return;
330 }
331
333 DiscordCoreInternal::HttpsWorkloadData workload{ DiscordCoreInternal::HttpsWorkloadType::Delete_Pin_Message };
334 co_await NewThreadAwaitable<void>();
335 workload.workloadClass = DiscordCoreInternal::HttpsWorkloadClass::Delete;
336 workload.relativePath = "/channels/" + dataPackage.channelId + "/pins/" + dataPackage.messageId;
337 workload.callStack = "Messages::unpinMessageAsync()";
338 if (dataPackage.reason != "") {
339 workload.headersToInsert["X-Audit-Log-Reason"] = dataPackage.reason;
340 }
341 Messages::httpsClient->submitWorkloadAndGetResult(std::move(workload));
342 co_return;
343 }
344
345 DiscordCoreInternal::HttpsClient* Messages::httpsClient{};
346}
A CoRoutine - representing a potentially asynchronous operation/function.
Definition: CoRoutine.hpp:88
Snowflake guildId
Snowflake of the Guild that the referenced Message was sent in.
Snowflake channelId
Snowflake of the ChannelData that the referenced Message was sent in.
Snowflake messageId
Snowflake of the Message to reference.
Data structure representing a single MessageData.
Message response base, for responding to messages.
MessageResponseBase & addContent(const std::string &dataPackage)
For setting the Message content in a response.
MessageResponseBase & addAllowedMentions(AllowedMentionsData dataPackage)
For setting the allowable mentions in a response.
CoRoutine< ObjectCollectorReturnData > collectObjects(int32_t quantityToCollect, int32_t msToCollectForNew, ObjectFilter< ValueType > filteringFunctionNew)
Begin waiting for Objects.
For getting a collection of Messages.
Snowflake channelId
ChannelData from which to collect the Messages.
uint64_t aroundThisId
Around this id.
Snowflake beforeThisId
Before this id.
Snowflake afterThisId
After this id.
int32_t limit
Limit of Messages to collect.
Snowflake id
The id of the Message to collect.
Snowflake channelId
The ChannelData from which to collect the MessageData.
Snowflake messageId
Snowflake of the message to be crossposted.
Snowflake channelId
ChannelData within which to crosspost the Message from.
int32_t timeDelay
Number of Milliseconds to wait before deleting the MessageData.
Snowflake messageId
The message Snowflake of the Message to delete.
Snowflake channelId
The channel Snowflake of the Message to delete.
std::string reason
The reason for deleting the MessageData.
TimeStampParse timeStamp
The created-at timeStamp of the original message.
For deleting a bulk of Messages.
std::string reason
The reason for deleting the Messages.
Snowflake channelId
ChannelData within which to delete the Messages.
For getting a collection of pinned Messages.
Snowflake channelId
The ChannelData from which to collect pinned Messages.
For pinning a single MessageData.
Snowflake channelId
The ChannelData within which to pin the MessageData.
Snowflake messageId
The Message which you would like to pin.
std::string reason
Reason for pinning this MessageData.
For unpinning a single MessageData.
std::string reason
Reason for pinning this MessageData.
Snowflake messageId
The Message which you would like to unpin.
Snowflake channelId
The ChannelData within which to unpin the MessageData.
static CoRoutine< MessageData > createMessageAsync(CreateMessageData dataPackage)
Creates a new MessageData.
static CoRoutine< MessageData > crosspostMessageAsync(CrosspostMessageData dataPackage)
Crossposts a message from a News ChannelData to the following Channels.
static CoRoutine< void > deleteMessagesBulkAsync(DeleteMessagesBulkData dataPackage)
Deletes a collection of Messages.
static CoRoutine< jsonifier::vector< MessageData > > getPinnedMessagesAsync(GetPinnedMessagesData dataPackage)
Collects a collection of pinned Messages from the Discord servers.
static CoRoutine< MessageData > editMessageAsync(EditMessageData dataPackage)
Edit a Message.
static CoRoutine< void > deleteMessageAsync(DeleteMessageData dataPackage)
Deletes a Message.
static CoRoutine< MessageData > getMessageAsync(GetMessageData dataPackage)
Collects a Message from the Discord servers.
static CoRoutine< void > pinMessageAsync(PinMessageData dataPackage)
Pins a Message to a given Channel.
static CoRoutine< void > unpinMessageAsync(UnpinMessageData dataPackage)
Unpins a Message from a given Channel.
static CoRoutine< jsonifier::vector< MessageData > > getMessagesAsync(GetMessagesData dataPackage)
Collects a collection of Message from the Discord servers.
bool hasTimeElapsed(uint64_t days, uint64_t hours, uint64_t minutes) const
Checks if a certain time duration has elapsed.
Definition: Base.hpp:397
uint64_t id
The Snowflake ID.
Definition: Base.hpp:870