Skip to content

Commit

Permalink
docs: convert tons more examples and fix some
Browse files Browse the repository at this point in the history
  • Loading branch information
braindigitalis committed Sep 13, 2023
1 parent 31afd69 commit acfd7e4
Show file tree
Hide file tree
Showing 27 changed files with 1,137 additions and 1,127 deletions.
37 changes: 33 additions & 4 deletions docpages/example_code/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1,45 @@
cmake_minimum_required (VERSION 3.6)
#
# D++ (DPP), The Lightweight C++ Discord Library
#
# Copyright 2021 Craig Edwards <[email protected]>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

# Example programs test compilation
# This build script is executed by a GitHub action to ensure all example
# programs compile correctly. It does not attempt to run them, as there
# is no way to know if the program successfully did its thing, plus
# examples do not have a valid token. This build script assumes the
# following system dependencies are available:
#
# g++-12 or later
# liboggz-dev
# libmpg123-dev
# dpp latest master with -DDPP_CORO=ON installed sytemwide

cmake_minimum_required (VERSION 3.16)
project(documentation_tests)

string(ASCII 27 Esc)

set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -pthread -O0 -fPIC -rdynamic -DFMT_HEADER_ONLY -Wall -Werror")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDPP_CORO -std=c++20 -pthread -O0 -fPIC -rdynamic -DFMT_HEADER_ONLY -Wall -Werror")
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0")

file(GLOB example_list ./*.cpp)
foreach (example ${example_list})
get_filename_component(examplename ${example} NAME)
message(STATUS "Found example '${Esc}[1;34m${examplename}${Esc}[m'")
add_executable(${examplename}_out ${example})
target_link_libraries(${examplename}_out dl dpp)
target_link_libraries(${examplename}_out dl dpp mpg123 oggz)
endforeach(example)

88 changes: 88 additions & 0 deletions docpages/example_code/callbacks.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#include <dpp/dpp.h>

int main() {
dpp::cluster bot("Token Was Here", dpp::i_default_intents | dpp::i_message_content);
/* the second argument is a bitmask of intents - i_message_content is needed to get messages */

bot.on_log(dpp::utility::cout_logger());

/* The event is fired when someone issues your commands */
bot.on_slashcommand([&bot](const dpp::slashcommand_t& event) -> void {
if (event.command.get_command_name() == "msgs-get") {
int64_t limit = std::get<int64_t>(event.get_parameter("quantity"));

/* get messages using ID of the channel the command was issued in */
bot.messages_get(event.command.channel_id, 0, 0, 0, limit, [event](const dpp::confirmation_callback_t& callback) -> void {
if (callback.is_error()) { /* catching an error to log it */
std::cout << callback.get_error().message << std::endl;
return;
}

auto messages = callback.get<dpp::message_map>();
/* std::get<dpp::message_map>(callback.value) would give the same result */

std::string contents;
for (const auto& x : messages) { /* here we iterate through the dpp::message_map we got from callback... */
contents += x.second.content + '\n'; /* ...where x.first is ID of the current message and x.second is the message itself. */
}

event.reply(contents); /* we will see all those messages we got, united as one! */
});
} else if (event.command.get_command_name() == "channel-create") {
/* create a text channel */
dpp::channel channel = dpp::channel()
.set_name("test")
.set_guild_id(event.command.guild_id);

bot.channel_create(channel, [&bot, event](const dpp::confirmation_callback_t& callback) -> void {
if (callback.is_error()) { /* catching an error to log it */
bot.log(dpp::loglevel::ll_error, callback.get_error().message);
return;
}

auto channel = callback.get<dpp::channel>();
/* std::get<dpp::channel>(callback.value) would give the same result */

/* reply with the created channel information */
dpp::message message = dpp::message("The channel's name is `" + channel.name + "`, ID is `" + std::to_string(channel.id) + " and type is `" + std::to_string(channel.get_type()) + "`.");
/* note that channel types are represented as numbers */
event.reply(message);
});
} else if (event.command.get_command_name() == "msg-error") {
bot.message_get(0, 0, [event](const dpp::confirmation_callback_t& callback) -> void {
/* the error will occur since there is no message with ID '0' that is in a channel with ID '0' (I'm not explaining why) */
if (callback.is_error()) {
event.reply(callback.get_error().message);
return;
}

/* we won't be able to get here because of the return; statement */
auto message = callback.get<dpp::message>();
event.reply(message);
});
}
});

bot.on_ready([&bot](const dpp::ready_t& event) {
if (dpp::run_once <struct register_global_commands>()) {
dpp::slashcommand msgs_get("msgs-get", "Get messages", bot.me.id);

constexpr int64_t min_val{1};
constexpr int64_t max_val{100};

msgs_get.add_option(
dpp::command_option(dpp::co_integer, "quantity", "Quantity of messages to get. Max - 100.")
.set_min_value(min_val)
.set_max_value(max_val)
);

dpp::slashcommand channel_create("channel-create", "Create a channel", bot.me.id);
dpp::slashcommand msg_error("msg-error", "Get an error instead of message :)", bot.me.id);

bot.global_bulk_command_create({ msgs_get, channel_create, msg_error });
}
});

bot.start(dpp::st_wait);
return 0;
}
39 changes: 39 additions & 0 deletions docpages/example_code/coro_awaiting_events.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#include <dpp/dpp.h>

