Register process info on topic and replicate it across cluster.
Simple use case would be showing whose online
metadata should be minimized and used to store small, ephemeral state, such as a user's "online" or "away" status. Can fetch more substantial stuff by overriding the fetch/2 ft
lib/channels/user_socket.ex - add user_id to socket
defmoduleSsWeb.UserSocketdousePhoenix.Socket channel "room:*",SsWeb.RoomChanneldefconnect(params, socket,_connect_info) do {:ok,assign(socket, :user_id, params["user_id"])}endend
lib/channels/room_channel.ex
defmoduleHelloWeb.RoomChanneldousePhoenix.ChannelaliasHelloWeb.Presence# intercept ["presence_diff"]defjoin("room:lobby",_message, socket) dosend(self(), :after_join) {:ok, :hiii, socket}enddefhandle_info(:after_join, socket) dopush(socket,"presence_state",Presence.list(socket))#Presence.track links channel's process as a presence for the socket's userID with map of metadata {:ok,_} =Presence.track(socket, socket.assigns.user_id, %{ online_at: inspect(System.system_time(:second)) }) {:noreply, socket}end# To alter or stop presence updates# def handle_out("presence_diff", msg, socket) do# {:noreply, socket}# endend
Client
Actually (and before 1.4?) recieved "presence_diff" and "presence_state" events
Only one onSync handler allowed
import {Socket, Presence} from"phoenix"let socket =newSocket("/socket", { params: {user_id:window.location.search.split("=")[1]}})let channel =socket.channel("room:lobby", {})let presence =newPresence(channel)functionrenderOnlineUsers(presence) {let response =""presence.list((id, {metas: [first,...rest]}) => {let count =rest.length+1 response +=`<br>${id} (count: ${count})</br>` }) //metas is list of users with this iddocument.querySelector("main[role=main]").innerHTML = response}socket.connect()presence.onSync(() =>renderOnlineUsers(presence))channel.join()
More Client
let presence =newPresence(channel)// detect if user has joined for the 1st time or from another tab/devicepresence.onJoin((id, current, newPres) => {if(!current){console.log("user has entered for the first time", newPres) } else {console.log("user additional presence", newPres) }})// detect if user has left from all tabs/devices, or is still presentpresence.onLeave((id, current, leftPres) => {if(current.metas.length===0){console.log("user has left from all devices", leftPres) } else {console.log("user left from a device", leftPres) }})// receive presence data from serverpresence.onSync(() => {displayUsers(presence.list())})