A Discord library: the gateway, the REST API, interactions and voice.
Write a bot module with Lingo.Bot, then add it to your supervision tree
(the options are listed in Lingo.Bot):
children = [
{MyBot,
token: System.fetch_env!("BOT_TOKEN"),
intents: [:guilds, :guild_messages, :message_content],
register_commands: :global}
]
Supervisor.start_link(children, strategy: :one_for_one)Where things are
Lingo.Api.*- the REST API, one module per resource, such asLingo.Api.Message.create/2(errors areLingo.Error)Lingo.Cache.*- what the gateway and REST API have told the bot, such asLingo.Cache.Role.list/1(opt-in, seeLingo.Cache)Lingo.Gateway- presence, shards and gateway requests, and what Lingo does for large botsLingo.Voice- joining voice channels, playing and receiving audioLingo.ComponentandLingo.Embed- building message contentLingo.Endpoint- interactions and webhook events over HTTPLingo.OAuth2- authorizing users and calling the API as themLingo.Testing- testing a bot without DiscordLingo.Telemetry- the events to build metrics on
Which bot a call goes to
Calls such as Lingo.Api.Message.create/2 don't take a bot argument; they
go to the current bot, found in this order:
- the bot chosen in this process with
with_bot/2orput_bot/1. Every process Lingo starts for a bot, including the ones running your callbacks, has it set. - the bot of a process that started this one through
Task(Task.async/1,Task.Supervisor...), since tasks know their callers. - the only running bot. With none, or several, the call raises
ArgumentError.
With one bot you never need to think about it. With several, choose one
wherever step 1 and 2 don't apply: processes you start with spawn/1, and
your own GenServers, which don't inherit it even when started from a
callback. Call put_bot/1 in their GenServer.init/1.
A Lingo.Context carries its bot, so an interaction can be answered from
any process.
Summary
Functions
The names of the running bots.
Makes calls from this process go to the bot named name; returns the
previous choice. Use it in processes Lingo doesn't start, such as your own
GenServers when running several bots.
Sends the bot's declared commands to Discord, replacing the ones there.
Runs fun with calls going to the bot named name. Only needed when
running several bots, outside the processes Lingo starts for them.
Caps how long the API calls fun makes may wait on rate limits, in ms.
Functions
@spec bots() :: [atom()]
The names of the running bots.
Makes calls from this process go to the bot named name; returns the
previous choice. Use it in processes Lingo doesn't start, such as your own
GenServers when running several bots.
def init(opts) do
Lingo.put_bot(SupportBot)
{:ok, opts}
end
@spec register_commands(:global | {:guild, String.t()} | {:guilds, [String.t()]}) :: {:ok, [Lingo.Type.ApplicationCommand.t()]} | {:error, Lingo.Error.t()}
Sends the bot's declared commands to Discord, replacing the ones there.
scope is :global (the default), {:guild, guild_id} or
{:guilds, guild_ids}. Guild commands update instantly, which helps during
development.
Runs fun with calls going to the bot named name. Only needed when
running several bots, outside the processes Lingo starts for them.
Lingo.with_bot(SupportBot, fn -> Lingo.Api.Message.create(channel_id, "Hi") end)
@spec with_max_wait(non_neg_integer() | :infinity, (-> result)) :: result when result: any()
Caps how long the API calls fun makes may wait on rate limits, in ms.
Calls that would wait longer return {:error, %Lingo.Error{reason: :rate_limited}}
instead of blocking. Only applies to the calling process.