From 897468be6fa01ab87f38189f2daf266f3289c9fb Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Sun, 2 Mar 2008 19:38:35 +0000 Subject: [PATCH] MOD avancement dans les conversations (il reste la partie JS) --- doc/protocole2.txt | 23 +- modules/erl/euphorik_minichat.erl | 78 ++++-- .../erl/euphorik_minichat_conversation.erl | 236 +++++++++++------- modules/erl/euphorik_protocole.erl | 128 +++++----- modules/erl/euphorik_requests.erl | 24 +- sessions/erl.session | 50 ++-- 6 files changed, 310 insertions(+), 229 deletions(-) diff --git a/doc/protocole2.txt b/doc/protocole2.txt index f691780..22bebcc 100644 --- a/doc/protocole2.txt +++ b/doc/protocole2.txt @@ -95,20 +95,21 @@ Page peut dernierMessageId est en base 36 (l'histoire de rigoler un peu) c -> s - - LKJDLAKSJBFLKASN - 10 - - RE - 6ZR - 1 - - - + + LKJDLAKSJBFLKASN + 10 + 6ZR + 1 + + RE + 1 + + + s -> c - + true Hier 17:26:54 diff --git a/modules/erl/euphorik_minichat.erl b/modules/erl/euphorik_minichat.erl index a7d267c..a507027 100755 --- a/modules/erl/euphorik_minichat.erl +++ b/modules/erl/euphorik_minichat.erl @@ -12,15 +12,17 @@ messages/1, messages/2, messages/3, - get_messages_depuis_ids/1, + message_by_id/1, + messages_by_ids/1, reponses/0, repond_a/1, - get_nb_page/1, + nb_page/1, users/0, - get_user_by_cookie/1, - get_user_by_id/1, - get_user_by_login/1, - get_user_by_login_password/2, + user_by_cookie/1, + user_by_id/1, + user_by_login/1, + user_by_login_password/2, + user_by_mess/1, possede_message/2, a_repondu_a_message/2, est_une_reponse_a_user/2, @@ -70,7 +72,7 @@ reset() -> % Est-ce qu'un utilisateur existe en fonction de son cookie ? % Renvoie {ok, User} ou erreur -get_user_by_cookie(Cookie) -> +user_by_cookie(Cookie) -> resultat_transaction(mnesia:transaction( fun() -> Users = qlc:e(qlc:q([E || E <- mnesia:table(user), E#user.cookie =:= Cookie])), @@ -82,7 +84,7 @@ get_user_by_cookie(Cookie) -> )). -get_user_by_id(ID) -> +user_by_id(ID) -> resultat_transaction(mnesia:transaction( fun() -> Users = qlc:e(qlc:q([E || E <- mnesia:table(user), E#user.id =:= ID])), @@ -94,7 +96,7 @@ get_user_by_id(ID) -> )). -get_user_by_login(Login) -> +user_by_login(Login) -> resultat_transaction(mnesia:transaction( fun() -> Users = qlc:e(qlc:q([E || E <- mnesia:table(user), E#user.login =:= Login])), @@ -106,7 +108,7 @@ get_user_by_login(Login) -> )). -get_user_by_login_password(Login, Password) -> +user_by_login_password(Login, Password) -> resultat_transaction(mnesia:transaction( fun() -> Users = qlc:e(qlc:q([E || E <- mnesia:table(user), E#user.login =:= Login, E#user.password =:= Password])), @@ -115,12 +117,24 @@ get_user_by_login_password(Login, Password) -> _ -> erreur end end + )). + + +% Renvoie {ok, User} où User est un #user possédant le message donné. +user_by_mess(Id) -> + resultat_transaction(mnesia:transaction( + fun() -> + case qlc:e(qlc:q([U || U <- mnesia:table(user), M <- mnesia:table(minichat), M#minichat.id =:= Id, M#minichat.auteur_id =:= U#user.id])) of + [User] -> {ok, User}; + _ -> erreur + end + end )). % Renvoie l'utilisateur root -get_root() -> - {ok, User} = get_user_by_id(0), +root() -> + {ok, User} = user_by_id(0), User. @@ -184,9 +198,9 @@ update_pseudo_user(UserId, Pseudo) -> set_profile(Cookie, Login, Password, Pseudo, Email, Css) -> resultat_transaction(mnesia:transaction( fun() -> - case get_user_by_cookie(Cookie) of + case user_by_cookie(Cookie) of {ok, User} -> - case get_user_by_login(Login) of + case user_by_login(Login) of {ok, U} when U#user.id =/= User#user.id -> login_deja_pris; _ -> @@ -223,7 +237,7 @@ update_date_derniere_connexion(UserId) -> % Ajoute un nouveau user et le renvoie nouveau_user(Pseudo, Cookie) -> F = fun() -> - Id = get_nouvel_id(user), + Id = nouvel_id(user), User = #user{id = Id, cookie = Cookie, pseudo = Pseudo, date_creation = now(), date_derniere_connexion = now()}, mnesia:write(User), User @@ -234,7 +248,7 @@ nouveau_user(Pseudo, Cookie) -> % Ajoute un nouveau user et le renvoie nouveau_user(Login, Password, Cookie) -> F = fun() -> - Id = get_nouvel_id(user), + Id = nouvel_id(user), User = #user{id = Id, cookie = Cookie, pseudo = Login, login = Login, password = Password, date_creation = now(), date_derniere_connexion = now()}, mnesia:write(User), User @@ -256,7 +270,7 @@ nouveau_message(Mess, Auteur_id, Repond_A) -> if Nb_id_trouve =/= length(Repond_A) -> throw("Un ou plusieurs messages introuvable"); true -> ok end, - Id = get_nouvel_id(minichat), + Id = nouvel_id(minichat), % compare les dernière Delta = delta_date_ms(Auteur#user.date_derniere_connexion, now()), Nouvel_indice_flood = Auteur#user.indice_flood + if Delta =< ?DUREE_SPAM -> 2; true -> -1 end, @@ -266,7 +280,7 @@ nouveau_message(Mess, Auteur_id, Repond_A) -> }, % est-ce que l'auteur à trop floodé ? if Auteur#user.indice_flood =/= ?INDICE_SPAM_MAX, Auteur_maj#user.indice_flood =:= ?INDICE_SPAM_MAX, Delta =< ?DUREE_BLOCAGE_SPAM -> - Root = get_root(), + Root = root(), mnesia:write(Auteur#user{indice_flood = Auteur_maj#user.indice_flood}), mnesia:write(#minichat{id=Id, auteur_id=Root#user.id, date=now(), pseudo=Root#user.pseudo, contenu=Auteur#user.pseudo ++ "(" ++ Auteur#user.login ++ ") est bloqué pour " ++ integer_to_list(trunc(?DUREE_BLOCAGE_SPAM / 1000)) ++ " secondes pour cause de flood.."}), Id; @@ -296,7 +310,7 @@ inserer_reponses(_, []) -> % Renvoie un nouvel id pour une table donnée -get_nouvel_id(Table) -> +nouvel_id(Table) -> mnesia:dirty_update_counter(counter, Table, 1). @@ -325,13 +339,25 @@ messages(N) -> messages(N, 1). +% Renvoie {ok, #minichat} (voir #minichat de euphorik_bd.hrl) à partir de son id. +message_by_id(Id) -> + case resultat_transaction(mnesia:transaction( + fun() -> + qlc:e(qlc:q([E || E <- qlc:keysort(2, mnesia:table(minichat), [{order, ascending}]), Id =:= E#minichat.id])) + end + )) of + [M] -> {ok, M}; + _ -> erreur + end. + + % Renvoie une liste de message (voir #minichat de euphorik_bd.hrl) à partir d'une liste d'id (Ids). -get_messages_depuis_ids(Ids) -> +messages_by_ids(Ids) -> resultat_transaction(mnesia:transaction( fun() -> % TODO : optimisations ? serait-ce du O(n) ? Query = qlc:q([E || E <- qlc:keysort(2, mnesia:table(minichat), [{order, ascending}]), lists:any(fun(Id) -> Id =:= E#minichat.id end, Ids)]), - io:format("~s~n", [qlc:info(Query)]), + %io:format("~s~n", [qlc:info(Query)]), qlc:e(Query) end )). @@ -339,17 +365,17 @@ get_messages_depuis_ids(Ids) -> % Renvoie le nombre de page total en fonction du nombre de message par page N % TODO : ya pas un moyen moins pourri pour avoir le nombre de record d'une table ? -get_nb_page(N) -> +nb_page(N) -> resultat_transaction(mnesia:transaction(fun() -> ceiling(length(qlc:e(qlc:q([E#minichat.id || E <- mnesia:table(minichat)]))) / N) end)). % Renvoie le numéro de la page sur lequel se trouve le message M en sachant qu'il y a N messages par page. -page(M, N) -> - resultat_transaction(mnesia:transaction(fun() -> - ceiling((length(qlc:e(qlc:q([E || E <- mnesia:table(minichat), E#minichat.id >= M])))) / N) - end)). +%~ page(M, N) -> + %~ resultat_transaction(mnesia:transaction(fun() -> + %~ ceiling((length(qlc:e(qlc:q([E || E <- mnesia:table(minichat), E#minichat.id >= M])))) / N) + %~ end)). % Bizarre, cette fonction n'existe pas dans la stdlib. diff --git a/modules/erl/euphorik_minichat_conversation.erl b/modules/erl/euphorik_minichat_conversation.erl index 42412c6..0c762fb 100755 --- a/modules/erl/euphorik_minichat_conversation.erl +++ b/modules/erl/euphorik_minichat_conversation.erl @@ -14,106 +14,165 @@ -import(euphorik_minichat, [resultat_transaction/1]). -import(qlc, [e/1, q/1, keysort/3]). -import(mnesia, [table/1, transaction/1]). --compile(export_all). - +-export([conversations/4]). -% Renvoie la liste des cibles d'un message M, c'est à dire des messages auquel M répond. N étant le nombre de message par page et -% P la page à laquelle se limite la recherche. -% Voir 'conversation/2' pour plus de détail sur la structure retournée. -%~ get_liste_cibles(M, N, P) -> - %~ resultat_transaction(mnesia:transaction(fun() -> - %~ Cibles = qlc:e(qlc:q([E#reponse_minichat.cible || E <- mnesia:table(reponse_minichat), E#reponse_minichat.repondant =:= M])), - %~ lists:foldl( - %~ fun(E, A) -> - %~ PageE = page(E, N), - %~ if PageE =:= P -> % si E fait partit de la page de l'élément de base alors on le prend - %~ [{E, get_liste_cibles(E, N, P)}| A]; - %~ true -> - %~ A - %~ end - %~ end, [], Cibles) - %~ end)). - -tester(Racines, N, D, P) -> - io:format("~w~n", [conversations(Racines, N, D, P)]). - -% Crée un process représentant le minichat, renvoie un tuple {Pid, Conversations} -start(Racines, N, D, P) -> - {mise_en_forme_conversations(loop(conversations(Racines, N, D, P))), conversations(Racines, N, D, P)}. - -% Attend pour d'autres messages. -wait(Pid) -> - Pid ! {wait, self()}, - receive - {nouveau, Message} -> Message +% Renvoie les conversations sous la forme d'une liste de conversation. +% Chaque conversation est un tuple {[{Message, Parents}], Plus} où +% Message est le message de type #minichat et Parents une liste d'Id. +% Plus est un bool. Si Plus vaut true alors il y a encore des messages. +% Si il n'y a pas de nouveaux message alors la fonction est bloquante et attend un nouveau message. +conversations(Racines, N, D, P) -> + % écoute des nouveaux messages + case subscribe(minichat, 2) of + erreur = E -> + E; + _ -> + % demande des conversations + Conversations = conversations_detailees(Racines, N, D, P), + %io:format("~p~n", [Conversations]), + % si les conversations sont vides alors on attend un nouveau message + Vide = not lists:any( + fun(C) -> + case C of + {[], _} -> false; + {_, [], _, _} -> false; + _ -> true + end + end, + Conversations + ), + Conversations_mises_en_forme = mise_en_forme_conversations( + if Vide -> + attend_nouveau_message(), + conversations_detailees(Racines, N, D, P); + true -> + Conversations + end + ), + unsubscribe(minichat), + Conversations_mises_en_forme end. +% Ecoute les événements de modification d'une table. +subscribe(_Table, 0) -> + erreur; +subscribe(Table, C) -> + case mnesia:subscribe({table, Table, simple}) of + {error, {not_active_local, Table}} -> + mnesia:add_table_copy(minichat, node(), ram_copies), + subscribe(Table, C - 1); + {error, _}-> + erreur; + _ -> + ok + end. + + +% Arrête d'écouter les modifications d'une table. +unsubscribe(Table) -> + mnesia:unsubscribe({table, Table, simple}). + + +% Attend qu'un nouveau message arrive, function bloquante. +% Renvoie le nouveau message. +attend_nouveau_message() -> + %io:format(F, "En attente d'un message !~n", []), + receive % attente d'un post + {mnesia_table_event, {write, Message, _}} -> + Message; + %io:format(F, "Debloquage !~n", []), + %file:close(F); + %~ {tcp_closed, _} -> + %~ mnesia:unsubscribe({table, minichat, simple}); + _ -> + %io:format(F, "~p~n", [M]), + attend_nouveau_message() + % 60 minutes de timeout (le cas ou il n'y a que des consultations et jamais de post) + % Après 60 minutes de connexion, le client doit donc reétablir une connexion + % TODO : pour être mieux : quand le socket se ferme alors un message devrait être envoyé et débloquer ce receive (demande en cours sur la mailing list de yaws) + after 1000 * 60 * 60 -> + timeout + end. + % Mise en forme des conversations pour l'utilisateur du module. mise_en_forme_conversations([]) -> []; -mise_en_forme_conversations([Principale | Conversations]) -> - [mise_en_forme_conversation(Principale), lists:map(fun({_, Cn, _}) -> mise_en_forme_conversation(Cn) end, Conversations)]. +mise_en_forme_conversations([{Principale, Plus_principale} | Conversations]) -> + [{mise_en_forme_conversation(Principale), Plus_principale} | lists:map(fun({_, Cn, _, Plus}) -> {mise_en_forme_conversation(Cn), Plus} end, Conversations)]. -% Mise en forme d'une liste d'id de message : [4, 5, 8, ...]. -mise_en_forme_conversation(Messages) -> - lists:map(fun(M) -> {euphorik_minichat:get_messages_depuis_ids(), get_parents(M)} end, Messages). - -loop(Conversations) -> - receive - {wait, Pid} -> - Pid ! {nouveau, attends_nouveaux_messages()} - end, - loop(Conversations). +% Mise en forme d'une liste d'id de messages : [4, 5, 8, ...]. +mise_en_forme_conversation(Messages) -> + lists:map( + fun(Id) -> + {ok, Message} = euphorik_minichat:message_by_id(Id), + {Message, parents(Id)} + end, + Messages + ). % Renvoie une liste de conversations, le première élément correspond à la conversation principale. % Les autres éléments sont des tuples {C, Cn, X}, voir conversation/4 pour plus d'infos. % Racines est une liste de tuple {Id, P} des racines des conversations ou P est la page et Id l'id du message. -conversations(Racines, N, D, P) -> +conversations_detailees(Racines, N, D, P) -> Conversations = map(fun({Racine, P_conv}) -> conversation(Racine, N, D, P_conv) end, Racines), Conversation_principale = resultat_transaction(transaction(fun() -> Curseur = qlc:cursor(q([E#minichat.id || E <- qlc:sort(table(minichat), [{order, descending}])])), - CP2 = get_conversation_principale(Curseur, Conversations, N, P), + {CP, Plus} = conversation_principale(Curseur, Conversations, N, P), qlc:delete_cursor(Curseur), - CP2 + {reverse([M || M <- CP, M > D]), Plus} % filtre en fonction de D end)), - [reverse(Conversation_principale) | Conversations]. + [Conversation_principale | Conversations]. % Construit la conversation principale en fonction d'un curseur C initialement placé sur le dernier message % et la liste de conversations. % N est le nombre de messages que l'on souhaite. % P est le numéro de la page (1, 2, 3...) -get_conversation_principale(C, Conversations, N, P) -> - get_conversation_principale2(C, lists:flatten(map(fun({C2, _, X}) -> C2 -- X end, Conversations)), N, (P - 1) * N). +% Renvoie {[Id], Plus} +conversation_principale(C, Conversations, N, P) -> + CP = conversation_principale2(C, lists:flatten(map(fun({C2, _, X, _}) -> C2 -- X end, Conversations)), N + 1, (P - 1) * N), + Plus = length(CP) =:= N + 1, + { + if Plus -> + [_| Suivants] = CP, + Suivants; + true -> + CP + end, + Plus + }. + + % C est le curseur (voir ci dessus) % 'Messages' sont les messages que l'on doit enlever de la conversation % S est le nombre de messages qu'il faut sauter -get_conversation_principale2(_, _, 0, _) -> +conversation_principale2(_, _, 0, _) -> []; -get_conversation_principale2(C, Messages, N, S) -> +conversation_principale2(C, Messages, N, S) -> case qlc:next_answers(C, 1) of [] -> []; [M] -> % traitement message par message (pas des plus performant :/) %io:format("M: ~p~n", [M]), Doit_etre_saute = lists:any(fun(E) -> E == M end, Messages), if Doit_etre_saute -> - get_conversation_principale2(C, Messages, N, S); % le message ne fait pas partie de la conversation + conversation_principale2(C, Messages, N, S); % le message ne fait pas partie de la conversation S =:= 0 -> - [M | get_conversation_principale2(C, Messages, N - 1, S)]; % ok : le message fait partie de la conversation + [M | conversation_principale2(C, Messages, N - 1, S)]; % ok : le message fait partie de la conversation true -> - get_conversation_principale2(C, Messages, N, S - 1) % on n'a pas encore atteint le début de la page + conversation_principale2(C, Messages, N, S - 1) % on n'a pas encore atteint le début de la page end end. -% Renvoie un tuple {C, Cn, X} où +% Renvoie un tuple {C, Cn, X, Plus} où % C : La conversation complète % Cn : La conversation tronqué en fonction de N, D et P % X : La liste des messages répondant à des mess qui ne font pas partie de la conversation +% Plus : true s'il y a encore des messages après % Inputs : % R : l'id d'un message représentant la racine de la conversation % N : le nombre de message par page @@ -121,18 +180,32 @@ get_conversation_principale2(C, Messages, N, S) -> % P : La page désirée conversation(R, N, D, P) -> {C, X} = conversation([], [R], []), - {reverse(C), reverse(filter(fun(E) -> E > D end, sublist(C, N*(P-1)+1, N))), reverse(X)}. + Decalage = N*(P-1)+1, + { + reverse(C), + if Decalage > length(C) -> + []; + true -> + reverse(filter( + fun(E) -> E > D end, + sublist(C, Decalage, N) + )) + end, + reverse(X), + Decalage + N - 1 < length(C) + }. % Renvoie un tuple {C, X} où C est la conversation complète et X les messages répondant à des mess qui ne font pas partie de la conversation -% Attention : les messages de C et de X sont ordrés du plus grand Id au plus petit +% Attention : les messages de C et de X sont ordrés du plus grand Id au plus petit. +% @spec conversation([integer()], [integer()], [integer()]) -> {} conversation(Messages, [M | Reste], X) -> Est_deja_traite = any(fun(E) -> E =:= M end, Messages), if Est_deja_traite -> conversation(Messages, Reste, X); true -> - Enfants = get_enfants(M), - Parents = get_parents(M), + Enfants = enfants(M), + Parents = parents(M), % un message est dit exiterne si un de ses parent ne fait pas partie de la conversation ou si un de ses parents fait partie de X Est_message_externe = Parents -- Messages =/= [] orelse intersection(Parents, X) =/= [], conversation([M | Messages], Reste ++ Enfants, if Est_message_externe -> [M | X]; true -> X end) @@ -143,55 +216,24 @@ conversation(Messages, [], X) -> % Renvoie les enfants d'un message M (les messages qui répondent à M) % ordrés du plus petit au plus grand. -get_enfants(M) -> +% @spec enfants(integer()) -> [integer()] +enfants(M) -> resultat_transaction(transaction(fun() -> e(q([E#reponse_minichat.repondant || E <- qlc:sort(table(reponse_minichat), [{order, ascending}]), E#reponse_minichat.cible =:= M])) end)). % Renvoie les parents d'un message M (les messages auquels répond M) -% ordrés du plus petit au plus grand. -get_parents(M) -> +% ordrés du plus petit au plus grand.. +% @spec parents(integer()) -> [integer()] +parents(M) -> resultat_transaction(transaction(fun() -> e(q([E#reponse_minichat.cible || E <- keysort(1, table(reponse_minichat), [{order, ascending}]), E#reponse_minichat.repondant =:= M])) end)). % Intersection entre deux listes : [1, 3, 4] n [2, 4, 7] = [4] +% @spec intersection(list(term()), list(term())) -> list(term()) intersection(L1, L2) -> lists:filter(fun(X) -> lists:member(X, L1) end, L2). - - -% Attend qu'au moins un nouveau message arrive, function bloquante. -% Renvoie un tuple {C, M} où C est une liste de numéro de conversation auquel appartient M et M l'Id du nouveau message -attends_nouveaux_messages() -> - case mnesia:subscribe({table, minichat, simple}) of - {error, _} = E -> E; - _ -> - %{ok, F} = file:open("/tmp/log_euphorik_" ++ pid_to_list(self()) ++ ".txt", [write]), - %io:format(F, "Test2~n", []), - attends_nouveaux_messages2() - end. -attends_nouveaux_messages2() -> - %io:format(F, "En attente d'un message !~n", []), - receive % attente d'un post - {mnesia_table_event, {write, _, _}} -> - mnesia:unsubscribe({table, minichat, simple}); - %io:format(F, "Debloquage !~n", []), - %file:close(F); - %~ {tcp_closed, _} -> - %~ mnesia:unsubscribe({table, minichat, simple}); - _ -> - %io:format(F, "~p~n", [M]), - attends_nouveaux_messages2() - % 60 minutes de timeout (le cas ou il n'y a que des consultations et jamais de post) - % Après 60 minutes de connexion, le client doit donc reétablir une connexion - % TODO : pour être mieux : quand le socket se ferme alors un message devrait être envoyé et débloquer ce receive (demande en cours sur la mailing list de yaws) - after 1000 * 60 * 60 -> - mnesia:unsubscribe({table, minichat, simple}) - end. - - - - - \ No newline at end of file + diff --git a/modules/erl/euphorik_protocole.erl b/modules/erl/euphorik_protocole.erl index 7b9423a..99eb300 100755 --- a/modules/erl/euphorik_protocole.erl +++ b/modules/erl/euphorik_protocole.erl @@ -20,8 +20,7 @@ ]). -include_lib("xmerl/include/xmerl.hrl"). -include("../include/euphorik_bd.hrl"). --include("../include/euphorik_defines.hrl"). -%-compile(export_all). +-include("../include/euphorik_defines.hrl"). % Génère un nouveau captchat dans ?DOSSIER_CAPTCHA @@ -30,8 +29,8 @@ generation_captcha(_) -> simple_xml_to_string(xml_reponse_generation_captcha(?DOSSIER_CAPTCHA_RELATIF "/" ++ Nom_fichier, Mot_crypt)). -% Un nouvel utilisateur doit être créé -% Action est un xmlElement() +% Un nouvel utilisateur doit être créé. +% Action est un xmlElement(). nouveau_user_captcha(Action) -> simple_xml_to_string( case {xmerl_xpath:string("captchaCrypt", Action), xmerl_xpath:string("captchaInput", Action)} of @@ -49,10 +48,12 @@ nouveau_user_captcha(Action) -> end ). + +% Une utilisateur s'enregistre avec un tuple {Login, Password}. nouveau_user_login(Action) -> {Login, Password, Login_deja_pris} = case {xmerl_xpath:string("login", Action), xmerl_xpath:string("password", Action)} of {[#xmlElement{content = [#xmlText{value = L}]}], [#xmlElement{content = [#xmlText{value = P}]}]} -> - {L, P, case euphorik_minichat:get_user_by_login(L) of {ok, _} -> true; _ -> false end}; + {L, P, case euphorik_minichat:user_by_login(L) of {ok, _} -> true; _ -> false end}; _ -> {[], [], false} end, simple_xml_to_string( @@ -66,15 +67,15 @@ nouveau_user_login(Action) -> ). -% Un utilisateur se logge +% Un utilisateur se logge. login(Action) -> case xmerl_xpath:string("cookie", Action) of [#xmlElement{content = [#xmlText{value = Cookie}]}] -> - loginUser(euphorik_minichat:get_user_by_cookie(Cookie)); + loginUser(euphorik_minichat:user_by_cookie(Cookie)); _ -> case {xmerl_xpath:string("login", Action), xmerl_xpath:string("password", Action)} of {[#xmlElement{content = [#xmlText{value = Login}]}], [#xmlElement{content = [#xmlText{value = Password}]}]} -> - loginUser(euphorik_minichat:get_user_by_login_password(Login, Password)); + loginUser(euphorik_minichat:user_by_login_password(Login, Password)); _ -> simple_xml_to_string(xml_reponse_login_pas_ok("XML malformé")) end @@ -138,61 +139,72 @@ refreshMessage(Action) -> Dernier_id = case xmerl_xpath:string("dernierMessageId", Action) of % l'id du dernier message que connait le client [#xmlElement{content = [#xmlText{value = D}]}] -> erlang:list_to_integer(D, 36); _ -> 0 - end, + end, User = case xmerl_xpath:string("cookie", Action) of [#xmlElement{content = [#xmlText{value = Cookie}]}] -> - case euphorik_minichat:get_user_by_cookie(Cookie) of + case euphorik_minichat:user_by_cookie(Cookie) of {ok, U} -> U; _ -> inconnu end; _ -> inconnu - end, - % accrochez-vous ca va siouxer ;) - Mess = lists:map( - fun(Mess) -> - Est_proprietaire = User =/= inconnu andalso User#user.id =:= Mess#minichat.auteur_id, - A_repondu_a_message = User =/= inconnu andalso euphorik_minichat:a_repondu_a_message(User#user.id, Mess#minichat.id), - Est_une_reponse_a_user = User =/= inconnu andalso euphorik_minichat:est_une_reponse_a_user(User#user.id, Mess#minichat.id), - User_mess = if Mess#minichat.auteur_id =:= 0 -> inconnu; true -> - {ok, U2} = euphorik_minichat:get_user_by_id(Mess#minichat.auteur_id), - U2 - end, - {message, [{id, erlang:integer_to_list(Mess#minichat.id, 36)}], - [ - {date, [], [format_date(Mess#minichat.date)]}, - {systeme, [], [atom_to_list(Mess#minichat.auteur_id =:= 0)]}, - {proprietaire, [], [atom_to_list(Est_proprietaire)]}, - {repondu, [], [atom_to_list(A_repondu_a_message)]}, - {reponse, [], [atom_to_list(Est_une_reponse_a_user)]}, - {pseudo, [], [Mess#minichat.pseudo]}, - {login, [], [if User_mess =:= inconnu -> Mess#minichat.pseudo; true -> User_mess#user.login end]}, - {contenu, [], [Mess#minichat.contenu]}, - {repondA, [], xml_repond_a(Mess#minichat.id)} - ] - } - end, - get_dernieres_messages(Dernier_id, Nb_message, Page) + end, + % extraction des conversations en [{id, page}, ..] + Conversations = lists:map( + fun(Conv) -> + [#xmlElement{content = [#xmlText{value = Id_racine_str}]}] = xmerl_xpath:string("racine", Conv), + [#xmlElement{content = [#xmlText{value = Page_conv_str}]}] = xmerl_xpath:string("page", Conv), + {erlang:list_to_integer(Id_racine_str, 36), erlang:list_to_integer(Page_conv_str)} + end, + xmerl_xpath:string("conversation", Action) ), + Poulpe = euphorik_minichat_conversation:conversations(Conversations, Nb_message, Dernier_id, Page), + io:format("Poulpe = ~p~n", [Poulpe]), + % accrochez-vous ca va siouxer ;) [{reponse, [{name, "refreshMessages"}], - % la fonction get_nb_page DOIT être évalué après get_dernieres_messages (merci les effets de bord) - [{nbPage, [], [integer_to_list(euphorik_minichat:get_nb_page(Nb_message))]} | Mess] + lists:map( + fun({Conv, Plus}) -> + {conversation, [], + [{autresPages, [], [atom_to_list(Plus)]} | + lists:map( + fun({Mess, Repond_a}) -> + Est_proprietaire = User =/= inconnu andalso User#user.id =:= Mess#minichat.auteur_id, + A_repondu_a_message = User =/= inconnu andalso euphorik_minichat:a_repondu_a_message(User#user.id, Mess#minichat.id), + Est_une_reponse_a_user = User =/= inconnu andalso euphorik_minichat:est_une_reponse_a_user(User#user.id, Mess#minichat.id), + User_mess = + if Mess#minichat.auteur_id =:= 0 -> + inconnu; + true -> + {ok, U2} = euphorik_minichat:user_by_id(Mess#minichat.auteur_id), + U2 + end, + {message, [{id, erlang:integer_to_list(Mess#minichat.id, 36)}], + [ + {date, [], [format_date(Mess#minichat.date)]}, + {systeme, [], [atom_to_list(Mess#minichat.auteur_id =:= 0)]}, + {proprietaire, [], [atom_to_list(Est_proprietaire)]}, + {repondu, [], [atom_to_list(A_repondu_a_message)]}, + {reponse, [], [atom_to_list(Est_une_reponse_a_user)]}, + {pseudo, [], [Mess#minichat.pseudo]}, + {login, [], [if User_mess =:= inconnu -> Mess#minichat.pseudo; true -> User_mess#user.login end]}, + {contenu, [], [Mess#minichat.contenu]}, + {repondA, [], xml_repond_a(Repond_a)} + ] + } + end, + Conv + ) + ] + } + end, + Poulpe + ) }]; _ -> [{reponse, [{name, "refreshMessages"}], [{erreur, [], ["erreur"]}]}] end ). - -% Renvoie les derniers messages, s'il n'y en a pas on effectue une attente. -get_dernieres_messages(Dernier_id, Nb_message, Page) -> - Messages = euphorik_minichat:messages(Dernier_id, Nb_message, Page), - if Messages =:= [] -> - euphorik_minichat:attends_nouveau_messages(), - euphorik_minichat:messages(Dernier_id, Nb_message, Page); - true -> - Messages - end. - + % Prend une liste de xml text node et en resort un string() % xmerl : "test & test" devient deux fragments de texte : "test " et "& test", il faut donc rassembler les morceaux... defragmenter(Text_nodes) -> @@ -212,7 +224,7 @@ message(Action) -> [#xmlElement{content = Pseudo_fragments}], [#xmlElement{content = Contenu_fragments}] } -> - case euphorik_minichat:get_user_by_cookie(Cookie) of + case euphorik_minichat:user_by_cookie(Cookie) of {ok, U} -> Pseudo = defragmenter(Pseudo_fragments), Contenu = defragmenter(Contenu_fragments), @@ -266,7 +278,8 @@ format_date(Date) -> %%%%%%%%% %%%%%%%%% simple_xml_to_string(XML) -> - lists:flatten(xmerl:export_simple(XML, xmerl_xml, [{prolog, ["\n"]}])). + io:format("~p~n", [XML]), + lists:flatten(xmerl:export_simple(XML, xmerl_xml, [{prolog, ["\n"]}])). % Construit une réponse positive à un login @@ -327,13 +340,14 @@ xml_reponse_profile_pas_ok(Message) -> % Renvoie un element XML representant une liste de messages auquel le message M_id repond -xml_repond_a(Mess_id) -> +xml_repond_a(Reponses) -> lists:map( - fun(M) -> - {ok, User} = euphorik_minichat:get_user_by_id(M#minichat.auteur_id), + fun(Id_mess) -> + {ok, M} = euphorik_minichat:message_by_id(Id_mess), + {ok, User} = euphorik_minichat:user_by_mess(Id_mess), {id, [{id, erlang:integer_to_list(M#minichat.id, 36)}, {pseudo, M#minichat.pseudo}, {login, User#user.login}], []} end, - euphorik_minichat:repond_a(Mess_id) + Reponses ). @@ -356,7 +370,3 @@ xml_reponse_generation_captcha(Chemin, Captcha) -> } ]. %%%%%%%%% %%%%%%%%% - - - - diff --git a/modules/erl/euphorik_requests.erl b/modules/erl/euphorik_requests.erl index a289f0d..5b3a6d2 100755 --- a/modules/erl/euphorik_requests.erl +++ b/modules/erl/euphorik_requests.erl @@ -21,18 +21,19 @@ tester() -> %~ ""), %~ io:format("Nouvel user : ~p~n", [nouveau_user(XML)]). - {XML2, _} = xmerl_scan:string( - "" - " 5DZQ2HCRO7JIX3QCSWRNL" - ""), - io:format("Login : ~p~n", [euphorik_protocole:login(XML2)]). - - %~ {XML, _} = xmerl_scan:string( - %~ "" - %~ "5" - %~ "1" + %~ {XML2, _} = xmerl_scan:string( + %~ "" + %~ " 5DZQ2HCRO7JIX3QCSWRNL" %~ ""), - %~ io:format("Messages de la premières page : ~p~n", [euphorik_protocole:refreshMessage(XML)]). + %~ io:format("Login : ~p~n", [euphorik_protocole:login(XML2)]). + + XML = + "" + "2" + "1" + "31" + "", + io:format("Messages de la premières page : ~p~n", [traiter_xml(XML)]). %~ traiter_xml("" %~ "4UDUSY6Z2IZNTQO484S8X" @@ -42,6 +43,7 @@ tester() -> %~ traiter_xml( %~ "" %~ ""). + % il faut catcher toutes les exceptions possibles out(A) -> diff --git a/sessions/erl.session b/sessions/erl.session index 806aa93..b8fe724 100755 --- a/sessions/erl.session +++ b/sessions/erl.session @@ -1,26 +1,26 @@ -buffer.1.path=../modules/include/euphorik_defines.hrl -buffer.1.position=1 - -buffer.2.path=../modules/include/euphorik_bd.hrl -buffer.2.position=1 - -buffer.3.path=../modules/erl/euphorik_bd.erl -buffer.3.position=1 - -buffer.4.path=../modules/erl/euphorik_minichat.erl -buffer.4.position=1 - -buffer.5.path=../modules/erl/euphorik_minichat_conversation.erl -buffer.5.position=1 -buffer.5.current=1 - -buffer.6.path=../modules/erl/euphorik_protocole.erl -buffer.6.position=1 - -buffer.7.path=../modules/erl/euphorik_requests.erl -buffer.7.position=1 - - - - +buffer.1.path=../modules/include/euphorik_defines.hrl +buffer.1.position=1 + +buffer.2.path=../modules/include/euphorik_bd.hrl +buffer.2.position=1 + +buffer.3.path=../modules/erl/euphorik_bd.erl +buffer.3.position=1 + +buffer.4.path=../modules/erl/euphorik_minichat.erl +buffer.4.position=1 + +buffer.5.path=../modules/erl/euphorik_minichat_conversation.erl +buffer.5.position=1 +buffer.5.current=1 + +buffer.6.path=../modules/erl/euphorik_protocole.erl +buffer.6.position=1 + +buffer.7.path=../modules/erl/euphorik_requests.erl +buffer.7.position=1 + + + + -- 2.45.2