Current section

Files

Jump to
kraft src kraft_ws_json.erl
Raw

src/kraft_ws_json.erl

-module(kraft_ws_json).
% Callbacks
-export([init/2]).
-ignore_xref(init/2).
-export([handle/2]).
-ignore_xref(handle/2).
-export([info/2]).
-ignore_xref(info/2).
-export([terminate/3]).
-ignore_xref(terminate/3).
%--- Includes ------------------------------------------------------------------
-include_lib("kernel/include/logger.hrl").
%--- Types ---------------------------------------------------------------------
-type commands() :: [frame()].
-type state() :: any().
-type frame() ::
kraft_json:body_json()
| cow_ws:frame()
| {active, boolean()}
| {deflate, boolean()}
| {set_options, map()}
| {shutdown_reason, any()}.
-optional_callbacks([handshake/3]).
-callback handshake(kraft:conn(), kraft_conn:params(), state()) ->
{reply, kraft:status(), kraft:headers(), kraft:body()}
| {ok, state()}.
-callback init(kraft:conn(), state()) -> {commands(), state()}.
-callback handle(frame(), state()) -> {commands(), state()}.
-optional_callbacks([info/2]).
-callback info(any(), state()) -> {commands(), state()}.
%--- Callbacks -----------------------------------------------------------------
init(Conn, State0) -> call(?FUNCTION_NAME, [Conn], State0).
handle({text, Data}, State0) ->
try
call(?FUNCTION_NAME, [{json, kraft_json:decode(Data)}], State0)
catch
error:badarg ->
?LOG_WARNING("Bad JSON received: ~p", [cut(Data, 200)]),
{[], State0}
end.
info(Info, State) -> call(?FUNCTION_NAME, [Info], State).
terminate(Reason, _Req, State0) ->
kraft_ws_util:raw_call(?FUNCTION_NAME, [Reason], State0).
%--- Internal ------------------------------------------------------------------
call(Func, Args, State0) ->
{Commands, State1} = kraft_ws_util:call(Func, Args, State0),
{[encode(C) || C <- Commands], State1}.
encode(close = Close) -> Close;
encode({close, _IOData} = Close) -> Close;
encode({close, _Code, _IOData} = Close) -> Close;
encode({json, JSON}) -> {text, kraft_json:encode(JSON)};
encode({text, Text}) -> {text, Text};
encode({binary, Binary}) -> {binary, Binary}.
cut(Data, Len) ->
case Data of
Data when byte_size(Data) =< Len -> Data;
<<Prefix:Len/binary, _/binary>> -> <<Prefix/binary, "...">>
end.