<commit_before>%%% @doc This is the Ranch protocol that decodes the messages from TCP/SSL, and turns them into something the server can
%%% understand. This module is in charge of handling the decoding of the netstrings, and the AES encryption, as well as
%%% starting the client connection pid when an SSL connection happens.
%%% -------------------------------------------------------------------------------------------------------------------

-module(pre_channels_proto).

-behaviour(gen_server).
-behaviour(ranch_protocol).

-include("pre_client.hrl").

-define(AES_BLOCK_SIZE, 16).

% API
-export([start_link/4,
	send_envelope/2
]).

% gen_server callbacks
-export([init/1,
	handle_call/3,
	handle_cast/2,
	handle_info/2,
	terminate/2,
	code_change/3
]).

-record(state, {
	ref :: any(),
	socket :: any(),
	transport :: atom(),
	client :: pid(),
	aes_key :: binary(),
	aes_vector :: binary(),
	netstring_cont = 10 :: integer() | term()
}).

%% --------------------------------------------------------------------------------------------------------------------
%% API
%% --------------------------------------------------------------------------------------------------------------------

%% @doc Starts the server

start_link(Ref, Socket, Transport, Opts) ->
	gen_server:start_link(?MODULE, [Ref, Socket, Transport], Opts).

%% --------------------------------------------------------------------------------------------------------------------

send_envelope(ProtoPid, Envelope) ->
	gen_server:cast(ProtoPid, {send, Envelope}).

%% --------------------------------------------------------------------------------------------------------------------
%% gen_server
%% --------------------------------------------------------------------------------------------------------------------

