DiscordCoreAPI
A Discord bot library written in C++, with custom asynchronous coroutines.
Loading...
Searching...
No Matches
InteractionEntities.cpp
Go to the documentation of this file.
1/*
2 DiscordCoreAPI, A bot library for Discord, written in C++, and featuring explicit multithreading through the usage of custom, asynchronous C++ CoRoutines.
3
4 Copyright 2021, 2022 Chris M. (RealTimeChris)
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 USA
20*/
21/// InteractionEntities.cpp - Source file for the interaction related classes and structs.
22/// May 28, 2021
23/// https://discordcoreapi.com
24/// \file InteractionEntities.cpp
25
31
32namespace DiscordCoreAPI {
33
34 InteractionResponseBase& InteractionResponseBase::addButton(bool disabled, const std::string& customIdNew, const std::string& buttonLabel,
35 ButtonStyle buttonStyle, const std::string& emojiName, Snowflake emojiId, const std::string& url) {
36 if (this->data.data.components.size() == 0) {
37 ActionRowData actionRowData;
38 this->data.data.components.emplace_back(actionRowData);
39 }
40 if (this->data.data.components.size() < 5) {
41 if (this->data.data.components[this->data.data.components.size() - 1].components.size() < 5) {
42 ComponentData component;
43 component.type = ComponentType::Button;
44 component.emoji.name = emojiName;
45 component.label = buttonLabel;
46 component.style = static_cast<int32_t>(buttonStyle);
47 component.customId = customIdNew;
48 component.disabled = disabled;
49 component.emoji.id = emojiId;
50 component.url = url;
51 this->data.data.components[this->data.data.components.size() - 1].components.emplace_back(component);
52 } else if (this->data.data.components[this->data.data.components.size() - 1].components.size() == 5) {
53 ActionRowData actionRowData;
54 this->data.data.components.emplace_back(actionRowData);
55 }
56 }
57 return *this;
58 }
59
60 InteractionResponseBase& InteractionResponseBase::addSelectMenu(bool disabled, const std::string& customIdNew,
61 std::vector<SelectOptionData> options, const std::string& placeholder, int32_t maxValues, int32_t minValues, SelectMenuType type,
62 std::vector<ChannelType> channelTypes) {
63 if (this->data.data.components.size() == 0) {
64 ActionRowData actionRowData;
65 this->data.data.components.emplace_back(actionRowData);
66 }
67 if (this->data.data.components.size() < 5) {
68 if (this->data.data.components[this->data.data.components.size() - 1].components.size() < 5) {
69 ComponentData componentData;
70 componentData.type = static_cast<ComponentType>(type);
71 componentData.channelTypes = channelTypes;
72 componentData.placeholder = placeholder;
73 componentData.customId = customIdNew;
74 componentData.maxValues = maxValues;
75 componentData.minValues = minValues;
76 componentData.disabled = disabled;
77 componentData.options = options;
78 this->data.data.components[this->data.data.components.size() - 1].components.emplace_back(componentData);
79 } else if (this->data.data.components[this->data.data.components.size() - 1].components.size() == 5) {
80 ActionRowData actionRowData;
81 this->data.data.components.emplace_back(actionRowData);
82 }
83 }
84 return *this;
85 }
86
87 InteractionResponseBase& InteractionResponseBase::addModal(const std::string& topTitleNew, const std::string& topCustomIdNew,
88 const std::string& titleNew, const std::string& customIdNew, bool required, int32_t minLength, int32_t maxLength, TextInputStyle inputStyle,
89 const std::string& label, const std::string& placeholder) {
90 this->data.data.title = topTitleNew;
91 this->data.data.customId = topCustomIdNew;
92 if (this->data.data.components.size() == 0) {
93 ActionRowData actionRowData;
94 this->data.data.components.emplace_back(actionRowData);
95 }
96 if (this->data.data.components.size() < 5) {
97 if (this->data.data.components[this->data.data.components.size() - 1].components.size() < 5) {
98 ComponentData component{};
99 component.type = ComponentType::Text_Input;
100 component.customId = customIdNew;
101 component.style = static_cast<int32_t>(inputStyle);
102 component.title = titleNew;
103 component.maxLength = maxLength;
104 component.minLength = minLength;
105 component.label = label;
106 component.required = required;
107 component.placeholder = placeholder;
108 this->data.data.components[this->data.data.components.size() - 1].components.emplace_back(component);
109 } else if (this->data.data.components[this->data.data.components.size() - 1].components.size() == 5) {
110 ActionRowData actionRowData;
111 this->data.data.components.emplace_back(actionRowData);
112 }
113 }
114 return *this;
115 }
116
117 InteractionResponseBase& InteractionResponseBase::addFile(const File& theFile) {
118 this->data.data.files.emplace_back(theFile);
119 return *this;
120 }
121
122 InteractionResponseBase& InteractionResponseBase::addAllowedMentions(const AllowedMentionsData& dataPackage) {
123 this->data.data.allowedMentions = dataPackage;
124 return *this;
125 }
126
127 InteractionResponseBase& InteractionResponseBase::addComponentRow(const ActionRowData& dataPackage) {
128 this->data.data.components.emplace_back(dataPackage);
129 return *this;
130 }
131
132 InteractionResponseBase& InteractionResponseBase::setResponseType(InteractionCallbackType type) {
133 this->data.type = type;
134 return *this;
135 }
136
137 InteractionResponseBase& InteractionResponseBase::addMessageEmbed(const EmbedData& dataPackage) {
138 this->data.data.embeds.emplace_back(dataPackage);
139 return *this;
140 }
141
142 InteractionResponseBase& InteractionResponseBase::addContent(const std::string& dataPackage) {
143 this->data.data.content = dataPackage;
144 return *this;
145 }
146
147 InteractionResponseBase& InteractionResponseBase::setTTSStatus(bool enabledTTs) {
148 this->data.data.tts = enabledTTs;
149 return *this;
150 }
151
152 InteractionResponseBase& InteractionResponseBase::setFlags(int64_t flagsNew) {
153 this->data.data.flags = flagsNew;
154 return *this;
155 }
156
157 InteractionResponseData InteractionResponseBase::getInteractionResponseData() {
158 return this->data;
159 }
160
161 void Interactions::initialize(DiscordCoreInternal::HttpsClient* client) {
162 Interactions::httpsClient = client;
163 }
164
165 CreateEphemeralInteractionResponseData::CreateEphemeralInteractionResponseData(const RespondToInputEventData& dataPackage) {
166 this->data = dataPackage;
167 if (dataPackage.eventType == InteractionType::Message_Component) {
169 } else {
171 }
172 this->interactionPackage.interactionToken = dataPackage.interactionToken;
173 this->interactionPackage.applicationId = dataPackage.applicationId;
174 this->interactionPackage.interactionId = dataPackage.interactionId;
175 this->data.data.flags = 64;
176 }
177
178 CreateDeferredInteractionResponseData::CreateDeferredInteractionResponseData(const RespondToInputEventData& dataPackage) {
179 this->data = dataPackage;
180 if (dataPackage.eventType == InteractionType::Message_Component) {
182 } else {
184 }
185 this->interactionPackage.interactionToken = dataPackage.interactionToken;
186 this->interactionPackage.applicationId = dataPackage.applicationId;
187 this->interactionPackage.interactionId = dataPackage.interactionId;
188 this->data = dataPackage;
189 }
190
191 CreateInteractionResponseData::CreateInteractionResponseData(const CreateDeferredInteractionResponseData& dataPackage) {
192 this->interactionPackage.interactionToken = dataPackage.interactionPackage.interactionToken;
193 this->interactionPackage.applicationId = dataPackage.interactionPackage.applicationId;
194 this->interactionPackage.interactionId = dataPackage.interactionPackage.interactionId;
195 this->data.data.components = dataPackage.data.data.components;
196 this->data.type = dataPackage.data.type;
197 this->data = dataPackage.data;
198 }
199
200 CreateInteractionResponseData::CreateInteractionResponseData(const CreateEphemeralInteractionResponseData& dataPackage) {
201 this->interactionPackage.interactionToken = dataPackage.interactionPackage.interactionToken;
202 this->interactionPackage.applicationId = dataPackage.interactionPackage.applicationId;
203 this->interactionPackage.interactionId = dataPackage.interactionPackage.interactionId;
204 this->data.data.components = dataPackage.data.data.components;
205 this->data.type = dataPackage.data.type;
206 this->data = dataPackage.data;
207 this->data.data.flags = 64;
208 }
209
210 CreateInteractionResponseData::CreateInteractionResponseData(const RespondToInputEventData& dataPackage) {
211 this->data = dataPackage;
212 if (dataPackage.eventType == InteractionType::Message_Component && dataPackage.type == InputEventResponseType::Deferred_Response) {
214 } else if (dataPackage.eventType == InteractionType::Message_Component) {
216 } else if (dataPackage.eventType == InteractionType::Application_Command_Autocomplete ||
219 } else {
221 }
222 if (dataPackage.type == InputEventResponseType::Modal_Interaction_Response || dataPackage.title != "") {
223 this->data.type = InteractionCallbackType::Modal;
224 }
225 this->interactionPackage.interactionToken = dataPackage.interactionToken;
226 this->interactionPackage.applicationId = dataPackage.applicationId;
227 this->interactionPackage.interactionId = dataPackage.interactionId;
228 this->data.data.files = dataPackage.files;
229 }
230
231 CreateInteractionResponseData::CreateInteractionResponseData(const InteractionData& dataPackage) {
232 if (dataPackage.type == InteractionType::Message_Component) {
234 } else {
236 }
237 this->interactionPackage.applicationId = dataPackage.applicationId;
238 this->interactionPackage.interactionToken = dataPackage.token;
239 this->interactionPackage.interactionId = dataPackage.id;
240 }
241
242 EditInteractionResponseData::EditInteractionResponseData(const RespondToInputEventData& dataPackage) {
243 this->interactionPackage.interactionToken = dataPackage.interactionToken;
244 this->interactionPackage.applicationId = dataPackage.applicationId;
245 this->interactionPackage.interactionId = dataPackage.interactionId;
246 this->data.allowedMentions = dataPackage.allowedMentions;
247 this->data.components = dataPackage.components;
248 this->data.content = dataPackage.content;
249 this->data.embeds = dataPackage.embeds;
250 this->data.title = dataPackage.title;
251 this->data.flags = dataPackage.flags;
252 this->data.files = dataPackage.files;
253 this->data.tts = dataPackage.tts;
254 }
255
256 CreateEphemeralFollowUpMessageData::CreateEphemeralFollowUpMessageData(const RespondToInputEventData& dataPackage) {
257 this->interactionPackage.interactionToken = dataPackage.interactionToken;
258 this->interactionPackage.applicationId = dataPackage.applicationId;
259 this->interactionPackage.interactionId = dataPackage.interactionId;
260 this->allowedMentions = dataPackage.allowedMentions;
261 this->components = dataPackage.components;
262 this->content = dataPackage.content;
263 this->embeds = dataPackage.embeds;
264 this->files = dataPackage.files;
265 this->tts = dataPackage.tts;
266 this->flags = 64;
267 }
268
269 CreateFollowUpMessageData::CreateFollowUpMessageData(const CreateEphemeralFollowUpMessageData& dataPackage) {
270 this->interactionPackage = dataPackage.interactionPackage;
271 this->allowedMentions = dataPackage.allowedMentions;
272 this->components = dataPackage.components;
273 this->content = dataPackage.content;
274 this->embeds = dataPackage.embeds;
275 this->flags = dataPackage.flags;
276 this->files = dataPackage.files;
277 this->tts = dataPackage.tts;
278 this->flags = 64;
279 }
280
281 CreateFollowUpMessageData::CreateFollowUpMessageData(const RespondToInputEventData& dataPackage) {
282 this->interactionPackage.interactionToken = dataPackage.interactionToken;
283 this->interactionPackage.applicationId = dataPackage.applicationId;
284 this->interactionPackage.interactionId = dataPackage.interactionId;
285 this->allowedMentions = dataPackage.allowedMentions;
286 this->components = dataPackage.components;
287 this->content = dataPackage.content;
288 this->embeds = dataPackage.embeds;
289 this->flags = dataPackage.flags;
290 this->files = dataPackage.files;
291 this->tts = dataPackage.tts;
292 }
293
294 EditFollowUpMessageData::EditFollowUpMessageData(const RespondToInputEventData& dataPackage) {
295 this->interactionPackage.interactionToken = dataPackage.interactionToken;
296 this->interactionPackage.applicationId = dataPackage.applicationId;
297 this->interactionPackage.interactionId = dataPackage.interactionId;
298 this->data.allowedMentions = dataPackage.allowedMentions;
299 this->messagePackage.channelId = dataPackage.channelId;
300 this->messagePackage.messageId = dataPackage.messageId;
301 this->data.components = dataPackage.components;
302 this->data.content = dataPackage.content;
303 this->data.embeds = dataPackage.embeds;
304 this->data.files = dataPackage.files;
305 }
306
307 DeleteFollowUpMessageData::DeleteFollowUpMessageData(const RespondToInputEventData& dataPackage) {
308 this->interactionPackage.interactionToken = dataPackage.interactionToken;
309 this->interactionPackage.applicationId = dataPackage.applicationId;
310 this->interactionPackage.interactionId = dataPackage.interactionId;
311 this->messagePackage.channelId = dataPackage.channelId;
312 this->messagePackage.messageId = dataPackage.messageId;
313 }
314
315 DeleteInteractionResponseData::DeleteInteractionResponseData(const RespondToInputEventData& dataPackage) {
316 this->interactionPackage.interactionToken = dataPackage.interactionToken;
317 this->interactionPackage.applicationId = dataPackage.applicationId;
318 this->interactionPackage.interactionId = dataPackage.interactionId;
319 }
320
322 DiscordCoreInternal::HttpsWorkloadData workload{ DiscordCoreInternal::HttpsWorkloadType::Post_Interaction_Response };
323 co_await NewThreadAwaitable<Message>();
324 workload.workloadClass = DiscordCoreInternal::HttpsWorkloadClass::Post;
325 workload.relativePath =
326 "/interactions/" + dataPackage.interactionPackage.interactionId + "/" + dataPackage.interactionPackage.interactionToken + "/callback";
327 if (dataPackage.data.data.files.size() > 0) {
328 workload.payloadType = DiscordCoreInternal::PayloadType::Multipart_Form;
329 auto serializer = dataPackage.data.operator Jsonifier();
330 serializer.refreshString(JsonifierSerializeType::Json);
331 workload.content = constructMultiPartData(serializer.operator std::string(), dataPackage.data.data.files);
332 } else {
333 auto serializer = dataPackage.data.operator Jsonifier();
334 serializer.refreshString(JsonifierSerializeType::Json);
335 workload.content = serializer.operator std::string();
336 }
337 workload.callStack = "Interactions::createInteractionResponseAsync()";
338 Interactions::httpsClient->submitWorkloadAndGetResult<void>(workload);
339 GetInteractionResponseData dataPackage01{};
340 dataPackage01.applicationId = dataPackage.interactionPackage.applicationId;
341 dataPackage01.interactionToken = dataPackage.interactionPackage.interactionToken;
343 co_return Interactions::getInteractionResponseAsync(dataPackage01).get();
344 } else {
345 co_return Message{};
346 }
347 }
348
350 DiscordCoreInternal::HttpsWorkloadData workload{ DiscordCoreInternal::HttpsWorkloadType::Get_Interaction_Response };
351 co_await NewThreadAwaitable<Message>();
352 workload.workloadClass = DiscordCoreInternal::HttpsWorkloadClass::Get;
353 workload.relativePath = "/webhooks/" + dataPackage.applicationId + "/" + dataPackage.interactionToken + "/messages/@original";
354 workload.callStack = "Interactions::getInteractionResponseAsync()";
355 Message returnValue{};
356 co_return Interactions::httpsClient->submitWorkloadAndGetResult<Message>(workload, &returnValue);
357 }
358
360 DiscordCoreInternal::HttpsWorkloadData workload{ DiscordCoreInternal::HttpsWorkloadType::Patch_Interaction_Response };
361 co_await NewThreadAwaitable<Message>();
362 workload.workloadClass = DiscordCoreInternal::HttpsWorkloadClass::Patch;
363 workload.relativePath = "/webhooks/" + dataPackage.interactionPackage.applicationId + "/" + dataPackage.interactionPackage.interactionToken +
364 "/messages/@original";
365 if (dataPackage.data.files.size() > 0) {
366 workload.payloadType = DiscordCoreInternal::PayloadType::Multipart_Form;
367 auto serializer = dataPackage.data.operator Jsonifier();
368 serializer.refreshString(JsonifierSerializeType::Json);
369 workload.content = constructMultiPartData(serializer.operator std::string(), dataPackage.data.files);
370 } else {
371 auto serializer = dataPackage.data.operator Jsonifier();
372 serializer.refreshString(JsonifierSerializeType::Json);
373 workload.content = serializer.operator std::string();
374 }
375 Message messageNew{};
376 workload.callStack = "Interactions::editInteractionResponseAsync()";
377 co_return Interactions::httpsClient->submitWorkloadAndGetResult<Message>(workload, &messageNew);
378 }
379
381 DiscordCoreInternal::HttpsWorkloadData workload{ DiscordCoreInternal::HttpsWorkloadType::Delete_Interaction_Response };
382 co_await NewThreadAwaitable<void>();
383 std::this_thread::sleep_for(Milliseconds{ dataPackage.timeDelay });
384 workload.workloadClass = DiscordCoreInternal::HttpsWorkloadClass::Delete;
385 workload.relativePath = "/webhooks/" + dataPackage.interactionPackage.applicationId + "/" + dataPackage.interactionPackage.interactionToken +
386 "/messages/@original";
387 workload.callStack = "Interactions::deleteInteractionResponseAsync()";
388 co_return Interactions::httpsClient->submitWorkloadAndGetResult<void>(workload);
389 }
390
392 DiscordCoreInternal::HttpsWorkloadData workload{ DiscordCoreInternal::HttpsWorkloadType::Post_Followup_Message };
393 co_await NewThreadAwaitable<Message>();
394 workload.workloadClass = DiscordCoreInternal::HttpsWorkloadClass::Post;
395 workload.relativePath = "/webhooks/" + dataPackage.interactionPackage.applicationId + "/" + dataPackage.interactionPackage.interactionToken;
396 if (dataPackage.files.size() > 0) {
397 workload.payloadType = DiscordCoreInternal::PayloadType::Multipart_Form;
398 auto serializer = dataPackage.operator Jsonifier();
399 serializer.refreshString(JsonifierSerializeType::Json);
400 workload.content = constructMultiPartData(serializer.operator std::string(), dataPackage.files);
401 } else {
402 auto serializer = dataPackage.operator Jsonifier();
403 serializer.refreshString(JsonifierSerializeType::Json);
404 workload.content = serializer.operator std::string();
405 }
406 workload.callStack = "Interactions::createFollowUpMessageAsync()";
407 Message returnValue{};
408 co_return Interactions::httpsClient->submitWorkloadAndGetResult<Message>(workload, &returnValue);
409 }
410
412 DiscordCoreInternal::HttpsWorkloadData workload{ DiscordCoreInternal::HttpsWorkloadType::Get_Followup_Message };
413 co_await NewThreadAwaitable<Message>();
414 workload.workloadClass = DiscordCoreInternal::HttpsWorkloadClass::Get;
415 workload.relativePath = "/webhooks/" + dataPackage.applicationId + "/" + dataPackage.interactionToken + "/messages/" + dataPackage.messageId;
416 workload.callStack = "Interactions::getFollowUpMessageAsync()";
417 Message returnValue{};
418 co_return Interactions::httpsClient->submitWorkloadAndGetResult<Message>(workload, &returnValue);
419 }
420
422 DiscordCoreInternal::HttpsWorkloadData workload{ DiscordCoreInternal::HttpsWorkloadType::Patch_Followup_Message };
423 co_await NewThreadAwaitable<Message>();
424 workload.workloadClass = DiscordCoreInternal::HttpsWorkloadClass::Patch;
425 workload.relativePath = "/webhooks/" + dataPackage.interactionPackage.applicationId + "/" + dataPackage.interactionPackage.interactionToken +
426 "/messages/" + dataPackage.messagePackage.messageId;
427 if (dataPackage.data.files.size() > 0) {
428 workload.payloadType = DiscordCoreInternal::PayloadType::Multipart_Form;
429 auto serializer = dataPackage.data.operator Jsonifier();
430 serializer.refreshString(JsonifierSerializeType::Json);
431 workload.content = constructMultiPartData(serializer.operator std::string(), dataPackage.data.files);
432 } else {
433 auto serializer = dataPackage.data.operator Jsonifier();
434 serializer.refreshString(JsonifierSerializeType::Json);
435 workload.content = serializer.operator std::string();
436 }
437 workload.callStack = "Interactions::editFollowUpMessageAsync()";
438 Message returnValue{};
439 co_return Interactions::httpsClient->submitWorkloadAndGetResult<Message>(workload, &returnValue);
440 }
441
443 DiscordCoreInternal::HttpsWorkloadData workload{ DiscordCoreInternal::HttpsWorkloadType::Delete_Followup_Message };
444 co_await NewThreadAwaitable<void>();
445 std::this_thread::sleep_for(Milliseconds{ dataPackage.timeDelay });
446 workload.workloadClass = DiscordCoreInternal::HttpsWorkloadClass::Delete;
447 workload.relativePath = "/webhooks/" + dataPackage.interactionPackage.applicationId + "/" + dataPackage.interactionPackage.interactionToken +
448 "/messages/" + dataPackage.messagePackage.messageId;
449 workload.callStack = "Interactions::deleteFollowUpMessageToBeWrappe()";
450 co_return Interactions::httpsClient->submitWorkloadAndGetResult<void>(workload);
451 }
452
454 this->channelId = dataPackage.getChannelData().id;
455 this->messageId = dataPackage.getMessageData().id;
456 *this->interactionData = dataPackage.getInteractionData();
457 this->buffersMapKey = this->channelId + this->messageId;
458 }
459
461 int32_t maxWaitTimeInMsNew, int32_t maxCollectedSelectMenuCountNew, CreateInteractionResponseData errorMessageDataNew, Snowflake targetUser) {
462 co_await NewThreadAwaitable<std::vector<SelectMenuResponseData>>();
463 SelectMenuCollector::selectMenuInteractionBuffersMap[this->buffersMapKey] = &this->selectMenuIncomingInteractionBuffer;
464 if (targetUser == 0 && !getSelectMenuDataForAllNew) {
465 this->getSelectMenuDataForAll = true;
466 } else {
467 this->getSelectMenuDataForAll = getSelectMenuDataForAllNew;
468 }
469 if (targetUser != 0) {
470 this->userId = targetUser;
471 }
472 this->maxCollectedSelectMenuCount = maxCollectedSelectMenuCountNew;
473 this->getSelectMenuDataForAll = getSelectMenuDataForAllNew;
474 this->errorMessageData = errorMessageDataNew;
475 this->maxTimeInMs = maxWaitTimeInMsNew;
476 this->run();
477 co_return std::move(this->responseVector);
478 }
479
480 void SelectMenuCollector::collectSelectMenuData(std::function<bool(InteractionData)> triggerFunctionNew,
482 functionNew.setTestFunction(triggerFunctionNew);
483 SelectMenuCollector::selectMenuInteractionEventsMap.add(std::move(functionNew));
484 }
485
486 SelectMenuCollector::~SelectMenuCollector() {
487 if (SelectMenuCollector::selectMenuInteractionBuffersMap.contains(this->buffersMapKey)) {
488 SelectMenuCollector::selectMenuInteractionBuffersMap.erase(this->buffersMapKey);
489 }
490 }
491
492 void SelectMenuCollector::run() {
493 int64_t currentCollectedSelectMenuCount{};
494 StopWatch stopWatch{ Milliseconds{ this->maxTimeInMs } };
495 while (!this->doWeQuit && !stopWatch.hasTimePassed()) {
496 if (this->getSelectMenuDataForAll == false) {
497 auto selectMenuInteractionData = std::make_unique<InteractionData>();
498 if (waitForTimeToPass(this->selectMenuIncomingInteractionBuffer, *selectMenuInteractionData.get(), this->maxTimeInMs)) {
499 this->selectMenuId = "empty";
500 auto response = std::make_unique<SelectMenuResponseData>();
501 response->selectionId = this->selectMenuId;
502 response->channelId = this->channelId;
503 response->messageId = this->messageId;
504 response->userId = selectMenuInteractionData->user.id;
505 *response->interactionData = *this->interactionData;
506 response->values = std::vector<std::string>{ "empty" };
507 this->responseVector.emplace_back(*response);
508 break;
509 }
510 if (selectMenuInteractionData->user.id != this->userId) {
511 this->errorMessageData.interactionPackage.applicationId = selectMenuInteractionData->applicationId;
512 this->errorMessageData.interactionPackage.interactionId = selectMenuInteractionData->id;
513 this->errorMessageData.interactionPackage.interactionToken = selectMenuInteractionData->token;
514 this->errorMessageData.messagePackage.messageId = selectMenuInteractionData->message.id;
515 this->errorMessageData.messagePackage.channelId = selectMenuInteractionData->message.channelId;
516 this->errorMessageData.data.type = InteractionCallbackType::Channel_Message_With_Source;
517 Interactions::createInteractionResponseAsync(this->errorMessageData).get();
518 } else {
519 *this->interactionData = *selectMenuInteractionData;
520 this->selectMenuId = selectMenuInteractionData->data.componentData.customId;
521 auto response = std::make_unique<SelectMenuResponseData>();
522 response->selectionId = this->selectMenuId;
523 response->channelId = this->channelId;
524 response->messageId = this->messageId;
525 response->userId = selectMenuInteractionData->user.id;
526 response->values = this->interactionData->data.componentData.values;
527 *response->interactionData = *selectMenuInteractionData;
528 this->responseVector.emplace_back(*response);
529 ++currentCollectedSelectMenuCount;
530 stopWatch.resetTimer();
531 if (this->maxCollectedSelectMenuCount > 1 && currentCollectedSelectMenuCount < this->maxCollectedSelectMenuCount - 1) {
532 auto createResponseData = std::make_unique<CreateInteractionResponseData>(*selectMenuInteractionData);
533 createResponseData->data.type = InteractionCallbackType::Deferred_Update_Message;
534 Interactions::createInteractionResponseAsync(*createResponseData).get();
535 }
536 if (currentCollectedSelectMenuCount >= this->maxCollectedSelectMenuCount) {
537 for (auto& value: this->responseVector) {
538 *value.interactionData = *selectMenuInteractionData;
539 }
540 doWeQuit = true;
541 }
542 }
543 } else {
544 auto selectMenuInteractionData = std::make_unique<InteractionData>();
545 if (waitForTimeToPass(this->selectMenuIncomingInteractionBuffer, *selectMenuInteractionData.get(), this->maxTimeInMs)) {
546 this->selectMenuId = "empty";
547 auto response = std::make_unique<SelectMenuResponseData>();
548 response->selectionId = this->selectMenuId;
549 response->channelId = this->channelId;
550 response->messageId = this->messageId;
551 response->userId = selectMenuInteractionData->user.id;
552 *response->interactionData = *this->interactionData;
553 response->values = std::vector<std::string>{ "empty" };
554 this->responseVector.emplace_back(*response);
555 break;
556 }
557 *this->interactionData = *selectMenuInteractionData;
558 this->selectMenuId = selectMenuInteractionData->data.componentData.customId;
559 auto response = std::make_unique<SelectMenuResponseData>();
560 response->selectionId = this->selectMenuId;
561 response->channelId = this->channelId;
562 response->messageId = this->messageId;
563 response->userId = selectMenuInteractionData->user.id;
564 *response->interactionData = *selectMenuInteractionData;
565 response->values = this->interactionData->data.componentData.values;
566 this->responseVector.emplace_back(*response);
567 ++currentCollectedSelectMenuCount;
568 stopWatch.resetTimer();
569 if (this->maxCollectedSelectMenuCount > 1 && currentCollectedSelectMenuCount < this->maxCollectedSelectMenuCount - 1) {
570 auto createResponseData = std::make_unique<CreateInteractionResponseData>(*selectMenuInteractionData);
571 createResponseData->data.type = InteractionCallbackType::Deferred_Update_Message;
572 Interactions::createInteractionResponseAsync(*createResponseData).get();
573 }
574 if (currentCollectedSelectMenuCount >= this->maxCollectedSelectMenuCount) {
575 this->doWeQuit = true;
576 for (auto& value: this->responseVector) {
577 *value.interactionData = *selectMenuInteractionData;
578 }
579 }
580 }
581 std::this_thread::sleep_for(1ms);
582 }
583 SelectMenuCollector::selectMenuInteractionBuffersMap.erase(this->buffersMapKey);
584 }
585
587 this->channelId = dataPackage.getChannelData().id;
588 this->messageId = dataPackage.getMessageData().id;
589 *this->interactionData = dataPackage.getInteractionData();
590 this->buffersMapKey = this->channelId + this->messageId;
591 ButtonCollector::buttonInteractionBuffersMap[this->buffersMapKey] = &this->buttonIncomingInteractionBuffer;
592 }
593
594 CoRoutine<std::vector<ButtonResponseData>> ButtonCollector::collectButtonData(bool getButtonDataForAllNew, int32_t maxWaitTimeInMsNew,
595 int32_t maxNumberOfPressesNew, CreateInteractionResponseData errorMessageDataNew, Snowflake targetUser) {
596 co_await NewThreadAwaitable<std::vector<ButtonResponseData>>();
597 if (targetUser == 0 && !getButtonDataForAllNew) {
598 throw DCAException{ "ButtonCollector::collectButtonData(), You've failed to "
599 "properly set the collectButtonData() parameters!\n\n" };
600 }
601 if (targetUser != 0) {
602 this->userId = targetUser;
603 }
604 this->maxCollectedButtonCount = maxNumberOfPressesNew;
605 this->getButtonDataForAll = getButtonDataForAllNew;
606 this->errorMessageData = errorMessageDataNew;
607 this->maxTimeInMs = maxWaitTimeInMsNew;
608 this->run();
609 co_return std::move(this->responseVector);
610 }
611
612 void ButtonCollector::collectButtonData(std::function<bool(InteractionData)> triggerFunctionNew,
614 functionNew.setTestFunction(triggerFunctionNew);
615 ButtonCollector::buttonInteractionEventsMap.add(std::move(functionNew));
616 }
617
618 ButtonCollector::~ButtonCollector() {
619 if (ButtonCollector::buttonInteractionBuffersMap.contains(this->buffersMapKey)) {
620 ButtonCollector::buttonInteractionBuffersMap.erase(this->buffersMapKey);
621 }
622 }
623
624 void ButtonCollector::run() {
625 int64_t currentCollectedButtonCount{};
626 StopWatch stopWatch{ Milliseconds{ this->maxTimeInMs } };
627 while (!this->doWeQuit && !stopWatch.hasTimePassed()) {
628 if (this->getButtonDataForAll == false) {
629 auto buttonInteractionData = std::make_unique<InteractionData>();
630 if (waitForTimeToPass(this->buttonIncomingInteractionBuffer, *buttonInteractionData.get(), this->maxTimeInMs)) {
631 this->buttonId = "empty";
632 auto response = std::make_unique<ButtonResponseData>();
633 response->buttonId = this->buttonId;
634 response->channelId = this->channelId;
635 response->messageId = this->messageId;
636 response->userId = buttonInteractionData->user.id;
637 *response->interactionData = *this->interactionData;
638 this->responseVector.emplace_back(*response);
639 break;
640 }
641 if (buttonInteractionData->user.id != this->userId) {
642 this->errorMessageData.interactionPackage.applicationId = buttonInteractionData->applicationId;
643 this->errorMessageData.interactionPackage.interactionId = buttonInteractionData->id;
644 this->errorMessageData.interactionPackage.interactionToken = buttonInteractionData->token;
645 this->errorMessageData.messagePackage.messageId = buttonInteractionData->message.id;
646 this->errorMessageData.messagePackage.channelId = buttonInteractionData->message.channelId;
647 this->errorMessageData.data.type = InteractionCallbackType::Channel_Message_With_Source;
648 Interactions::createInteractionResponseAsync(this->errorMessageData).get();
649 } else {
650 *this->interactionData = *buttonInteractionData;
651 this->buttonId = buttonInteractionData->data.componentData.customId;
652 auto response = std::make_unique<ButtonResponseData>();
653 response->buttonId = this->buttonId;
654 response->channelId = this->channelId;
655 response->messageId = this->messageId;
656 response->userId = buttonInteractionData->user.id;
657 *response->interactionData = *buttonInteractionData;
658 this->responseVector.emplace_back(*response);
659 ++currentCollectedButtonCount;
660 stopWatch.resetTimer();
661 if (this->maxCollectedButtonCount > 1 && currentCollectedButtonCount < this->maxCollectedButtonCount) {
662 auto createResponseData = std::make_unique<CreateInteractionResponseData>(*buttonInteractionData);
663 createResponseData->data.type = InteractionCallbackType::Deferred_Update_Message;
664 Interactions::createInteractionResponseAsync(*createResponseData).get();
665 }
666 if (currentCollectedButtonCount >= this->maxCollectedButtonCount) {
667 for (auto& value: this->responseVector) {
668 *value.interactionData = *buttonInteractionData;
669 }
670 doWeQuit = true;
671 }
672 }
673 } else {
674 auto buttonInteractionData = std::make_unique<InteractionData>();
675 if (waitForTimeToPass(this->buttonIncomingInteractionBuffer, *buttonInteractionData.get(), this->maxTimeInMs)) {
676 this->buttonId = "empty";
677 auto response = std::make_unique<ButtonResponseData>();
678 response->buttonId = this->buttonId;
679 response->channelId = this->channelId;
680 response->messageId = this->messageId;
681 response->userId = buttonInteractionData->user.id;
682 *response->interactionData = *buttonInteractionData;
683 this->responseVector.emplace_back(*response);
684 break;
685 }
686 *this->interactionData = *buttonInteractionData;
687 this->buttonId = buttonInteractionData->data.componentData.customId;
688 auto response = std::make_unique<ButtonResponseData>();
689 response->buttonId = this->buttonId;
690 response->channelId = this->channelId;
691 response->messageId = this->messageId;
692 response->userId = buttonInteractionData->user.id;
693 *response->interactionData = *buttonInteractionData;
694 this->responseVector.emplace_back(*response);
695 ++currentCollectedButtonCount;
696 stopWatch.resetTimer();
697 if (this->maxCollectedButtonCount > 1 && currentCollectedButtonCount < this->maxCollectedButtonCount) {
698 auto createResponseData = std::make_unique<CreateInteractionResponseData>(*buttonInteractionData);
699 createResponseData->data.type = InteractionCallbackType::Deferred_Update_Message;
700 Interactions::createInteractionResponseAsync(*createResponseData).get();
701 }
702 if (currentCollectedButtonCount >= this->maxCollectedButtonCount) {
703 for (auto& value: this->responseVector) {
704 *value.interactionData = *buttonInteractionData;
705 }
706 this->doWeQuit = true;
707 }
708 }
709 std::this_thread::sleep_for(1ms);
710 }
711 ButtonCollector::buttonInteractionBuffersMap.erase(this->buffersMapKey);
712 }
713
715 this->channelId = dataPackage.getChannelData().id;
716 ModalCollector::modalInteractionBuffersMap[this->channelId] = &this->modalIncomingInteractionBuffer;
717 }
718
720 co_await NewThreadAwaitable<ModalResponseData>();
721 this->maxTimeInMs = maxWaitTimeInMsNew;
722 this->run();
723 co_return std::move(this->responseData);
724 }
725
726 void ModalCollector::collectModalData(std::function<bool(InteractionData)> triggerFunctionNew,
728 functionNew.setTestFunction(triggerFunctionNew);
729 ModalCollector::modalInteractionEventsMap.add(std::move(functionNew));
730 }
731
732 ModalCollector::~ModalCollector() {
733 if (ModalCollector::modalInteractionBuffersMap.contains(this->channelId)) {
734 ModalCollector::modalInteractionBuffersMap.erase(this->channelId);
735 }
736 }
737
738 void ModalCollector::run() {
739 StopWatch stopWatch{ Milliseconds{ this->maxTimeInMs } };
740 while (!this->doWeQuit && !stopWatch.hasTimePassed()) {
741 auto buttonInteractionData = std::make_unique<InteractionData>();
742 if (waitForTimeToPass(this->modalIncomingInteractionBuffer, *buttonInteractionData.get(), this->maxTimeInMs)) {
743 *this->responseData.interactionData = *buttonInteractionData;
744 this->responseData.channelId = buttonInteractionData->channelId;
745 this->responseData.customId = buttonInteractionData->data.modalData.customId;
746 this->responseData.customIdSmall = buttonInteractionData->data.modalData.customIdSmall;
747 this->responseData.userId = buttonInteractionData->user.id;
748 this->responseData.value = buttonInteractionData->data.modalData.value;
749 break;
750 } else {
751 *this->responseData.interactionData = *buttonInteractionData;
752 this->responseData.channelId = buttonInteractionData->channelId;
753 this->responseData.customId = buttonInteractionData->data.modalData.customId;
754 this->responseData.customIdSmall = buttonInteractionData->data.modalData.customIdSmall;
755 this->responseData.userId = buttonInteractionData->user.id;
756 this->responseData.value = buttonInteractionData->data.modalData.value;
757 break;
758 }
759 std::this_thread::sleep_for(1ms);
760 }
761
762 ModalCollector::modalInteractionBuffersMap.erase(this->channelId);
763 }
764
765 std::unordered_map<std::string, UnboundedMessageBlock<InteractionData>*> SelectMenuCollector::selectMenuInteractionBuffersMap{};
766 std::unordered_map<std::string, UnboundedMessageBlock<InteractionData>*> ButtonCollector::buttonInteractionBuffersMap{};
767 std::unordered_map<std::string, UnboundedMessageBlock<InteractionData>*> ModalCollector::modalInteractionBuffersMap{};
768 DiscordCoreInternal::TriggerEvent<void, InteractionData> SelectMenuCollector::selectMenuInteractionEventsMap{};
769 DiscordCoreInternal::TriggerEvent<void, InteractionData> ButtonCollector::buttonInteractionEventsMap{};
770 DiscordCoreInternal::TriggerEvent<void, InteractionData> ModalCollector::modalInteractionEventsMap{};
771 DiscordCoreInternal::HttpsClient* Interactions::httpsClient{ nullptr };
772};
ButtonStyle
Button styles.
InteractionCallbackType
Interaction callback types.
ComponentType
Component types.
TextInputStyle
Text input style for modals.
@ Deferred_Channel_Message_With_Source
ACK an interaction and edit a response later, the user sees a loading state.
@ Channel_Message_With_Source
Respond to an interaction with a message.
@ Deferred_Update_Message
For components, ACK an interaction and edit the original message later; the user does not see a loadi...
@ Modal
Respond to an interaction with a popup modal.
@ Application_Command_Autocomplete_Result
Respond to an autocomplete interaction with suggested choices.
@ Update_Message
For components, edit the message the component was attached to.
@ Text_Input
Text input object.
@ Message_Component
Message component.
@ Application_Command_Autocomplete
Application command autocomplete.
@ Modal_Interaction_Response
Respond to an interaction with a popup modal.
@ Application_Command_AutoComplete_Result
Respond to an autocomplete interaction with suggested choices.
The main namespace for this library.
A CoRoutine - representing a potentially asynchronous operation/function.
Definition: CoRoutine.hpp:59
An event that gets fired depending on the result of a "trigger-function" return value.
Data representing an input-event, which is any Message or Interaction that is coming into the bot as ...
MessageData getMessageData() const
Returns the Message data, if applicable, of this input-event.
ChannelData getChannelData() const
Returns the Channel of this input-event.
InteractionData getInteractionData() const
Returns the Interaction data, if appplicable, of this input-event.
For creating an Interaction response.
For getting an Interaction response.
std::string interactionToken
Interaction token.
For editing an Interaction response.
For deleting an Interaction response.
For getting a follow-up Message.
std::string interactionToken
Interaction token.
For editing a follow up Message.
static CoRoutine< Message > createFollowUpMessageAsync(CreateFollowUpMessageData dataPackage)
Creates a follow up Message to an input Interaction.
static CoRoutine< Message > editInteractionResponseAsync(EditInteractionResponseData dataPackage)
Edits an Interaction response.
static CoRoutine< Message > getFollowUpMessageAsync(GetFollowUpMessageData dataPackage)
Creates a follow up Message to an input Interaction.
static CoRoutine< void > deleteFollowUpMessageAsync(DeleteFollowUpMessageData dataPackage)
Deletes a follow up Message.
static CoRoutine< Message > createInteractionResponseAsync(CreateInteractionResponseData dataPackage)
Creates a response to an input Interaction.
static CoRoutine< Message > editFollowUpMessageAsync(EditFollowUpMessageData dataPackage)
Edits a follow up Message.
static CoRoutine< void > deleteInteractionResponseAsync(DeleteInteractionResponseData dataPackage)
Deletes an Interaction respnose.
static CoRoutine< Message > getInteractionResponseAsync(GetInteractionResponseData dataPackage)
Collects an Interaction response.
CoRoutine< std::vector< SelectMenuResponseData > > collectSelectMenuData(bool getSelectMenuDataForAllNew, int32_t maxWaitTimeInMsNew, int32_t maxCollectedSelectMenuCountNew, CreateInteractionResponseData errorMessageDataNew, Snowflake targetUserId=Snowflake{})
Used to collect the select-menu inputs from one or more users.
SelectMenuCollector(InputEventData &dataPackage)
Constructor.
CoRoutine< std::vector< ButtonResponseData > > collectButtonData(bool getButtonDataForAllNew, int32_t maxWaitTimeInMsNew, int32_t maxNumberOfPressesNew, CreateInteractionResponseData errorMessageDataNew, Snowflake targetUserId=Snowflake{})
Used to collect the button inputs from one or more users.
ButtonCollector(InputEventData &dataPackage)
Constructor.
Snowflake channelId
The Channel id where it took place.
std::unique_ptr< InteractionData > interactionData
Interaction data.
Snowflake userId
The input value of the modal component.
std::string customIdSmall
The customId of the particular input.
std::string customId
The customId of the modal component.
CoRoutine< ModalResponseData > collectModalData(int32_t maxWaitTimeInMsNew)
Used to collect the button inputs from one or more users.
ModalCollector(InputEventData &dataPackage)
Constructor.
std::vector< File > files
File contents the contents of the file being sent.
AllowedMentionsData allowedMentions
Allowed mention object.
bool tts
True if this is a TTS message.
std::string title
Title for the modal.
int32_t flags
Flags combined as a bitfield.
std::vector< EmbedData > embeds
Array of up to 10 embed objects.
std::string content
The message contents (up to 2000 characters) one of content, file, embeds.
std::vector< ActionRowData > components
Array of message component the components to include with the message.