<commit_before>%% @author <NAME> <<EMAIL>>
%% @copyright 2012, <NAME>
%% @doc Websocket Client

-module(wsecli).
-behaviour(gen_fsm).

-include("wsecli.hrl").

-export([start/3, stop/0, send/1]).
-export([on_open/1, on_error/1, on_message/1, on_close/1]).
-export([init/1, connecting/2, open/2, closing/2, closed/2]).
-export([handle_event/3, handle_sync_event/4, handle_info/3, terminate/3, code_change/4]).

-record(callbacks, {
    on_open = fun()-> undefined end,
    on_error = fun(_Reason)-> undefined end,
    on_message = fun(_Type, _Message) -> undefined end,
    on_close = fun(_Reason) -> undefined end
  }).
-record(data, {
    socket :: gen_tcp:socket(),
    handshake :: #handshake{},
    cb  = #callbacks{},
    fragmented_message = undefined :: #message{}
  }).

%%%%%%%%%%%%%%%%%%%%%
%
% PUBLIC API
%
%%%%%%%%%%%%%%%%%%%%%
%% @doc This function will start the websocket client
%%
%% This function will open a connection with the specified remote endpoint. Parameters
%% <ul>
%% <li>Host, a string. The URL of the remote endpoint</li>
%% <li>Port, an integer. The port where the remote endpoint is listening</li>
%% <li>Resouce, an string. The resource path where the websockets live</li>
%% </ul>
-spec start(Host::string(), Port::integer(), Resource::string()) -> pid().
start(Host, Port, Path)->
  {ok, Pid} = gen_fsm:start_link({local, wsecli}, ?MODULE, {Host, Port, Path}, [{timeout, 5000}]),
  Pid.

%% @doc This function will stop the websocket client
%%
%% Calling this function doesn't mean that the connection will be inmediatelly closed. A
%%closing handshake is tryed and only after that the connection is closed.
-spec stop() -> ok.
stop() ->
  %error_logger:info_msg("Calling stop on wsecli\n"),
  gen_fsm:sync_send_all_state_event(wsecli, stop).

%% @doc Send data to a remote endpoint
%%
%% Websockets only support 2 types of data in the payload of a message: binary or text, so the type to apply
%%to the data given as parameter to this will depend on the result of the BIFs is_binary and is_list
-spec send(Data::string()) -> ok;
          (Data::binary()) -> ok.
send(Data) ->
  gen_fsm:send_event(wsecli, {send, Data}).

%% @doc Add a callback to be called when a connection is opened
%%
%% This callback is called when the connection is opened (after a successful websocket handshake)
%%or inmediatelly if called while in the open state.
%%
%% The callback function must be a function which takes no parameters
-spec on_open(Callback::fun()) -> any().
on_open(Callback) ->
  gen_fsm:send_event(wsecli, {on_open, Callback}).

%% @doc Add a callback to be called when an error occurs
%%
%% The callback function must be a function which takes one parameter, the reason for
%%the error
-spec on_error(Callback::fun()) -> any().
on_error(Callback) ->
  gen_fsm:send_all_state_event(wsecli, {on_error, Callback}).

%% @doc Add a callback to be called when a message arrives
%%
%% The callback function must be a function which takes two parameters:
%% <ul>
%% <li> The first is an atom with values binary or text depending on the type of the websocket message</li>
%% <li> The second parameter is the message payload</li><commit_msg>Fix doc<commit_after>%% @author <NAME> <<EMAIL>>
%% @copyright 2012, <NAME>
%% @doc Websocket Client

-module(wsecli).
-behaviour(gen_fsm).

-include("wsecli.hrl").

-export([start/3, stop/0, send/1]).
-export([on_open/1, on_error/1, on_message/1, on_close/1]).
-export([init/1, connecting/2, open/2, closing/2, closed/2]).
-export([handle_event/3, handle_sync_event/4, handle_info/3, terminate/3, code_change/4]).

-record(callbacks, {
    on_open = fun()-> undefined end,
    on_error = fun(_Reason)-> undefined end,
    on_message = fun(_Type, _Message) -> undefined end,
    on_close = fun(_Reason) -> undefined end
  }).
-record(data, {
    socket :: gen_tcp:socket(),
    handshake :: #handshake{},
    cb  = #callbacks{},
    fragmented_message = undefined :: #message{}
  }).

%%%%%%%%%%%%%%%%%%%%%
%
% PUBLIC API
%
%%%%%%%%%%%%%%%%%%%%%
%% @doc This function will start the websocket client
%%
%% This function will open a connection with the specified remote endpoint. Parameters
%% <ul>
%% <li>Host, a string. The URL of the remote endpoint</li>
%% <li>Port, an integer. The port where the remote endpoint is listening</li>
%% <li>Resouce, an string. The resource path where the websockets live</li>
%% </ul>
-spec start(Host::string(), Port::integer(), Resource::string()) -> pid().
start(Host, Port, Path)->
  {ok, Pid} = gen_fsm:start_link({local, wsecli}, ?MODULE, {Host, Port, Path}, [{timeout, 5000}]),
  Pid.

%% @doc This function will stop the websocket client
%%
%% Calling this function doesn't mean that the connection will be inmediatelly closed. A
%%closing handshake is tryed and only after that the connection is closed.
-spec stop() -> ok.
stop() ->
  %error_logger:info_msg("Calling stop on wsecli\n"),
  gen_fsm:sync_send_all_state_event(wsecli, stop).

%% @doc Send data to a remote endpoint
%%
%% Websockets only support 2 types of data in the payload of a message: binary or text, so the type to apply
%%to the data given as parameter to this will depend on the result of the BIFs is_binary and is_list
-spec send(Data::string()) -> ok;
          (Data::binary()) -> ok.
send(Data) ->
  gen_fsm:send_event(wsecli, {send, Data}).

%% @doc Add a callback to be called when a connection is opened
%%
%% This callback is called when the connection is opened (after a successful websocket handshake)
%%or inmediatelly if called while in the open state. Adding it not it connecting or open state will
%%raise an error.
%%
%% The callback function must be a function which takes no parameters
-spec on_open(Callback::fun()) -> any().
on_open(Callback) ->
  gen_fsm:send_event(wsecli, {on_open, Callback}).

%% @doc Add a callback to be called when an error occurs
%%
%% The callback function must be a function which takes one parameter, the reason for
%%the error
-spec on_error(Callback::fun()) -> any().
on_error(Callback) ->
  gen_fsm:send_all_state_event(wsecli, {on_error, Callback}).

%% @doc Add a callback to be called when a message arrives
%%
%% The callback function must be a function which takes two parameters:
%% <ul>
%% <li> The first is an atom with values binary or text depending on the type of the websocket message</li>
%% <li> The second parameter is the message payload</li>
{'fraction_non_alphanumeric': 0.1475974330881202, 'fraction_numerical': 0.00813898888714979, 'mean_word_length': 4.456874466268147, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 67, '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': '295618', 'n_tokens_mistral': 2011, 'n_tokens_neox': 1975, 'n_words': 746}