/
lychizdes
/
hw10
Обзор
Документация
Войти
/
lychizdes
/
hw10
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
code_lock/src/code_lock.erl
103 строки
3 KB
lychizdes
create code_lock/src/code_lock.erl
09 фев 2026, 16:22
Верифицирован
09 фев 2026, 16:22
dd35e03
Код
Авторство
О чём код?
-module(code_lock). -behaviour(gen_statem). -export([start_link/1, button/1, change_code/1]). -export([init/1, callback_mode/0, handle_event/4, terminate/3]). -define(NAME, ?MODULE). -record(state, { code :: [integer()], buttons = [] :: [integer()], failed_attempts = 0 :: non_neg_integer() }). %% API start_link(Code) -> gen_statem:start_link({local, ?NAME}, ?MODULE, Code, []). button(Button) -> gen_statem:cast(?NAME, {button, Button}). change_code(NewCode) -> case gen_statem:call(?NAME, {change_code, NewCode}) of ok -> ok; Error -> Error end. %% Callbacks init(Code) -> {ok, locked, #state{code = Code}}. callback_mode() -> [handle_event_function, state_enter]. handle_event(enter, _OldState, locked, State) -> do_lock(), {keep_state, State#state{buttons = [], failed_attempts = 0}}; handle_event(state_timeout, forget_buttons, locked, State) -> {keep_state, State#state{buttons = []}}; handle_event(cast, {button, Button}, locked, #state{code = Code, buttons = Buttons, failed_attempts = FA} = State) -> MaxLen = length(Code), NewButtons = case length(Buttons) >= MaxLen of true -> tl(Buttons) ++ [Button]; false -> Buttons ++ [Button] end, NewState = State#state{buttons = NewButtons}, case NewButtons of Code -> {next_state, open, NewState#state{failed_attempts = 0}, [{state_timeout, 10_000, lock}]}; _ -> NewFA = FA + 1, if NewFA >= 3 -> {next_state, suspended, NewState#state{failed_attempts = NewFA}, [{timeout, 10_000, resume_locked}]}; true -> {keep_state, NewState#state{failed_attempts = NewFA}, [{state_timeout, 30_000, forget_buttons}]} end end; handle_event(enter, _OldState, open, _State) -> do_unlock(), {keep_state_and_data, [hibernate]}; handle_event(cast, {button, _}, open, State) -> {keep_state, State, [postpone]}; handle_event({call, From}, {change_code, NewCode}, open, State) when is_list(NewCode), NewCode =/= [] -> Valid = lists:all(fun(X) -> is_integer(X) andalso X >= 0 end, NewCode), Reply = case Valid of true -> ok; false -> {error, invalid_code} end, NewState = if Valid -> State#state{code = NewCode}; true -> State end, {keep_state, NewState, [{reply, From, Reply}]}; handle_event({call, From}, {change_code, _}, _, _) -> {keep_state_and_data, [{reply, From, {error, not_open}}]}; handle_event(state_timeout, lock, open, State) -> {next_state, locked, State}; handle_event(enter, _OldState, suspended, _State) -> io:format("SUSPENDED: Too many failed attempts. Try again in 10 seconds.~n", []), {keep_state_and_data}; handle_event(cast, {button, _}, suspended, State) -> io:format("ERROR: Lock is suspended. Cannot accept input.~n", []), {keep_state, State}; handle_event(timeout, resume_locked, suspended, State) -> {next_state, locked, State}; handle_event(_EventType, _Content, StateName, Data) -> io:format("Unhandled event in ~p: ~p ~p~n", [StateName, _EventType, _Content]), {keep_state_and_data}. do_lock() -> io:format("Lock~n", []). do_unlock() -> io:format("Unlock~n", []). terminate(_Reason, open, _Data) -> do_lock(), ok; terminate(_Reason, _State, _Data) -> ok.