dexcord/examples/echo_bot.exs
Luna 1b0914d60e docs: write README, example bot, and ex_doc setup for Phase 6
Adds the full README (quickstart, interaction styles, privileged intents,
cache, REST, slash registration, event semantics, Nostrum porting guide,
reliability design), an examples/echo_bot.exs Mix.install script, ex_doc
config in mix.exs, and rewrites Dexcord.Gateway's moduledoc to describe
the finished reliability behavior instead of stale Phase 0-1 scope notes.
2026-07-04 01:45:36 -03:00

89 lines
2.7 KiB
Elixir

# Dexcord example bot: raw events, a prefix command, and a slash command.
#
# Run it from the repo root with:
#
# DISCORD_TOKEN=your-bot-token elixir examples/echo_bot.exs
#
# Optionally set DEV_GUILD_ID to a guild id to register the `/ping` slash
# command to that guild only (instant propagation, good for development).
# Without it, the command registers globally (propagation can take ~1h).
#
# What it demonstrates:
#
# * `intents: :all` - every documented gateway intent, including the
# privileged ones. If you see a 4014 (disallowed intents) error in the
# logs, enable SERVER MEMBERS / PRESENCE / MESSAGE CONTENT under
# Bot -> Privileged Gateway Intents in the Discord Developer Portal (see
# the README's "Privileged intents" section).
# * A raw `Dexcord.Handler` that logs every `MESSAGE_CREATE` and sets the
# bot's presence on `READY`.
# * A `!ping` prefix command via `Dexcord.Prefix.Router`.
# * A `/ping` slash command that responds ephemerally.
#
# This script does not connect to Discord on its own - it only starts if you
# provide a real DISCORD_TOKEN and run it, at which point it connects for
# real and stays running until you stop it (Ctrl-C twice).
Mix.install([
{:dexcord, path: Path.expand("..", __DIR__)}
])
defmodule EchoBot.Commands do
@moduledoc false
use Dexcord.Prefix.Router
def handle_command("ping", _args, msg) do
Dexcord.Api.create_message(msg["channel_id"], "pong")
end
end
defmodule EchoBot.Slash do
@moduledoc false
use Dexcord.Slash
def commands do
[%{name: "ping", description: "Replies with pong (only you can see it)."}]
end
def handle_interaction("ping", interaction) do
Dexcord.Slash.respond(interaction, %{content: "pong", ephemeral: true})
end
end
defmodule EchoBot.Handler do
@moduledoc false
use Dexcord.Handler
def handle_event({:READY, data}) do
IO.puts("Ready as #{get_in(data, ["user", "username"])}")
Dexcord.update_presence(%{
"since" => nil,
"activities" => [%{"name" => "!ping / /ping", "type" => 0}],
"status" => "online",
"afk" => false
})
end
def handle_event({:MESSAGE_CREATE, msg}) do
IO.puts("#{get_in(msg, ["author", "username"])}: #{msg["content"]}")
Dexcord.Prefix.dispatch(msg, prefix: "!", to: EchoBot.Commands)
end
end
token = System.fetch_env!("DISCORD_TOKEN")
dev_guild_id = System.get_env("DEV_GUILD_ID")
children = [
{Dexcord,
token: token,
handler: EchoBot.Handler,
intents: :all,
slash: EchoBot.Slash,
slash_guild_ids: if(dev_guild_id, do: [dev_guild_id])}
]
{:ok, _supervisor} =
Supervisor.start_link(children, strategy: :one_for_one, name: EchoBot.Supervisor)
Process.sleep(:infinity)