This is for creating Slack applications or bots in Elixir.
The existing libraries I was looking at use the deprecated RTM API, and no longer work with new apps or bots.
To listen for subscribed events, it uses Socket Mode to connect to Slack. It has some pros and cons, so please read up on it (and pay attention to the info blocks).
It's a relatively thin wrapper, which keeps it flexible and easy to maintain.
- connects to Slack using a websocket connection to listen for your event subscriptions.
- uses the Web API to send messages, etc.
- uses dynamically supervised gen servers to handle each channel's message rate-limiting with a message queue per channel.
Add slack_elixir
to your list of dependencies in mix.exs
:
def deps do
[
{:slack_elixir, "~> 1.2.0"}
]
end
You will need to:
- Create a Slack app for your workspace
- Add permissions (scopes)
- Connect it to your workspace
- Get an OAuth Bot Token (will have the scopes you defined)
- Enable Socket Mode
- Get an app-level token with
connections:write
scope - Add Event Subscriptions
See below for some minimum required scopes and event subscriptions. You will need to add more scopes and subscriptions depending on what you want to do.
channels:history
channels:read
groups:read
im:read
mpim:read
message.channels
member_joined_channel
channel_left
Write the Bot module:
defmodule MyApp.Slackbot do
use Slack.Bot
require Logger
@impl true
# A silly example of old-school style bot commands.
def handle_event("message", %{"text" => "!" <> cmd, "channel" => channel, "user" => user}, _bot) do
case cmd do
"roll" ->
send_message(channel, "<@#{user}> rolled a #{Enum.random(1..6)}")
"echo " <> text ->
send_message(channel, text)
_ ->
send_message(channel, "Unknown command: #{cmd}")
end
end
def handle_event("message", %{"channel" => channel, "text" => text, "user" => user}, _bot) do
if String.match?(text, ~r/hello/i) do
send_message(channel, "Hello! <@#{user}>")
end
end
def handle_event(type, payload, _bot) do
Logger.debug("Unhandled #{type} event: #{inspect(payload)}")
:ok
end
end
Then you start the Slack Supervisor in your application's supervision tree.
For example:
def start(_type, _args) do
children = [
# ...
{Slack.Supervisor, Application.fetch_env!(:my_app, MyApp.SlackBot)}
]
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, opts)
end
# config/runtime.exs
config :my_app, MyApp.SlackBot,
app_token: "MY_SLACK_APP_TOKEN",
bot_token: "MY_SLACK_BOT_TOKEN",
bot: MyApp.SlackBot,
# Add this if you want to customize the channel types to join.
# By default we join all channel types: public_channel, private_channel, im, mpim.
channels: [
types: ["public_channel", "im", "private_channel"]
]
PRs welcome!
- Socket Mode for events
- Web API POST requests
- Web API GET requests
- Message Server per channel (rate-limited to 1 message per second per channel).