init([]) ->
	lager:debug("Wrong init: not called from ranch?"),
	{ok, #state{}};

init([Ref, Socket, Transport]) ->
	% If you return a timeout value of 0 then the `gen_server' will call `handle_info(timeout, _, _)' right away.
	% We do this to work around issues with `gen_server' and ranch's protocols. See the ranch docs:
	%   http://ninenines.eu/docs/en/ranch/HEAD/guide/protocols/#using_gen_server
	{ok, #state{ref = Ref, socket = Socket, transport = Transport}, 0}.

%% --------------------------------------------------------------------------------------------------------------------

%% @hidden
handle_call(Request, _From, State) ->
	lager:debug("Unhandled call:  ~p", [Request]),
	{reply, unknown, State}.

%% --------------------------------------------------------------------------------------------------------------------

%% @hidden
handle_cast(stop, State) ->
	{stop, normal, State};

%% @hidden
handle_cast({send, Envelope}, State) ->
	% If we have an aes key, we assume we need to aes encrypt the message.
	Data = case State#state.aes_key of
		undefined ->
			pre_json:to_json(envelope_to_json(Envelope));
		_ ->
			% Encrypt the envelope
			aes_encrypt(pre_json:to_json(Envelope), State#state.aes_key, State#state.aes_vector)
	end,

	Packet = netstring:encode(Data),

	Transport = State#state.transport,
	Socket = State#state.socket,
	Transport:send(Socket, Packet),

	{noreply, State};

%% @hidden
handle_cast(Request, State) ->
	lager:debug("Unhandled cast:  ~p", [Request]),
	{noreply, State}.

%% --------------------------------------------------------------------------------------------------------------------

%% @hidden Handles incoming SSL data
handle_info({ssl, _Socket, Data}, State) ->
	lager:debug("SSL Message: ~p", [Data]),

	{Messages, Cont} = netstring:decode(Data, State#state.netstring_cont),
	State1 = State#state{netstring_cont = Cont},

	DecodedMessages = [json_to_envelope(Message) || Message <- Messages],

	% Send the messages to the client connection pid.
	pre_client:handle_messages(State#state.client, ssl, DecodedMessages),

	{noreply, State1};

%% @hidden Handles incoming TCP data
handle_info({tcp, _Socket, Data}, State) ->
	lager:debug("TCP Message: ~p", [Data]),

	{Messages, Cont} = netstring:decode(Data, State#state.netstring_cont),
	State1 = State#state{netstring_cont = Cont},

	% Check to see if we have our client yet. If not, we look through the messages for a cookie. (Om nom nom.)
	State2 = case State1#state.client of
		undefined ->
			check_for_cookie(Messages, State1);
		_ ->
			% Messages are only encrypted if we have found our client pid.
			DecryptedMessages = [aes_decrypt_envelope(Message, State1) || Message <- Messages],

			% Send the messages to the client connection pid.
			pre_client:handle_messages(State1#state.client, tcp, DecryptedMessages)
	end,

	{noreply, State2};

%% @hidden Sets up the ranch protocol.
handle_info(timeout, State=#state{ref = Ref, socket = Socket, transport = Transport}) ->
	ok = ranch:accept_ack(Ref),
	ok = Transport:setopts(Socket, [{active, once}]),

	State1 = case Transport of
		ranch_ssl ->
			% Spawn a new client pid
			{ok, ClientPid} = pre_client_sup:start_child(self()),
			State#state{client = ClientPid};<commit_msg>Added missing active, once call.<commit_after>%%% @doc This is the Ranch protocol that decodes the messages from TCP/SSL, and turns them into something the server can
%%% understand. This module is in charge of handling the decoding of the netstrings, and the AES encryption, as well as
%%% starting the client connection pid when an SSL connection happens.
%%% -------------------------------------------------------------------------------------------------------------------

-module(pre_channels_proto).

-behaviour(gen_server).
-behaviour(ranch_protocol).

-include("pre_client.hrl").

-define(AES_BLOCK_SIZE, 16).

% API
-export([start_link/4,
	send_envelope/2
]).

% gen_server callbacks
-export([init/1,
	handle_call/3,
	handle_cast/2,
	handle_info/2,
	terminate/2,
	code_change/3
]).

-record(state, {
	ref :: any(),
	socket :: any(),
	transport :: atom(),
	client :: pid(),
	aes_key :: binary(),
	aes_vector :: binary(),
	netstring_cont = 10 :: integer() | term()
}).

%% --------------------------------------------------------------------------------------------------------------------
%% API
%% --------------------------------------------------------------------------------------------------------------------

%% @doc Starts the server

start_link(Ref, Socket, Transport, Opts) ->
	gen_server:start_link(?MODULE, [Ref, Socket, Transport], Opts).

%% --------------------------------------------------------------------------------------------------------------------

send_envelope(ProtoPid, Envelope) ->
	gen_server:cast(ProtoPid, {send, Envelope}).

%% --------------------------------------------------------------------------------------------------------------------
%% gen_server
%% --------------------------------------------------------------------------------------------------------------------

init([]) ->
	lager:debug("Wrong init: not called from ranch?"),
	{ok, #state{}};

init([Ref, Socket, Transport]) ->
	% If you return a timeout value of 0 then the `gen_server' will call `handle_info(timeout, _, _)' right away.
	% We do this to work around issues with `gen_server' and ranch's protocols. See the ranch docs:
	%   http://ninenines.eu/docs/en/ranch/HEAD/guide/protocols/#using_gen_server
	{ok, #state{ref = Ref, socket = Socket, transport = Transport}, 0}.

%% --------------------------------------------------------------------------------------------------------------------

%% @hidden
handle_call(Request, _From, State) ->
	lager:debug("Unhandled call:  ~p", [Request]),
	{reply, unknown, State}.

%% --------------------------------------------------------------------------------------------------------------------

%% @hidden
handle_cast(stop, State) ->
	{stop, normal, State};

%% @hidden
handle_cast({send, Envelope}, State) ->
	% If we have an aes key, we assume we need to aes encrypt the message.
	Data = case State#state.aes_key of
		undefined ->
			pre_json:to_json(envelope_to_json(Envelope));
		_ ->
			% Encrypt the envelope
			aes_encrypt(pre_json:to_json(Envelope), State#state.aes_key, State#state.aes_vector)
	end,

	Packet = netstring:encode(Data),

	Transport = State#state.transport,
	Socket = State#state.socket,
	Transport:send(Socket, Packet),

	{noreply, State};

%% @hidden
handle_cast(Request, State) ->
	lager:debug("Unhandled cast:  ~p", [Request]),
	{noreply, State}.

%% --------------------------------------------------------------------------------------------------------------------

%% @hidden Handles incoming SSL data
handle_info({ssl, Socket, Data}, State) ->
	lager:debug("SSL Message: ~p", [Data]),

	{Messages, Cont} = netstring:decode(Data, State#state.netstring_cont),
	State1 = State#state{netstring_cont = Cont},

	DecodedMessages = [json_to_envelope(Message) || Message <- Messages],

	% Send the messages to the client connection pid.
	pre_client:handle_messages(State#state.client, ssl, DecodedMessages),

	% Tell the transport to get the next message
	Transport = State1#state.transport,
	ok = Transport:setopts(Socket, [{active, once}]),

	{noreply, State1};

%% @hidden Handles incoming TCP data
handle_info({tcp, Socket, Data}, State) ->
	lager:debug("TCP Message: ~p", [Data]),

	{Messages, Cont} = netstring:decode(Data, State#state.netstring_cont),
	State1 = State#state{netstring_cont = Cont},

	% Check to see if we have our client yet. If not, we look through the messages for a cookie. (Om nom nom.)
	State2 = case State1#state.client of
		undefined ->
			check_for_cookie(Messages, State1);
		_ ->
			% Messages are only encrypted if we have found our client pid.
			DecryptedMessages = [aes_decrypt_envelope(Message, State1) || Message <- Messages],

			% Send the messages to the client connection pid.
			pre_client:handle_messages(State1#state.client, tcp, DecryptedMessages)
	end,

	% Tell the transport to get the next message
	Transport = State2#state.transport,
	ok = Transport:setopts(Socket, [{active, once}]),

	{noreply, State2};

%% @hidden Sets up the ranch protocol.
handle_info(timeout, State=#state{ref = Ref, socket = Socket, transport = Transport}) ->
	ok = ranch:accept_ack(Ref),
	ok = Transport:setopts(Socket, [{active, once}]),

	State1 = case Transport of
		ranch_ssl ->
			% Spawn a new client pid
			{ok, ClientPid} = pre_client_sup:start_child(self()),
			State#state{client = ClientPid};
{'fraction_non_alphanumeric': 0.3146913937988989, 'fraction_numerical': 0.004829518014102193, 'mean_word_length': 1.9381384790011351, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 35, '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': '369361', 'n_tokens_mistral': 2932, 'n_tokens_neox': 2775, 'n_words': 783}