defmodule AbsintheWebSocket.SubscriptionServer do use GenServer require Logger def start_link(args, opts) do socket = Keyword.get(args, :socket) subscriber = Keyword.get(args, :subscriber) state = %{ connected?: false, disconnected_casts: [], socket: socket, subscriber: subscriber, subscriptions: %{}, } GenServer.start_link(__MODULE__, state, opts) end def init(state) do {:ok, state} end def subscribe(mod, subscription_name, callback, query, variables \\ []) do GenServer.cast(mod, {:subscribe, subscription_name, callback, query, variables}) end def unsubscribe(mod, subscription_name) do GenServer.cast(mod, {:unsubscribe, subscription_name}) end def handle_cast({:subscribe, _, _, _, _} = message, %{connected?: false} = state) do state = Map.put(state, :disconnected_casts, state.disconnected_casts ++ [message]) {:noreply, state} end def handle_cast({:subscribe, subscription_name, callback, query, variables}, %{socket: socket, subscriptions: subscriptions} = state) do AbsintheWebSocket.WebSocket.subscribe(socket, self(), subscription_name, query, variables) subscriptions = Map.put(subscriptions, subscription_name, [callback]) state = Map.put(state, :subscriptions, subscriptions) {:noreply, state} end def handle_cast({:unsubscribe, _} = message, %{connected?: false} = state) do state = Map.put(state, :disconnected_casts, state.disconnected_casts ++ [message]) {:noreply, state} end def handle_cast({:unsubscribe, subscription_name}, %{socket: socket, subscriptions: subscriptions} = state) do AbsintheWebSocket.WebSocket.unsubscribe(socket, self(), subscription_name) subscriptions = Map.delete(subscriptions, subscription_name) state = Map.put(state, :subscriptions, subscriptions) {:noreply, state} end # Incoming Notifications (from AbsintheWebSocket.WebSocket) def handle_cast({:subscription, subscription_name, response}, %{subscriptions: subscriptions} = state) do # handle_subscription(subscription_name, response) Map.get(subscriptions, subscription_name, []) |> Enum.each(fn(callback) -> callback.(response) end) {:noreply, state} end def handle_cast({:joined}, %{subscriber: subscriber} = state) do apply(subscriber, :subscribe, []) Enum.each(state.disconnected_casts, &GenServer.cast(self(), &1)) state = Map.merge(state, %{connected?: true, disconnected_casts: []}) {:noreply, state} end def handle_cast({:disconnected}, state) do {:noreply, Map.put(state, :connected?, false)} end end