Presence

에단(손형규)·2022년 7월 26일

Phoenix Presence는 주제에 대한 프로세스 정보를 등록하고 클러스터 전체에 투명하게 복제할 수 있는 기능입니다. 서버 측과 클라이언트 측 라이브러리의 조합으로 구현이 간단합니다. 간단한 사용 사례는 애플리케이션에서 현재 온라인 상태인 사용자를 표시하는 것입니다.

Phoenix Presence는 여러 가지 이유로 특별합니다. 단일 실패 지점이 없고 단일 소스 소스가 없으며 운영 종속성과 자가 치유가 없는 표준 라이브러리에 전적으로 의존합니다..

Setting up

Presence를 사용하여 서버에 연결된 사용자를 추적하고 사용자가 가입하고 나갈 때 업데이트를 클라이언트에 보낼 것입니다. 피닉스 채널을 통해 이러한 업데이트를 제공할 것입니다. 따라서 채널 가이드에서 했던 것처럼 RoomChannel을 생성해 보겠습니다.

mix phx.gen.channel Room

생성기 이후의 단계를 따르면 존재 추적을 시작할 준비가 된 것입니다.

The Presence generator

Presence를 시작하려면 먼저 Presence 모듈을 생성해야 합니다. mix phx.gen.presence 작업으로 이 작업을 수행할 수 있습니다.

mix phx.gen.presence
* creating lib/hello_web/channels/presence.ex

새로운 모듈을 lib/hello/application.ex에서 슈퍼비젼 트리에 추가합니다. :

children = [
  ...
  HelloWeb.Presence,
]

준비가 완료되었습니다! 자세한 내용은 Phoenix.Presence 문서를 참조하세요.
https://hexdocs.pm/phoenix/Phoenix.Presence.html
lib/hello_web/channels/presence.ex 파일을 열면 다음 줄이 표시됩니다.

use Phoenix.Presence,
  otp_app: :hello,
  pubsub_server: Hello.PubSub

이것은 현재 상태를 추적하는 데 필요한 기능을 정의하여 현재 상태에 대한 모듈을 설정합니다. 생성기 작업에서 언급했듯이 이 모듈을 application.ex의 감독 트리에 추가해야 합니다.


children = [
  ...
  HelloWeb.Presence,
]

다음으로 우리는 존재감을 전달할 채널을 만들 것입니다. 사용자가 가입한 후 현재 상태 목록을 채널 아래로 푸시한 다음 연결을 추적할 수 있습니다. 추적할 추가 정보의 지도를 제공할 수도 있습니다.

defmodule HelloWeb.RoomChannel do
  use Phoenix.Channel
  alias HelloWeb.Presence

  def join("room:lobby", %{"name" => name}, socket) do
    send(self(), :after_join)
    {:ok, assign(socket, :name, name)}
  end

  def handle_info(:after_join, socket) do
    {:ok, _} =
      Presence.track(socket, socket.assigns.name, %{
        online_at: inspect(System.system_time(:second))
      })

    push(socket, "presence_state", Presence.list(socket))
    {:noreply, socket}
  end
end

마지막으로 phoenix.js에 포함된 클라이언트 측 Presence 라이브러리를 사용하여 소켓으로 내려오는 상태 및 존재(Presence) 차이를 관리할 수 있습니다. "presence_state" 및 "presence_diff" 이벤트를 수신 대기하고 onSync 콜백을 사용하여 이벤트가 발생할 때 이를 처리할 수 있는 간단한 콜백을 제공합니다.

onSync 콜백을 사용하면 현재 상태 변경에 쉽게 대응할 수 있으며, 이로 인해 업데이트된 활성 사용자 목록이 다시 렌더링되는 경우가 많습니다. list 메서드를 사용하여 응용 프로그램의 요구 사항에 따라 각 개별 프레즌스를 형식화하고 반환할 수 있습니다.

사용자를 반복하기 위해 우리는 콜백을 수락하는 Presence.list() 함수를 사용합니다. 콜백은 2개의 인수, 프레즌스 ID 및 메타 목록(해당 프레즌스 ID에 대한 각 프레즌스에 대해 하나씩)이 있는 각 프레즌스 항목에 대해 호출됩니다. 우리는 이것을 사용하여 사용자와 온라인 상태에 있는 장치 수를 표시합니다.

asset/js/app.js에 다음을 추가하여 존재감을 확인할 수 있습니다.

import {Socket, Presence} from "phoenix"

let socket = new Socket("/socket", {params: {token: window.userToken}})
let channel = socket.channel("room:lobby", {name: window.location.search.split("=")[1])
let presence = new Presence(channel)

function renderOnlineUsers(presence) {
  let response = ""

  presence.list((id, {metas: [first, ...rest]}) => {
    let count = rest.length + 1
    response += `<br>${id} (count: ${count})</br>`
  })

  document.querySelector("main[role=main]").innerHTML = response
}

socket.connect()

presence.onSync(() => renderOnlineUsers(presence))

channel.join()

3개의 브라우저 탭을 열어 이것이 작동하는지 확인할 수 있습니다. 두 개의 브라우저 탭에서 http://localhost:4000/?name=Alicehttp://localhost:4000/?name=Bob으로 이동하면 다음이 표시되어야 합니다.

Alice (count: 2)
Bob (count: 1)

Alice 탭 중 하나를 닫으면 개수가 1로 감소해야 합니다. 다른 탭을 닫으면 사용자가 목록에서 완전히 사라져야 합니다.

Making it safe

초기 구현에서는 사용자 이름을 URL의 일부로 전달합니다. 그러나 많은 시스템에서 로그인한 사용자만 현재 상태 기능에 액세스할 수 있도록 허용하려고 합니다. 그렇게 하려면 채널 가이드의 토큰 인증 섹션에 설명된 대로 토큰 인증을 설정해야 합니다.

토큰 인증을 사용하면 매개변수에서 설정한 socket.assigns.name 대신 UserSocket에서 설정한 socket.assigns.user_id에 액세스해야 합니다

profile
asdasdasdasd

0개의 댓글