Client
Discord.Client — Type.Client(
token::String;
prefix::String="",
presence::Union{Dict, NamedTuple}=Dict(),
strategies::Dict{DataType, <:CacheStrategy}=Dict(),
version::Int=6,
) -> ClientA Discord bot. Clients can connect to the gateway, respond to events, and make REST API calls to perform actions such as sending/deleting messages, kicking/banning users, etc.
Bot Token
A bot token can be acquired by creating a new application here. Make sure not to hardcode the token into your Julia code! Use an environment variable or configuration file instead.
Command Prefix
The prefix keyword specifies the command prefix, which is used by commands added with add_command!. It can be changed later, both globally and on a per-guild basis, with set_prefix!.
Presence
The presence keyword sets the bot's presence upon connection. It also sets defaults for future calls to set_game. The schema here must be followed.
Cache Control
By default, most data that comes from Discord is cached for later use. However, to avoid memory leakage, not all of it is kept forever. The default setings are to keep everything but Messages, which are deleted after 6 hours, forever. Although the default settings are sufficient for most workloads, you can specify your own strategies per type with the strategies keyword. Keys can be any of the following:
For potential values, see CacheStrategy.
The cache can also be disabled/enabled permanently and temporarily as a whole with enable_cache! and disable_cache!.
API Version
The version keyword chooses the Version of the Discord API to use. Using anything but 6 is not officially supported by the Discord.jl developers.
Sharding
Sharding is handled automatically. The number of available processes is the number of shards that are created. See the sharding example for more details.
Discord.enable_cache! — Function.enable_cache!(c::Client)
enable_cache!(f::Function c::Client)Enable the cache. do syntax is also accepted.
Discord.disable_cache! — Function.disable_cache!(c::Client)
disable_cache!(f::Function, c::Client)Disable the cache. do syntax is also accepted.
Discord.me — Function.me(c::Client) -> Nullable{User}Get the Client's bot user.
Gateway
Base.open — Function.open(c::Client; delay::Period=Second(7))Connect a Client to the Discord gateway.
The delay keyword is the time between shards connecting. It can be increased from its default if you are using multiple shards and frequently experiencing invalid sessions upon connection.
Base.isopen — Function.isopen(c::Client) -> BoolDetermine whether the Client is connected to the gateway.
Base.close — Function.close(c::Client)Disconnect the Client from the gateway.
Base.wait — Function.wait(c::Client)Wait for an open Client to close.
Discord.request_guild_members — Function.request_guild_members(
c::Client,
guilds::Union{Integer, Vector{<:Integer};
query::AbstractString="",
limit::Int=0,
) -> BoolRequest offline guild members of one or more Guilds. GuildMembersChunk events are sent by the gateway in response. More details here.
Discord.update_voice_state — Function.update_voice_state(
c::Client,
guild::Integer,
channel::Nullable{Integer},
mute::Bool,
deaf::Bool,
) -> BoolJoin, move, or disconnect from a voice channel. A VoiceStateUpdate event is sent by the gateway in response. More details here.
Discord.update_status — Function.update_status(
c::Client,
since::Nullable{Int},
activity::Nullable{Activity},
status::Union{PresenceStatus, AbstractString},
afk::Bool,
) -> BoolIndicate a presence or status update. A PresenceUpdate event is sent by the gateway in response. More details here.
Discord.heartbeat_ping — Function.heartbeat_ping(c::Client) -> Nullable{Period}Get the Client's ping time to the gateway. If the client is not connected, or no heartbeats have been sent/acknowledged, nothing is returned.
Event Handlers
See Events for more details.
Discord.add_handler! — Function.add_handler!(
c::Client,
[T::Type{<:AbstractEvent}],
handler::Function;
tag::Symbol=gensym(),
predicate::Function=alwaystrue,
fallback::Function=donothing,
priority::Int=100,
count::Nullable{Int}=nothing,
timeout::Nullable{Period}=nothing,
until::Function=alwaysfalse,
wait::Bool=false,
compile::Bool=false,
kwargs...,
) -> Nullable{Vector{Any}}Add an event handler. do syntax is also accepted.
Handler Function
The handler function does the real work and must take two arguments: A Client and an AbstractEvent (or a subtype). If an event type T is supplied, then the handler is registered for that event. Otherwise, the second argument of the handler must be annotated, and the type annotation determines what events will invoke the handler. Union types are also accepted to register handlers for multiple events.
Handler Tag
The tag keyword gives a label to the handler, which can be used to remove it with delete_handler!.
Predicate/Fallback Functions
The predicate keyword specifies a predicate function. The handler will only run if this function returns true. Otherwise, a fallback function, specified by the fallback keyword, is run. Their signatures should match that of the handler.
Handler Priority
The priority keyword indicates the handler's priority relative to other handlers for the same event. Handlers with higher values execute before those with lower ones.
Handler Expiry
Handlers can have multiple types of expiries. The count keyword sets the number of times a handler is run before expiring. The timeout keyword determines how long the handler remains active. The until keyword takes a function which is called on the handler's previous results (in a Vector), and if it returns true, the handler expires. These keywords can be combined; the first condition to be met causes the handler to expire.
Blocking Handlers + Result Collection
To collect results from a handler, set the wait keyword along with n, timeout, and/or until. The call will block until the handler expires, at which point the return value of each invocation is returned in a Vector.
Forcing Precompilation
Handler functions are precompiled without running them, but it's not always successful, especially if your functions are not type-safe. If the compile keyword is set, precompilation is forced by running the predicate and handler on a randomized input. Any trailing keywords are passed to the constructors of the event and its fields.
Examples
Basic "hello world" with explicit event type:
add_handler!(c, MessageCreate, (c, e) -> println(e.message.content); tag=:print)Adding a handler with a predicate and fallback:
handler(::Client, e::ChannelCreate) = println(e.channel.name)
predicate(::Client, e::ChannelCreate) = length(e.channel.name) < 10
fallback(::Client, ::ChannelCreate) = println("channel name too long")
add_handler!(c, handler; predicate=predicate, fallback=fallback)Assigning maximum priority to a handler:
handler(:::Client, ::MessageCreate) = println("this runs before any other handlers!")
add_handler!(c, handler; priority=typemax(Int))Adding a handler with various expiry conditions:
handler(::Client, e::ChannelCreate) = e.channel.name
until(results::Vector{Any}) = "foo" in results
add_handler!(c, handler; count=10, timeout=Minute(1), until=until)Aggregating results of a handler:
handler(::Client, e::MessageCreate) = e.message.content
msgs = add_handler!(c, handler; count=5, wait=true)Forcing precompilation:
handler(::Client, e::MessageDelete) = @show e
add_handler!(c, handler; compile=true, id=0xff)add_handler!(c::Client, m::Module; kwargs...)Add all of the event handlers defined in a module. Any function you wish to use as a handler must be exported. Only functions with correct, annotated type signatures (see above) are used.
If you set keywords, they are applied to all of the handlers in the module. For example, if you add two handlers for the same event type with the same tag, one of them will be immediately overwritten.
Discord.delete_handler! — Function.delete_handler!(c::Client, T::Type{<:AbstractEvent}, tag::Symbol)
delete_handler!(c::Client, T::Type{<:AbstractEvent})Delete event handlers. If no tag is supplied, all handlers for the event are deleted. Using the tagless method is generally not recommended because it also clears default handlers which maintain the client state. If you do want to delete a default handler, use DEFAULT_HANDLER_TAG.
Discord.DEFAULT_HANDLER_TAG — Constant.Tag assigned to default handlers, which you can use to delete them.
Bot Commands
Discord.add_command! — Function.add_command!(
c::Client,
name::Symbol,
handler::Function;
help::AbstractString="",
parsers::Vector=[],
separator::StringOrChar=' ',
pattern::Regex=defaultpattern(name, length(parsers), separator),
allowed::Vector{<:Integer}=Snowflake[],
permissions::Integer=PERM_NONE,
cooldown::Nullable{Period}=nothing,
fallback_parsers::Function=donothing,
fallback_allowed::Function=donothing,
fallback_permissions::Function=donothing,
fallback_cooldown::Function=donothing,
priority::Int=100,
count::Nullable{Int}=nothing,
timeout::Nullable{Period}=nothing,
compile::Bool=false,
kwargs...,
)Add a text command handler. do syntax is also accepted.
Handler Function
The handler function must accept a Client and a Message. Additionally, it can accept any number of additional arguments, which are captured from pattern and parsed with parsers (see below).
Command Pattern
The pattern keyword specifies how to invoke the command. The given Regex must match the message contents after having removed the command prefix. By default, it's the command name with as many wildcard capture groups as there are parsers, separated by the separator keyword (a space character by default).
Command Help
The help keyword specifies a help string which can be used by add_help!.
Argument Parsing
The parsers keyword sets the parsers of the command arguments, and can contain both types and functions. If pattern contains captures, then they are run through the parsers before being passed into the handler. For repeating arguments, see Splat.
Authorization + Required Permissions
The allowed keyword specifies Users or Roles (by ID) that are allowed to use the command. The permissions keyword sets the minimum permissions that command callers must have.
Rate Limiting
The cooldown keyword sets the rate at which a user can invoke the command. The default of nothing indicates no limit.
Fallback Functions
The fallback_* keywords specify functions to be run whenever a command is called but cannot be run, such as failed argument parsing, missing permissions, or rate limiting. They should accept a Client and a Message.
Additional keyword arguments are a subset of those to add_handler!.
Examples
Basic echo command with a help string:
add_command!(c, :echo, (c, m) -> reply(c, m, m.content); help="repeat a message")The same, but excluding the command part:
add_command!(c, :echo, (c, m, msg) -> reply(c, m, msg); pattern=r"^echo (.+)")Parsing a subtraction expression with custom parsers and separator:
add_command!(
c, :sub, (c, m, a, b) -> reply(c, m, string(a - b));
parsers=[Float64, Float64], separator='-',
)Splatting some comma-separated numbers with a parsing fallback function:
add_command!(
c, :sum, (c, m, xs...) -> reply(c, m, string(sum(collect(xs))));
parsers=[Splat(Float64, ',')],
fallback_parsers=(c, m) -> reply(c, m, "Args must be numbers."),
)add_command!(c::Client, m::Module; compile::Bool=false; kwargs...)Add all of the bot commands defined in a module. To set up commands to be included, see @command.
Discord.@command — Macro.@command name=name handler=handler kwargs...Mark a function as a bot command to be collected by add_command! (from a module). Supported keywords are identical to add_command!.
Example
module Commands
using Discord
echo(c::Client, m::Message, noprefix::AbstractString) = reply(c, m, noprefix)
@command name=:echo handler=echo help="Echo a message" pattern=r"^echo (.+)"
end
c = Client("token")
add_command!(c, Commands)Discord.delete_command! — Function.delete_command!(c::Client, name::Symbol)Delete a command.
Discord.add_help! — Function.add_help!(
c::Client;
pattern::Regex=r"^help(?: (.+))?",
help::AbstractString="Show this help message",
nohelp::AbstractString="No help provided",
nocmd::AbstractString="Command not found",
)Add a help command. This can be called at any time, new commands will be included automatically.
Keywords
separator::StringOrChar: Separator between commands.pattern::Regex: The command pattern (seeadd_command!).help::AbstractString: Help for the help command.nohelp::AbstractString: Help for commands without their own help string.nocmd::AbstractString: Help for commands that aren't found.
Discord.set_prefix! — Function.Discord.Splat — Type.Splat(func::Base.Callable=identity, split::StringOrChar=' ') -> SplatCollect a variable number of arguments from one capture group with a single parser.
Caching
Discord.CacheStrategy — Type.A method of handling cache insertion and eviction.
Discord.CacheForever — Type.CacheForever() -> CacheForeverStore everything and never evict items from the cache.
Discord.CacheNever — Type.CacheNever() -> CacheNeverDon't store anything in the cache.
Discord.CacheTTL — Type.CacheTTL(ttl::Period) -> CacheTTLEvict items from the cache after ttl has elapsed.
Discord.CacheLRU — Type.CacheLRU(size::Int) -> CacheLRUEvict the least recently used item from the cache when there are more than size items.
Discord.CacheFilter — Type.CacheFilter(f::Function) -> CacheFilterOnly store value v at key k if f(v) === true (k is always v.id).