             callback_state: callback_state,
             transport_pid: nil,
             transport_mref: nil,
-            message_refs: :ets.new(:message_refs, [:private, :set])
           })
         }
       other -> other

  @spec push(transport, topic, event, out_payload) :: {:ok, ref} | {:error, reason::any}
  def push(%{transport_pid: nil}, _topic, _event, _payload), do: {:error, :disconnected}
  def push(transport, topic, event, payload) do
    ref = next_ref(topic, transport.message_refs)
    cond do
      # first message on a channel must always be a join
      event != "phx_join" and ref == 1 ->
        :ets.delete(transport.message_refs, topic)
        {:error, :not_joined}
      # join must always be a first message
      event == "phx_join" and ref > 1 ->

  end

  defp reinit(state) do
    Process.get_keys()
    |> Enum.filter(&match?({__MODULE__, _}, &1))
    |> Enum.map(&Process.delete/1)

    if (state.transport_mref != nil), do: Process.demonitor(state.transport_mref, [:flush])
    %{state | transport_pid: nil, transport_mref: nil}
  end

  defp transport(state),
    do: Map.take(state, [:transport_mod, :transport_pid, :serializer])

  defp next_ref(topic) do
    ref = Process.get({__MODULE__, topic}, 0) + 1
    Process.put({__MODULE__, topic}, ref)
    ref
  end

  defp invoke_callback(state, function, args) do
    callback_response = apply(state.callback, function, args ++ [state.callback_state])