int main() {
dpp::cluster bot{"token"};

bot.on_log(dpp::utility::cout_logger());

bot.on_slashcommand([](dpp::slashcommand_t event) -> dpp::job {
if (event.command.get_command_name() == "test") {
// Make a message and add a button with its custom ID set to the command interaction's ID so we can identify it
dpp::message m{"Test"};
std::string id{event.command.id.str()};
m.add_component(
dpp::component{}.add_component(dpp::component{}.set_type(dpp::cot_button).set_label("Click me!").set_id(id))
);
co_await event.co_reply(m);

dpp::button_click_t click_event = co_await event.from->creator->on_button_click.when(
// Note!! Due to a bug in g++11 and g++12, id must be captured as a reference here or the compiler will destroy it twice. This is fixed in g++13
[&id] (dpp::button_click_t const &b) {
return b.custom_id == id;
}
);
// Acknowledge the click and edit the original response, removing the button
click_event.reply();
event.edit_original_response(dpp::message{"You clicked the button!"});
}
});

bot.on_ready([&bot](const dpp::ready_t & event) {
if (dpp::run_once<struct register_bot_commands>()) {
dpp::slashcommand command{"test", "Test awaiting for an event", bot.me.id};

bot.global_command_create(command);
}
});

bot.start(dpp::st_wait);
}
43 changes: 43 additions & 0 deletions docpages/example_code/coro_expiring_buttons.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include <dpp/dpp.h>

int main() {
dpp::cluster bot{"token"};

bot.on_log(dpp::utility::cout_logger());

bot.on_slashcommand([](dpp::slashcommand_t event) -> dpp::job {
if (event.command.get_command_name() == "test") {
// Make a message and add a button with its custom ID set to the command interaction's ID so we can identify it
dpp::message m{"Test"};
std::string id{event.command.id.str()};
m.add_component(
dpp::component{}.add_component(dpp::component{}.set_type(dpp::cot_button).set_label("Click me!").set_id(id))
);
co_await event.co_reply(m);

auto result = co_await dpp::when_any{ // Whichever completes first...
event.from->creator->on_button_click.when([&id](const dpp::button_click_t &b) { return b.custom_id == id; }), // Button clicked
event.from->creator->co_sleep(5) // Or sleep 5 seconds
};
// Note!! Due to a bug in g++11 and g++12, id must be captured as a reference above or the compiler will destroy it twice. This is fixed in g++13
if (result.index() == 0) { // Awaitable #0 completed first, that is the button click event
// Acknowledge the click and edit the original response, removing the button
const dpp::button_click_t &click_event = result.get<0>();
click_event.reply();
event.edit_original_response(dpp::message{"You clicked the button with the id " + click_event.custom_id});
} else { // Here index() is 1, the timer expired
event.edit_original_response(dpp::message{"I haven't got all day!"});
}
}
});

bot.on_ready([&bot](const dpp::ready_t & event) {
if (dpp::run_once<struct register_bot_commands>()) {
dpp::slashcommand command{"test", "Test awaiting for an event", bot.me.id};

bot.global_command_create(command);
}
});

bot.start(dpp::st_wait);
}
35 changes: 35 additions & 0 deletions docpages/example_code/coro_intro.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include <dpp/dpp.h>

