MOD avancement dans le module 'communication'
[euphorik.git] / js / comet.js
1 // coding: utf-8
2 // Copyright 2008 Grégory Burri
3 //
4 // This file is part of Euphorik.
5 //
6 // Euphorik is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // Euphorik is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with Euphorik. If not, see <http://www.gnu.org/licenses/>.
18
19 /*jslint laxbreak:true */
20
21 /**
22 * Permet de gérer les événements (push serveur).
23 * Principe de fonctionnement :
24 * - La page courante créer un objet euphorik.Comet en indiquant le nom de la page et la version du protocole.
25 * - La page courante attend un événement en appelant 'waitEvent' (non-bloquant) et en donnant deux fonctions :
26 * - 'funSend' une fonction qui renvoie l'objet à envoyer avant l'attente, par exemple {"dernierMess" : 23}
27 * ("header" et "page" sont automatiquement ajoutés à l'objet)
28 * - 'funsReceive' un ensemble de fonctions à appeler en fonction du "reply" du serveur, par exemple {"set_nom" : function(data) { print("ok : " + data.nom); } }
29 *
30 * l'information envoyée est sous la forme :
31 * {
32 * "header" : {"action" : "wait_event", "version" : <v> },
33 * "page" : <page>
34 * [..]
35 * }
36 * l'information reçue est sous la forme :
37 * {
38 * "reply" : <reply>
39 * [..]
40 * }
41 * <reply> et <page> sont de type chaine
42 *
43 * @page [string] la page courante pour laquelle on écoute des événements (un string)
44 * @util [int] la version
45 */
46 Comet = function(page, version) {
47 this.page = page;
48 this.version = version;
49
50 // l'objet JSONHttpRequest représentant la connexion d'attente
51 this.attenteCourante = undefined;
52
53 // le multhreading du pauvre, merci javascript de m'offrire autant de primitives pour la gestion de la concurrence...
54 this.stop = false;
55 };
56
57 /**
58 * Arrête l'attente courante s'il y en a une.
59 */
60 Comet.prototype.stopAttenteCourante = function() {
61 this.stop = true;
62
63 if (this.attenteCourante) {
64 this.attenteCourante.abort();
65 }
66 };
67
68 /**
69 * Attend un événement lié à la page. Non-bloquant.
70 * @funSend une fonction renvoyant les données json à envoyer
71 * @funsReceive est un objet comprenant les fonctions à appeler en fonction du "reply"
72 * les fonctions acceptent un paramètre correspondant au données reçues.
73 * exemple : {"new_message" : function(data){ ... }}
74 */
75 Comet.prototype.waitEvent = function(funSend, funsReceive) {
76 this.stopAttenteCourante();
77
78 this.stop = false;
79
80 var thisComet = this;
81
82 // on doit conserver l'ordre des valeurs de l'objet JSON (le serveur les veut dans l'ordre définit dans le protocole)
83 // TODO : ya pas mieux ?
84 var dataToSend = {
85 "header" : { "action" : "wait_event", "version" : this.version },
86 "page" : this.page
87 };
88 var poulpe = funSend();
89 objectEach(poulpe, function(k, v) {
90 dataToSend[k] = v;
91 });
92
93 this.attenteCourante = jQuery.ajax({
94 type: "POST",
95 url: "request",
96 dataType: "json",
97 // TODO : doit disparaitre
98 timeout: 180000, // timeout de 3min. Gros HACK pas beau. FIXME problème décrit ici : http://groups.google.com/group/jquery-en/browse_thread/thread/8724e64af3333a76
99 data: { action : JSON.stringify(dataToSend) },
100 success:
101 function(data) {
102 funsReceive[data.reply](data);
103
104 // rappel de la fonction dans 100 ms
105 setTimeout(function(){ thisComet.waitEvent2(funSend, funsReceive); }, 100);
106 },
107 error:
108 function(XMLHttpRequest, textStatus, errorThrown) {
109 ;; console.log("Connexion perdue dans PageEvent.prototype.waitEvent()");
110 setTimeout(function(){ thisComet.waitEvent2(funSend, funsReceive); }, 1000);
111 }
112 });
113 };
114
115 /**
116 * Si un stopAttenteCourante survient un peu n'importe quand il faut imédiatement arreter de boucler.
117 */
118 Comet.prototype.waitEvent2 = function(funSend, funsReceive) {
119 if (this.stop) {
120 return;
121 }
122 this.waitEvent(funSend, funsReceive);
123 };