refactor(portal): Move client updates to WAL broadcaster (#9288)

Client updates are next on the path to moving more side effects to the
WAL broadcaster. This one has the following notable changes:

- ~~The `actor_clients` pubsub topic were only used to broadcast removal
of clients belonging to an actor; these are no longer needed since we
handle this in the individual removal event~~ EDIT: only the presence is
kept
- The `account_clients:{account_id}` pubsub and presence topic
definition has been moved to `Events.Hooks.Accounts` because these are
broadcasted using the account_id field based on account changes, and
have nothing to do with the client lifecycle


Related: #6294 
Related: #8187
This commit is contained in:
Jamil
2025-05-29 09:56:08 -07:00
committed by GitHub
parent 7c674ea21c
commit 6cea0cd6ec
21 changed files with 232 additions and 210 deletions

View File

@@ -2,7 +2,7 @@ defmodule Web.Actors.Show do
use Web, :live_view
import Web.Actors.Components
import Web.Clients.Components
alias Domain.{Accounts, Auth, Tokens, Flows, Clients}
alias Domain.{Accounts, Auth, Events, Tokens, Flows, Clients}
alias Domain.Actors
def mount(%{"id" => id}, _session, socket) do
@@ -10,7 +10,9 @@ defmodule Web.Actors.Show do
Actors.fetch_actor_by_id(id, socket.assigns.subject,
preload: [:identities, :last_seen_at, groups: [:provider]]
) do
:ok = Clients.subscribe_to_clients_presence_for_actor(actor)
if connected?(socket) do
:ok = Events.Hooks.Actors.subscribe_to_clients_presence(actor.id)
end
available_providers =
Auth.all_active_providers_for_account!(socket.assigns.account)

View File

@@ -3,10 +3,11 @@ defmodule Web.Clients.Index do
import Web.Actors.Components
import Web.Clients.Components
alias Domain.Clients
alias Domain.Events
def mount(_params, _session, socket) do
if connected?(socket) do
:ok = Clients.subscribe_to_clients_presence_in_account(socket.assigns.subject.account)
:ok = Events.Hooks.Accounts.subscribe_to_clients_presence(socket.assigns.subject.account.id)
end
socket =

View File

@@ -2,7 +2,7 @@ defmodule Web.Clients.Show do
use Web, :live_view
import Web.Policies.Components
import Web.Clients.Components
alias Domain.{Accounts, Clients, Flows}
alias Domain.{Accounts, Clients, Events, Flows}
def mount(%{"id" => id}, _session, socket) do
with {:ok, client} <-
@@ -16,7 +16,7 @@ defmodule Web.Clients.Show do
]
) do
if connected?(socket) do
:ok = Clients.subscribe_to_clients_presence_for_actor(client.actor)
:ok = Events.Hooks.Actors.subscribe_to_clients_presence(client.actor_id)
end
socket =

View File

@@ -60,7 +60,7 @@ defmodule Web.Live.Actors.IndexTest do
admin_actor = Fixtures.Actors.create_actor(account: account, type: :account_admin_user)
Fixtures.Actors.create_membership(account: account, actor: admin_actor)
client = Fixtures.Clients.create_client(account: account, actor: admin_actor)
Domain.Clients.connect_client(client)
Domain.Events.Hooks.Clients.connect(client)
admin_actor = Repo.preload(admin_actor, identities: [:provider], groups: [])
user_actor = Fixtures.Actors.create_actor(account: account, type: :account_user)

View File

@@ -1,5 +1,6 @@
defmodule Web.Live.Actors.ShowTest do
use Web.ConnCase, async: true
alias Domain.Events
test "redirects to sign in page for unauthorized user", %{conn: conn} do
account = Fixtures.Accounts.create_account()
@@ -91,8 +92,8 @@ defmodule Web.Live.Actors.ShowTest do
|> live(~p"/#{account}/actors/#{actor}")
Domain.Config.put_env_override(:test_pid, self())
Domain.Clients.subscribe_to_clients_presence_for_actor(actor)
assert Domain.Clients.connect_client(client) == :ok
:ok = Events.Hooks.Actors.subscribe_to_clients_presence(actor.id)
assert Events.Hooks.Clients.connect(client) == :ok
assert_receive %Phoenix.Socket.Broadcast{topic: "presences:actor_clients:" <> _}
assert_receive {:live_table_reloaded, "clients"}, 500

View File

@@ -1,5 +1,6 @@
defmodule Web.Live.Clients.IndexTest do
use Web.ConnCase, async: true
alias Domain.Events
setup do
account = Fixtures.Accounts.create_account()
@@ -59,7 +60,7 @@ defmodule Web.Live.Clients.IndexTest do
online_client = Fixtures.Clients.create_client(account: account)
offline_client = Fixtures.Clients.create_client(account: account)
:ok = Domain.Clients.connect_client(online_client)
:ok = Events.Hooks.Clients.connect(online_client)
{:ok, lv, _html} =
conn
@@ -102,8 +103,8 @@ defmodule Web.Live.Clients.IndexTest do
|> live(~p"/#{account}/clients")
Domain.Config.put_env_override(:test_pid, self())
Domain.Clients.subscribe_to_clients_presence_for_actor(actor)
assert Domain.Clients.connect_client(client) == :ok
:ok = Events.Hooks.Actors.subscribe_to_clients_presence(client.actor_id)
assert Events.Hooks.Clients.connect(client) == :ok
assert_receive %Phoenix.Socket.Broadcast{topic: "presences:actor_clients:" <> _}
assert_receive {:live_table_reloaded, "clients"}, 250

View File

@@ -1,5 +1,6 @@
defmodule Web.Live.Clients.ShowTest do
use Web.ConnCase, async: true
alias Domain.Events
setup do
account = Fixtures.Accounts.create_account()
@@ -116,7 +117,7 @@ defmodule Web.Live.Clients.ShowTest do
identity: identity,
conn: conn
} do
:ok = Domain.Clients.connect_client(client)
:ok = Events.Hooks.Clients.connect(client)
{:ok, lv, _html} =
conn
@@ -144,8 +145,8 @@ defmodule Web.Live.Clients.ShowTest do
|> authorize_conn(identity)
|> live(~p"/#{account}/clients/#{client}")
Domain.Clients.subscribe_to_clients_presence_for_actor(actor)
assert Domain.Clients.connect_client(client) == :ok
Events.Hooks.Actors.subscribe_to_clients_presence(actor.id)
assert Events.Hooks.Clients.connect(client) == :ok
assert_receive %Phoenix.Socket.Broadcast{topic: "presences:actor_clients:" <> _}
wait_for(fn ->