<commit_before>defmodule Poxa.WebsocketHandler do
  @behaviour :cowboy_websocket_handler
  @moduledoc """
  This module contains Cowboy Websocket handler callbacks to requests on /apps/:app_key

  More info on Cowboy HTTP handler at: http://ninenines.eu/docs/en/cowboy/HEAD/guide/ws_handlers

  More info on Pusher protocol at: http://pusher.com/docs/pusher_protocol
  """

  require Logger
  alias Poxa.PusherEvent
  alias Poxa.Event
  alias Poxa.PresenceSubscription
  alias Poxa.Subscription
  alias Poxa.Channel
  alias Poxa.Time
  alias Poxa.SocketId
  alias Poxa.Registry

  @max_protocol 7
  @min_protocol 5

  defmodule State do
    defstruct [:socket_id, :time]
  end

  @doc false
  def init(_transport, _req, _opts), do: {:upgrade, :protocol, :cowboy_websocket}

  @doc """
  This function checks for proper app_key and protocol before continuing
  It can return 4007 code if the protocol is wrong or 4001 if the app key is incorrect
  """
  def websocket_init(_transport_name, req, _opts) do
    {app_key, req} = :cowboy_req.binding(:app_key, req)
    {protocol, req} = :cowboy_req.qs_val("protocol", req, to_string(@max_protocol))
    case :application.get_env(:poxa, :app_key) do
      {:ok, ^app_key} ->
        if supported_protocol?(protocol) do
          send self, :start
          {:ok, req, nil}
        else
          Logger.error "Protocol #{protocol} not supported"
          send self, :start_error
          {:ok, req, {4007, "Unsupported protocol version"}}
        end
      {:ok, expected_app_key} ->
        Logger.error "Invalid app_key, expected #{expected_app_key}, found #{app_key}"
          send self, :start_error
          {:ok, req, {4001, "Application does not exist"}}
    end
  end

  defp supported_protocol?(protocol) do
    try do
      protocol = String.to_integer(protocol)
      protocol >= @min_protocol and protocol <= @max_protocol
    rescue
      ArgumentError -> false
    end
  end

  @doc """
  The handle function can receive the following requests:

  * pusher:subscribe
  * pusher:unsubscribe
  * pusher:ping
  * client-* event

  More info: http://pusher.com/docs/pusher_protocol
  """
  def websocket_handle({:text, json}, req, state) do
    JSX.decode!(json) |> handle_pusher_event(req, state)
  end
  def websocket_handle({:ping, _}, req, state), do: { :ok, req, state }

  defp handle_pusher_event(decoded_json, req, state) do
    handle_pusher_event(decoded_json["event"], decoded_json, req, state)
  end

  defp handle_pusher_event("pusher:subscribe", decoded_json, req, %State{socket_id: socket_id} = state) do
    data = decoded_json["data"]
    reply = case Subscription.subscribe!(data, socket_id) do
      {:ok, channel} ->
        Event.notify(:subscribed, %{socket_id: socket_id, channel: channel})
        PusherEvent.subscription_succeeded(channel)
      subscription = %PresenceSubscription{channel: channel} ->
        Event.notify(:subscribed, %{socket_id: socket_id, channel: channel})
        PusherEvent.subscription_succeeded(subscription)
      {:error, error} -> error
    end
    {:reply, {:text, reply}, req, state}
  end
  defp handle_pusher_event("pusher:unsubscribe", decoded_json, req, %State{socket_id: socket_id} = state) do
    {:ok, channel} = Subscription.unsubscribe! decoded_json["data"]
    Event.notify(:unsubscribed, %{socket_id: socket_id, channel: channel})
    {:ok, req, state}
  end
  defp handle_pusher_event("pusher:ping", _decoded_json, req, state) do<commit_msg>remove some extra spaces for consistency<commit_after>defmodule Poxa.WebsocketHandler do
  @behaviour :cowboy_websocket_handler
  @moduledoc """
  This module contains Cowboy Websocket handler callbacks to requests on /apps/:app_key

  More info on Cowboy HTTP handler at: http://ninenines.eu/docs/en/cowboy/HEAD/guide/ws_handlers

  More info on Pusher protocol at: http://pusher.com/docs/pusher_protocol
  """

  require Logger
  alias Poxa.PusherEvent
  alias Poxa.Event
  alias Poxa.PresenceSubscription
  alias Poxa.Subscription
  alias Poxa.Channel
  alias Poxa.Time
  alias Poxa.SocketId
  alias Poxa.Registry

  @max_protocol 7
  @min_protocol 5

  defmodule State do
    defstruct [:socket_id, :time]
  end

  @doc false
  def init(_transport, _req, _opts), do: {:upgrade, :protocol, :cowboy_websocket}

  @doc """
  This function checks for proper app_key and protocol before continuing
  It can return 4007 code if the protocol is wrong or 4001 if the app key is incorrect
  """
  def websocket_init(_transport_name, req, _opts) do
    {app_key, req} = :cowboy_req.binding(:app_key, req)
    {protocol, req} = :cowboy_req.qs_val("protocol", req, to_string(@max_protocol))
    case :application.get_env(:poxa, :app_key) do
      {:ok, ^app_key} ->
        if supported_protocol?(protocol) do
          send self, :start
          {:ok, req, nil}
        else
          Logger.error "Protocol #{protocol} not supported"
          send self, :start_error
          {:ok, req, {4007, "Unsupported protocol version"}}
        end
      {:ok, expected_app_key} ->
        Logger.error "Invalid app_key, expected #{expected_app_key}, found #{app_key}"
          send self, :start_error
          {:ok, req, {4001, "Application does not exist"}}
    end
  end

  defp supported_protocol?(protocol) do
    try do
      protocol = String.to_integer(protocol)
      protocol >= @min_protocol and protocol <= @max_protocol
    rescue
      ArgumentError -> false
    end
  end

  @doc """
  The handle function can receive the following requests:

  * pusher:subscribe
  * pusher:unsubscribe
  * pusher:ping
  * client-* event

  More info: http://pusher.com/docs/pusher_protocol
  """
  def websocket_handle({:text, json}, req, state) do
    JSX.decode!(json) |> handle_pusher_event(req, state)
  end
  def websocket_handle({:ping, _}, req, state), do: {:ok, req, state}

  defp handle_pusher_event(decoded_json, req, state) do
    handle_pusher_event(decoded_json["event"], decoded_json, req, state)
  end

  defp handle_pusher_event("pusher:subscribe", decoded_json, req, %State{socket_id: socket_id} = state) do
    data = decoded_json["data"]
    reply = case Subscription.subscribe!(data, socket_id) do
      {:ok, channel} ->
        Event.notify(:subscribed, %{socket_id: socket_id, channel: channel})
        PusherEvent.subscription_succeeded(channel)
      subscription = %PresenceSubscription{channel: channel} ->
        Event.notify(:subscribed, %{socket_id: socket_id, channel: channel})
        PusherEvent.subscription_succeeded(subscription)
      {:error, error} -> error
    end
    {:reply, {:text, reply}, req, state}
  end
  defp handle_pusher_event("pusher:unsubscribe", decoded_json, req, %State{socket_id: socket_id} = state) do
    {:ok, channel} = Subscription.unsubscribe! decoded_json["data"]
    Event.notify(:unsubscribed, %{socket_id: socket_id, channel: channel})
    {:ok, req, state}
  end
  defp handle_pusher_event("pusher:ping", _decoded_json, req, state) do
{'fraction_non_alphanumeric': 0.10994689249318214, 'fraction_numerical': 0.00516721687957514, 'mean_word_length': 3.727272727272727, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4713059', 'n_tokens_mistral': 2310, 'n_tokens_neox': 2286, 'n_words': 598}