-
-
Save niamtokik/3db37f0749a3c338f08b80b9bd076d04 to your computer and use it in GitHub Desktop.
Linux Magazine - Erlang/OTP
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%%%------------------------------------------------------------------- | |
%%% @doc le module cache permet de créer un processus permettant de | |
%%% stockée des clés associés à des valeurs. | |
%%% @end | |
%%%------------------------------------------------------------------- | |
-module(cache). | |
-behaviour(gen_server). | |
-export([init/1, terminate/2]). | |
-export([handle_cast/2, handle_call/3]). | |
-export([add/3, delete/2, get/2, get_keys/1, get_values/1]). | |
-export([start_link/0]). | |
%%-------------------------------------------------------------------- | |
%% @doc start_link/0 permet d'utiliser la fonction | |
%% gen_server:start_link/3 pour démarrer un processus lié. | |
%% @end | |
%%-------------------------------------------------------------------- | |
start_link() -> | |
gen_server:start_link(?MODULE, [], []). | |
%%-------------------------------------------------------------------- | |
%% @doc ce processus ajout un event handler au démarrage et configure | |
%% l'état avec une map nulle. | |
%% @end | |
%%-------------------------------------------------------------------- | |
init(_Args) -> | |
Etat = #{}, | |
{ok, Etat}. | |
%%-------------------------------------------------------------------- | |
%% @doc terminate/2 ne fait rien et n'est pas essentielle dans ce cas | |
%% là. | |
%% @end | |
%%-------------------------------------------------------------------- | |
terminate(_Raison, _Etat) -> | |
ok. | |
%%-------------------------------------------------------------------- | |
%% @doc handle_cast/2 est un callback permet, dans ce cas là de: | |
%% - créé une nouvelle clé/valeur | |
%% - supprimé une clé et sa valeur associée | |
%% @end | |
%%-------------------------------------------------------------------- | |
handle_cast({add, Key, Value}, Etat) -> | |
{noreply, maps:put(Key, Value, Etat)}; | |
handle_cast({delete, Key}, Etat) -> | |
{noreply, maps:remove(Key, Etat)}. | |
%%-------------------------------------------------------------------- | |
%% @doc handle_cast/ est un callback qui permet de: | |
%% - récupérer la liste des clés | |
%% - récupérer la liste des valeurs | |
%% - récupéré la valeur associée à une clé. | |
%% @end | |
%%-------------------------------------------------------------------- | |
handle_call(get_keys, _From, Etat) -> | |
{reply, maps:keys(Etat), Etat}; | |
handle_call(get_values, _From, Etat) -> | |
{reply, maps:values(Etat), Etat}; | |
handle_call({get, Key}, _From, Etat) -> | |
{reply, maps:get(Key, Etat, undefined), Etat}. | |
%%-------------------------------------------------------------------- | |
%% @doc add/3 est une interface permettant de rajouter une clé | |
%% associée à une valeur. | |
%% @end | |
%%-------------------------------------------------------------------- | |
add(Pid, Key, Value) -> | |
gen_server:cast(Pid, {add, Key, Value}). | |
%%-------------------------------------------------------------------- | |
%% @doc delete/2 est une interface permettant de supprimer une clé | |
%% avec sa valeur associée. | |
%% @end | |
%%-------------------------------------------------------------------- | |
delete(Pid, Key) -> | |
gen_server:cast(Pid, {delete, Key}). | |
%%-------------------------------------------------------------------- | |
%% @doc get_keys/1 permet de récupérer la liste des clés. | |
%% @end | |
%%-------------------------------------------------------------------- | |
get_keys(Pid) -> | |
gen_server:call(Pid, get_keys). | |
%%-------------------------------------------------------------------- | |
%% @doc get_values/1 permet de récupérer la liste des valeurs. | |
%% @end | |
%%-------------------------------------------------------------------- | |
get_values(Pid) -> | |
gen_server:call(Pid, get_values). | |
%%-------------------------------------------------------------------- | |
%% @doc get/2 permet de récupéré une valeur associée à un clé. | |
%% @end | |
%%-------------------------------------------------------------------- | |
get(Pid, Key) -> | |
gen_server:call(Pid, {get, Key}). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%%%------------------------------------------------------------------- | |
%%% @doc cache_event est un module permettant de montrer le | |
%%% fonctionnement d'un event handler utilisant le behaviour | |
%%% gen_event. | |
%%% @end | |
%%%------------------------------------------------------------------- | |
-module(cache_event). | |
-behaviour(gen_event). | |
-export([init/1]). | |
-export([handle_event/2]). | |
%%-------------------------------------------------------------------- | |
%% @doc init/1 est un callback obligatoire. Dans ce cas, il configure | |
%% simplement l'état avec une liste nulle | |
%% @end | |
%%-------------------------------------------------------------------- | |
init(_) -> | |
{ok, []}. | |
%%-------------------------------------------------------------------- | |
%% @doc handle_event/2 récupère un évènement et affiche simplement un | |
%% message sur la sortie standard | |
%% @end | |
%%-------------------------------------------------------------------- | |
handle_event(Event, State) -> | |
io:format("receive: ~p~n", [Event]), | |
{ok, State}. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-module(cache_SUITE). | |
-compile(export_all). | |
-include_lib("common_test/include/ct.hrl"). | |
suite() -> | |
[]. | |
init_per_suite(_Config) -> | |
c:c(cache), | |
c:c(cache_sup), | |
c:c(cache_event), | |
[]. | |
end_per_suite(_Config) -> | |
ok. | |
init_per_testcase(cache, Config) -> | |
io:format("ta mere!"), | |
{ok, Pid} = gen_server:start(cache, [], []), | |
[{pid, Pid}|Config]; | |
init_per_testcase(cache_event, Config) -> | |
{ok, Pid} = gen_event:start(), | |
[{pid, Pid}|Config]; | |
init_per_testcase(cache_sup, Config) -> | |
{ok, Pid} = supervisor:start_link(cache_sup, []), | |
[{pid, Pid}|Config]. | |
end_per_testcase(cache, Config) -> | |
Pid = proplists:get_value(pid, Config), | |
gen_server:stop(Pid); | |
end_per_testcase(cache_event, Config) -> | |
Pid = proplists:get_value(pid, Config), | |
gen_event:stop(Pid); | |
end_per_testcase(cache_sup, Config) -> | |
Pid = proplists:get_value(pid, Config), | |
gen_server:stop(Pid). | |
all() -> | |
[cache, cache_event, cache_sup]. | |
cache(Config) -> | |
Pid = proplists:get_value(pid, Config), | |
ok = cache:add(Pid, cle, value), | |
value = cache:get(Pid, cle), | |
ok = cache:delete(Pid, cle), | |
undefined = cache:get(Pid, cle), | |
ok. | |
cache_event(Config) -> | |
Pid = proplists:get_value(pid, Config), | |
gen_event:add_handler(Pid, cache_event, []), | |
[cache_event] = gen_event:which_handlers(Pid), | |
ok. | |
cache_sup(Config) -> | |
Pid = proplists:get_value(pid, Config), | |
Counter = supervisor:count_children(Pid), | |
2 = proplists:get_value(specs, Counter), | |
2 = proplists:get_value(active, Counter), | |
0 = proplists:get_value(supervisors, Counter), | |
2 = proplists:get_value(workers, Counter), | |
{ok, #{ id := cache }} = supervisor:get_childspec(Pid, cache), | |
{ok, #{ id := cache_event }} = supervisor:get_childspec(Pid, cache_event). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%%%------------------------------------------------------------------- | |
%%% @doc cache_sup permet de superviser le module cache et un | |
%%% gestionnaire d'évènement. | |
%%% @end | |
%%%------------------------------------------------------------------- | |
-module(cache_sup). | |
-behaviour(supervisor). | |
-export([init/1, start_link/0]). | |
%%-------------------------------------------------------------------- | |
%% @doc start_link/0 se base sur la fonction supervisor:start_link/2 | |
%% pour démarrer un processus basé sur le module cache_sup. | |
%% @end | |
%%-------------------------------------------------------------------- | |
start_link() -> | |
supervisor:start_link(?MODULE, []). | |
%%-------------------------------------------------------------------- | |
%% @doc init/1 est un callback obligatoire. Dans ce cas là, 2 enfants | |
%% sont créés, un pour cache_event et un autre pour le module cache. | |
%% @end | |
%%-------------------------------------------------------------------- | |
init(_Args) -> | |
SupervisorConf = #{ strategy => one_for_one, | |
intensity => 1, | |
period => 5 }, | |
EventStart = {gen_event, start_link, [{local, cache_event}, []]}, | |
EventSpec = #{ id => cache_event, start => EventStart }, | |
CacheStart = {gen_server, start_link, [{local, cache}, cache, [], []]}, | |
CacheSpec = #{ id => cache, start => CacheStart }, | |
{ok, {SupervisorConf, [EventSpec, CacheSpec]}}. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%%%------------------------------------------------------------------- | |
%%% @doc | |
%%% @end | |
%%%------------------------------------------------------------------- | |
-module(exemple_server). | |
-export([start/0, start/1, start/2]). | |
-export([start_link/0, start_link/1, start_link/2]). | |
-export([init/1, terminate/2]). | |
-export([handle_cast/2, handle_call/3, handle_info/2]). | |
%%-------------------------------------------------------------------- | |
%% @doc start/1 | |
%% @end | |
%%-------------------------------------------------------------------- | |
start() -> | |
start([]). | |
%%-------------------------------------------------------------------- | |
%% @doc start/2 | |
%% @end | |
%%-------------------------------------------------------------------- | |
start(Arguments) -> | |
start(Arguments, []). | |
%%-------------------------------------------------------------------- | |
%% @doc start/3 | |
%% @end | |
%%-------------------------------------------------------------------- | |
start(Arguments, Options) -> | |
gen_server:start(?MODULE, Arguments, Options). | |
%%-------------------------------------------------------------------- | |
%% @doc start_link/1 | |
%% @end | |
%%-------------------------------------------------------------------- | |
start_link() -> | |
start_link([]). | |
%%-------------------------------------------------------------------- | |
%% @doc start_link/1 | |
%% @end | |
%%-------------------------------------------------------------------- | |
start_link(Arguments) -> | |
start_link(Arguments, []). | |
%%-------------------------------------------------------------------- | |
%% @doc start_link/2 | |
%% @end | |
%%-------------------------------------------------------------------- | |
start_link(Arguments, Options) -> | |
gen_server:start_link(?MODULE, Arguments, Options). | |
%%-------------------------------------------------------------------- | |
%% @doc init/1 | |
%% @end | |
%%-------------------------------------------------------------------- | |
init(Arguments) -> | |
io:format("Argument: ~p~n", [Arguments]), | |
{ok, Arguments}. | |
%%-------------------------------------------------------------------- | |
%% @doc terminate/2 | |
%% @end | |
%%-------------------------------------------------------------------- | |
terminate(Raison, Etat) -> | |
io:format("arret raison: ~p~n", [Raison]), | |
io:format("arret etat: ~p~n", [Etat]), | |
ok. | |
%%-------------------------------------------------------------------- | |
%% @doc handle_cast/2 | |
%% @end | |
%%-------------------------------------------------------------------- | |
handle_cast(Message, Etat) -> | |
io:format("cast message: ~p~n", [Message]), | |
io:format("cast etat: ~p~n", [Etat]), | |
{noreply, Etat}. | |
%%-------------------------------------------------------------------- | |
%% @doc handle_cast/3 | |
%% @end | |
%%-------------------------------------------------------------------- | |
handle_call(Message, From, Etat) -> | |
io:format("call message: ~p~n", [Message]), | |
io:format("call from: ~p~n", [From]), | |
io:format("call etat: ~p~n", [Etat]), | |
{reply, {Message, From, Etat}, Etat}. | |
%%-------------------------------------------------------------------- | |
%% @doc handle_info/2 | |
%% @end | |
%%-------------------------------------------------------------------- | |
handle_info(Message, Etat) -> | |
io:format("info message: ~p~n", [Message]), | |
io:format("info etat: ~p~n", [Etat]), | |
{noreply, Etat}. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%%%------------------------------------------------------------------- | |
%%% @doc exemple_statem permet de montrer l'utilisation du behaviour | |
%%% gen_statem en implémentant un interrupteur. Une implémentation | |
%%% similaire est donnée dans la documentation officielle. | |
%%% @end | |
%%%------------------------------------------------------------------- | |
-module(exemple_statem). | |
-export([init/1, terminate/3]). | |
-export([callback_mode/0]). | |
-export([handle_event/4]). | |
-export([start/1, start/2, start/0, start/3]). | |
-export([start_link/1, start_link/2, start_link/0, start_link/3]). | |
-export([appuyer/1, lampe/1]). | |
%%-------------------------------------------------------------------- | |
%% @doc start/0 est une fonction pour simplifié le démarrage. Elle se | |
%% base sur start/1. | |
%% @end | |
%% -------------------------------------------------------------------- | |
start() -> | |
start([], []). | |
%%-------------------------------------------------------------------- | |
%% @doc start/1 est une fonction pour simplifié le démarrage et se | |
%% base sur start/2 avec des options par défaut. | |
%% @end | |
%% -------------------------------------------------------------------- | |
start(Arguments) -> | |
start(Arguments, []). | |
%%-------------------------------------------------------------------- | |
%% @doc start/2 est une fonction qui s'appuie sur gen_statem:start/3 | |
%% pour démarrer le module exemple_statem. | |
%% @end | |
%% -------------------------------------------------------------------- | |
start(Arguments, Options) -> | |
gen_statem:start(?MODULE, Arguments, Options). | |
%%-------------------------------------------------------------------- | |
%% @doc start/3 est une fonction qui s'appuie sur gen_statem:start/4, | |
%% permettant de démarrer un processus enregistré localement. C'est à | |
%% dire qu'un autre processus avec le même nom peut-être lancé sur un | |
%% autre noeud du cluster. | |
%% @end | |
%%-------------------------------------------------------------------- | |
start(Nom, Arguments, Options) -> | |
gen_statem:start({local, Nom}, Arguments, Options). | |
%%-------------------------------------------------------------------- | |
%% @doc start_link/0 est une fonction pour simplifier le démarrer de | |
%% exemple_statem en créant un lien. Cette fonction s'appuie sur | |
%% start_link/1. | |
%% @end | |
%% -------------------------------------------------------------------- | |
start_link() -> | |
start_link([]). | |
%%-------------------------------------------------------------------- | |
%% @doc start_link/1 est une fonction pour simplifier le démarrer de | |
%% exemple_statem en créant un lien. Cette fonction s'appuie sur | |
%% start_link/2. | |
%% @end | |
%%-------------------------------------------------------------------- | |
start_link(Arguments) -> | |
start_link(Arguments, []). | |
%%-------------------------------------------------------------------- | |
%% @doc start_link/2 s'appuie sur la fonctio gen_statem:start_link/3 | |
%% pour démarrer le module exemple_statem pour créer un lien entre le | |
%% processus qui le démarre et celui créé. | |
%% @end | |
%%-------------------------------------------------------------------- | |
start_link(Arguments, Options) -> | |
gen_statem:start_link(?MODULE, Arguments, Options). | |
%%-------------------------------------------------------------------- | |
%% @doc start_link/3 s'appuie sur la fonction gen_statem:start_link/4 | |
%% et permet de démarrer un processus nommé au sein d'un cluster de | |
%% noeud. | |
%% @end | |
%% -------------------------------------------------------------------- | |
start_link(Nom, Arguments, Options) -> | |
gen_statem:start_link({local, Nom}, Arguments, Options). | |
%%-------------------------------------------------------------------- | |
%% @doc init/1 permet d'initialiser l'état du processus ainsi que les | |
%% données associées. Cette fonction est équivalent à un constructeur | |
%% en orienté objet. | |
%% @end | |
%%-------------------------------------------------------------------- | |
init(_Arguments) -> | |
io:format("interrupteur ouvert~n"), | |
{ok, ouvert, eteint}. | |
%%-------------------------------------------------------------------- | |
%% @doc terminate/3 permet de "détruire" le processus. Équivalent à un | |
%% destructeur en orienté objet. | |
%% @end | |
%%-------------------------------------------------------------------- | |
terminate(Raison, Etat, Donnee) -> | |
io:format("interrupteur détruit.~n"), | |
io:format("raison: ~p~n", [Raison]), | |
io:format("état: ~p~n", [Etat]), | |
io:format("lampe: ~p~n", [Donnee]), | |
ok. | |
%%-------------------------------------------------------------------- | |
%% @doc callback_mode/0 est un callback obligatoire permettant de | |
%% définir le fonction du module basé sur le behaviour gen_statem. | |
%% @end | |
%%-------------------------------------------------------------------- | |
callback_mode() -> [handle_event_function]. | |
%%-------------------------------------------------------------------- | |
%% @doc handle_event/4 est une fonction utilisé pour récupéré les | |
%% différents évènements envoyé sur le processus. Ce callback est | |
%% défini ici due au mode du callback définis dans callback_mode/0. | |
%% @end | |
%%-------------------------------------------------------------------- | |
handle_event(cast, appuyer, ferme, allume) -> | |
io:format("lampe éteinte.~n"), | |
{next_state, ouvert, eteint}; | |
handle_event(cast, appuyer, ouvert, eteint) -> | |
io:format("lampe allumée.~n"), | |
{next_state, ferme, allume}; | |
handle_event({call, From}, lampe, _Etat, Donnee) -> | |
{keep_state, Donnee, [{reply, From, Donnee}]}; | |
handle_event(TypeEvenement, Evenement, Etat, Donnee) -> | |
io:format("Type évènement: ~p~n", [TypeEvenement]), | |
io:format("Contenu évènement: ~p~n", [Evenement]), | |
io:format("État: ~p~n", [Etat]), | |
io:format("État (données) processus: ~p~n", [Donnee]), | |
{keep_state, Donnee}. | |
%%-------------------------------------------------------------------- | |
%% @doc appuyer/1 est une fonction exporté servant d'API. Elle se base | |
%% sur la fonction gen_statem:cast/2 pour envoyer un message au | |
%% processus. | |
%% @end | |
%% -------------------------------------------------------------------- | |
appuyer(Pid) -> | |
gen_statem:cast(Pid, appuyer). | |
%%-------------------------------------------------------------------- | |
%% @doc tout comme appuyer/1, cette fonction est exporté et sert d'API | |
%% pour envoyer un message basé sur gen_statem:call/3. | |
%% @end | |
%% -------------------------------------------------------------------- | |
lampe(Pid) -> | |
gen_statem:call(Pid, lampe, 1000). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-module(exemple_SUITE). | |
-compile(export_all). | |
-include_lib("common_test/include/ct.hrl"). | |
suite() -> | |
[]. | |
init_per_suite(Config) -> | |
c:c(exemple_server), | |
c:c(exemple_statem), | |
c:c(exemple_event), | |
c:c(exemple_supervisor), | |
[]. | |
end_per_suite(Config) -> | |
ok. | |
init_per_testcase(server, Config) -> | |
{ok, Pid} = gen_server:start(exemple_server, [], []), | |
[{pid, Pid}|Config]; | |
init_per_testcase(statem, Config) -> | |
{ok, Pid} = gen_statem:start(exemple_statem, [], []), | |
[{pid, Pid}|Config]; | |
init_per_testcase(event, Config) -> | |
{ok, Pid} = gen_event:start(), | |
gen_event:add_handler(Pid, exemple_event, test), | |
[{pid, Pid}|Config]; | |
init_per_testcase(supervisor, Config) -> | |
{ok, Pid} = supervisor:start_link(exemple_supervisor, []), | |
[{pid, Pid}|Config]. | |
end_per_testcase(server, Config) -> | |
Pid = proplists:get_value(pid, Config), | |
gen_server:stop(Pid); | |
end_per_testcase(statem, Config) -> | |
Pid = proplists:get_value(pid, Config), | |
gen_statem:stop(Pid); | |
end_per_testcase(event, Config) -> | |
Pid = proplists:get_value(pid, Config), | |
gen_event:stop(Pid); | |
end_per_testcase(supervisor, Config) -> | |
Pid = proplists:get_value(pid, Config), | |
gen_server:stop(Pid). | |
all() -> | |
[server, statem, event, supervisor]. | |
server(Config) -> | |
Pid = proplists:get_value(pid, Config), | |
ok = gen_server:cast(Pid, message), | |
{message, _, _} = gen_server:call(Pid, message). | |
event(Config) -> | |
Pid = proplists:get_value(pid, Config), | |
ok = gen_event:notify(Pid, test). | |
statem(Config) -> | |
Pid = proplists:get_value(pid, Config), | |
eteint = exemple_statem:lampe(Pid), | |
ok = exemple_statem:appuyer(Pid), | |
allume = exemple_statem:lampe(Pid), | |
ok = exemple_statem:appuyer(Pid), | |
eteint = exemple_statem:lampe(Pid). | |
supervisor(Config) -> | |
Pid = proplists:get_value(pid, Config), | |
Counter = supervisor:count_children(Pid), | |
2 = proplists:get_value(specs, Counter), | |
2 = proplists:get_value(active, Counter), | |
0 = proplists:get_value(supervisors, Counter), | |
2 = proplists:get_value(workers, Counter), | |
{ok, #{ id := exemple_server }} = supervisor:get_childspec(Pid, exemple_server), | |
{ok, #{ id := exemple_statem }} = supervisor:get_childspec(Pid, exemple_statem). | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%%%------------------------------------------------------------------- | |
%%% @doc exemple_supervisor permet de démarrer 2 processus, | |
%%% exemple_statem et exemple_server. La stratégie utilisé est | |
%%% one_for_one, si un des 2 processus crash, il sera alors redémarré | |
%%% automatiquement. | |
%%% @end | |
%%%------------------------------------------------------------------- | |
-module(exemple_supervisor). | |
-export([init/1]). | |
-export([start_link/0]). | |
%%-------------------------------------------------------------------- | |
%% @doc start_link/0 permet d'offrir une facilité de démarrage. Pour | |
%% l'exécuter et démarrer ce module, rien de plus simple que de faire | |
%% exemple_supervisor:start_link(). | |
%% @end | |
%%-------------------------------------------------------------------- | |
start_link() -> | |
supervisor:start_link(?MODULE, []). | |
%%-------------------------------------------------------------------- | |
%% @doc init/1 est un callback utilisé pour configuré le | |
%% superviseur. Il permet de configuré la spécification du superviseur | |
%% ainsi que la liste des spécifications des enfants à superviser. | |
%% @end | |
%%-------------------------------------------------------------------- | |
init(Arguments) -> | |
SupervisorConf = #{ strategy => one_for_one, | |
intensity => 1, | |
period => 5 }, | |
SpecStatem = #{ id => exemple_statem | |
, start => {exemple_statem, start_link, []}}, | |
SpecServer = #{ id => exemple_server | |
, start => {exemple_server, start_link, []}}, | |
{ok, {SupervisorConf, [SpecStatem, SpecServer]}}. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment