+// coding: utf-8
// tout un tas d'améliorations de JavaScript ;)
this.communication = communication;\r
\r
this.cookie = null;\r
- this.regexCookie = /^cookie=([^;]*)/;\r
+ this.regexCookie = /cookie=([^;]*)/;\r
\r
// données personnels\r
this.resetDonneesPersonnelles();\r
};\r
\r
/**\r
- * Connexion. Réalisée de manière synchrone.\r
+ * Connexion. Réalisé de manière synchrone.\r
*/\r
euphorik.Client.prototype.connexion = function(action, messageJson) {\r
var thisClient = this;\r
if (!this.authentifie()) {\r
return false;\r
}\r
-\r
+ \r
var thisClient = this;\r
var ok = true;\r
\r
\r
this.regexUrl = new RegExp("(?:(?:" + this.protocoles + ")://|www\\.)[^ ]*", "gi");\r
this.regexImg = new RegExp("^.*?\\.(gif|jpg|png|jpeg|bmp|tiff)$", "i");\r
- this.regexDomaine = new RegExp("^(?:(?:" + this.protocoles + ")://|www\\.).*?([^/.]+\\.[^/.]+)(?:$|/).*$", "i");\r
+ this.regexDomaine = new RegExp("^(?:(?:" + this.protocoles + ")://)(.*?)(?:$|/).*$", "i");\r
this.regexTestProtocoleExiste = new RegExp("^(?:" + this.protocoles + ")://.*$", "i");\r
this.regexNomProtocole = new RegExp("^(.*?)://");\r
};\r
\r
/**\r
* Renvoie une version courte de l'url.\r
- * par exemple : http://en.wikipedia.org/wiki/Yakov_Smirnoff devient wikipedia.org\r
+ * par exemple : http://en.wikipedia.org/wiki/Yakov_Smirnoff devient en.wikipedia.org\r
*/\r
euphorik.Formateur.prototype.getShort = function(url) {\r
var estUneImage = false;\r
*/
Fragment = function() {
var thisFragment = this;
+ // remplacement des codes de type %22 (en hexa)
+ var replaceHtmlCode = function(str) {
+ return str.replace(/%(\d\d)/g, function(text, code) {
+ return String.fromCharCode(parseInt(code, 16));
+ });
+ };
this.fragments = {};
if (!window.location.hash) {
return;
}
try {
- var fragmentsStr = window.location.hash.slice(1).split(";");
+ var fragmentsStr = replaceHtmlCode(window.location.hash.slice(1)).split(";");
fragmentsStr.each(function(i, tuple) {
tuple = tuple.split("=");
thisFragment.fragments[tuple[0]] = JSON.parse(tuple[1]);
* /nick <nouveau nick>
* Modifie le pseudo courant
*/
-euphorik.Commandes = function(client) {
+euphorik.Commandes = function(client, pageMinichat, util, formateur) {
+ var thisCommandes = this;
+
this.client = client;
+ this.pageMinichat = pageMinichat;
+ this.util = util;
+ this.formateur = formateur;
+
+ // construction du texte d'aide (liste des commandes) de manière statique
+ this.texteAide = "<div id=\"aideCommandes\"><h1>Commandes</h1><ul>";
+ objectEach(
+ euphorik.Commandes.liste,
+ function(nom, commande) {
+ thisCommandes.texteAide += "<li><span class=\"usage\">" + thisCommandes.formateur.traitementComplet(commande.usage) + "</span> : " + thisCommandes.formateur.traitementComplet(commande.description) + "</li>";
+ }
+ );
+ this.texteAide += "</ul></div>";
};
euphorik.Commandes.statut = {ok : 0, pas_une_commande : 1, erreur_commande : 2};
euphorik.Commandes.liste = {
"nick" : {
+ description : "Change le pseudo courant",
usage : "/nick <nouveau pseudo>",
exec : function(args, client) {
return [euphorik.Commandes.statut.ok, ''];
}
- }
+ },
+ "cpf" : {
+ description : "Envoie le message \"C'est pas faux\"",
+ usage : "/cpf",
+ exec : function(args, client, pageMinichat) {
+ pageMinichat.envoyerMessage("C'est pas faux");
+ return [euphorik.Commandes.statut.ok, ''];
+ }
+ }
};
/**
if (nomCommande === "") {
return [euphorik.Commandes.statut.erreur_commande, 'La commande est vide'];
}
+ // commandes spéciales pour afficher l'aide : "?", "h", "help", "aide"
+ if (nomCommande === "?" || nomCommande === "h" || nomCommande === "help" || nomCommande === "aide") {
+ this.util.messageDialogue(
+ this.texteAide,
+ euphorik.Util.messageType.informatif,
+ {"fermer" : function(){}},
+ false,
+ -1
+ );
+ return [euphorik.Commandes.statut.ok, ''];
+ }
if (euphorik.Commandes.liste.hasOwnProperty(nomCommande)) {
- return euphorik.Commandes.liste[nomCommande].exec(args, this.client);
+ return euphorik.Commandes.liste[nomCommande].exec(args, this.client, this.pageMinichat);
}
return [euphorik.Commandes.statut.erreur_commande, 'La commande /' + nomCommande + ' est inconnue'];
\r
var messagePair = (this.idDernierMessageAffiche === 0 ? true :\r
($("#" + this.getId() + " .messages div:" + (reverse ? "first" : "last")).attr("class").search("messagePair") === -1)\r
- );\r
+ );
+
+ // permet d'itérer sur les nouveaux messages à afficher
+ var pourChaqueNouveauMessage = function(f) {
+ thisConversation.messages.each(function(i, mess) {
+ if (mess.id > thisConversation.idDernierMessageAffiche) {
+ f(mess);
+ }
+ });
+ };\r
\r
// construction de l'XHTML des messages\r
- var XHTML = "";\r
- this.messages.each(function(i, mess) {\r
- if (mess.id > thisConversation.idDernierMessageAffiche) {\r
- XHTML += mess.XHTML(messagePair, thisConversation.getId());\r
- messagePair = !messagePair;\r
- }\r
+ var XHTML = "";
+ pourChaqueNouveauMessage(function(mess) {\r
+ XHTML += mess.XHTML(messagePair, thisConversation.getId());\r
+ messagePair = !messagePair;\r
});\r
\r
var DOM = $(XHTML); \r
} else {\r
$("#" + this.getId() + " .messages .message").slice(0, nbMessagesAffiche - this.nbMessageMax).remove();\r
}\r
- }\r
+ }
+
+ // met à jour la classe des messages auquels repondent les nouveaux messages
+ // dans le cas où ce message appartient au client courant (c'est un peu de la triche) TODO : ya mieux ?
+ pourChaqueNouveauMessage(function(mess) {
+ if (mess.auteurId === thisConversation.client.id) {
+ objectEach(mess.repondA, function(messId) {
+ var mess = thisConversation.messagesParId[messId];
+ if (mess) {
+ mess.clientARepondu = true;
+ $("#conversations #" + mess.getId(thisConversation.getId())).addClass("repondu")
+ }
+ });
+ }
+ });
\r
if (this.messages.length > 0) {\r
this.idDernierMessageAffiche = this.messages[this.messages.length-1].id;\r
- }\r
+ }
\r
// met à jour la racine de la conversation\r
this.majRacine();\r
// donne le focus à la ligne de saisie\r
$("form input.message").focus();\r
}).hover(function() { // affiche les outils liées au message\r
- var top = $(this).offset().top\r
+ var top = $(this).offset().top;\r
var left = $(this).offset().left + $(this).outerWidth() - thisConversation.util.outilsMessage.outerWidth();\r
$(".extraire", thisConversation.util.outilsMessage).unbind();\r
$(".extraireCompletement", thisConversation.util.outilsMessage).unbind();\r
thisConversation.util.infoBulle("Extraction de la conversation complète", $(".extraireCompletement", thisConversation.util.outilsMessage));\r
thisConversation.util.outilsMessage.css("top", top).css("left", left).prependTo(this).show();\r
}, function() {\r
- thisConversation.util.outilsMessage.hide()\r
+ thisConversation.util.outilsMessage.hide();\r
});\r
\r
// mise en évidence de la conversation\r
euphorik.Conversations.prototype.mettreAJourFragment = function() {\r
conv = [];\r
for(var i = 1; i < this.conversations.length; i++) {\r
- conv.push(this.conversations[i].racine.id)\r
+ conv.push(this.conversations[i].racine.id);\r
}\r
this.fragment.setVal("conv", conv);\r
this.fragment.write();\r
-}\r
+};\r
\r
/**\r
* Enlève tous les messages auquel l'utilisateur souhaite répondre.\r
};\r
\r
euphorik.Conversations.prototype.getJSONConversations = function() {\r
- var thisConversations = this\r
+ var thisConversations = this;\r
var clientConv = [];\r
\r
this.client.conversations.each(function(i, conv) {\r
this.formateur = formateur;
this.util = util;
this.communication = communication;
- this.commandes = new euphorik.Commandes(this.client);
+ this.commandes = new euphorik.Commandes(this.client, this, this.util, this.formateur);
// permet d'éviter d'envoyer plusieurs messages simultanément en pressant
// rapidement sur "enter" par exemple
var retCommandes = thisPage.commandes.exec(message);
switch (retCommandes[0]) {
case euphorik.Commandes.statut.pas_une_commande :
- thisPage.envoyerMessage($("form#posterMessage input.pseudo").val(), message);
+ thisPage.envoyerMessage(message);
break;
case euphorik.Commandes.statut.erreur_commande :
thisPage.util.messageDialogue(retCommandes[1], euphorik.Util.messageType.erreur);
} catch(e) {
;; console.log(e)
}
-}
+};
euphorik.PageMinichat.prototype.decharger = function() {
this.conversations.comet.stopAttenteCourante();
$("body #smiles").remove();
- this.fragment.delVal("conv")
+ this.fragment.delVal("conv");
};
-euphorik.PageMinichat.prototype.envoyerMessage = function(pseudo, message) {
- var thisPageMinichat = this;
+/**
+ * Envoie un nouve message donné, le pseudo utilisé est celui se trouvant
+ * dans la zone de saisie (form#posterMessage input.pseudo).
+ */
+euphorik.PageMinichat.prototype.envoyerMessage = function(message) {
+ var thisPageMinichat = this;
+ var pseudo = $("form#posterMessage input.pseudo").val();
// (un pseudo vide est autorisé)
pseudo = this.formateur.filtrerInputPseudo(pseudo);
this.util.messageDialogue("Le message est vide");
return;
}
+
+ this.client.pseudo = pseudo;
if (!this.client.authentifie()) {
if (!this.client.enregistrement()) {
}
}
- this.client.pseudo = pseudo;
-
// évite le double post
if (this.envoieMessageEnCours) {
this.util.messageDialogue("Message en cours d'envoie...");
"put_message",
this.getJSONMessage(pseudo, message),
function() {
- // TODO : revoir cette partie
- // met à jour la classe des messages auquel repond celui ci (c'est un peu de la triche) TODO : ya mieux ?
- objectEach(thisPageMinichat.conversations.messagesRepond, function(messId) {
- thisPageMinichat.conversations.conversations.each(function(i, conv) {
- var mess = conv.messagesParId[messId];
- if (mess) {
- mess.clientARepondu = true;
- $("#conversations #" + mess.getId(conv.getId())).addClass("repondu")
- }
- });
- });
$("form#posterMessage input.message").val("");
thisPageMinichat.conversations.enleverMessagesRepond();
thisPageMinichat.envoieMessageEnCours = false;
* @param message le message (string)\r
* @param type voir 'messageType'. par défaut messageType.informatif\r
* @param les boutons sous la forme d'un objet ou les clefs sont les labels des boutons\r
- * et les valeurs les fonctions executées lorsqu'un bouton est activé.\r
- * @param formate faut-il formaté le message ? true par défaut\r
+ * et les valeurs les fonctions executées lorsqu'un bouton est activé.
+ * Lorsqu'un bouton est activé le message se ferme. \r
+ * @param formate faut-il formaté le message ? true par défaut
+ * @param temps le temps d'affichage du message en seconde, -1 pour une durée infinie\r
*/\r
-euphorik.Util.prototype.messageDialogue = function(message, type, boutons, formate) {\r
+euphorik.Util.prototype.messageDialogue = function(message, type, boutons, formate, temps) {\r
var thisUtil = this;\r
\r
type = type || euphorik.Util.messageType.informatif;\r
- formate = formate || true;\r
+ formate = formate === undefined ? true : formate;\r
\r
if (this.timeoutMessageDialogue) {\r
clearTimeout(this.timeoutMessageDialogue);\r
\r
var fermer = function() { $("#info").slideUp(100); };\r
fermer();\r
- \r
+\r
$("#info .message").html(!thisUtil.formateur || !formate ? message : thisUtil.formateur.traitementComplet(message));\r
\r
switch(type) {\r
$("#info .boutons").append("<div>" + nom + "</div>").find("div:last").click(bouton).click(fermer);\r
});\r
\r
- $("#info").slideDown(200);\r
- this.timeoutMessageDialogue = setTimeout(fermer, euphorik.conf.tempsAffichageMessageDialogue);\r
+ $("#info").slideDown(200);
+ if (temps !== -1) {\r
+ this.timeoutMessageDialogue = setTimeout(fermer, temps || euphorik.conf.tempsAffichageMessageDialogue);
+ }\r
};\r
\r
euphorik.Util.positionTypeX = {gauche: 0, gaucheRecouvrement: 1, centre: 2, droiteRecouvrement: 3, droite: 4};\r
erlc $(erlc_params)
# Module pour la mise à jour de la BD
-$(rep_ebin)/euphorik_bd_admin.beam: $(rep_erl)/euphorik_bd_admin.erl $(rep_erl)/euphorik_bd.erl $(rep_include)/euphorik_bd.hrl $(rep_include)/euphorik_defines.hrl
+$(rep_ebin)/euphorik_bd_admin.beam: $(rep_erl)/euphorik_bd_admin.erl $(rep_include)/euphorik_bd.hrl $(rep_include)/euphorik_defines.hrl
erlc $(erlc_params)
# Module permettant l'extraction des conversations du minichat
# erlc $(erlc_params)
# Module effectuant periodiquement certaines tâches
-$(rep_ebin)/euphorik_daemon.beam: $(rep_erl)/euphorik_daemon.erl $(rep_include)/euphorik_defines.hrl $(rep_erl)/euphorik_bd_admin.erl
+$(rep_ebin)/euphorik_daemon.beam: $(rep_erl)/euphorik_daemon.erl $(rep_include)/euphorik_defines.hrl
erlc $(erlc_params)
# Module avec plein de bordel dedant
erlc $(erlc_params)
# Module dédié au tests
-$(rep_ebin)/euphorik_test.beam: $(rep_erl)/euphorik_test.erl $(rep_erl)/euphorik_bd.erl $(rep_include)/euphorik_bd.hrl
+$(rep_ebin)/euphorik_test.beam: $(rep_erl)/euphorik_test.erl $(rep_include)/euphorik_bd.hrl
erlc $(erlc_params)
# Suppression des modules compilés
% messages :\r
nouveau_message/3,\r
nouveau_message_sys/1,\r
- nouveau_message_sys/2,\r
messages/1,\r
messages/2,\r
messages/3,\r
troll_by_id/1,\r
current_troll/0,\r
elire_troll/0,\r
- message_id_associe/1,\r
\r
% utiles :\r
resultat_transaction/1\r
nouveau_message(Mess, Auteur_id, Repond_A_ids) ->\r
% regarde si les id 'Repond_A' existent\r
F = fun() -> \r
- Repond_a = lists:map(\r
- fun(Repond_a_id) ->\r
- [M] = mnesia:wread({minichat, Repond_a_id}),\r
- M\r
- end,\r
+ Repond_a = lists:foldr(\r
+ fun(Repond_a_id, Acc) ->\r
+ case mnesia:read({minichat, Repond_a_id}) of
+ [M] -> [M | Acc];\r
+ _ -> Acc % le message n'est pas trouvé
+ end\r
+ end,
+ [],\r
Repond_A_ids\r
- ), \r
+ ),\r
Racine_id = case Repond_a of\r
[] -> undefined;\r
[M | _] -> \r
_ ->\r
{erreur, "Les messages ne font pas partie de la même conversation"}\r
end\r
- end,\r
- case Racine_id of\r
- {erreur, E} -> {erreur, E};\r
- _ ->\r
- % est-ce que l'auteur existe ?\r
- case mnesia:wread({user, Auteur_id}) of\r
- [#user{profile = Profile} = Auteur] ->\r
- if length(Repond_a) =/= length(Repond_A_ids) ->\r
- {erreur, "Un ou plusieurs messages introuvable"};\r
- true ->\r
+ end,
+ if length(Repond_a) =/= length(Repond_A_ids) ->
+ {erreur, "Un ou plusieurs messages introuvable"};
+ true ->\r
+ case Racine_id of\r
+ {erreur, E} -> {erreur, E};\r
+ _ ->\r
+ % est-ce que l'auteur existe ?\r
+ case mnesia:wread({user, Auteur_id}) of\r
+ [#user{profile = Profile} = Auteur] ->\r
% comparaison entre la date du dernier poste et maintenant (gestion du flood)\r
Now = now(),\r
Delta = euphorik_common:delta_date_ms(Auteur#user.date_derniere_connexion, Now),\r
racine_id = if Racine_id =:= undefined -> Id; true -> Racine_id end\r
}),\r
Id\r
- end\r
- end;\r
- _ ->\r
- {erreur, "L'auteur du message est introuvable"}\r
- end\r
+ end;\r
+ _ ->\r
+ {erreur, "L'auteur du message est introuvable"}\r
+ end\r
+ end
end\r
end,\r
resultat_transaction(mnesia:transaction(F)).\r
% Permet de créer un message système.\r
% Renvoie l'id du message système\r
nouveau_message_sys(Mess) ->\r
- nouveau_message_sys(Mess, undefined).\r
- \r
-\r
-% Création d'un message système lié à un troll.\r
-nouveau_message_sys(Mess, Troll_id) ->\r
{ok, #user{profile = Profile}} = user_by_id(0),\r
resultat_transaction(mnesia:transaction(\r
fun() ->\r
Id = nouvel_id(minichat),\r
- mnesia:write(#minichat{id = Id, auteur_id = 0, date = now(), pseudo = Profile#profile.pseudo, contenu = Mess, troll_id = Troll_id, racine_id = Id}),\r
+ mnesia:write(#minichat{id = Id, auteur_id = 0, date = now(), pseudo = Profile#profile.pseudo, contenu = Mess, racine_id = Id}),\r
Id\r
end\r
)).\r
messages(N, 1).\r
\r
\r
-% Renvoie N messages se trouvant sur la page P\r
+% Renvoie N messages se trouvant sur la page P
+% TODO FIXME : fonction en O(N * P) !\r
messages(N, P) ->\r
- F = fun() ->\r
- C = cursor(\r
- qlc:keysort(\r
- #minichat.id, \r
- q([E#minichat{contenu = contenu_message(E)} || E <- mnesia:table(minichat)]),\r
- [{order, descending}]\r
- ),\r
- [{tmpdir, ?KEY_SORT_TEMP_DIR}]\r
- ),\r
- if P > 1 -> qlc:next_answers(C, N * (P - 1));\r
- true -> ok\r
- end,\r
- R = qlc:next_answers(C, N),\r
- qlc:delete_cursor(C),\r
- R\r
+ F = fun() ->
+ % % #minichat{contenu = contenu_message(E)}
+ get_tuples_avant(minichat, reculer(minichat, mnesia:last(minichat), N * (P - 1)), N) \r
end,\r
- lists:reverse(resultat_transaction(mnesia:transaction(F))).\r
-\r
+ resultat_transaction(mnesia:transaction(F)).
+
+get_tuples_avant(Table, Id, N) ->
+ get_tuples_avant(Table, Id, N, []).
+get_tuples_avant(_, '$end_of_table', _, Tuples) -> Tuples;
+get_tuples_avant(_, _, 0, Tuples) ->
+ Tuples;
+get_tuples_avant(Table, Id, N, Tuples) ->
+ [T] = mnesia:read({Table, Id}),
+ get_tuples_avant(Table, mnesia:prev(Table, Id), N - 1, [T | Tuples]).
+
+reculer(_, '$end_of_table' = Fin, _) -> Fin;
+reculer(_, Id, 0) -> Id;
+reculer(Table, Id, N) ->
+ reculer(Table, mnesia:prev(Table, Id), N - 1).
+ \r
\r
% Renvoie les messages manquants pour la page P en sachant qu'il y a N message\r
% par page et que le dernier message que l'on possède est Id\r
\r
\r
% Renvoie le contenu d'un message donnée en fonction du troll associé, à utiliser à l'intérieur d'une transaction.\r
-% TODO : Cette fonction pourrait être remplacé par un "outer-join", est-ce possible avec qlc ?\r
+% TODO : Cette fonction pourrait être remplacée par un "outer-join", est-ce possible avec qlc ?\r
contenu_message(E) ->\r
- case mnesia:read({troll, E#minichat.troll_id}) of\r
+ case mnesia:index_read(troll, E#minichat.id, #troll.id_minichat) of\r
[] -> E#minichat.contenu;\r
[T] -> E#minichat.contenu ++ T#troll.content\r
end.\r
plus_de_trolls;\r
Trolls ->\r
Troll = lists:nth(random:uniform(length(Trolls)), Trolls),\r
- Troll2 = Troll#troll{date_post = now()},\r
- mnesia:write(Troll2),\r
- nouveau_message_sys("Troll de la semaine : ", Troll2#troll.id)\r
+ Id_message = nouveau_message_sys("Troll de la semaine : "),\r
+ Troll2 = Troll#troll{date_post = now(), id_minichat = Id_message},\r
+ mnesia:write(Troll2)\r
end\r
end\r
).\r
\r
-\r
-% Renvoie l'id du message associé au troll dont l'id est donnée.\r
-% Renvoie undefined si il n'y en a pas.\r
-message_id_associe(Troll_id) ->\r
- resultat_transaction(mnesia:transaction(\r
- fun() ->\r
- case e(q([M#minichat.id || M <- mnesia:table(minichat), M#minichat.troll_id =:= Troll_id]), [{tmpdir, ?KEY_SORT_TEMP_DIR}]) of\r
- [Id] -> Id;\r
- _ -> undefined\r
- end\r
- end\r
- )).\r
-\r
\r
% Renvoie le résultat d'une transaction (en décomposant le tuple fournit)\r
resultat_transaction({_, T}) ->\r
reset/0,
update/0,
- backup_text/1,
- restore_text/1,
+ backup/1,
+ restore/1,
+ change_node_name/4,
toggle_ek_master/1,
print_users/0,
% Instructions pour créer une nouvelle base :
-% $erl -sname yaws -mnesia dir '"/projets/euphorik/var/BD"'
+% $erl -sname yaws -mnesia dir '"/projets/euphorik/BD"'
% voir doc/installation.txt
% >l(euphorik_bd).
% >euphorik_bd:create().
{disc_copies, [node()]}
]),
mnesia:create_table(minichat, [
+ {type, ordered_set},
{attributes, record_info(fields, minichat)},
{disc_copies, [node()]}
]),
% mis à part car lors de la reprise de données avec load_textfile les indexes ne sont pas recréés
creer_indexes() ->
+ % commence par supprimer les anciens indexes
+ lists:foreach(fun(T) ->
+ lists:foreach(fun(P) ->
+ mnesia:del_table_index(T, P)
+ end,
+ mnesia:table_info(T, index)
+ )
+ end,
+ ?TABLES
+ ),
mnesia:add_table_index(minichat, auteur_id),
- mnesia:add_table_index(minichat, troll_id),
mnesia:add_table_index(reponse_minichat, cible),
mnesia:add_table_index(user, cookie),
mnesia:add_table_index(user, login),
- mnesia:add_table_index(troll, date_post).
+ mnesia:add_table_index(troll, date_post),\r
+ mnesia:add_table_index(troll, id_minichat).
% Connexion à la base de données de yaws sur overnux
% Applique une modification de la BD pour passer d'une version à la suivante.
% crée un backup avant l'application du patch
-% dans var/BD/backups nommé "backup<num>" où <num> et le numéro de la version.
+% dans BD/backups nommé "backup<num>" où <num> et le numéro de la version.
% 1 -> 2
patch(1) ->
+ % Prend un chemin vers la feuille de style de type "css/1/euphorik.css"\r
+ % et renvoie "styles/1/euphorik.css"\r
+ Transforme_css = fun("css" ++ Reste) ->
+ "styles" ++ Reste;\r
+ (F) -> F\r
+ end,\r
+ Traiter_message = fun(M, Racine) ->\r
+ F = fun(F, M2) -> % seul moyen à ma connaissance pour faire de la récursion dans une lambda fonction, voir : http://www.nabble.com/Auto-generated-functions-td15279499.html\r
+ % met à jour la racine de chaque message qui répond à M\r
+ lists:foreach(\r
+ fun(M3) ->\r
+ mnesia:write(M2#minichat{racine_id = Racine}),\r
+ F(F, M3)\r
+ end,\r
+ euphorik_bd:enfants(M#minichat.id)\r
+ )\r
+ end,\r
+ F(F, M, Racine)\r
+ end,
mnesia:create_table(texte, [
{attributes, record_info(fields, texte)},
{disc_copies, [node()]}
mnesia:transform_table(
user,
fun({user, Id, Cookie, Pseudo, Login, Password, Email, Date_creation, Date_derniere_connexion, Css, Nick_format, View_times, View_tooltips, Indice_flood, _Page_principale, Conversations, Ek_master, Last_ip}) ->
- {user, Id, Cookie, Login, Password, {profile, Pseudo, Email, patch1_transforme_css(Css), Nick_format, View_times, View_tooltips, light, reverse, lists:map(fun({R, _}) -> {R, false} end, Conversations)}, Date_creation, Date_derniere_connexion, Indice_flood, Ek_master, Last_ip}
+ {user, Id, Cookie, Login, Password, {profile, Pseudo, Email, Transforme_css(Css), Nick_format, View_times, View_tooltips, light, reverse, lists:map(fun({R, _}) -> {R, false} end, Conversations)}, Date_creation, Date_derniere_connexion, Indice_flood, Ek_master, Last_ip}
end,
- record_info(fields, user),
- user
+ record_info(fields, user)
),
mnesia:transform_table(
minichat,
fun({minichat, Id, Auteur_id, Date, Pseudo, Contenu, Troll_id}) ->
{minichat, Id, Auteur_id, Date, Pseudo, Contenu, Troll_id, Id}
end,
- record_info(fields, minichat),
- minichat
+ record_info(fields, minichat)
),
case mnesia:transaction(
fun() ->
% met à jour les enfants des racines
% idéalement : utiliser un cursor mais je crois qu'il n'est pas possible de faire des modifs en itérant en même temps avec un cursor, a voir..
Messages = e(q([M || M <- mnesia:table(minichat), euphorik_bd:parents(M#minichat.id) =:= []]), [{tmpdir, ?KEY_SORT_TEMP_DIR}]),
- lists:foreach(fun(M) -> patch_1_traiter_message(M, M#minichat.id) end, Messages)
+ lists:foreach(fun(M) -> Traiter_message(M, M#minichat.id) end, Messages)
end
) of
{aborted, Raison} -> {erreur, Raison};
{atomic, _} -> ok
- end.
-
+ end;\r
+% 2 -> 3\r
+patch(2) ->
+ % première étape : changer le type de la table minichat de set à ordered_set
+ % TODO : trouver un meilleur moyen que de passer par un backup
+ backup("tmp"),
+ create(),
+ restore("tmp"),
+ file:delete(dossier_backups() ++ "tmp"),\r
+ mnesia:transform_table(\r
+ troll,\r
+ fun({troll, Id_troll, Id_user, Date_create, Date_post, Content}) ->\r
+ % recherche le message associé s'il existe\r
+ Id_minichat = case e(q([M || M <- mnesia:table(minichat), element(7, M) =:= Id_troll]), [{tmpdir, ?KEY_SORT_TEMP_DIR}]) of\r
+ [M] -> element(2, M);\r
+ _ -> undefined\r
+ end,\r
+ {troll, Id_troll, Id_user, Id_minichat, Date_create, Date_post, Content}\r
+ end,\r
+ record_info(fields, troll)\r
+ ),\r
+ %mnesia:del_table_index(minichat, troll_id),\r
+ mnesia:transform_table(\r
+ minichat,\r
+ fun({minichat, Id, Auteur_id, Date, Pseudo, Contenu, _Troll_id, Racine_id}) ->\r
+ {minichat, Id, Auteur_id, Date, Pseudo, Contenu, Racine_id}\r
+ end,\r
+ record_info(fields, minichat)\r
+ ),\r
+ creer_indexes(). % uniquement pour l'indice sur id_minichat de la table troll\r
-% Prend un chemin vers la feuille de style de type "css/1/euphorik.css"
-% et renvoie "styles/1/euphorik.css"
-patch1_transforme_css("css" ++ Reste) ->
- "styles" ++ Reste;
-patch1_transforme_css(F) ->
- F.
-
-patch_1_traiter_message(M, Racine) ->
- % met à jour la racine de chaque message qui répond à M
- lists:foreach(
- fun(M2) ->
- mnesia:write(M2#minichat{racine_id = Racine}),
- patch_1_traiter_message(M2, Racine)
- end,
- euphorik_bd:enfants(M#minichat.id)
- ).
+% Renvoie le dossier dans lequel les backups sont effectué, ce dossier doit être en écriture.
+dossier_backups() ->
+ mnesia:system_info(directory) ++ "/backups/".
-% crée un backup dont le nom est fournit dans le repertoire backups qui se trouve dans le repertoire de la BD.
-%backup(Nom) ->
-% mnesia:backup(mnesia:system_info(directory) ++ "/backups/" ++ Nom).
-
-% Reviens à une version précédente de la base de données
-% (les données insérées durant les versions plus récentes sont perdues)
-%restore(N) ->
-% mnesia:restore(fichier_backup(N), [{default_op, recreate_tables}]).
+% Renvoie le fichier (avec le chemin) correspondant à la version Version, par exemple : "/var/euphorik/BD/backups/backup1"
+fichier_backup(Version) when is_integer(Version) ->
+ dossier_backups() ++ "backup" ++ integer_to_list(Version).
+\r
+% crée un backup dont le nom est fournit dans le repertoire backups qui se trouve dans le repertoire de la BD.
+backup(Fichier) ->
+ mnesia:backup(dossier_backups() ++ Fichier).
+
+
+% Restaure un backup de la BD.
+restore(Fichier) when is_list(Fichier) ->
+ mnesia:restore(dossier_backups() ++ Fichier, []);
+% Reviens à une version précédente de la base de données.
+% (les données insérées durant les versions plus récentes sont perdues).
+restore(Version) when is_integer(Version) ->
+ mnesia:restore(fichier_backup(Version), []). % [{default_op, recreate_tables}]).
+
-% Renvoie le fichier (avec le chemin) correspondant à la version Version, par exemple : "/var/euphorik/var/BD/backups/backup1"
-fichier_backup(Version) ->
- mnesia:system_info(directory) ++ "/backups/" ++ if is_integer(Version) -> "backup" ++ integer_to_list(Version); true -> Version end.
+% Change le nom du noeud d'un backup.
+% provient d'ici : http://www.erlang.org/doc/apps/mnesia/Mnesia_chap7.html#6.9
+% From : l'ancien nom
+% To : le nouveau nom
+% Source : le nom du fichier de backup
+% Target : le nom du fichier du nouveau backup
+change_node_name(From, To, Source, Target) ->
+ Switch =
+ fun(Node) when Node == From -> To;
+ (Node) when Node == To -> throw({error, already_exists});
+ (Node) -> Node
+ end,
+ Convert =
+ fun({schema, db_nodes, Nodes}, Acc) ->
+ {[{schema, db_nodes, lists:map(Switch,Nodes)}], Acc};
+ ({schema, version, Version}, Acc) ->
+ {[{schema, version, Version}], Acc};
+ ({schema, cookie, Cookie}, Acc) ->
+ {[{schema, cookie, Cookie}], Acc};
+ ({schema, Tab, CreateList}, Acc) ->
+ Keys = [ram_copies, disc_copies, disc_only_copies],
+ OptSwitch =
+ fun({Key, Val}) ->
+ case lists:member(Key, Keys) of
+ true -> {Key, lists:map(Switch, Val)};
+ false-> {Key, Val}
+ end
+ end,
+ {[{schema, Tab, lists:map(OptSwitch, CreateList)}], Acc};
+ (Other, Acc) ->
+ {[Other], Acc}
+ end,
+ mnesia:traverse_backup(Source, Target, Convert, switched).
-backup_text(_) -> todo.
-restore_text(File) ->
- mnesia:stop(),
- mnesia:delete_schema([node()]),
- mnesia:start(),
- case mnesia:load_textfile(File) of
- {atomic, ok} ->
- update(),
- creer_indexes();
- Erreur ->
- Erreur
- end.
+% Obsolète
+%~ backup_text(File) ->
+ %~ mnesia:dump_to_textfile(File).
+%~ restore_text(File) ->
+ %~ mnesia:stop(),
+ %~ mnesia:delete_schema([node()]),
+ %~ mnesia:start(),
+ %~ create_tables(),
+ %~ case mnesia:load_textfile(File) of
+ %~ {atomic, ok} ->
+ %~ update(),
+ %~ creer_indexes();
+ %~ Erreur ->
+ %~ Erreur
+ %~ end.
toggle_ek_master(User_id) ->
_ ->
{erreur, "Id pas trouvé : " ++ integer_to_list(Id)}
end.
-
\ No newline at end of file
+
% Un message est un tuple représentant le message et la liste des id\r
% des messages auquels il répond\r
% @type Message() = {#minichat, [int()]}\r
-% \r
-\r
+
\r
-module(euphorik_minichat_conversation).\r
-export([\r
]).\r
-include("../include/euphorik_bd.hrl").\r
-include("../include/euphorik_defines.hrl").\r
--include_lib("stdlib/include/qlc.hrl").\r
-import(lists, [reverse/1, any/2, map/2, sublist/3, filter/2]).\r
-import(euphorik_bd, [resultat_transaction/1]).\r
--import(qlc, [e/2, q/1]).\r
-import(mnesia, [table/1, transaction/1]).\r
\r
\r
% @spec conversations_detailees([{integer(), integer()}], integer(), integer(), integer()) -> [[{integer(), bool()}] | Conversation_detailee()]\r
conversations_detailees(Racines, N, D, P) -> \r
Conversations = map(fun({Racine, P_conv, Dernier}) -> conversation(Racine, N, Dernier, P_conv) end, Racines),\r
- Conversation_principale = resultat_transaction(transaction(fun() ->\r
- Curseur = qlc:cursor(\r
- qlc:sort(q([E#minichat.id || E <- table(minichat)]), [{order, descending}]),\r
- [{tmpdir, ?KEY_SORT_TEMP_DIR}]\r
- ),\r
- {CP, Plus} = conversation_principale(Curseur, Conversations, N, P),\r
- qlc:delete_cursor(Curseur),\r
+ Conversation_principale = resultat_transaction(transaction(fun() ->
+ Dernier_id = mnesia:last(minichat),\r
+ {CP, Plus} = conversation_principale(Dernier_id, Conversations, N, P),\r
{[M || M <- CP, M > D], Plus} % filtre en fonction de D\r
end)),\r
[Conversation_principale | Conversations].\r
\r
\r
-% Construit la conversation principale en fonction d'un curseur C initialement placé sur le dernier message\r
+% Construit la conversation principale en fonction d'un id de message initialement placé sur le dernier message\r
% et la liste de conversations.\r
% N est le nombre de messages que l'on souhaite.\r
% P est le numéro de la page (1, 2, 3...)\r
-% @spec conversation_principale(qlc:QueryCursor(), [Conversation_detailee()], integer(), integer()) -> {[integer()], bool()}\r
-conversation_principale(C, Conversations, N, P) ->\r
+% @spec conversation_principale(integer(), [Conversation_detailee()], integer(), integer()) -> {[integer()], bool()}\r
+conversation_principale(Id, Conversations, N, P) ->\r
% on prend en message de plus pour savoir s'il y en a plus que ce que l'on désire\r
- CP = reverse(conversation_principale2(C, lists:flatten(map(fun({C2, _, X, _}) -> C2 -- X end, Conversations)), N + 1, (P - 1) * N)),\r
+ CP = reverse(conversation_principale2(Id, lists:flatten(map(fun({C2, _, X, _}) -> C2 -- X end, Conversations)), N + 1, (P - 1) * N)),\r
Plus = length(CP) =:= N + 1,\r
{\r
if Plus ->\r
}.\r
\r
\r
-% C est le curseur (voir ci dessus)\r
+% Id est l'id d'un message, voir ce dessus\r
% 'Messages' sont les messages que l'on doit enlever de la conversation\r
% S est le nombre de messages qu'il faut sauter.\r
-% @spec conversation_principale2(qlc:QueryCursor(), [integer()], integer(), integer()) -> [integer()]\r
+% @spec conversation_principale2(integer(), [integer()], integer(), integer()) -> [integer()]\r
conversation_principale2(_, _, 0, _) ->\r
+ [];
+conversation_principale2('$end_of_table', _, _, _) ->
[];\r
-conversation_principale2(C, Messages, N, S) ->\r
- case qlc:next_answers(C, 1) of\r
- [] -> [];\r
- [M] -> % traitement message par message (pas des plus performant :/)\r
- Doit_etre_saute = any(fun(E) -> E == M end, Messages),\r
- if Doit_etre_saute -> \r
- conversation_principale2(C, Messages, N, S); % le message ne fait pas partie de la conversation\r
- S =:= 0 ->\r
- [M | conversation_principale2(C, Messages, N - 1, S)]; % ok : le message fait partie de la conversation\r
- true ->\r
- conversation_principale2(C, Messages, N, S - 1) % on n'a pas encore atteint le début de la page\r
- end\r
- end.\r
+conversation_principale2(Id, Messages, N, S) ->
+ % traitement message par message (pas des plus performant :/)
+ Id_prev = mnesia:prev(minichat, Id),\r
+ Doit_etre_saute = any(fun(E) -> E == Id end, Messages),\r
+ if Doit_etre_saute -> \r
+ conversation_principale2(Id_prev, Messages, N, S); % le message ne fait pas partie de la conversation\r
+ S =:= 0 ->\r
+ [Id | conversation_principale2(Id_prev, Messages, N - 1, S)]; % ok : le message fait partie de la conversation\r
+ true ->\r
+ conversation_principale2(Id_prev, Messages, N, S - 1) % on n'a pas encore atteint le début de la page\r
+ end.\r
\r
\r
% Renvoie un tuple {C, Cn, X, Plus} où\r
{struct, [\r
{reply, "new_troll"},\r
{troll_id, Current#troll.id},\r
- {message_id, euphorik_bd:message_id_associe(Current#troll.id)},\r
+ {message_id, Current#troll.id_minichat},\r
{content, Current#troll.content}\r
]};\r
_ ->\r
-module(euphorik_test).
-export([
+ bench_write_minichat/1,
start/2,
stop/1,
bench_get_messages/0,
-define(INTERVALLE_MIN, 2).\r
-define(INTERVALLE_MAX, 5).
+
% N est le nombre d'utilisateur
% M est le nombre de message que chaque utilisateur va poster
start(N, M) ->
stop(Pids) ->
lists:foreach(fun(Pid) -> exit(Pid, kill) end, Pids).
-
+% des trucs qui trainent
bench_get_messages() ->
T = [
{page,"chat"},
{conversations,{array,[]}}
],
moyenne_temps(euphorik_protocole, wait_event, [T], 20).
-
-
bench_get_messages_avec_2_conversations() ->
T = [
{page,"chat"},
]}}
],
moyenne_temps(euphorik_protocole, wait_event, [T], 20).
-
-
moyenne_temps(Module, Fun, Args, N) ->
moyenne_temps(Module, Fun, Args, N, N, 0).
moyenne_temps(_, _, _, 0, Total, Temps_acc) ->
% Tire au hasard de 0 à 3 messages sur les 10 derniers postés, renvoie une liste de int()
% répartition :
% 0 : 0.1
-% 1 : 0.7
-% 2 : 0.15
-% 3 : 0.05
+% 1 : 0.95
+% 2 : 0.04
+% 3 : 0.01
messages_id_rand() ->
R = random:uniform(),
if R =< 0.1 ->
true ->
Messages = lists:map(fun(#minichat{id = Id}) -> Id end, euphorik_bd:messages(8)),
if
- R > 0.1 andalso R =< 0.8 ->
+ R > 0.1 andalso R =< 0.95 ->
tire_element_rand(1, Messages);
- R > 0.8 andalso R =< 0.95 ->
+ R > 0.95 andalso R =< 0.99 ->
tire_element_rand(2, Messages);
true ->
tire_element_rand(3, Messages)
% attend un temp aléatoire compris entre INTERVALLE_MIN sec et INTERVALLE_MAX sec
timer:sleep(1000 * (random:uniform(?INTERVALLE_MAX - ?INTERVALLE_MIN + 1) + ?INTERVALLE_MIN - 1)),
% poste un message aléatoire par une personne aléatoire répondant à des messages aléatoires
- {Message, Repond_a} = {message_rand(), messages_id_rand()},\r
- %{Message, Repond_a} = {"blablablablablabla", []},
- io:format("~p poste ~p et repond a ~w~n", [User_id, Message, Repond_a]),
+ {Message, Repond_a} = {message_rand(), messages_id_rand()},
+ % io:format("~p poste ~p et repond a ~w~n", [User_id, Message, Repond_a]),
case euphorik_bd:nouveau_message(Message, User_id, Repond_a) of
{erreur, E} ->
io:format("~p : erreur : ~p~n", [User_id, E]),
loop(User_id, M - 1)
end.
+
+% Permet de tester la vitesse d'écriture en fonction de la
+% taille de la BD
+% voir : http://erlang.org/pipermail/erlang-questions/2008-October/038697.html
+bench_write_minichat(Filename) ->
+ Times = bench_write_minichat(1, []),
+ {ok, File} = file:open(Filename, [write]),
+ lists:foreach(
+ fun({Id, Time}) ->
+ io:format(File, "~w ~w~n", [Id, Time])
+ end,
+ Times
+ ),
+ file:close(File).
+bench_write_minichat(100000, Temps) -> Temps;
+bench_write_minichat(N, Temps) ->
+ {T, _} = timer:tc(mnesia, transaction, [fun() ->
+ Id = mnesia:dirty_update_counter(counter, minichat, 1),
+ mnesia:write(#minichat{
+ id = Id,
+ auteur_id = random:uniform(10000),
+ date = now(),
+ pseudo = "Test",
+ contenu = "Blabla blabla bla.",
+ racine_id = random:uniform(10000)
+ })
+ end]),
+ bench_write_minichat(N + 1, if N rem 500 =:= 0 -> [{N, T} | Temps]; true -> Temps end).
+
+
+
\ No newline at end of file
+% coding: utf-8
% Copyright 2008 Grégory Burri
%
% This file is part of Euphorik.
% Version de la BD
--define(VERSION_BD, 2).
+-define(VERSION_BD, 3).
-define(TABLES, [counter, proprietes, minichat, reponse_minichat, user, ip_table, troll]).
date, % erlang:now()
pseudo, % chaine de caractère
contenu, % chaine de caractère
- troll_id = undefined, % l'id du troll associé correspondant
racine_id = undefined % la racine, par défaut correspond à l'id du message
}).
}).
-
-record(profile, % attention : pas une table !
{
pseudo = [], % string()
ostentatious_master = light, % peut valoir invisible, light ou heavy. seulement pour ek_master
chat_order = reverse, % peut valoir chrono ou reverse
conversations = [] % [{integer(), bool}], la liste des messages correspondant au conversation {racine, reduite?}
- }).
+ }).\r
+ \r
+
-record(user,
{
id,
-record(troll,
{
id,
- id_user,
+ id_user,\r
+ id_minichat = undefined, % l'id du message associé
date_create, % erlang:now()
date_post = undefined, % date à laquelle le troll est affiché sur la page principale. undefined initialement puis erlang:now() quand affiché
content % chaine de caractère
margin: 0px;
}
+/***** Textile *****/
+em.leger {
+ font-style: italic
+}
+em.fort {
+ font-style: normal;
+ font-weight: bold
+}
+
/***** Menu *****/
ul#menu {
background-image: url(img/logo_fond.png);
form input,
form button,
form select {
+ color: #841919;
background-color: #f0df95;
border: #841919 1px solid;
}
vertical-align: middle;
}
+/***** L'aide sur les commandes *****/
+#aideCommandes h1 {
+ font-size: 14px;
+ font-weight: bold;
+}
+#aideCommandes .usage {
+ font-weight: bold;
+}
+#aideCommandes li {
+ list-style-type: none;
+}
+
/***** La boite de sélection des smiles *****/
#smiles {
text-align: center;
top: 77px;
line-height: 32px;
}
+
+#page.minichat #trollCourant a:link, #page.minichat #trollCourant a:visited {
+ color: #f85b31;
+}
+ #page.minichat #trollCourant a:hover, #page.minichat #trollCourant a:active {
+ color: #f87e5d;
+}
+
#page.minichat #trollCourant .troll {
cursor: pointer;
font-style: italic
margin-top: 40px;
}
+/***** Textile *****/
+em.leger {
+ font-style: italic
+}
+em.fort {
+ font-style: normal;
+ font-weight: bold
+}
+
/***** Menu *****/
ul#menu {
padding-left: 300px;
vertical-align: middle;
}
+/***** L'aide sur les commandes *****/
+#aideCommandes h1 {
+ font-size: 14px;
+ font-weight: bold;
+}
+#aideCommandes .usage {
+ font-weight: bold;
+}
+#aideCommandes li {
+ list-style-type: none;
+}
+
/***** La boite de sélection des smiles *****/
#smiles {
text-align: center;
% Recharge les modules de euphorik et met à jour la BD.
% TODO : construire le nom du noeud en fonction du nom de l'host
-main(_) ->
+hote() ->
+ '@overnux'.
+
+% le premier argument est le nom du noeud est peut valoir :
+% - yaws : noeud de production
+% - yaws_dev : noeud de pre-production
+main([Nom_node]) when Nom_node =:= "yaws"; Nom_node =:= "yaws_dev" ->
+ Node = list_to_atom(Nom_node ++ atom_to_list(hote())),
net_kernel:start([flynux, shortnames]),
io:format("rechargement des modules..~n"),
- _Pid = spawn_link(yaws@overnux, euphorik_daemon, reload_euphorik, []),
- receive
- {'EXIT', _, _} ->
- io:format("mise à jour de la BD..~n"),
- spawn(yaws@overnux, euphorik_bd_admin, update, [])
- end.
+ rpc:call(Node, euphorik_daemon, reload_euphorik, []),
+ if Nom_node =:= "yaws_dev" -> copier_bd(Node);
+ true -> true
+ end,
+ io:format("mise à jour de la BD..~n"),
+ rpc:call(Node, euphorik_bd_admin, update, []);
+main(_) ->
+ io:format("Usage : mise_en_prod.erl <node>"),
+ halt(1).
+% Copie la bd du noeud de production
+copier_bd(Node) ->
+ io:format("Copie de la BD de production vers le noeude pre-production~n"),
+ Fichier = "/tmp/backup_ek_tmp",
+ Fichier2 = "/tmp/backup_ek_tmp2",
+ rpc:call(yaws@overnux, mnesia, backup, [Fichier]),
+ rpc:call(Node, euphorik_bd_admin, change_node_name, [yaws@overnux, yaws_dev@overnux, Fichier, Fichier2]),
+ rpc:call(Node, mnesia, restore, [Fichier2, [{default_op, recreate_tables}]]),
+ rpc:call(yaws@overnux, file, delete, [Fichier]),
+ rpc:call(Node, file, delete, [Fichier2]).
+
+
+
+
+
+
#!/bin/bash
+# coding: utf-8
# screen est utilisé par exemple pour lancé une version de preproduction et permettre de la faire tourner après un délog
-yaws --conf ./yaws.conf --sname yaws_dev --mnesiadir "../var/BD/" -I debian_yaws_dev
+yaws --conf ./yaws.conf --sname yaws_dev --mnesiadir "../var/BD/" -I debian_yaws_dev\r
def verifierRecur(dossier)
Dir.foreach(dossier){|fichier|
- if fichier != '.' and fichier != '..' and File.directory?(fichier) and fichier != 'dirs'
- if not verifierRecur(dossier + '/' + fichier)
+ cheminComplet = "#{dossier}/#{fichier}"
+ if fichier[0,1] != '.' and File.directory?(cheminComplet) and fichier != 'libs'
+ if not verifierRecur(cheminComplet)
return false
end
elsif fichier[-3, 3] == '.js'
- puts "== Vérification de #{dossier}/#{fichier} =="
+ puts "== Vérification de #{cheminComplet} =="
# TODO : mettre un if pour la version windows si dessous
- #system("java org.mozilla.javascript.tools.shell.Main jslint.js #{dossier}/#{fichier}")
- system("rhino ./tools/jslint.js #{dossier}/#{fichier}")
+ #system("java org.mozilla.javascript.tools.shell.Main jslint.js #{cheminComplet}")
+ system("rhino ./tools/jslint.js #{cheminComplet}")
# puts $?.exitstatus
if $?.exitstatus > 0
return false
# Effectue la mise en production.
def miseEnProd
copierFichiers()
- maj()
+ maj('yaws')
end
# Effectue la mise en préproduction.
copierFichiers()
copierVAR()
lancerYaws()
+ maj('yaws_dev')
end
def copierFichiers
creer_rep("tools")
system("rsync tools/yaws.conf #{@uri}:#{@rep}/tools")
system("rsync tools/start_yaws.sh #{@uri}:#{@rep}/tools")
- # TODO
+ system("ssh #{@uri} \"cd #{@rep}/tools; screen -d -m -S yaws_dev ./start_yaws.sh\"")
end
def exec(commande)
end
def compiler_partie_serveuse
+ log "compilation des modules serveur"
Dir.chdir('modules')
system("make")
if $?.exitstatus != 0
# css, images, html, etc..
def copier_partie_statique
+ log "copie de la partie statique"
uri = "#{@uri}:#{@rep}"
system("awk '$0 !~ /prod=\"delete\"/' index.yaws | ssh #{@uri} \" cat > #{@rep}/index.yaws\"")
system("rsync favicon.ico #{uri}")
# minification et package des fichiers js dans euphorik.js
def pack_js
+ log "minification, assemblage et copie du javascript"
rep_js = 'js'
creer_rep(rep_js)
# jquery.js et euphorik.js doivent se trouve en premier
end
def copie_modules_serveurs
+ log "copie des modules du serveur"
# copie des modules erlang
creer_rep('modules')
system("rsync -r --exclude 'euphorik_test.beam' modules/ebin #{@uri}:#{@rep}/modules")
end
def set_droits_fichiers
+ log "attribution des droits sur les fichiers"
# attribution des droits
exec("chmod -R g+rx .")
end
- def maj
+ # noeud : le nom du noeud sur lequel le script de mise en prod est exécuté
+ # Execute le script 'mise_en_prod.erl' sur le serveur afin de :
+ # - Recharger les modules
+ # - Mettre à jour la base de données
+ def maj(noeud)
+ log "rechargement des modules serveur et mise à jour de la base de données"
# execution du script de mise à jour
system("cat tools/mise_en_prod.erl | ssh #{@uri} \"cat > /tmp/mise_en_prod.erl\"")
- system("ssh #{@uri} \"chmod u+x /tmp/mise_en_prod.erl; /tmp/mise_en_prod.erl; rm /tmp/mise_en_prod.erl\"")
+ system("ssh #{@uri} \"chmod u+x /tmp/mise_en_prod.erl; /tmp/mise_en_prod.erl #{noeud}; rm /tmp/mise_en_prod.erl\"")
+ end
+
+ def log(message)
+ puts "----- #{message} -----"
end
end
@verifJS.verifier()
when 'version'
@version.maj()
- end
-
-=begin
- Net::SSH.start('euphorik.ch', 'gburri') {|ssh|
- output = ssh.exec!("hostname")
- stdout = ""
- ssh.exec!("ls -l /tmp"){|channel, stream, data|
- stdout << data if stream == :stdout
- }
- puts stdout
- }
-=end
+ end
end
def afficherUsage