int main() {
dpp::cluster bot{"token"};

bot.on_log(dpp::utility::cout_logger());

/* The event is fired when someone issues your commands */
/* Make note of passing the event by value, this is important (explained below) */
bot.on_slashcommand([](dpp::slashcommand_t event) -> dpp::job {
if (event.command.get_command_name() == "file") {
/* Request the image from the URL specified and co_await the response */
dpp::http_request_completion_t result = co_await event.from->creator->co_request("https://dpp.dev/DPP-Logo.png", dpp::m_get);

/* Create a message and attach the image on success */
dpp::message msg(event.command.channel_id, "This is my new attachment:");
if (result.status == 200) {
msg.add_file("logo.png", result.body);
}

/* Send the message, with our attachment. */
event.reply(msg);
}
});

bot.on_ready([&bot](const dpp::ready_t& event) {
if (dpp::run_once<struct register_bot_commands>()) {
/* Create and register a command when the bot is ready */
bot.global_command_create(dpp::slashcommand{"file", "Send a message with an image attached from the internet!", bot.me.id});
}
});

bot.start(dpp::st_wait);
return 0;
}
63 changes: 63 additions & 0 deletions docpages/example_code/coro_simple_commands1.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#include <dpp/dpp.h>

int main() {
dpp::cluster bot("token");

bot.on_log(dpp::utility::cout_logger());

bot.on_slashcommand([](dpp::slashcommand_t event) -> dpp::job {
if (event.command.get_command_name() == "addemoji") {
dpp::cluster *cluster = event.from->creator;
// Retrieve parameter values
dpp::snowflake file_id = std::get<dpp::snowflake>(event.get_parameter("file"));
std::string emoji_name = std::get<std::string>(event.get_parameter("name"));

// Get the attachment from the resolved list
const dpp::attachment &attachment = event.command.get_resolved_attachment(file_id);

// For simplicity for this example we only support PNG
if (attachment.content_type != "image/png") {
// While we could use event.co_reply, we can just use event.reply, as we will exit the command anyway and don't need to wait on the result
event.reply("Error: type " + attachment.content_type + " not supported");
co_return;
}
// Send a "<bot> is thinking..." message, to wait on later so we can edit
dpp::async thinking = event.co_thinking(false);

// Download and co_await the result
dpp::http_request_completion_t response = co_await cluster->co_request(attachment.url, dpp::m_get);

if (response.status != 200) { // Page didn't send the image
co_await thinking; // Wait for the thinking response to arrive so we can edit
event.edit_response("Error: could not download the attachment");
} else {
// Load the image data in a dpp::emoji
dpp::emoji emoji(emoji_name);
emoji.load_image(response.body, dpp::image_type::i_png);

// Create the emoji and co_await the response
dpp::confirmation_callback_t confirmation = co_await cluster->co_guild_emoji_create(event.command.guild_id, emoji);

co_await thinking; // Wait for the thinking response to arrive so we can edit
if (confirmation.is_error()) {
event.edit_response("Error: could not add emoji: " + confirmation.get_error().message);
} else { // Success
event.edit_response("Successfully added " + confirmation.get<dpp::emoji>().get_mention()); // Show the new emoji
}
}
}
});

bot.on_ready([&bot](const dpp::ready_t & event) {
if (dpp::run_once<struct register_bot_commands>()) {
dpp::slashcommand command("addemoji", "Add an emoji", bot.me.id);
// Add file and name as required parameters
command.add_option(dpp::command_option(dpp::co_attachment, "file", "Select an image", true));
command.add_option(dpp::command_option(dpp::co_string, "name", "Name of the emoji to add", true));

bot.global_command_create(command);
}
});

bot.start(dpp::st_wait);
}
Loading

0 comments on commit acfd7e4

Please sign in to comment.