Skip to content

Instantly share code, notes, and snippets.

@dealloc
Created October 10, 2020 12:19
Show Gist options
  • Save dealloc/cae812882ca8501e223531e2516e2572 to your computer and use it in GitHub Desktop.
Save dealloc/cae812882ca8501e223531e2516e2572 to your computer and use it in GitHub Desktop.
Echo socket demo
defmodule PooledConnWeb.Socket.EchoSocket do
@moduledoc """
Javascript code to run this (put in .html.eex file):
const id = <%= :rand.uniform(10) %>;
const websocket = new WebSocket('ws://localhost:4000/socket/websocket?id=' + id);
websocket.onopen = (args) => console.info('Open', args);
websocket.onmessage = (msg, args) => console.info('Message', msg, args);
websocket.onclose = (args) => console.warn('Close', args);
"""
@behaviour Phoenix.Socket.Transport
require Logger
def child_spec(_opts) do
%{id: Task, start: {Task, :start_link, [fn -> :ok end]}, restart: :transient}
end
# This gets called on connection, but does NOT run in the process of the socket yet!
def connect(map) do
{:ok, map}
end
# This gets called after connecting, and runs INSIDE process of the socket, register your socket in here!
def init(%{params: %{"id" => id}} = state) do
# Right now I just get the ID of a socket from the query parameters, but you can obviously use whatever logic you want.
Registry.register(SocketRegistry, id, nil)
# For simplicity I just store the ID of this socket as the state, again use whatever suits your needs here.
{:ok, id}
end
# This is called for incoming SOCKET messages (aka anything sent over the websocket).
def handle_in({text, _opts}, state) do
# Here text is the ID of the socket I want to sent to (see the demo javascript), and I send "Hello from <id of this websocket here>" to the other socket
case Registry.lookup(SocketRegistry, text) do
[] ->
raise "Could not find #{text}"
[{pid, _meta}] ->
# This will send an ERLANG message to the other socket, and invokes handle_info
send(pid, "Hello from #{state}")
end
{:reply, :ok, {:text, text}, state}
end
# This gets invoked when send/3 is called by the other socket.
# Basically you can send whatever you want, just make sure to return {:push, {:text, "message here"}, state} which will return the message to the client.
def handle_info(msg, state) do
Logger.info("handle_info##{state}: #{inspect(msg)}")
{:push, {:text, "handle_info: #{msg}"}, state}
end
def terminate(reason, _state) do
Logger.info("terminate: #{inspect(reason)}")
:ok
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment