<commit_before>-module(betfair_session).

-behaviour(gen_server).

%% API
-export([start_link/1]).
-export([login/0]).
-export([get_token/0]).
-export([update_token/1]).
-export([keep_alive/0]).

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

-define(SERVER, ?MODULE).
-define(SCOPE, l).

-type token() :: string().

-export_type([credentials/0]).
-export_type([token/0]).

-record(state, {credentials::betfair:credentials(),
                connection, token, keep_alive}).

-type credentials() :: #{username => string(),
                         password => <PASSWORD>(),
                         app_key=> string()}.


%%%===================================================================
%%% API
%%%===================================================================

start_link(Opts) ->
    gen_server:start_link({local, ?SERVER}, ?MODULE, [Opts], []).

login() ->
    gen_server:call(?MODULE, login).

get_token() ->
    gen_server:call(?MODULE, token).

update_token(Token) ->
    gen_server:cast(?MODULE, {token, Token}).

keep_alive() ->
    betfair_session ! keep_alive.


%%%===================================================================
%%% gen_server callbacks
%%%===================================================================

init([Opts]) ->
    lager:info("Starting new session"),
    Credentials = proplists:get_value(credentials, Opts),
    lager:info("Credentials: ~p~n", [Credentials]),

    SslOpts = proplists:get_value(ssl, Opts),

    lager:info("Connecting with ssl opts ~p~n", [SslOpts]),
    {ok, _} = gun:open("identitysso.betfair.com", 443,
                       #{transport => ssl, transport_opts => SslOpts}),

    %% {ok, #state{credentials=Credentials, keep_alive = 10000}}.
    {ok, #state{credentials=maps:from_list(Credentials), keep_alive = 1000 * 60 * 60 * 60}}.


handle_call(token, _From, #state{token=Token} = State) ->
    {reply, Token, State};
handle_call(_Request, _From, State) ->
    Reply = ok,
    {reply, Reply, State}.

handle_cast({token, Token}, State) ->
    lager:info("Updating token with ~p", [Token]),

    {noreply, State#state{token=Token}};
handle_cast(_Msg, State) ->
    {noreply, State}.


handle_info({token, Token}, #state{token=Token} = State) when is_binary(Token) ->
    lager:info("Updating with token ~p", [Token]),
    gproc_ps:publish(?SCOPE, session_token, Token),
    {noreply, State#state{token=Token}};
handle_info({token, Token}, State) ->
    lager:info("Updating with first token with ~p", [Token]),
    gproc_ps:publish(?SCOPE, session_token, Token),
    {noreply, State#state{token=Token}};
handle_info(keep_alive, #state{token=Token, connection=Connection,
                               credentials=Credentials} = State) ->
    _ = lager:info("Keeping session ~p alive..", [Token]),

    #{app_key := Appkey} = Credentials,
    Headers = [{<<"Content-Type">>, "application/json"},
                  {<<"X-Application">>, Appkey},
                  {<<"X-Authentication">>, Token}],

    Stream = gun:get(Connection, "/api/keepAlive", Headers),
    _ = receive_response(self(), Stream, Connection, fun keep_alive_handler/1),
    _ = keep_alive(State#state.keep_alive),
    {noreply, State};
handle_info(login, #state{credentials=Credentials,
                          connection=Connection} = State) ->
    #{app_key := Appkey} = Credentials,
    lager:info("Logging in"),
    ReqBody = betfair_http:url_encode(maps:without([app_key], Credentials)),
    ReqHeaders = [{<<"Content-Type">>, "application/x-www-form-urlencoded"},
                  {<<"X-Application">>, Appkey}],
    Stream = gun:post(Connection, "/api/certlogin", ReqHeaders, ReqBody),
    _ = receive_response(self(), Stream, Connection, fun login_handler/1),
    _ = keep_alive(State#state.keep_alive),
    {noreply, State};
handle_info({gun_up, Connection, _Transport}, State) ->
    lager:info("Connection established .."),
    self() ! login,
    {noreply, State#state{connection = Connection}};
handle_info({gun_response, _Connection, _StreamRef, nofin, _Status, _}, State) ->
    lager:info("Headers received .."),
    {noreply, State};
handle_info(Info, State) -><commit_msg>fixed keep alive request headers<commit_after>-module(betfair_session).

-behaviour(gen_server).

%% API
-export([start_link/1]).
-export([login/0]).
-export([get_token/0]).
-export([update_token/1]).
-export([keep_alive/0]).

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

-define(SERVER, ?MODULE).
-define(SCOPE, l).

-type token() :: string().

-export_type([credentials/0]).
-export_type([token/0]).

-record(state, {credentials::betfair:credentials(),
                connection, token, keep_alive}).

-type credentials() :: #{username => string(),
                         password => <PASSWORD>(),
                         app_key=> string()}.


%%%===================================================================
%%% API
%%%===================================================================

start_link(Opts) ->
    gen_server:start_link({local, ?SERVER}, ?MODULE, [Opts], []).

login() ->
    gen_server:call(?MODULE, login).

get_token() ->
    gen_server:call(?MODULE, token).

update_token(Token) ->
    gen_server:cast(?MODULE, {token, Token}).

keep_alive() ->
    betfair_session ! keep_alive.


%%%===================================================================
%%% gen_server callbacks
%%%===================================================================

init([Opts]) ->
    lager:info("Starting new session"),
    Credentials = proplists:get_value(credentials, Opts),
    lager:info("Credentials: ~p~n", [Credentials]),

    SslOpts = proplists:get_value(ssl, Opts),

    lager:info("Connecting with ssl opts ~p~n", [SslOpts]),
    {ok, _} = gun:open("identitysso.betfair.com", 443,
                       #{transport => ssl, transport_opts => SslOpts}),

    %% {ok, #state{credentials=Credentials, keep_alive = 10000}}.
    {ok, #state{credentials=maps:from_list(Credentials), keep_alive = 1000 * 60 * 60 * 60}}.


handle_call(token, _From, #state{token=Token} = State) ->
    {reply, Token, State};
handle_call(_Request, _From, State) ->
    Reply = ok,
    {reply, Reply, State}.

handle_cast({token, Token}, State) ->
    lager:info("Updating token with ~p", [Token]),

    {noreply, State#state{token=Token}};
handle_cast(_Msg, State) ->
    {noreply, State}.


handle_info({token, Token}, #state{token=Token} = State) when is_binary(Token) ->
    lager:info("Updating with token ~p", [Token]),
    gproc_ps:publish(?SCOPE, session_token, Token),
    {noreply, State#state{token=Token}};
handle_info({token, Token}, State) ->
    lager:info("Updating with first token with ~p", [Token]),
    gproc_ps:publish(?SCOPE, session_token, Token),
    {noreply, State#state{token=Token}};
handle_info(keep_alive, #state{token=Token, connection=Connection} = State) ->
    _ = lager:info("Keeping session ~p alive..", [Token]),

    Headers = [{<<"Accept">>, "application/json"},
                  {<<"X-Application">>, <<"AppKey">>},
                  {<<"X-Authentication">>, Token}],

    Stream = gun:get(Connection, "/api/keepAlive", Headers),
    _ = receive_response(self(), Stream, Connection, fun keep_alive_handler/1),
    _ = keep_alive(State#state.keep_alive),
    {noreply, State};
handle_info(login, #state{credentials=Credentials,
                          connection=Connection} = State) ->
    #{app_key := Appkey} = Credentials,
    lager:info("Logging in"),
    ReqBody = betfair_http:url_encode(maps:without([app_key], Credentials)),
    ReqHeaders = [{<<"Content-Type">>, "application/x-www-form-urlencoded"},
                  {<<"X-Application">>, Appkey}],
    Stream = gun:post(Connection, "/api/certlogin", ReqHeaders, ReqBody),
    _ = receive_response(self(), Stream, Connection, fun login_handler/1),
    _ = keep_alive(State#state.keep_alive),
    {noreply, State};
handle_info({gun_up, Connection, _Transport}, State) ->
    lager:info("Connection established .."),
    self() ! login,
    {noreply, State#state{connection = Connection}};
handle_info({gun_response, _Connection, _StreamRef, nofin, _Status, _}, State) ->
    lager:info("Headers received .."),
    {noreply, State};
handle_info(Info, State) ->
{'fraction_non_alphanumeric': 0.23074200778577328, 'fraction_numerical': 0.00778577326884511, 'mean_word_length': 3.9204875217643647, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 71, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '2096948', 'n_tokens_mistral': 2781, 'n_tokens_neox': 2630, 'n_words': 484}