NAME
Discord::Client - Discord bots using IO::Async and Future
SYNOPSIS
use v5.26;
use warnings;
use Discord::Client;
# Create the bot.
my $bot = Discord::Client->new(token => $ENV{DISCORD_BOT_TOKEN});
# Reply to /ping.
$bot->command(
ping => (
description => 'Replies with Pong',
handler => sub {
my ($interaction) = @_;
return $interaction->reply('Pong!');
},
),
);
# Run until shutdown.
$bot->run;
DESCRIPTION
Build Discord bots with IO::Async and Future. REST, Gateway and HTTP Interactions can also be used independently. The API is experimental. This library is unofficial and is not affiliated with or endorsed by Discord.
Declare commands locally and deploy them explicitly with "sync" in Discord::Client::Commands. Startup never deploys commands. Return Futures from handlers so the SDK can report failures and cancel work on shutdown. Blocking code stops the shared loop.
METHODS
new
my $bot = Discord::Client->new(
token => $token, loop => $loop, intents => ['GUILDS'],
);
Returns a client without network I/O. token is the bot token. loop is an optional IO::Async::Loop; otherwise one is created. intents accepts names or a bitmask and defaults to ['GUILDS'].
application_id can set the command application's ID. shards accepts auto or a positive count; see Discord::Client::Gateway::Shards. cache accepts 1, an options hash or a Discord::Client::Cache object; it is disabled by default.
rest_options, gateway_options and interaction_options pass constructor options to those components. Tests can inject rest and gateway objects. Shutdown closes an injected Gateway and leaves an injected REST client caller-owned. max_callbacks defaults to 1024 pending event callback Futures; excess work reports queue_full.
on_error accepts a synchronous callback receiving ($error, $interaction_or_undef, $bot). Without an error callback, the SDK warns with a sanitized message.
run
Runs startup, Gateway lifetime and shutdown; blocks until stopped. Handles INT/TERM where supported and removes its signal handlers on exit. Startup or lifetime errors are raised after shutdown is attempted; otherwise a shutdown error is raised. Returns no value.
start
Returns a Future resolving to the client when the Gateway is ready. Cancelling it closes the client. The caller drives the loop.
completion
Returns the Gateway lifetime Future. It resolves on orderly shutdown and fails on a fatal error.
close
Returns a Future waiting for shutdown. Repeated calls return the same Future. Cancels handlers and owned network work. Closing from a handler stops later callbacks and cancels that handler's pending Future, unless it is the Future returned by close itself. Returning close lets graceful shutdown finish.
command
$bot->command(name => description => 'Description', handler => $callback);
Declares a command and returns the client. The callback receives an Discord::Client::Interaction. Options follow "define" in Discord::Client::Commands. Invalid declarations throw before changing the registry.
component
$bot->component(custom_id => $callback);
Registers a button, select menu or modal handler receiving an Interaction. Returns the client.
on
$bot->on(MESSAGE_CREATE => sub {
my ($data, $packet, $bot) = @_;
return handle_message($data);
});
Registers an event callback and returns the client. Event names accept either case. Data is a hashref with unknown fields and string IDs preserved. Thrown exceptions or failed handler Futures reach the error callbacks. Gateway callback queue limits may drop these notifications. SDK cache and READY updates and command dispatch precede this queue; command dispatch is separately bounded by interaction_options. on(error => CODE) receives the same arguments as on_error.
on_message
# Ignore bot messages and return the reply Future.
$bot->on_message(sub {
my ($message, $bot) = @_;
return if $message->is_from_bot;
return unless $message->content eq '!ping';
return $message->reply('Pong!');
});
Registers a callback receiving ($message, $bot) and returns the client. The message is a Discord::Client::Model::Message snapshot using the client's REST transport. Wrapping performs no request and needs no cache. Set message intents explicitly and enable Message Content in the Developer Portal when reading message text. Bot messages are not filtered automatically. Raw MESSAGE_CREATE callbacks still receive hashrefs.
model
my $channel = $bot->model(channel => {id => $channel_id});
Synchronously wraps data with the client's REST transport. Types are message, channel, user and guild; see "wrap" in Discord::Client::Model. Invalid data throws. Wrapping performs no request.
rest
Returns the Discord::Client::REST client.
gateway
Returns the Discord::Client::Gateway or Discord::Client::Gateway::Shards.
commands
Returns the Discord::Client::Commands registry.
interactions
Returns the Discord::Client::Interactions dispatcher.
loop
Returns the IO::Async::Loop.
user
Returns the bot user hashref after READY, or undef before it.
cache
Returns the configured Cache object, or undef when disabled.
stats
Returns a hashref of REST, Gateway, pending callback and optional cache counters. It does not include payloads or credentials.
EXAMPLES
From a source checkout, set DISCORD_BOT_TOKEN and TEST_GUILD_ID. Invite the bot with bot and applications.commands scopes and leave the Interactions Endpoint URL empty for Gateway delivery.
# Deploy /ping once, then run the bot.
perl examples/sync-commands.pl examples/ping.pl
perl examples/ping.pl
Deployment replaces this application's commands in the test server, removing commands absent from the example. Run one example receiver per bot token.
The example scripts cover arguments, buttons, forms, channels, messages and asynchronous work. Replace ping.pl in both commands to run a slash-command example. messages.pl needs no deployment; it selects GUILDS, GUILD_MESSAGES, DIRECT_MESSAGES and MESSAGE_CONTENT. Enable Message Content in the portal. workflow-await.pl additionally needs cpanm Future::AsyncAwait. For dependencies under local/, prefix commands with PERL5LIB=local/lib/perl5.
LICENSE
Apache License 2.0.