defmodule Slack.Socket do
@moduledoc """
Slack websocket connection for "Socket Mode."
"""
use WebSockex
require Logger
def start_link(config) do
state = %{
app_token: Keyword.fetch!(config, :app_token),
bot_token: Keyword.fetch!(config, :bot_token),
bot: Keyword.fetch!(config, :bot)
}
{:ok, %{"url" => url}} = Slack.API.post("apps.connections.open", state.app_token)
Logger.info("[Socket] connecting...")
WebSockex.start_link(url, __MODULE__, state)
end
def handle_frame({:text, msg}, state) do
case Jason.decode(msg) do
{:ok, %{"type" => "hello"} = hello} ->
Logger.info("[Socket] hello: #{inspect(hello)}")
{:ok, state}
{:ok, %{"payload" => %{"event" => event}} = msg} ->
Logger.debug("[Socket] message: #{inspect(msg)}")
case state.bot.handle_event(event["type"], event) do
{:reply, response} ->
Slack.API.post("chat.postMessage", state.bot_token, response)
:ok ->
:noop
end
{:reply, ack_frame(msg), state}
_ ->
Logger.debug("[Socket] Unhandled payload: #{msg}")
{:ok, state}
end
end
def handle_frame({type, msg}, state) do
Logger.debug("[Socket] unhandled message type: #{inspect(type)}, msg: #{inspect(msg)}")
{:ok, state}
end
def handle_cast({:send, {type, msg} = frame}, state) do
IO.puts("Sending #{type} frame with payload: #{msg}")
{:reply, frame, state}
end
defp ack_frame(payload) do
ack =
payload
|> Map.take(["envelope_id"])
|> Jason.encode!()
{:text, ack}
end
end