|
Mix.install([ |
|
{:bandit, "== 1.5.7"}, |
|
{:poison, "== 6.0.0"}, |
|
{:websock, "== 0.5.3"}, |
|
{:websock_adapter, "== 0.5.7"} |
|
]) |
|
|
|
defmodule EchoServer do |
|
@behaviour WebSock |
|
|
|
@impl WebSock |
|
def init(state) do |
|
IO.inspect(state, label: :state) |
|
{:reply, :ok, {:text, build(:connect, state)}, state} |
|
end |
|
|
|
@impl WebSock |
|
def handle_in({message, [opcode: :text]}, state) do |
|
reply_message = process(message, state) |
|
IO.inspect(message, label: :received) |
|
IO.inspect(reply_message, label: :sent) |
|
{:reply, :ok, {:text, reply_message}, state} |
|
end |
|
|
|
@impl WebSock |
|
def terminate(:timeout, state) do |
|
{:ok, state} |
|
end |
|
|
|
@impl WebSock |
|
def terminate({:error, :closed}, state) do |
|
{:ok, state} |
|
end |
|
|
|
defp build(category, %{provider: provider, identity: identity}) do |
|
base = |
|
%{ |
|
provider: provider, |
|
phone_number: identity |
|
} |
|
|
|
category |
|
|> message() |
|
|> Map.merge(base) |
|
|> Poison.encode!() |
|
end |
|
|
|
defp message(:connect) do |
|
%{ |
|
type: "CONNECT", |
|
message: %{ |
|
encode: "text", |
|
value: "SUCCESS" |
|
} |
|
} |
|
end |
|
|
|
defp message(:authentication_challenge) do |
|
%{ |
|
type: "AUTHENTICATION_CHALLENGE", |
|
message: %{ |
|
encode: "json", |
|
value: %{ |
|
auth: "segredo", |
|
expire_at: NaiveDateTime.utc_now() |> NaiveDateTime.to_iso8601() |
|
} |
|
} |
|
} |
|
end |
|
|
|
defp message(:chat_list) do |
|
%{ |
|
type: "CHAT_LIST", |
|
message: %{ |
|
encode: "json", |
|
value: [ |
|
%{ |
|
full_name: "João Paulo Dubas", |
|
phone_number: "5511999999999" |
|
}, |
|
%{ |
|
full_name: "João Paulo Dubas", |
|
phone_number: "5511999999998" |
|
} |
|
] |
|
} |
|
} |
|
end |
|
|
|
defp message(:message_list) do |
|
%{ |
|
type: "MESSAGE_LIST", |
|
message: %{ |
|
encode: "json", |
|
value: %{ |
|
full_name: "João Paulo Dubas", |
|
phone_number: "5511999999999", |
|
messages: [ |
|
%{ |
|
type: "text", |
|
value: "Olá" |
|
} |
|
] |
|
} |
|
} |
|
} |
|
end |
|
|
|
defp message(:unknown) do |
|
%{ |
|
type: "UNKNOWN", |
|
message: %{ |
|
encode: "text", |
|
value: "error" |
|
} |
|
} |
|
end |
|
|
|
defp process(raw_message, state) do |
|
Process.sleep(Enum.random(500..5_000)) |
|
|
|
raw_message |
|
|> Poison.decode() |
|
|> case do |
|
{:ok, %{"type" => "AUTHENTICATION_REQUEST"}} -> |
|
build(:authentication_challenge, state) |
|
|
|
{:ok, %{"type" => "CHAT_LIST"}} -> |
|
build(:chat_list, state) |
|
|
|
{:ok, %{"type" => "MESSAGE_LIST"}} -> |
|
build(:message_list, state) |
|
|
|
{:ok, _} -> |
|
build(:unknown, state) |
|
|
|
error -> |
|
error |
|
end |
|
end |
|
end |
|
|
|
defmodule Router do |
|
use Plug.Router |
|
|
|
plug(Plug.Logger) |
|
plug(:match) |
|
plug(:dispatch) |
|
|
|
get "/" do |
|
send_resp(conn, 200, """ |
|
Use the JavaScript console to interact using websockets |
|
|
|
sock = new WebSocket("ws://localhost:4000/websocket") |
|
sock.addEventListener("message", console.log) |
|
sock.addEventListener("open", () => sock.send("ping")) |
|
""") |
|
end |
|
|
|
get "/:provider/:identity" do |
|
state = Enum.into(conn.path_params, %{}, fn {key, value} -> {String.to_atom(key), value} end) |
|
|
|
conn |
|
|> WebSockAdapter.upgrade(EchoServer, state, timeout: 60_000) |
|
|> halt() |
|
end |
|
|
|
match _ do |
|
send_resp(conn, 404, "not found") |
|
end |
|
end |
|
|
|
require Logger |
|
webserver = {Bandit, plug: Router, scheme: :http, port: 4000} |
|
{:ok, _} = Supervisor.start_link([webserver], strategy: :one_for_one) |
|
Logger.info("Plug now running on localhost:4000") |
|
Process.sleep(:infinity) |