Real-Time
The Neutron.Channels module provides Phoenix-style real-time communication with topic-based routing, presence tracking, and Nucleus-backed multi-instance sync.
Channels
Define a channel to handle WebSocket messages by topic:
defmodule MyApp.ChatChannel do
use Neutron.Channel
def join("chat:" <> room_id, _params, socket) do
{:ok, assign(socket, :room_id, room_id)}
end
def handle_in("message", %{"body" => body}, socket) do
room = socket.assigns.room_id
user_id = socket.assigns.user_id
{:ok, msg} = Neutron.Nucleus.query_one!(MyApp.Pool,
"INSERT INTO messages (room, user_id, body) VALUES ($1, $2, $3) RETURNING *",
[room, user_id, body])
broadcast!(socket, "message", msg)
{:noreply, socket}
end
end
Socket Setup
Mount channels on your router:
defmodule MyApp.Socket do
use Neutron.Socket
channel "chat:*", MyApp.ChatChannel
channel "notifications:*", MyApp.NotificationChannel
def connect(%{"token" => token}, socket) do
case Neutron.Auth.verify_token(token) do
{:ok, user_id} -> {:ok, assign(socket, :user_id, user_id)}
_ -> :error
end
end
end
# In your router
websocket "/ws", MyApp.Socket
Presence
Track who is online in each topic with CRDT-based presence:
defmodule MyApp.ChatChannel do
use Neutron.Channel
def join("chat:" <> room_id, _params, socket) do
Neutron.Presence.track(socket, socket.assigns.user_id, %{
name: socket.assigns.user_name,
online_at: System.system_time(:second)
})
presences = Neutron.Presence.list(socket)
{:ok, %{presences: presences}, socket}
end
end
Clients receive presence_diff events automatically when users join or leave.
Multi-Instance Sync
Use Nucleus PubSub to sync broadcasts across multiple Elixir nodes:
# config/config.exs
config :neutron, :pubsub,
adapter: Neutron.PubSub.Nucleus,
pool: MyApp.Pool
# Broadcasts automatically fan out to all connected nodes
broadcast!(socket, "message", payload)
Server-Sent Events
For one-way streaming, use SSE:
get "/events" do
conn = Neutron.SSE.start(conn)
Neutron.Nucleus.pubsub(MyApp.Pool)
|> Neutron.PubSub.subscribe("events:*", fn channel, payload ->
Neutron.SSE.send(conn, channel, payload)
end)
end