-module(grisp_connect_updater_progress).
%--- Includes ------------------------------------------------------------------
-include_lib("kernel/include/logger.hrl").
%--- Types ---------------------------------------------------------------------
%--- Exports -------------------------------------------------------------------
% Behaviour grisp_updater_progress callbacks
-export([progress_init/1]).
-export([progress_update/2]).
-export([progress_warning/3]).
-export([progress_error/4]).
-export([progress_done/2]).
%--- records -------------------------------------------------------------------
-record(state, {
client :: pid(),
last_notification :: undefined | integer()
}).
%--- API Functions -------------------------------------------------------------
%--- Behavior grisp_updater_progress Callback ----------------------------------
progress_init(#{client := PID} = _Opts) ->
{ok, #state{
last_notification = erlang:system_time(millisecond),
client = PID
}}.
progress_update(#state{last_notification = LastLog} = State, Stats) ->
case (erlang:system_time(millisecond) - LastLog) > 1000 of
false ->
{ok, State};
true ->
UpdatePercentage = progress_percent(Stats),
% Recheck log level when there is another way to check the progress update
?LOG_INFO("Update progress: ~b%", [UpdatePercentage]),
grisp_connect_client:notify(
<<"update">>,
<<"software_update_event">>,
#{event => progress,
percentage => UpdatePercentage}),
{ok, State#state{last_notification = erlang:system_time(millisecond)}}
end.
progress_warning(State, Reason, Msg) ->
?LOG_WARNING("Update warning; ~s: ~p", [Msg, Reason]),
grisp_connect_client:notify(
<<"update">>,
<<"software_update_event">>,
#{event => warning,
reason => as_json(Reason),
message => as_json_string(Msg)}),
{ok, State}.
progress_error(#state{}, Stats, Reason, Msg) ->
UpdatePercentage = progress_percent(Stats),
?LOG_ERROR("Update failed after ~b% : ~p", [UpdatePercentage, Reason]),
grisp_connect_client:notify(
<<"update">>,
<<"software_update_event">>,
#{event => error,
reason => as_json(Reason),
message => as_json_string(Msg),
percentage => UpdatePercentage}),
ok.
progress_done(#state{}, _Stats) ->
?LOG_NOTICE("Update done", []),
grisp_connect_client:notify(
<<"update">>,
<<"software_update_event">>,
#{event => done}),
ok.
%--- Internal Functions --------------------------------------------------------
as_json_string(undefined) -> null;
as_json_string(Value) when is_binary(Value) -> Value;
as_json_string(Value) when is_atom(Value) -> Value;
as_json_string(Value) when is_integer(Value) -> integer_to_binary(Value);
as_json_string(Value) when is_float(Value) -> float_to_binary(Value);
as_json_string(Value) when is_list(Value) -> list_to_binary(Value).
as_json(undefined) -> null;
as_json(Value) when is_binary(Value) -> Value;
as_json(Value) when is_atom(Value) -> Value;
as_json(Value) when is_integer(Value) -> Value;
as_json(Value) when is_float(Value) -> Value;
as_json(Value) when is_list(Value) -> [as_json(V) || V <- Value];
as_json(Value) when is_map(Value) ->
maps:from_list([{as_json_string(K), as_json(V)} || {K, V} <- maps:to_list(Value)]).
progress_percent(Stats) ->
#{data_total := Total, data_checked := Checked,
data_skipped := Skipped, data_written := Written} = Stats,
(Checked + Skipped + Written) * 100 div (Total * 2).