2

The Phoenix app I’m working on creates subscriptions to the changes on a document as long as that document is “public”. If someone changes their document to “private”, though, I don’t want those subscriptions to continue receiving updates.

I know how to prevent new subscriptions from being created on the private document, but I’m not sure how to disable pre-existing ones from the server side?

neurodynamic
  • 4,294
  • 3
  • 28
  • 39

1 Answers1

0

You need to assign an ID to every socket that corresponds to a particular user. Then you can do this:

MyAppWeb.Endpoint.broadcast(socket_id, "disconnect", %{})

To assign the ID to the socket, find the module where you do this:

use Absinthe.Phoenix.Socket,
  schema: MyAppWeb.Schema

It is probably in lib/my_app_web/channels/user_socket.ex.

In that "socket" module, you write your ID callbacks like this:

  @impl true
  def id(%{
        assigns: %{
          absinthe: %{
            opts: [
              context: %{current_user: current_user}
            ]
          }
        }
      }),
      do: socket_id_for_user(current_user)

  def id(_socket), do: nil

  def socket_id_for_user(%{id: id}), do: "user_socket:#{id}"

Now you just have to make sure this current_user assign is on your socket.

First, go to your router and put this line in any pipelines that need it (usually just the :api pipeline, sometimes the :browser pipeline):

    plug :fetch_current_user

In your router (or in an imported module, whichever you prefer), write this function:

  def fetch_current_user(conn, _opts) do
    # I don't know how you do auth so get your user your own way.
    # For me, it usually involves finding their session token in the DB.
    user = get_user_from_conn(conn)

    context = if is_nil(user), do: %{}, else: %{current_user: user}

    conn
    |> Absinthe.Plug.assign_context(context)
  end

You may want to do other stuff in this function. If you use phx_gen_auth you are probably putting the user_token in private assigns, for example.

The main problem you have now is that if you are sending your log-out mutation over this socket, you will have closed it before you can send a response. Very fun problem.

As discussed here:https://elixirforum.com/t/is-there-a-way-to-force-disconnect-an-absinthe-graphql-subscription-from-the-server-side/41042 my approach does not let you terminate particular descriptions. What I have described is a way of terminating the entire socket. With this approach, a client would have to create a new "unauthenticated" socket if it needs that.

Peaceful James
  • 1,807
  • 1
  • 7
  • 16