Introducción a Flash Communication Server r.1.5 (II)
En este artículo trataremos el que quizá muchos consideremos el aspecto más potente y con más utilidades que nos brinda FCS: los SharedObjects.
Introducción a SharedObject. Su necesidad
Para introducir y entender la necesidad de los SharedObjects, recordaremos brevemente la aplicación que implementamos en la entrega anterior. En dicha aplicación se diseñó un sistema a través del que, bajo petición del usuario cliente, éste recibía un listado con los nombres de todos los usuarios conectados a la misma instancia de aplicación que él. Esta implementación la pudimos realizar recurriendo a llamadas a funciones en el servidor y en el cliente a través del método call(). La propiedad que nos permitía adquirir el listado era Application.clients, del lado del servidor.
Esta propiedad es similar a un Array en el que cada una de sus posiciones contiene una referencia al objeto representativo de cada uno de los clientes conectados. Sabiendo esto recorríamos cada una de sus posiciones y generábamos un Array con los nombres de los usuarios, para posteriormente mandarlo al cliente que lo había solicitado. Recordemos el código en el servidor:
Código Servidor
Client.prototype.getUsuarios_srv = function() {
var usuarios = new Array();
var i, length = application.clients.length;
for (i = 0; i < length; i++) {
usuarios.push(application.clients[i].usuario);
};
return usuarios
};
Si cambiamos un poco los requerimientos a satisfacer por esta aplicación, para que cada usuario tenga que ser notificado automáticamente tras la conexión o desconexión de otros usuarios y para recibir una lista completa de usuarios conectados en el momento de la conexión, la implementación podría ser muy parecida. Con los conocimientos adquiridos hasta el momento podríamos hacer la siguiente aproximación:
Código Servidor
application.onConnect = function(newClient,usuario) {
application.acceptConnection(newClient);
newClient.usuario = usuario;
var usuarios = [];
var length = application.clients.length;
for (i = 0; i < length; i++) {
usuarios.push(application.clients[i].usuario);
application.clients[i].call(“nuevoUsuario”,null,usuario);
}
newClient.call(“listarUsuarios”,null,usuarios);
};
El código anterior se encarga de aceptar cualquier conexión del usuario que la solicite. Tras almacenar el nombre de usuario en la propiedad usuario de newClient: newClient.usuario, recorremos application.clients y almacenamos en un Array el nombre de cada uno de los usuarios conectados a la vez que invocamos el método nuevoUsuario (implementado en el cliente) en cada uno de ellos. El método nuevoUsuario se podría encargar de mostrar al usuario las nuevas conexiones.
Una vez recorrido todo el array de clientes y generado el array con los nombres, invocamos el método listarUsuarios en el lado cliente, pero esta vez sólo para el usuario que ha solicitado la conexión. A través de esta llamada facilitaremos al nuevo cliente el listado de usuarios que hemos generado.
Vemos entonces que esta modificación haría que la aplicación se comportara tal como deseábamos. Si la concurrencia de usuarios de la aplicación fuera pequeña no sufriríamos una gran pérdida de eficiencia. Ahora bien, si por ejemplo tuviéramos un total de 100 usuarios para notificar o más, esta implementación utilizaría los recursos del servidor de una forma ineficiente y podría ralentizar el funcionamiento general introduciendo retardos innecesarios en el intercambio de información. Estos problemas se acentuarían aún más si tuviéramos que hacer múltiples notificaciones a los usuarios sobre distintos eventos. Imaginemos el caso de un Chat. En un Chat un usuario escribe un mensaje y lo manda al servidor para que éste lo reenvíe al resto de usuarios. Durante este proceso puede existir una gran concurrencia de datos ya que varios usuarios pueden estar mandando información simultáneamente al servidor para que éste la reenvíe. En esta situación y con el planteamiento anterior, mantendríamos ocupado al servidor un gran porcentaje de tiempo, tan sólo para recorrer una vez tras otra el vector de usuarios.
Si analizamos de nuevo el problema nos damos cuenta que el listado de usuarios lo podríamos entender como un recurso compartido al que todos los usuarios tendrían acceso en todo momento, tanto para recibir notificaciones sobre modificaciones como para realizarlas (contemplamos la opción de modificar el nombre de usuario propio).
La descripción anterior corresponde a una de las múltiples definiciones o funcionalidades que podemos dar a los SharedObjects.
Clasificación de SharedObject
En su esencia cualquier tipo de SharedObject es un almacén de datos sincronizados con una estructura para gestionar notificaciones de cambio, borrado o adición en dichos datos. Atendiendo al ámbito o a la durabilidad/persistencia de estos almacenes podemos clasificar los SO’s (SharedObjects) en remotos o local