Concord - C Discord API library
A Discord API wrapper library written in C
slash-commands2.c

Demonstrates registering and reacting to slash commands from the console

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <pthread.h>
#include <assert.h>
#include <errno.h>
#include <inttypes.h> /* SCNu64 */
#include "discord.h"
#include "logmod.h"
u64snowflake g_app_id;
void
print_usage(void)
{
printf("\n\nThis bot demonstrates how easy it is to create/update/delete "
"application commands\n"
"1. Input a valid application id from "
"https://discord.com/developers/applications\n"
"2. Type HELP to see commands\n"
"\nTYPE ANY KEY TO START BOT\n");
}
void
print_help(void)
{
logmod_log(INFO, NULL,
"\nHelp :\n"
"\tPrint help : HELP\n"
"\tList Commands : LIST <?guild_id>\n"
"\tCreate Command : CREATE <cmd_name>[<cmd_desc>] <?guild_id>\n"
"\tUpdate Command : UPDATE <cmd_id> <cmd_name>[<cmd_desc>] "
"<?guild_id>\n"
"\tDelete Command : DELETE <cmd_id> <?guild_id>\n");
}
void
on_ready(struct discord *client, const struct discord_ready *event)
{
logmod_log(INFO, NULL,
"Slash-Commands-Bot succesfully connected to Discord as %s#%s!",
event->user->username, event->user->discriminator);
}
void
fail_interaction_create(struct discord *client, struct discord_response *resp)
{
logmod_log(ERROR, NULL, "%s", discord_strerror(resp->code, client));
}
void
on_interaction_create(struct discord *client,
const struct discord_interaction *event)
{
logmod_log(INFO, NULL, "Interaction %" PRIu64 " received", event->id);
struct discord_interaction_callback_data data = {
.content = "Hello World!",
.flags = DISCORD_MESSAGE_EPHEMERAL,
};
struct discord_interaction_response params = {
.type = DISCORD_INTERACTION_CHANNEL_MESSAGE_WITH_SOURCE,
.data = &data,
};
.fail = &fail_interaction_create
};
discord_create_interaction_response(client, event->id, event->token,
&params, &ret);
}
void *
read_input(void *p_client)
{
struct discord *client = p_client;
ptrdiff_t bufoffset;
char cmd_action[9 + 1];
CCORDcode code;
pthread_detach(pthread_self());
while (1) {
memset(buf, 0, sizeof(buf));
fgets(buf, sizeof(buf), stdin);
if (!*buf) continue; // is empty
memset(cmd_action, 0, sizeof(cmd_action));
sscanf(buf, "%s", cmd_action);
bufoffset = strlen(cmd_action) + 1;
if (!*cmd_action || 0 == strcasecmp(cmd_action, "HELP")) goto _help;
if (0 == strcasecmp(cmd_action, "LIST")) {
struct discord_application_commands app_cmds = { 0 };
u64snowflake guild_id = 0;
sscanf(buf + bufoffset, "%" SCNu64, &guild_id);
.sync = &app_cmds,
};
if (guild_id)
code = discord_get_guild_application_commands(client, g_app_id,
guild_id, &ret);
else
g_app_id, &ret);
if (CCORD_OK == code && app_cmds.size) {
char list[4096] = ""; // should be large enough ?
size_t len = 0;
for (int i = 0; i < app_cmds.size; ++i) {
len +=
snprintf(list + len, sizeof(list) - len,
"\t%d:\t%s (%" PRIu64 ")\n", i,
app_cmds.array[i].name, app_cmds.array[i].id);
}
logmod_log(INFO, NULL, "\nCommands: \n%.*s", (int)len, list);
discord_data_cleanup(client, &app_cmds);
}
else {
logmod_log(ERROR, NULL, "Couldn't list commands");
}
}
else if (0 == strcasecmp(cmd_action, "CREATE")) {
char cmd_name[32 + 1] = "", cmd_desc[100 + 1] = "";
struct discord_application_command app_cmd = { 0 };
u64snowflake guild_id = 0;
sscanf(buf + bufoffset, "%32[^[][%100[^]]] %" SCNu64, cmd_name,
cmd_desc, &guild_id);
if (!*cmd_name || !*cmd_desc) goto _help;
.sync = &app_cmd,
};
if (guild_id) {
.name = cmd_name,
.description = cmd_desc,
.default_permission = true,
.type = 1,
};
client, g_app_id, guild_id, &params, &ret);
}
else {
.name = cmd_name,
.description = cmd_desc,
.default_permission = true,
.type = 1,
};
client, g_app_id, &params, &ret);
}
if (CCORD_OK == code && app_cmd.id) {
logmod_log(INFO, NULL, "Created command:\t%s (%" PRIu64 ")",
app_cmd.name, app_cmd.id);
discord_data_cleanup(client, &app_cmd);
}
else {
logmod_log(ERROR, NULL, "Couldn't create command '%s'",
cmd_name);
}
}
else if (0 == strcasecmp(cmd_action, "UPDATE")) {
char cmd_name[32 + 1] = "", cmd_desc[100 + 1] = "";
u64snowflake command_id = 0, guild_id = 0;
sscanf(buf + bufoffset, "%" SCNu64 " %32[^[][%100[^]]] %" SCNu64,
&command_id, cmd_name, cmd_desc, &guild_id);
if (!command_id) goto _help;
struct discord_application_command app_cmd = { 0 };
.sync = &app_cmd,
};
if (guild_id) {
.name = *cmd_name ? cmd_name : NULL,
.description = *cmd_desc ? cmd_desc : NULL,
.default_permission = true,
};
client, g_app_id, guild_id, command_id, &params, &ret);
}
else {
.name = *cmd_name ? cmd_name : NULL,
.description = *cmd_desc ? cmd_desc : NULL,
.default_permission = true,
};
client, g_app_id, command_id, &params, &ret);
}
if (CCORD_OK == code && app_cmd.id) {
logmod_log(INFO, NULL, "Edited command:\t%s (%" PRIu64 ")",
app_cmd.name, app_cmd.id);
discord_data_cleanup(client, &app_cmd);
}
else {
logmod_log(ERROR, NULL, "Couldn't create command '%s'",
cmd_name);
}
}
else if (0 == strcasecmp(cmd_action, "DELETE")) {
u64snowflake command_id = 0, guild_id = 0;
sscanf(buf + bufoffset, "%" SCNu64 "%" SCNu64, &command_id,
&guild_id);
if (!command_id) goto _help;
struct discord_ret ret = { .sync = true };
if (guild_id) {
client, g_app_id, guild_id, command_id, &ret);
}
else {
client, g_app_id, command_id, &ret);
}
if (CCORD_OK == code)
logmod_log(INFO, NULL, "Deleted command");
else
logmod_log(ERROR, NULL, "Couldn't delete command");
}
else {
goto _help;
}
continue;
_help:
print_help();
}
pthread_exit(NULL);
}
int
main(int argc, char *argv[])
{
const char *config_file;
if (argc > 1)
config_file = argv[1];
else
config_file = "../config.json";
struct discord *client = discord_from_json(config_file);
assert(NULL != client && "Could not initialize client");
discord_set_on_ready(client, &on_ready);
discord_set_on_interaction_create(client, &on_interaction_create);
print_usage();
fgetc(stdin); // wait for input
printf("Please provide a valid application id in order to test the Slash "
"Commands functionality, it can be obtained from: "
"https://discord.com/developers/applications\n");
do {
printf("Application ID:\n");
fscanf(stdin, "%" SCNu64, &g_app_id);
} while (!g_app_id || errno == ERANGE);
pthread_t tid;
pthread_create(&tid, NULL, &read_input, client);
discord_run(client);
discord_cleanup(client);
}
Public functions and datatypes.
int CCORDcode
Concord error codes.
Definition: concord-error.h:11
uint64_t u64snowflake
Snowflake datatype.
Definition: types.h:28
#define CCORD_OK
Definition: concord-error.h:60
CCORDcode discord_create_global_application_command(struct discord *client, u64snowflake application_id, struct discord_create_global_application_command *params, struct discord_ret_application_command *ret)
Create a new global command.
CCORDcode discord_edit_guild_application_command(struct discord *client, u64snowflake application_id, u64snowflake guild_id, u64snowflake command_id, struct discord_edit_guild_application_command *params, struct discord_ret_application_command *ret)
Edit a guild command.
CCORDcode discord_delete_guild_application_command(struct discord *client, u64snowflake application_id, u64snowflake guild_id, u64snowflake command_id, struct discord_ret *ret)
Deletes a guild command.
CCORDcode discord_edit_global_application_command(struct discord *client, u64snowflake application_id, u64snowflake command_id, struct discord_edit_global_application_command *params, struct discord_ret_application_command *ret)
Edit a global command.
CCORDcode discord_create_guild_application_command(struct discord *client, u64snowflake application_id, u64snowflake guild_id, struct discord_create_guild_application_command *params, struct discord_ret_application_command *ret)
Create a new guild command.
CCORDcode discord_get_global_application_commands(struct discord *client, u64snowflake application_id, struct discord_ret_application_commands *ret)
Fetch all of the global commands for your application.
CCORDcode discord_delete_global_application_command(struct discord *client, u64snowflake application_id, u64snowflake command_id, struct discord_ret *ret)
Deletes a global command.
CCORDcode discord_get_guild_application_commands(struct discord *client, u64snowflake application_id, u64snowflake guild_id, struct discord_ret_application_commands *ret)
Fetch all of the guild commands of a given guild.
CCORDcode discord_create_interaction_response(struct discord *client, u64snowflake interaction_id, const char interaction_token[], struct discord_interaction_response *params, struct discord_ret_interaction_response *ret)
Create a response to an Interaction from the gateway.
void discord_cleanup(struct discord *client)
Free a Discord Client handle.
CCORDcode discord_run(struct discord *client)
Start a connection to the Discord Gateway.
struct discord * discord_from_json(const char config_file[])
Creates a Discord Client handle from a config.json file.
#define DISCORD_MAX_MESSAGE_LEN
Definition: discord.h:71
#define discord_data_cleanup(_client, _data)
Cleanup a Discord data type wrapped into a reflectc_wrap structure.
Definition: discord.h:496
const char * discord_strerror(CCORDcode code, struct discord *client)
Return the meaning of CCORDcode.
void discord_set_on_interaction_create(struct discord *client, void(*callback)(struct discord *client, const struct discord_interaction *event))
Triggers when user has used an interaction, such as an application command.
void discord_set_on_ready(struct discord *client, void(*callback)(struct discord *client, const struct discord_ready *event))
Triggers when the client session is ready.
#define logmod_log
Alias to logmod_nlog for C89 compatibility.
Definition: logmod.h:487
The response for the completed request.
Definition: discord-response.h:12
CCORDcode code
Definition: discord-response.h:18
Request's return context.
Definition: discord-response.h:174
struct discord_application_command * sync
Definition: discord-response.h:174
Request's return context.
Definition: discord-response.h:175
struct discord_application_commands * sync
Definition: discord-response.h:175
Request's return context.
Definition: discord-response.h:184
void(* fail)(struct discord *client, struct discord_response *resp)
Definition: discord-response.h:184
Request's return context.
Definition: discord-response.h:59
The Discord client handler.
Definition: discord-internal.h:1206