Dado que la comunicaci�n bidireccional y la verificaci�n del estado de disponibilidad de un usuario en la red Jabber no es ya para nosotros ning�n problema, pong�monos manos a la obra y construyamos una aplicaci�n completa que permita a m�ltiples usuarios de Internet comunicarse con varios empleados (consultores). Hasta este momento hab�amos estudiado solamente el caso de un solo usuario que se comunica con un solo consultor, que es una situaci�n raramente encontrada en aplicaciones reales.
Nuestro plan de acci�n ser� el siguiente:
- el cliente visualiza la p�gina con los contactos,
- en la p�gina aparece la lista de los consultores disponibles en ese momento (est� claro que esta lista puede estar vac�a, en cuyo caso el cliente deber� esperar un momento),
- si alguno de los consultores est� disponible, el cliente puede iniciar con �l una conversaci�n,
- una vez iniciada la conversaci�n, el consultor desaparece de la lista de empleados disponibles y el cliente puede conversar sin interrupciones con la persona elegida.
El esquema de navegaci�n para las p�ginas web y la arquitectura de la aplicaci�n completa se muestran en la Figura 3.
![Figura 3: Esquema de navegación y arquitectura de la aplicación](/cursos_descargas/phpsol_livechat/fig3.gif)
Como podemos ver, m�ltiples usuarios virtuales hacen uso de una misma cuenta en la red Jabber. Debido a esto, se hace necesario un mecanismo que permita redireccionar los mensajes enviados por el consultor a un usuario determinado.
�El atributo thread
Como recordaremos, todo mensaje puede poseer el atributo opcional thread, que permite distribuir los mensajes enviados y recibidos en hilos l�gicos de conversaci�n sobre un tema dado. La especificaci�n del protocolo establece que un cliente Jabber, despu�s de haber recibido un mensaje con este atributo, deber�a:
- a�adir a cada respuesta dada al mensaje el identificador del hilo de conversaci�n obtenido como valor del atributo,
- ofrecer al usuario una interfaz que permita distinguir entre los diferentes hilos de conversaci�n, incluso cuando varios de ellos han sido realizados con el mismo usuario.
Pensemos un momento: si enviamos desde la p�gina web un comunicado que contenga el atributo thread, en cuyo valor se encuentre el identificador de la sesi�n PHP, las respuestas del consultor tambi�n contendr�n en su campo thread el identificador de sesi�n PHP. �Bingo! Esto nos permitir� diferenciar las preguntas hechas por diferentes usuarios de nuestro formulario a un mismo consultor.
Existe, desgraciadamente, un peque�o problema: Jabber es un protocolo bastante joven y no todas sus implementaciones est�n completamente conformes con la especificaci�n. En particular, en algunas soluciones el atributo thread es completamente ignorado, lo que evidentemente imposibilita el uso de la idea presentada m�s arriba. Sin embargo, no es cuesti�n de preocuparse demasiado por anticipado, puesto que tambi�n existen productos que implementan correctamente el protocolo, tales como Exodus, el cual ofrece todas las funciones est�ndar de un cliente de mensajer�a instant�nea, adem�s de una buena documentaci�n.
�Estoy ocupado
El �ltimo problema que debemos resolver para que nuestra aplicaci�n sea una herramienta realmente �til es el de la asignaci�n de un usuario de la web (o sea, de su n�mero de sesi�n) a un consultor determinado. Para resolverlo, supondremos que la sesi�n se desarrollar� de la siguiente manera:
- el consultor llega a su trabajo, arranca su cliente de mensajer�a instant�nea y cambia su estado de disponibilidad a chat, dando a saber de esta manera que est� listo para responder a las preguntas de los usuarios,
- la informaci�n acerca de la disponibilidad del consultor se introduce en la base de datos de la aplicaci�n,
- el usuario visita la p�gina web con la lista de consultores disponibles y selecciona uno de ellos para iniciar una conversaci�n,
- en la base de datos de la aplicaci�n anotamos que el usuario de n�mero de sesi�n PHP tal se ha conectado con el consultor de identificador JID tal. Cambiamos el estado (en la base de datos) de este consultor a no disponible,
- el consultor obtiene el primer mensaje del usuario web. Puesto que espera estar ocupado con esta conversaci�n por alg�n tiempo, cambia su estado de disponibilidad a �no molestar� (dnd),
- ambas partes conversan sirvi�ndose cada una de su propia interfaz de usuario,
- cada una de las partes puede finalizar la conversaci�n. Del lado del usuario, esto se realiza haciendo clic sobre un enlace determinado. El consultor debe cerrar la ventana en la que se ha llevado a cabo la conversaci�n (�muy importante!) y cambiar su estado de disponibilidad a chat,
- cuando una de las partes pone fin a la conversaci�n, la entrada de la base de datos que se�alizaba la existencia de una relaci�n entre la sesi�n PHP y el JID es autom�ticamente eliminada.
Observemos ahora c�mo podemos poner este plan a la pr�ctica. El Listado 4 muestra la parte (modificada) de la aplicaci�n de consola, la cual hace uso repetido de dos clases: JabberConsultants y JabberMessages, cuyas definiciones pueden verse en los Listados 5 y 6 al final del art�culo.
<?php /** * @package jabber.console */ require('lib/jabber/class.jabber.php'); require('inc/db.inc.php'); require('class/model/JabberConsultants.php'); require('class/model/JabberMessages.php'); $jmessages = new JabberMessages($db); $jconsultants = new JabberConsultants($db); $jconsultants->setAllUnavailableStatus(); $JABBER = new Jabber; $JABBER->server = 'localhost'; $JABBER->port = '5222'; $JABBER->username = 'www_send'; $JABBER->password = 'www_send'; $JABBER->resource = 'ClassJabberPHP'; print "Conect�ndose con el servidor $JABBER->server ... "; $JABBER->Connect() or die('�Ha sido imposible establecer la conexi�n!'); print "�la conexi�n ha sido correctamente establecida!\n"; print "Autorizando al usuario $JABBER->server ... "; $JABBER->SendAuth() or die('�No ha sido posible autorizar al usuario!'); print "�autorizaci�n correctamente realizada!\n"; print "Listo para enviar y recibir mensajes...\n"; $JABBER->SendPresence(); while(1) { $JABBER->CruiseControl(10); $msg_array = $jmessages->getMessagesForSend(); foreach ($msg_array as $msg_to_send) { print "Enviando un mensaje a ".$msg_to_send['jid']."... \n"; $JABBER->SendMessage($msg_to_send['jid'],"chat",NULL, array( "thread" => $msg_to_send['sid'], "body" => $msg_to_send['msg'] ) ); $jmessages->markAsSend($msg_to_send['msg_id']); } } $JABBER->Disconnect(); function Handler_message_chat($message) { global $JABBER; $msg = $JABBER->GetInfoFromMessageBody($message); $sid = $JABBER->GetInfoFromMessageThread($message); if ($sid!='') { global $jmessages; $jmessages->sendMsgFromConsultant($sid,$msg); } } function Handler_presence_available($message) { global $JABBER; $jid = $JABBER->StripJID($JABBER->GetInfoFromPresenceFrom($message)); $status = $JABBER->GetInfoFromPresenceShow($message); global $jconsultants; $jconsultants->setAvailableStatus($jid,1,$status); } function Handler_presence_unavailable($message) { global $JABBER; $jid = $JABBER->StripJID($JABBER->GetInfoFromPresenceFrom($message)); global $jconsultants; $jconsultants->setAvailableStatus($jid,0,null); } ?>
El proceso completo de comunicaci�n se muestra en la Figura 4.
![Figura 4: Proceso de conversación con el consultor](/cursos_descargas/phpsol_livechat/fig4.jpg)
Se hacen aqu� necesarias algunas aclaraciones acerca del c�digo presentado. No hemos hecho a�n menci�n del uso que hace �ste de ADOdb como su capa de abstracci�n para el acceso a la base de datos. Gracias a �sto no tenemos que preocuparnos por el problema de la dependencia de un tipo concreto de la base.
Notemos tambi�n la manera en que se env�an los mensajes nuevos: primero se introducen en la base de datos, y despu�s, con ayuda del script console.php, se transmiten a la red Jabber. Esta soluci�n tiene dos ventajas fundamentales: por un lado podemos conservar el historial de la comunicaci�n completa y, por el otro, el script console.php es el �nico (!) en toda la aplicaci�n que sabe de la existencia de la clase que implementa el protocolo Jabber. Esto hace sencilla la sustituci�n de esta clase por otra, o incluso, el uso de una red de mensajer�a instant�nea completamente diferente.