I. Présentation ♪▲
Dans un précédent article (https://ditch.developpez.com/javascript/partialupdate/), je vous avais présenté une des techniques pour réaliser des mises à jour partielles. Voici dès lors un exemple d'utilisation de cette technique.
II. Types de conversations possibles▲
Conversation publique
Tous les utilisateurs, lors de leur arrivée sur le dialogue en direct, se trouvent dans la salle appelée « Generale ». Cette salle est la salle la plus peuplée et servira de tremplin aux conversations privées ou de groupe.
Conversation privée
Souvent, il est utile pour un utilisateur de dialoguer avec un utilisateur en particulier, et ce afin d'éviter les interférences avec les autres conversations dans la salle d'accueil. Dans ce cas, uniquement les utilisateurs mis en contact verront la conversation.
Conversation de groupe
Parfois, un groupe d'utilisateurs peut souhaiter discuter d'un point particulier. De nouveau, afin d'éviter les interférences de la salle d'accueil, il est possible à plusieurs utilisateurs de se rendre dans une salle supplémentaire, salle que l'on peut créer de manière simple.
III. Interface▲
L'interface du dialogue en direct se doit d'être sobre. Ainsi, seules les informations nécessaires sont présentes dans la page afin d'éviter les interférences éventuelles.
Comme on le voit sur le schéma, il s'agit de garder à l'écran une zone de discussion (1), la liste des discussions en cours (2), la liste des salles disponibles (3) ainsi que la liste des utilisateurs participant à la discussion en cours d'affichage (4) et la zone d'envoi de messages (5).
Lors d'un clic droit sur un utilisateur, un menu contextuel apparaît :
Lors d'un clic droit sur une salle, un menu contextuel apparaît également :
Par ailleurs, la largeur des contrôles est étudiée de sorte que la page est supportée et affichable sans problème sur la plupart des navigateurs même lors d'un affichage dont la résolution est de 1024x768.
Le contenu HTML de cette page interface est des plus classiques. Il est cependant nécessaire de ne pas oublier d'effectuer les différents liens vers les fichiers CSS et les fichiers JavaScript.
Il est bon de noter que l'utilisation des balises « table » a été préférée à l'utilisation des « div » afin de faciliter la manipulation JavaScript.
IV. Fonctionnalités pour l'utilisateur au niveau de l'interface▲
Passage au-dessus d'un nom d'utilisateur
Affichage des informations le concernant (type d'utilisateur, école). Ces informations auront été envoyées au préalable lors de la connexion de l'utilisateur concerné ou lors du chargement des informations sur la salle en cours. Ces informations sont cachées dans la page dès la réception de celle-ci et affichées par du JavaScript.
Clic droit sur un nom d'utilisateur
Ouverture d'un menu contextuel contenant les options suivantes :
- Conversation privée
Ouverture d'une salle de dialogue privée avec l'utilisateur concerné.
- Voir son profil
Ouverture de la page du profil de l'utilisateur dans une nouvelle fenêtre du navigateur.
- Voir ses documents partagés
Ouverture de la page de recherche avec les résultats correspondants aux documents appartenant à l'utilisateur concerné.
- Voir tous les documents partagés
Ouverture de la liste des documents partagés par les membres de msdnacademie (il s'agit du site pour lequel ce dialogue en direct a été réalisé).
Clic droit dans la zone « salles »
Un clic droit dans la liste des salles permet l'ouverture d'un menu contextuel contenant les options suivantes :
- Rejoindre
Ouverture de la salle de discussion choisie.
- Créer une salle
Ouverture d'une nouvelle salle de discussion. Le nom de la salle est choisi par l'utilisateur.
Si le clic est effectué sur un nom de salle, le choix « Rejoindre » est accessible. Si le clic a été effectué dans une zone vide, ce choix n'est pas affiché.
Fin de la discussion
Lors du clic sur une image représentant une fermeture, la salle de discussion est fermée.
Affichage d'une zone de discussion
Lorsque plusieurs salles de discussion sont disponibles, il est possible de passer d'une salle à l'autre. Dans ce cas, la salle de discussion active disparaît et celle souhaitée apparaît.
Envoi d'un message
Un clic sur un bouton d'envoi permet d'envoyer le message aux autres participants. Un clic sur la touche entrée lors de l'encodage du message a le même effet.
V. Principe de fonctionnement du serveur▲
Le serveur du dialogue en direct est une application asp.NET classique utilisant des variables globales afin de stocker les informations le temps nécessaire pour s'assurer de la bonne réception des informations. Il est préférable d'éviter l'utilisation d'un protocole de chat existant comme IRC car celui-ci utilise un port différent du port utilisé pour effectuer les requêtes http, ce qui peut poser des problèmes avec l'utilisation de serveurs proxies et des firewalls.
Concernant la gestion des informations sur le serveur, plusieurs choix s'offrent à nous : - L'utilisation d'une base de données - L'utilisation de fichiers - L'utilisation de la mémoire o Instancier un « événement » par utilisateur et par salle o garder uniquement le dernier message de la salle o garder les dix derniers messages de la salle. La solution adoptée dans ce cas est la dernière citée. Les accès disques sont coûteux en temps et sont trop nombreux dans ce cas. Il s'agit donc d'utiliser diverses instances de classes dans la mémoire de manière globale, ce qui permet de faire passer des informations entre plusieurs utilisateurs. Ainsi chaque élément du dialogue en direct est matérialisé par une classe. Tout est ainsi stocké en mémoire. On veillera cependant à libérer les ressources au maximum et de ne garder que les informations nécessaires au bon déroulement du dialogue en direct. Comme on peut le voir sur le diagramme de classes, toutes les informations sont stockées à partir de deux listes. Par ailleurs, et c'est certainement le plus important, il n'y a qu'une instance des messages, ces messages ne sont pas redondants et la mémoire est ainsi allégée par rapport aux autres solutions. Pour ce qui est de la décision entre stocker un ou dix messages en mémoire, cela s'explique par le fait que certains navigateurs sont plus lents que d'autres et il pourrait y avoir des pertes d'informations. De plus, la personne qui entre dans une salle peut voir ces dix derniers messages, ce qui lui permet d'entrer dans la conversation rapidement.
VI. Principe de fonctionnement du client▲
Le client utilise deux voies de communication avec le serveur. Ces voies sont matérialisées par des iframes cachées, l'une étant utilisée pour l'envoi d'informations et l'autre pour la réception. Ces canaux de communication utilisent tous deux le protocole http pour les raisons précitées. Chacune de ces iframes fait des requêtes vers une page particulière. L'iframe destinée à la réception utilise une page Chat_Rcv.aspx et celle permettant l'envoi des informations utilise Chat_Snd.aspx. Il aurait été possible d'utiliser différentes pages pour ce qui est des envois, chacune ayant une fonction particulière. Cependant, le coût en temps de développement est bien plus élevé que le gain lors des différents appels. Voici les éléments importants de ces deux pages… La page qui permet de recevoir les informations est relativement simple avec l'utilisation d'un switch. Suivant l'action à effectuer, le javascript effectuera le traitement adéquat.
Page.
EnableViewState =
false
;
if
(
Chat_Global.
userList[
Chat_SessionTransfert.
User_Name].
HaveEventNotThreated)
{
Chat_Event OldestEvent =
Chat_Global.
userList[
Chat_SessionTransfert.
User_Name].
Events.
Oldest;
switch
(
OldestEvent.
Command)
{
case
Chat_Event_Command.
EnterRoom:
EnterRoom
(
OldestEvent);
break
;
// …
case
Chat_Event_Command.
Nothing:
break
;
}
Reload
(
);
}
else
{
Reload
(
);
}
Le javascript de la page est très simple puisqu'il fait appel à une fonction décrite dans le script de la page container. Cette dernière se charge d'appeler les fonctions correspondantes à l'action.
function SwitchRcv
(
)
{
if (
getObjectById)
if (
obj =
getObjectById
(
'Action'
))
parent
.SwitchRcvValue
(
obj.
value);
}
Comme on peut le voir dans le cadre suivant, la page contient une série de champs cachés qui permettent de passer les informations et de les utiliser dans le code-behind. C'est le javascript qui se charge de copier les informations dans ces différents champs.
<HTML>
<HEAD>
<script language
=
"javascript"
src
=
"../Chat_Snd.js"
></script>
</HEAD>
<body>
<form id
=
"Form1"
method
=
"post"
runat
=
"server"
>
<input type
=
"hidden"
id
=
"Action"
runat
=
"server"
/>
<input type
=
"hidden"
id
=
"RoomName"
runat
=
"server"
/>
<input type
=
"hidden"
id
=
"Message"
runat
=
"server"
/>
<asp:
LinkButton Runat
=
"server"
ID
=
"LbSnd"
></asp
:
LinkButton>
</form>
</body>
</HTML>
Voici le contenu du script javascript nécessaire pour effectuer la copie. Bien entendu, il n'est pas complet. Il se base sur des éléments décrits précédemment ainsi que sur des fonctions dont le nom est explicite.
function Switch
(
)
{
// parent.msg = parent.msg + 'Switch\n';
if (
getObjectByIdParent)
if (
objParent =
getObjectByIdParent
(
'Action'
))
if (
getObjectById)
if (
obj =
getObjectById
(
'Action'
))
obj.
value =
objParent.
value;
if (
copyValues)
copyValues
(
);
__doPostBack
(
'LbSnd'
,
''
);
}
function copyValues
(
)
{
if (
getObjectById)
if (
action =
getObjectById
(
'Action'
))
if (
action.
value ==
'EnterRoom'
)
copyRoomName
(
);
else if (
obj.
value ==
'LeaveRoom'
)
copyRoomName
(
);
else if (
obj.
value ==
'SendMsg'
)
{
copyRoomName
(
);
copyMessage
(
);
}
else if (
obj.
value ==
'NewRoom'
)
copyRoomName
(
);
else if (
obj.
value ==
'EnterPrivateRoom'
)
copyRoomName
(
);
}
Une fois les données récupérées, il ne reste plus qu'à différencier les traitements à effectuer. De nouveau, ceci se fait à l'aide d'un switch. Nous verrons les différentes fonctionnalités dans la suite de ce document.
private
void
Page_Load
(
object
sender,
System.
EventArgs e)
{
if
(!
Page.
IsPostBack)
Page.
RegisterStartupScript
(
"js"
,
"<script language=
\"
javascript
\"
>Switch();</script>"
);
}
private
void
LbSnd_Click
(
object
sender,
System.
EventArgs e)
{
switch
(
Action.
Value)
{
case
"EnterRoom"
:
EnterRoom
(
);
break
;
// …
case
"EnterPrivateRoom"
:
EnterPrivateRoom
(
);
break
;
}
Page.
RegisterClientScriptBlock
(
"jsclient"
,
"<script language=
\"
javascript
\"
>ChangeFrameLocationParent('FrameRcv', './Chat_Rcv.aspx');</script>"
);
}
Concernant la réception, il existe quatre techniques de programmation envisageables : - synchrone - asynchrone - web service - web service asynchrone. L'utilisation des web service allongerait les temps de transfert entre les différents clients et le serveur. De plus, la hiérarchie de classes est située sur le même serveur que les différentes pages. Il n'est pas donc nécessaire d'utiliser un web service. Par ailleurs, il n'existe aucun moyen de faire des pages asynchrones entre un navigateur client et un serveur mis à part l'utilisation de JavaScript avec la classe XMLHTTPRequest. Cependant, cette classe est toute jeune et ne se trouve pas dans la norme du W3C et, surtout, n'est implémentée que sur très peu de navigateurs. Il ne reste donc qu'un choix possible. C'est ce choix que nous allons utiliser pour simuler de l'asynchrone. Ainsi, toutes les trois secondes, le client fait une requête au serveur afin de vérifier qu'aucune information ne lui est destinée. Cependant, très peu d'informations transitent sur entre le client et le serveur, rendant cette requête très rapide et très peu contraignante que ce soit pour le client ou le serveur.
VII. Implémentation des différentes fonctionnalités▲
Comme il est noté dans le paragraphe précédent, le dialogue en direct doit gérer divers évènements. À chaque événement, un message est envoyé à d'autres utilisateurs. Le navigateur de ces utilisateurs doit pouvoir gérer ces messages.
Il s'agit donc d'un protocole orienté « messages ».
Quelle que soit la fonctionnalité, il est nécessaire, pour des raisons de sécurité, mais aussi pour éviter les problèmes de codage, de passer par des champs dans les iframes. Tout cela est détaillé dans le chapitre concerné au « Partial Update ».
Tout au long de l'utilisation du chat, le serveur gardera en mémoire un objet de type utilisateur. Cet objet sera détruit après une durée de non-réponse du client d'une vingtaine de secondes.
Par ailleurs, une variable de session est utilisée pour garder en mémoire le nom de l'utilisateur. C'est la seule information qu'il est nécessaire de garder au niveau des sessions. Effectivement c'est grâce à cette information que l'on peut définir la source des différents messages.
Connexion au dialogue en direct
Lors de la demande de la page, le serveur, par les méthodes d'authentification mises en place, enregistre l'utilisateur comme utilisateur du dialogue en direct.
Dès lors, il renvoie une page contenant l'interface du dialogue en direct. C'est cette interface qui sera utilisée durant toute la durée de l'utilisation du dialogue en direct.
L'événement onload de la page se charge de connecter l'utilisateur à une salle, en l'occurrence « Generale ». La possibilité de réaliser cette opération directement lors de la connexion existe, cependant la solution apportée permet d'éviter la redondance du code. La technique utilisée pour la connexion à une salle est détaillée au point suivant.
hideAll
(
);
hideDescription
(
);
if (
EnterRoom)
EnterRoom
(
'General'
);
Le principe est ainsi connu, mais les méthodes mises en place pour effectuer ces opérations ne sont pas encore détaillées. Nous allons remédier à cela :
Connexion à une salle de dialogue
Lorsqu'un utilisateur se connecte à une salle, les autres utilisateurs doivent en être avertis.
Par ailleurs, l'utilisateur qui se connecte doit recevoir la liste des utilisateurs connectés à la salle concernée ainsi que les dix derniers messages postés dans cette salle.
De ce fait, le client envoie une demande de connexion à la salle et en réponse il reçoit cette liste d'informations tandis que les autres utilisateurs reçoivent une notification de connexion avec les informations adéquates.
Les informations envoyées sont donc :
- « EnterRoom » comme commande de notre protocole afin de signaler qu'il s'agit d'une nouvelle connexion ;
- l'identifiant de la salle ;
- des informations complémentaires qui peuvent être, par exemple, la ville, l'âge ou toute autre information utile aux personnes connectées.
Le serveur se charge d'ajouter les informations sur l'utilisateur qui se trouvent dans des variables de session.
Les informations qui transitent dans le cadre de msdnacademie sont :
- pour le login : la concaténation du nom et du prénom (avec un espace entre les deux) ;
- pour les informations complémentaires : le type et l'établissement de l'utilisateur.
En retour, les autres utilisateurs reçoivent une notification « EnteringRoom », notification qui sera traitée par le JavaScript qui se chargera d'ajouter l'utilisateur dans la liste des utilisateurs connectés à la salle. Ces utilisateurs recevront toutes les informations qui ont été émises pour le nouvel arrivant. Il sera ainsi possible, lors d'un survol du nom d'utilisateur, de les récupérer.
La fonction permet l'entrée dans la salle est :
foreach
(
string
userName in
Chat_Global.
roomList[
RoomName.
Value].
Users.
UserNames)
if
(
userName ==
Chat_SessionTransfert.
User_Name) return
;
Chat_Global.
roomList[
RoomName.
Value].
Users.
Add
(
Chat_Global.
userList[
Chat_SessionTransfert.
User_Name]
);
Pour la réception, il faut scinder en deux cas. Le premier est l'entrée de l'arrivant. Il reçoit la liste des utilisateurs actuellement connectés et la liste des derniers messages afin de les afficher.
// Instanciation des objets de base
GenerateHiddenInput
(
"Action"
,
"EnterRoom"
);
GenerateHiddenInput
(
"Roomname"
,
evt[
Chat_Event_Parameters.
EnterRoom_RoomName]
);
// Déclarations diverses
foreach
(
Chat_User user in
Chat_Global.
roomList[
evt[
Chat_Event_Parameters.
EnterRoom_RoomName]].
Users.
Users)
{
// Mise en forme des informations sur les utilisateurs de la salle dans laquelle on entre
row =
new
HtmlTableRow
(
);
cell =
new
HtmlTableCell
(
);
cell.
InnerHtml =
user.
UserName;
cell.
ID =
"td_"
+
evt[
Chat_Event_Parameters.
EnterRoom_RoomName]
+
"_"
+
user.
UserName.
Replace
(
" "
,
"_"
);
// …
// Ajout des événements
// Création de la cellule contenant la description
row.
Cells.
Add
(
cell);
row.
Cells.
Add
(
cellInfos);
tableUsers.
Rows.
Add
(
row);
}
// Initialisation de certaines propriétés
foreach
(
Chat_Message message in
Chat_Global.
roomList[
evt[
Chat_Event_Parameters.
EnterRoom_RoomName]].
Messages.
AllMessages)
{
// Mise en forme des 10 derniers messages de la salle laquelle on entre
}
// Initialisation de certaines propriétés
// Ajout des composants HTML dans la page à envoyer au client
FormRcv.
Controls.
Add
(
divMessages);
FormRcv.
Controls.
Add
(
divRoomSwitch);
if (!(
exists =
getObjectById
(
'td_'
+
getObjectByIdFrame
(
'FrameRcv'
,
'Roomname'
).
value)))
{
var val =
getObjectByIdFrame
(
'FrameRcv'
,
'divUsers'
).
innerHTML;
if (
setInner)
setInner
(
'tdUsersList'
,
getObjectById
(
'tdUsersList'
).
innerHTML +
val);
val =
getObjectByIdFrame
(
'FrameRcv'
,
'divMessages'
).
innerHTML;
if (
setInner)
setInner
(
'divMessages'
,
getObjectById
(
'divMessages'
).
innerHTML +
val);
hide
(
'tableMessages_'
+
getObjectById
(
'RoomNameInUse'
).
value);
hide
(
'tableUsers_'
+
getObjectById
(
'RoomNameInUse'
).
value);
GenerateSwitchButton
(
getObjectByIdFrame
(
'FrameRcv'
,
'Roomname'
).
value);
}
if (
getObjectById)
if (
obj =
getObjectById
(
'RoomsListTable'
))
{
if (!(
exists =
getObjectById
(
getObjectByIdFrame
(
'FrameRcv'
,
'Roomname'
).
value)))
{
GenerateRoomInList
(
getObjectByIdFrame
(
'FrameRcv'
,
'Roomname'
).
value);
}
}
ChangeRoomNameInUse
(
getObjectByIdFrame
(
'FrameRcv'
,
'Roomname'
).
value);
Le deuxième cas est le fait d'être averti qu'un autre utilisateur vient de se connecter. Dans ce cas, il suffit de l'insérer dans la liste avec ses informations.
GenerateHiddenInput
(
"Username"
,
evt[
Chat_Event_Parameters.
EnteringRoom_Username]
);
GenerateHiddenInput
(
"UserId"
,
evt[
Chat_Event_Parameters.
EnteringRoom_Id]
);
GenerateHiddenInput
(
"UserDescription"
,
evt[
Chat_Event_Parameters.
EnteringRoom_Description]
);
GenerateHiddenInput
(
"Roomname"
,
evt[
Chat_Event_Parameters.
EnteringRoom_RoomName]
);
GenerateHiddenInput
(
"Action"
,
"EnteringRoom"
);
GenerateUserInList
(
getObjectByIdFrame
(
'FrameRcv'
,
'Username'
).
value,
getObjectByIdFrame
(
'FrameRcv'
,
'UserId'
).
value,
_
getObjectByIdFrame
(
'FrameRcv'
,
'UserDescription'
).
value,
getObjectByIdFrame
(
'FrameRcv'
,
'Roomname'
).
value);
Communication privée
Une communication privée peut être assimilée à une salle qui est invisible aux autres utilisateurs. L'appel se fait de nouveau lors d'un clic dans un menu. L'appel est donc semblable au schéma de connexion à une salle publique.
La différence majeure entre une salle publique et un dialogue privé est que, pour le dialogue privé, une fenêtre s'ajoute directement dans la liste des salles dans laquelle nous participons. Les autres utilisateurs ne verront bien entendu pas les informations concernant ce dialogue sauf l'utilisateur avec qui la conversation est entamée qui reçoit un événement « EnterRoom », ce qui permet d'ouvrir directement la salle ainsi créée.
string
PrivateRoomName =
RoomName.
Value;
PrivateRoomName =
PrivateRoomName.
Remove
(
0
,
5
);
PrivateRoomName =
PrivateRoomName +
"#"
+
Chat_Global.
userList[
Chat_SessionTransfert.
User_Name].
UserName.
Replace
(
" "
,
"_"
);
Chat_Global.
roomList.
Add
(
new
Chat_Room
(
PrivateRoomName,
true
));
// Voir EnterRoom présenté dans le point précédent.
Envoi d'un message
L'événement « envoi d'un message » peut se déclencher à deux moments :
- clic sur le bouton ou l'image « Envoyer » ;
- appui sur la touche « entrée » lorsque le focus est sur la boîte d'envoi.
Dès lors, les informations envoyées sont : « SendMsg | salle | message ».
Dans ce cas, les utilisateurs de la salle, y compris l'émetteur, recevront une notification qui sera matérialisée par « ReceiveMsg | salle | émetteur | date | message ».
Si la fenêtre de discussion n'est pas active, le message est tout de même traité et sera affiché lorsque celle-ci deviendra active, et ce afin de ne pas surcharger le serveur.
Les fonctions utilisées, que ce soit pour l'envoi ou la réception sont dans la même lignée que les précédentes. Ainsi, l'envoi se fait par l'ajout du message dans la liste des messages de la salle.
Chat_Global.
roomList[
RoomName.
Value].
Messages.
Add
(
new
Chat_Message
(
Chat_Global.
userList[
Chat_SessionTransfert.
User_Name],
Message.
Value));
Page.
RegisterStartupScript
(
"js"
,
"<script language=
\"
javascript
\"
>MoreMessages();</script>"
);
La réception est des plus classiques dans le dialogue en direct. Les informations se trouvent dans des champs caches…
GenerateHiddenInput
(
"Action"
,
"ReceiveMsg"
);
GenerateHiddenInput
(
"Roomname"
,
evt[
Chat_Event_Parameters.
ReceiveMessage_RoomName]
);
GenerateHiddenInput
(
"Sender"
,
evt[
Chat_Event_Parameters.
ReceiveMessage_Sender]
);
GenerateHiddenInput
(
"Date"
,
evt[
Chat_Event_Parameters.
ReceiveMessage_Date]
);
GenerateHiddenInput
(
"Message"
,
evt[
Chat_Event_Parameters.
ReceiveMessage_Message]
);
… et sont utilises par le javascript
var text
=
'['
+
getObjectByIdFrame
(
'FrameRcv'
,
'Date'
).
value+
'] '
+
getObjectByIdFrame
(
'FrameRcv'
,
'Sender'
).
value+
' > '
+
getObjectByIdFrame
(
'FrameRcv'
,
'Message'
).
value;
AddElementInMessagesList
(
getObjectByIdFrame
(
'FrameRcv'
,
'Roomname'
).
value,
text
);
Déconnexion d'une salle de dialogue
Le clic sur une image « Déconnecter » permet de quitter une salle. Le message qui transitera sera alors « LeaveRoom | salle ».
Chat_Global.
roomList[
RoomName.
Value].
Users.
Remove
(
Chat_Global.
userList[
Chat_SessionTransfert.
User_Name]
);
Les utilisateurs connectés à la salle concernée recevront un événement dont le but est de supprimer le nom de la liste des utilisateurs connectés. Cette notification sera identifiée par « LeavingRoom | sallle | user ».
De nouveau les fonctions se suivent et se ressemblent…
GenerateHiddenInput
(
"Action"
,
"LeavingRoom"
);
GenerateHiddenInput
(
"Roomname"
,
evt[
Chat_Event_Parameters.
LeavingRoom_RoomName]
);
GenerateHiddenInput
(
"Username"
,
evt[
Chat_Event_Parameters.
LeavingRoom_Username]
);
removeElement
(
'td_'
+
getObjectByIdFrame
(
'FrameRcv'
,
'Roomname'
).
value +
"_"
+
getObjectByIdFrame
(
'FrameRcv'
,
'Username'
).
value);
var text
=
'<font color=red><b>'
+
getObjectByIdFrame
(
'FrameRcv'
,
'Username'
).
value +
'</b> vient de quitter la salle</font>'
;
parent
.AddElementInMessagesList
(
getObjectByIdFrame
(
'FrameRcv'
,
'Roomname'
).
value,
text
);
Ce qui donne schématiquement,
Si l'utilisateur qui quitte la salle est le dernier utilisateur, le serveur doit signaler que la salle est fermée et non pas qu'un utilisateur est déconnecté. Dans ce cas, il s'agit de l'événement « CloseRoom | salle »
Suppression des utilisateurs
Un thread se charge de vérifier que les utilisateurs connectés le sont réellement. Ainsi, si le navigateur d'un utilisateur n'a pas envoyé de requête durant un certain laps de temps, cet utilisateur est déconnecté du dialogue en direct.
Dans ce cas, les autres utilisateurs reçoivent la notification afin d'enlever l'utilisateur de la liste.
GenerateHiddenInput
(
"Action"
,
"LeavingRoom"
);
GenerateHiddenInput
(
"Roomname"
,
evt[
Chat_Event_Parameters.
LeavingRoom_RoomName]
);
GenerateHiddenInput
(
"Username"
,
evt[
Chat_Event_Parameters.
LeavingRoom_Username]
);
Le javascript se charge d'effectuer cette suppression au niveau de l'interface.
removeElement
(
'td_'
+
getObjectByIdFrame
(
'FrameRcv'
,
'Roomname'
).
value +
"_"
+
getObjectByIdFrame
(
'FrameRcv'
,
'Username'
).
value);
var text
=
'<font color=red><b>'
+
getObjectByIdFrame
(
'FrameRcv'
,
'Username'
).
value +
'</b> vient de quitter la salle</font>'
;
parent
.AddElementInMessagesList
(
getObjectByIdFrame
(
'FrameRcv'
,
'Roomname'
).
value,
text
);
Suppression des salles
Il en va de même pour les salles. Le principe ici est de regarder le nombre d'utilisateurs qui se trouvent dans la salle. Si personne ne s'y trouve, la salle est fermée et les utilisateurs en sont avertis.
GenerateHiddenInput
(
"Action"
,
"CloseRoom"
);
GenerateHiddenInput
(
"Roomname"
,
evt[
Chat_Event_Parameters.
CloseRoom_RoomName]
);
removeElement
(
getObjectByIdFrame
(
'FrameRcv'
,
'Roomname'
).
value);
Créer une salle
Lors d'un clic droit suivant d'un clic dans le menu sur « Créer une salle », une boîte de dialogue apparaît afin d'encoder le nom de la salle.
Ce qui donne au niveau des événements du côté client :
Le message envoyé est ainsi « NewRoom | salle ». Tous les utilisateurs connectés au dialogue en direct recevront la notification afin d'ajouter la salle dans la liste des salles disponibles. Ceci se fera de cette manière :
De nouveau, le code est sensiblement le même que pour les autres fonctions si ce n'est qu'il y a d'abord quelques traitements sur le navigateur tels que l'affichage de la zone prévue pour encoder le nom de la salle, etc.
if (
getObjectById)
if (
obj =
getObjectById
(
'Action'
))
obj.
value =
'NewRoom'
;
ChangeRoomName
(
roomName);
ChangeFrameLocation
(
'FrameSnd'
,
'./Events/Chat_Snd.aspx'
);
foreach
(
string
userName in
Chat_Global.
roomList[
RoomName.
Value].
Users.
UserNames)
if
(
userName ==
Chat_SessionTransfert.
User_Name) return
;
Chat_Global.
roomList[
RoomName.
Value].
Users.
Add
(
Chat_Global.
userList[
Chat_SessionTransfert.
User_Name]
);
Les utilisateurs recevront eux une notification « NewRoom » également. Dans le cas de la réception, il s'agit d'ajouter cette salle dans la liste des salles disponibles. De nouveau, cela devient classique.
VIII. Conclusion▲
Nous venons de voir une utilisation de la technique du partial update, il y en a bien d'autres… Nous ne pouvons malheureusement pas toutes les détailler, mais n'hésitez pas à me contacter si vous avez des questions quant à l'utilisation de cette technique dans un autre contexte.