Phoenix Channel 에는
handle_out/3
콜백이 있다.
이 콜백은 브로드캐스트된 메시지가 클라이언트에게 전달되기 전에 메세지를 가로챌 수 있는 기능을 제공한다.사이드 프로젝트에서 특정 유저타입에게만 메세지를 broadcasting 할 필요가 있어서 사용하게 되었다.
여러가지로 단순히 필터링 용도 외에도 여러가지 목적으로 사용될 수 있다.
handle_out 기본 구조
def handle_out(event, payload, socket) do # 메시지 처리 로직 {:noreply, socket} end
사용 사례 1: 클라이언트 타입별 메시지 필터링
특정 타입의 클라이언트에게만 메시지를 전달하는 예시
defmodule GameChannel do use Phoenix.Channel def join("game:lobby", %{"client_type" => client_type}, socket) do socket = assign(socket, :client_type, client_type) {:ok, socket} end def handle_out("game_update", payload, socket) do case socket.assigns.client_type do "player" -> push(socket, "game_update", payload) "spectator" -> # 관전자에게는 일부 정보만 전달 filtered_payload = Map.take(payload, ["public_info"]) push(socket, "game_update", filtered_payload) _ -> :noop end {:noreply, socket} end end
사용 사례 2: 권한 기반 메시지 필터링
사용자 권한에 따라 메시지를 필터링하는 예시
defmodule AdminChannel do use Phoenix.Channel def handle_out("system_alert", payload, socket) do if authorized?(socket) do push(socket, "system_alert", payload) end {:noreply, socket} end defp authorized?(socket) do socket.assigns.user_role in ["admin", "supervisor"] end end
사용 사례 3: 동적 타겟팅
메시지 페이로드에 지정된 대상 유형에 따라 메세지 전달을 제어
defmodule NotificationChannel do use Phoenix.Channel def handle_out("notification", %{"target_types" => target_types} = payload, socket) do if socket.assigns.client_type in target_types do push(socket, "notification", payload) end {:noreply, socket} end end
사용 예시:
# 채널에서 브로드캐스트 NotificationChannel.broadcast("notification", %{ target_types: ["premium", "vip"], message: "VIP 전용 이벤트가 시작됩니다!" })
사용 사례 4: 메시지 변환
브로드캐스트된 메시지를 클라이언트별로 변환하여 전달
defmodule ChatChannel do use Phoenix.Channel def handle_out("new_msg", payload, socket) do transformed_payload = case socket.assigns.language do "ko" -> translate_to_korean(payload) "en" -> translate_to_english(payload) _ -> payload end push(socket, "new_msg", transformed_payload) {:noreply, socket} end end
사용 사례 5: 조건부 메시지 지연
특정 조건에서 메시지 전달을 지연시키는 예시
defmodule GameChannel do use Phoenix.Channel def handle_out("round_result", payload, socket) do if socket.assigns.player_status == "playing" do # 즉시 전달 push(socket, "round_result", payload) else # 5초 후 전달 Process.send_after(self(), {:delayed_push, "round_result", payload}, 5000) end {:noreply, socket} end def handle_info({:delayed_push, event, payload}, socket) do push(socket, event, payload) {:noreply, socket} end end
주의
handle_out
은 브로드캐스트된 모든 메시지에 대해 호출되므로, 성능을 고려해야 한다.
- 메시지를 필터링할 때는 default case를 항상 처리해야 함.